mirror of https://github.com/golang/go.git
net/http: update bundled http2, add test for Transport's User-Agent behavior
Adds a test that both http1 and http2's Transport send a default User-Agent, with the same behavior. Updates bundled http2 to golang.org/x/net git rev 1ade16a545 (for https://go-review.googlesource.com/18285) The http1 behavior changes slightly: if req.Header["User-Agent"] is defined at all, even if it's nil or a zero-length slice, then the User-Agent header is omitted. This is a slight behavior change for http1, but is consistent with how http1 & http2 do optional headers elsewhere (such as "Date", "Content-Type"). The old behavior (set it explicitly to "", aka []string{""}) still works as before. And now there are even tests. Fixes #13685 Change-Id: I5786a6913b560de4a5f1f90e595fe320ff567adf Reviewed-on: https://go-review.googlesource.com/18284 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
a4f10bddc3
commit
194a5c3e61
|
|
@ -734,3 +734,64 @@ func testConnectRequest(t *testing.T, h2 bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransportUserAgent_h1(t *testing.T) { testTransportUserAgent(t, h1Mode) }
|
||||||
|
func TestTransportUserAgent_h2(t *testing.T) { testTransportUserAgent(t, h2Mode) }
|
||||||
|
func testTransportUserAgent(t *testing.T, h2 bool) {
|
||||||
|
defer afterTest(t)
|
||||||
|
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||||
|
fmt.Fprintf(w, "%q", r.Header["User-Agent"])
|
||||||
|
}))
|
||||||
|
defer cst.close()
|
||||||
|
|
||||||
|
either := func(a, b string) string {
|
||||||
|
if h2 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
setup func(*Request)
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
func(r *Request) {},
|
||||||
|
either(`["Go-http-client/1.1"]`, `["Go-http-client/2.0"]`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
func(r *Request) { r.Header.Set("User-Agent", "foo/1.2.3") },
|
||||||
|
`["foo/1.2.3"]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
func(r *Request) { r.Header["User-Agent"] = []string{"single", "or", "multiple"} },
|
||||||
|
`["single"]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
func(r *Request) { r.Header.Set("User-Agent", "") },
|
||||||
|
`[]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
func(r *Request) { r.Header["User-Agent"] = nil },
|
||||||
|
`[]`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
req, _ := NewRequest("GET", cst.ts.URL, nil)
|
||||||
|
tt.setup(req)
|
||||||
|
res, err := cst.c.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d. RoundTrip = %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slurp, err := ioutil.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d. read body = %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if string(slurp) != tt.want {
|
||||||
|
t.Errorf("%d. body mismatch.\n got: %s\nwant: %s\n", i, slurp, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/net/http2/hpack"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -38,6 +37,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2/hpack"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientConnPool manages a pool of HTTP/2 client connections.
|
// ClientConnPool manages a pool of HTTP/2 client connections.
|
||||||
|
|
@ -4095,6 +4096,8 @@ const (
|
||||||
// transportDefaultStreamMinRefresh is the minimum number of bytes we'll send
|
// transportDefaultStreamMinRefresh is the minimum number of bytes we'll send
|
||||||
// a stream-level WINDOW_UPDATE for at a time.
|
// a stream-level WINDOW_UPDATE for at a time.
|
||||||
http2transportDefaultStreamMinRefresh = 4 << 10
|
http2transportDefaultStreamMinRefresh = 4 << 10
|
||||||
|
|
||||||
|
http2defaultUserAgent = "Go-http-client/2.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transport is an HTTP/2 Transport.
|
// Transport is an HTTP/2 Transport.
|
||||||
|
|
@ -4794,11 +4797,23 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
|
||||||
cc.writeHeader("trailer", trailers)
|
cc.writeHeader("trailer", trailers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var didUA bool
|
||||||
for k, vv := range req.Header {
|
for k, vv := range req.Header {
|
||||||
lowKey := strings.ToLower(k)
|
lowKey := strings.ToLower(k)
|
||||||
if lowKey == "host" {
|
if lowKey == "host" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if lowKey == "user-agent" {
|
||||||
|
|
||||||
|
didUA = true
|
||||||
|
if len(vv) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vv = vv[:1]
|
||||||
|
if vv[0] == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, v := range vv {
|
for _, v := range vv {
|
||||||
cc.writeHeader(lowKey, v)
|
cc.writeHeader(lowKey, v)
|
||||||
}
|
}
|
||||||
|
|
@ -4806,6 +4821,9 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
|
||||||
if addGzipHeader {
|
if addGzipHeader {
|
||||||
cc.writeHeader("accept-encoding", "gzip")
|
cc.writeHeader("accept-encoding", "gzip")
|
||||||
}
|
}
|
||||||
|
if !didUA {
|
||||||
|
cc.writeHeader("user-agent", http2defaultUserAgent)
|
||||||
|
}
|
||||||
return cc.hbuf.Bytes()
|
return cc.hbuf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -427,10 +427,8 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
|
||||||
// Use the defaultUserAgent unless the Header contains one, which
|
// Use the defaultUserAgent unless the Header contains one, which
|
||||||
// may be blank to not send the header.
|
// may be blank to not send the header.
|
||||||
userAgent := defaultUserAgent
|
userAgent := defaultUserAgent
|
||||||
if req.Header != nil {
|
if _, ok := req.Header["User-Agent"]; ok {
|
||||||
if ua := req.Header["User-Agent"]; len(ua) > 0 {
|
userAgent = req.Header.Get("User-Agent")
|
||||||
userAgent = ua[0]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if userAgent != "" {
|
if userAgent != "" {
|
||||||
_, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
|
_, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue