Commit 1535727e authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder Committed by Brad Fitzpatrick

net/http: do not send redundant Connection: close header in HTTP/1.0 responses

HTTP/1.0 connections are closed implicitly, unless otherwise specified.

Note that this change does not test or fix "request too large" responses.
Reasoning: (a) it complicates tests and fixes, (b) they should be rare,
and (c) this is just a minor wire optimization, and thus not really worth worrying
about in this context.

Fixes #5955.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12435043
parent ebe91d11
......@@ -1757,6 +1757,64 @@ func TestWriteAfterHijack(t *testing.T) {
}
}
// http://code.google.com/p/go/issues/detail?id=5955
// Note that this does not test the "request too large"
// exit path from the http server. This is intentional;
// not sending Connection: close is just a minor wire
// optimization and is pointless if dealing with a
// badly behaved client.
func TestHTTP10ConnectionHeader(t *testing.T) {
defer afterTest(t)
mux := NewServeMux()
mux.Handle("/", HandlerFunc(func(resp ResponseWriter, req *Request) {}))
ts := httptest.NewServer(mux)
defer ts.Close()
// net/http uses HTTP/1.1 for requests, so write requests manually
tests := []struct {
req string // raw http request
expect []string // expected Connection header(s)
}{
{
req: "GET / HTTP/1.0\r\n\r\n",
expect: nil,
},
{
req: "OPTIONS * HTTP/1.0\r\n\r\n",
expect: nil,
},
{
req: "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n",
expect: []string{"keep-alive"},
},
}
for _, tt := range tests {
conn, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil {
t.Fatal("dial err:", err)
}
_, err = fmt.Fprint(conn, tt.req)
if err != nil {
t.Fatal("conn write err:", err)
}
resp, err := ReadResponse(bufio.NewReader(conn), &Request{Method: "GET"})
if err != nil {
t.Fatal("ReadResponse err:", err)
}
conn.Close()
resp.Body.Close()
got := resp.Header["Connection"]
if !reflect.DeepEqual(got, tt.expect) {
t.Errorf("wrong Connection headers for request %q. Got %q expect %q", got, tt.expect)
}
}
}
func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs()
b.StopTimer()
......
......@@ -850,7 +850,9 @@ func (cw *chunkWriter) writeHeader(p []byte) {
if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") {
delHeader("Connection")
setHeader.connection = "close"
if w.req.ProtoAtLeast(1, 1) {
setHeader.connection = "close"
}
}
w.conn.buf.WriteString(statusLine(w.req, code))
......@@ -1458,7 +1460,9 @@ func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
w.Header().Set("Connection", "close")
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment