diff options
author | Anmol Sethi <hi@nhooyr.io> | 2020-10-24 00:40:41 +0000 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2020-12-01 19:47:12 +0000 |
commit | 50b16f9de590822a04ec8d6cbac476366c1bde32 (patch) | |
tree | fb46c24ff85b7588e475de44092b1284f58c46fa /src/net/http/serve_test.go | |
parent | 212d385a2f723a8dd5e7d2e83efb478ddd139349 (diff) | |
download | go-50b16f9de590822a04ec8d6cbac476366c1bde32.tar.gz go-50b16f9de590822a04ec8d6cbac476366c1bde32.zip |
net/http: allow upgrading non keepalive connections
If one was using http.Transport with DisableKeepAlives and trying
to upgrade a connection against net/http's Server, the Server
would not allow a "Connection: Upgrade" header to be written
and instead override it to "Connection: Close" which would
break the handshake.
This change ensures net/http's Server does not override the
connection header for successful protocol switch responses.
Fixes #36381.
Change-Id: I882aad8539e6c87ff5f37c20e20b3a7fa1a30357
GitHub-Last-Rev: dc0de83201dc26236527b68bd49dffc53dd0389b
GitHub-Pull-Request: golang/go#36382
Reviewed-on: https://go-review.googlesource.com/c/go/+/213277
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
Trust: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/net/http/serve_test.go')
-rw-r--r-- | src/net/http/serve_test.go | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index ba54b31a29..b1bf8e6c5e 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -6448,3 +6448,56 @@ func BenchmarkResponseStatusLine(b *testing.B) { } }) } +func TestDisableKeepAliveUpgrade(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + setParallel(t) + defer afterTest(t) + + s := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Connection", "Upgrade") + w.Header().Set("Upgrade", "someProto") + w.WriteHeader(StatusSwitchingProtocols) + c, _, err := w.(Hijacker).Hijack() + if err != nil { + return + } + defer c.Close() + + io.Copy(c, c) + })) + s.Config.SetKeepAlivesEnabled(false) + s.Start() + defer s.Close() + + cl := s.Client() + cl.Transport.(*Transport).DisableKeepAlives = true + + resp, err := cl.Get(s.URL) + if err != nil { + t.Fatalf("failed to perform request: %v", err) + } + defer resp.Body.Close() + + rwc, ok := resp.Body.(io.ReadWriteCloser) + if !ok { + t.Fatalf("Response.Body is not a io.ReadWriteCloser: %T", resp.Body) + } + + _, err = rwc.Write([]byte("hello")) + if err != nil { + t.Fatalf("failed to write to body: %v", err) + } + + b := make([]byte, 5) + _, err = io.ReadFull(rwc, b) + if err != nil { + t.Fatalf("failed to read from body: %v", err) + } + + if string(b) != "hello" { + t.Fatalf("unexpected value read from body:\ngot: %q\nwant: %q", b, "hello") + } +} |