From 49f29c9c22f15120811719f4f451c3469e9e174a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 26 Aug 2012 11:17:55 -0700 Subject: [PATCH] net/http: send an explicit zero Content-Length when Handler never Writes Fixes #4004 R=golang-dev, r CC=golang-dev https://golang.org/cl/6472055 --- src/pkg/net/http/serve_test.go | 32 ++++++++++++++++++++++++++++++++ src/pkg/net/http/server.go | 12 ++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/pkg/net/http/serve_test.go b/src/pkg/net/http/serve_test.go index 4624b5f5e4..17b7566b38 100644 --- a/src/pkg/net/http/serve_test.go +++ b/src/pkg/net/http/serve_test.go @@ -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) diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go index a6828dd451..272c8408c7 100644 --- a/src/pkg/net/http/server.go +++ b/src/pkg/net/http/server.go @@ -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" { -- 2.48.1