}
}
}
+
+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)
+ }
+ }
+}
"encoding/binary"
"errors"
"fmt"
- "golang.org/x/net/http2/hpack"
"io"
"io/ioutil"
"log"
"strings"
"sync"
"time"
+
+ "golang.org/x/net/http2/hpack"
)
// ClientConnPool manages a pool of HTTP/2 client connections.
// transportDefaultStreamMinRefresh is the minimum number of bytes we'll send
// a stream-level WINDOW_UPDATE for at a time.
http2transportDefaultStreamMinRefresh = 4 << 10
+
+ http2defaultUserAgent = "Go-http-client/2.0"
)
// Transport is an HTTP/2 Transport.
cc.writeHeader("trailer", trailers)
}
+ var didUA bool
for k, vv := range req.Header {
lowKey := strings.ToLower(k)
if lowKey == "host" {
continue
}
+ if lowKey == "user-agent" {
+
+ didUA = true
+ if len(vv) < 1 {
+ continue
+ }
+ vv = vv[:1]
+ if vv[0] == "" {
+ continue
+ }
+ }
for _, v := range vv {
cc.writeHeader(lowKey, v)
}
if addGzipHeader {
cc.writeHeader("accept-encoding", "gzip")
}
+ if !didUA {
+ cc.writeHeader("user-agent", http2defaultUserAgent)
+ }
return cc.hbuf.Bytes()
}
// Use the defaultUserAgent unless the Header contains one, which
// may be blank to not send the header.
userAgent := defaultUserAgent
- if req.Header != nil {
- if ua := req.Header["User-Agent"]; len(ua) > 0 {
- userAgent = ua[0]
- }
+ if _, ok := req.Header["User-Agent"]; ok {
+ userAgent = req.Header.Get("User-Agent")
}
if userAgent != "" {
_, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)