diff options
author | Meng Zhuo <mengzhuo1203@gmail.com> | 2018-11-27 16:16:43 +0800 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2018-11-28 21:33:21 +0000 |
commit | 9aadbf5755dc8e3c3b0a224f513c92b804a1a3a7 (patch) | |
tree | b2f0bece0b962e59469027ee43a86c52a08c8009 /src/net/http/transport_test.go | |
parent | 4f15b54780af7159732794f9d67c9a8a455bbf61 (diff) | |
download | go-9aadbf5755dc8e3c3b0a224f513c92b804a1a3a7.tar.gz go-9aadbf5755dc8e3c3b0a224f513c92b804a1a3a7.zip |
net/http: prevent transport sends two "Connection: close" headers
There are three functions that do Connection header write:
1. transport.go/ persistConn.roundTrip
2. transfer.go/ transferWriter.writeHeader
3. request.go/ Request.write
The root cause is roundTrip didn't lookup into request.Close and
transferWriter
didn't take care of extraHeaders.
Fixes #28886
Change-Id: I1d131019c7cd42eb1bcc972c631b7df7511c1f39
Reviewed-on: https://go-review.googlesource.com/c/150722
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/net/http/transport_test.go')
-rw-r--r-- | src/net/http/transport_test.go | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 22ca3f9550..1021ce5aa2 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -41,6 +41,8 @@ import ( "sync/atomic" "testing" "time" + + "golang_org/x/net/http/httpguts" ) // TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close @@ -310,6 +312,58 @@ func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) { } } +// Test that Transport only sends one "Connection: close", regardless of +// how "close" was indicated. +func TestTransportRespectRequestWantsClose(t *testing.T) { + tests := []struct { + disableKeepAlives bool + close bool + }{ + {disableKeepAlives: false, close: false}, + {disableKeepAlives: false, close: true}, + {disableKeepAlives: true, close: false}, + {disableKeepAlives: true, close: true}, + } + + for _, tc := range tests { + t.Run(fmt.Sprintf("DisableKeepAlive=%v,RequestClose=%v", tc.disableKeepAlives, tc.close), + func(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(hostPortHandler) + defer ts.Close() + + c := ts.Client() + c.Transport.(*Transport).DisableKeepAlives = tc.disableKeepAlives + req, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + count := 0 + trace := &httptrace.ClientTrace{ + WroteHeaderField: func(key string, field []string) { + if key != "Connection" { + return + } + if httpguts.HeaderValuesContainsToken(field, "close") { + count += 1 + } + }, + } + req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) + req.Close = tc.close + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if want := tc.disableKeepAlives || tc.close; count > 1 || (count == 1) != want { + t.Errorf("expecting want:%v, got 'Connection: close':%d", want, count) + } + }) + } + +} + func TestTransportIdleCacheKeys(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(hostPortHandler) |