]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: allow clients to disable keep-alive
authorGustavo Niemeyer <gustavo@niemeyer.net>
Tue, 24 Apr 2012 01:00:16 +0000 (22:00 -0300)
committerGustavo Niemeyer <gustavo@niemeyer.net>
Tue, 24 Apr 2012 01:00:16 +0000 (22:00 -0300)
Fixes #3540.

R=golang-dev, bradfitz, gustavo
CC=golang-dev
https://golang.org/cl/5996044

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

index f5bc6eb9100fb9aeca4d92e94f70e29fcc138c1e..219db483b48656be259e65a2341cf1e94020a39f 100644 (file)
@@ -732,12 +732,24 @@ func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, e
 }
 
 func (r *Request) expectsContinue() bool {
-       return strings.ToLower(r.Header.Get("Expect")) == "100-continue"
+       return hasToken(r.Header.Get("Expect"), "100-continue")
 }
 
 func (r *Request) wantsHttp10KeepAlive() bool {
        if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
                return false
        }
-       return strings.Contains(strings.ToLower(r.Header.Get("Connection")), "keep-alive")
+       return hasToken(r.Header.Get("Connection"), "keep-alive")
+}
+
+func (r *Request) wantsClose() bool {
+       return hasToken(r.Header.Get("Connection"), "close")
+}
+
+func hasToken(s, token string) bool {
+       if s == "" {
+               return false
+       }
+       // TODO This is a poor implementation of the RFC. See http://golang.org/issue/3535
+       return strings.Contains(strings.ToLower(s), token)
 }
index b6a6b4c77d159eac5361e5eff6ad80c8950f31e0..8b9592d181db2aeed0d3f1ea41defbe7b4050e17 100644 (file)
@@ -370,7 +370,7 @@ func TestIdentityResponse(t *testing.T) {
        })
 }
 
-func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
+func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
        s := httptest.NewServer(h)
        defer s.Close()
 
@@ -410,21 +410,28 @@ func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
 
 // TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
 func TestServeHTTP10Close(t *testing.T) {
-       testTcpConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+       testTCPConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
                ServeFile(w, r, "testdata/file")
        }))
 }
 
+// TestClientCanClose verifies that clients can also force a connection to close.
+func TestClientCanClose(t *testing.T) {
+       testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+               // Nothing.
+       }))
+}
+
 // TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close,
 // even for HTTP/1.1 requests.
 func TestHandlersCanSetConnectionClose11(t *testing.T) {
-       testTcpConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+       testTCPConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
                w.Header().Set("Connection", "close")
        }))
 }
 
 func TestHandlersCanSetConnectionClose10(t *testing.T) {
-       testTcpConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+       testTCPConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
                w.Header().Set("Connection", "close")
        }))
 }
index 924ffd348156e030a98e227ec4bb5691761af46e..ae93db8070de7471c8a652d264c3189ee7e584b4 100644 (file)
@@ -303,8 +303,7 @@ func (w *response) WriteHeader(code int) {
                if !connectionHeaderSet {
                        w.header.Set("Connection", "keep-alive")
                }
-       } else if !w.req.ProtoAtLeast(1, 1) {
-               // Client did not ask to keep connection alive.
+       } else if !w.req.ProtoAtLeast(1, 1) || w.req.wantsClose() {
                w.closeAfterReply = true
        }