From 5dbdd798168ecd5b594bc89c03c9d56bcc9849b3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Filip=20Gruszczy=C5=84ski?= Date: Sat, 11 Mar 2017 13:38:14 -0800 Subject: [PATCH] net/http: Don't write 'Connection: close' header multiple times. When writing the 'Connection: close' header based on response Close attribute we also check if it is already in the headers scheduled to be written and skip if necessary. Fixes #19499 Change-Id: I92357344a37ae385454ec8006114fa4cfa585810 Reviewed-on: https://go-review.googlesource.com/38076 Run-TryBot: Brad Fitzpatrick Reviewed-by: Emmanuel Odeke Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/response_test.go | 26 ++++++++++++++++++++++++++ src/net/http/transfer.go | 5 ++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go index 8b8c90ef50..f1a50bd598 100644 --- a/src/net/http/response_test.go +++ b/src/net/http/response_test.go @@ -949,3 +949,29 @@ func TestNeedsSniff(t *testing.T) { t.Errorf("needsSniff empty Content-Type = %t; want %t", got, want) } } + +// A response should only write out single Connection: close header. Tests #19499. +func TestResponseWritesOnlySingleConnectionClose(t *testing.T) { + const connectionCloseHeader = "Connection: close" + + res, err := ReadResponse(bufio.NewReader(strings.NewReader("HTTP/1.0 200 OK\r\n\r\nAAAA")), nil) + if err != nil { + t.Fatalf("ReadResponse failed %v", err) + } + + var buf1 bytes.Buffer + if err = res.Write(&buf1); err != nil { + t.Fatalf("Write failed %v", err) + } + if res, err = ReadResponse(bufio.NewReader(&buf1), nil); err != nil { + t.Fatalf("ReadResponse failed %v", err) + } + + var buf2 bytes.Buffer + if err = res.Write(&buf2); err != nil { + t.Fatalf("Write failed %v", err) + } + if count := strings.Count(buf2.String(), connectionCloseHeader); count != 1 { + t.Errorf("Found %d %q header", count, connectionCloseHeader) + } +} diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go index 2a021154c9..f87f80f51b 100644 --- a/src/net/http/transfer.go +++ b/src/net/http/transfer.go @@ -75,6 +75,7 @@ type transferWriter struct { ContentLength int64 // -1 means unknown, 0 means exactly none Close bool TransferEncoding []string + Header Header Trailer Header IsResponse bool bodyReadError error // any non-EOF error from reading Body @@ -96,6 +97,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { t.Method = valueOrDefault(rr.Method, "GET") t.Close = rr.Close t.TransferEncoding = rr.TransferEncoding + t.Header = rr.Header t.Trailer = rr.Trailer atLeastHTTP11 = rr.protoAtLeastOutgoing(1, 1) t.Body = rr.Body @@ -114,6 +116,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { t.ContentLength = rr.ContentLength t.Close = rr.Close t.TransferEncoding = rr.TransferEncoding + t.Header = rr.Header t.Trailer = rr.Trailer atLeastHTTP11 = rr.ProtoAtLeast(1, 1) t.ResponseToHEAD = noResponseBodyExpected(t.Method) @@ -266,7 +269,7 @@ func (t *transferWriter) shouldSendContentLength() bool { } func (t *transferWriter) WriteHeader(w io.Writer) error { - if t.Close { + if t.Close && !hasToken(t.Header.get("Connection"), "close") { if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil { return err } -- 2.50.0