1
0
mirror of https://github.com/golang/go synced 2024-11-26 05:37:57 -07:00

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
This commit is contained in:
Josh Bleecher Snyder 2013-08-06 18:37:34 -07:00 committed by Brad Fitzpatrick
parent ebe91d1105
commit 1535727e57
2 changed files with 64 additions and 2 deletions

View File

@ -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) { func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.StopTimer() b.StopTimer()

View File

@ -850,8 +850,10 @@ func (cw *chunkWriter) writeHeader(p []byte) {
if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") { if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") {
delHeader("Connection") delHeader("Connection")
if w.req.ProtoAtLeast(1, 1) {
setHeader.connection = "close" setHeader.connection = "close"
} }
}
w.conn.buf.WriteString(statusLine(w.req, code)) w.conn.buf.WriteString(statusLine(w.req, code))
cw.header.WriteSubset(w.conn.buf, excludeHeader) cw.header.WriteSubset(w.conn.buf, excludeHeader)
@ -1458,7 +1460,9 @@ func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
// pattern most closely matches the request URL. // pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" { if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close") w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest) w.WriteHeader(StatusBadRequest)
return return
} }