]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: send an explicit zero Content-Length when Handler never Writes
authorBrad Fitzpatrick <bradfitz@golang.org>
Sun, 26 Aug 2012 18:17:55 +0000 (11:17 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Sun, 26 Aug 2012 18:17:55 +0000 (11:17 -0700)
Fixes #4004

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6472055

src/pkg/net/http/serve_test.go
src/pkg/net/http/server.go

index 4624b5f5e4e118e88141dcae56532a10017689df..17b7566b381dc3ec733d12f42d50155392f05701 100644 (file)
@@ -1207,6 +1207,38 @@ func TestCaseSensitiveMethod(t *testing.T) {
        res.Body.Close()
 }
 
+// TestContentLengthZero tests that for both an HTTP/1.0 and HTTP/1.1
+// request (both keep-alive), when a Handler never writes any
+// response, the net/http package adds a "Content-Length: 0" response
+// header.
+func TestContentLengthZero(t *testing.T) {
+       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {}))
+       defer ts.Close()
+
+       for _, version := range []string{"HTTP/1.0", "HTTP/1.1"} {
+               conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+               if err != nil {
+                       t.Fatalf("error dialing: %v", err)
+               }
+               _, err = fmt.Fprintf(conn, "GET / %v\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n", version)
+               if err != nil {
+                       t.Fatalf("error writing: %v", err)
+               }
+               req, _ := NewRequest("GET", "/", nil)
+               res, err := ReadResponse(bufio.NewReader(conn), req)
+               if err != nil {
+                       t.Fatalf("error reading response: %v", err)
+               }
+               if te := res.TransferEncoding; len(te) > 0 {
+                       t.Errorf("For version %q, Transfer-Encoding = %q; want none", version, te)
+               }
+               if cl := res.ContentLength; cl != 0 {
+                       t.Errorf("For version %q, Content-Length = %v; want 0", version, cl)
+               }
+               conn.Close()
+       }
+}
+
 // goTimeout runs f, failing t if f takes more than ns to complete.
 func goTimeout(t *testing.T, d time.Duration, f func()) {
        ch := make(chan bool, 2)
index a6828dd4517d980eb9914426b78e0aa264fb4937..272c8408c78a7a731946652b858fc648458680b5 100644 (file)
@@ -512,8 +512,16 @@ func (w *response) Write(data []byte) (n int, err error) {
 }
 
 func (w *response) finishRequest() {
-       // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
-       // back, we can make this a keep-alive response ...
+       // If the handler never wrote any bytes and never sent a Content-Length
+       // response header, set the length explicitly to zero. This helps
+       // HTTP/1.0 clients keep their "keep-alive" connections alive, and for
+       // HTTP/1.1 clients is just as good as the alternative: sending a
+       // chunked response and immediately sending the zero-length EOF chunk.
+       if w.written == 0 && w.header.get("Content-Length") == "" {
+               w.header.Set("Content-Length", "0")
+       }
+       // If this was an HTTP/1.0 request with keep-alive and we sent a
+       // Content-Length back, we can make this a keep-alive response ...
        if w.req.wantsHttp10KeepAlive() {
                sentLength := w.header.get("Content-Length") != ""
                if sentLength && w.header.get("Connection") == "keep-alive" {