From ae69b78ba6dda3239845bb69d462091078f08592 Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Sat, 9 Jul 2022 19:47:19 +0200 Subject: [PATCH 01/74] updated go mod; --- .gitignore | 3 ++- go.mod | 11 +++++++---- go.sum | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 314f02b1..f5fadfbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.txt \ No newline at end of file +*.txt +.idea \ No newline at end of file diff --git a/go.mod b/go.mod index 411eb8c0..c44051a6 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,12 @@ module github.com/Carcraftz/fhttp -go 1.16 +go 1.18 require ( - github.com/andybalholm/brotli v1.0.3 - golang.org/x/net v0.0.0-20210610132358-84b48f89b13b - golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b + github.com/Carcraftz/utls v0.0.0-20220413235215-6b7c52fd78b6 + github.com/andybalholm/brotli v1.0.4 + golang.org/x/net v0.0.0-20220420153159-1850ba15e1be + golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 ) + +replace github.com/Carcraftz/utls => ../utls diff --git a/go.sum b/go.sum index 18574203..2a84d5d4 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,36 @@ -github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= +gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= +gitlab.com/yawning/utls.git v0.0.12-1 h1:RL6O0MP2YI0KghuEU/uGN6+8b4183eqNWoYgx7CXD0U= +gitlab.com/yawning/utls.git v0.0.12-1/go.mod h1:3ONKiSFR9Im/c3t5RKmMJTVdmZN496FNyk3mjrY1dyo= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220420153159-1850ba15e1be h1:yx80W7nvY5ySWpaU8UWaj5o9e23YgO9BRhQol7Lc+JI= +golang.org/x/net v0.0.0-20220420153159-1850ba15e1be/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From de6fdcde32cb4fb0f74b684bc65bfa38fc88315e Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Fri, 22 Apr 2022 00:00:19 +0200 Subject: [PATCH 02/74] refs #11: make http2 settings configureable and orderable; --- http2/transport.go | 90 ++++++++++++++++++++++++++++++++++------------ transport.go | 3 +- 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/http2/transport.go b/http2/transport.go index 8f00dce6..e721995f 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -11,9 +11,9 @@ import ( "bytes" "context" "crypto/rand" - tls "github.com/Carcraftz/utls" "errors" "fmt" + tls "github.com/Carcraftz/utls" "io" "io/ioutil" "log" @@ -96,7 +96,7 @@ type Transport struct { // want to advertise an unlimited value to the peer, Transport // interprets the highest possible value here (0xffffffff or 1<<32-1) // to mean no limit. - MaxHeaderListSize uint32 + // MaxHeaderListSize uint32 // StrictMaxConcurrentStreams controls whether the server's // SETTINGS_MAX_CONCURRENT_STREAMS should be respected @@ -144,19 +144,27 @@ type Transport struct { connPoolOrDef ClientConnPool // non-nil version of ConnPool // Settings should not include InitialWindowSize or HeaderTableSize, set that in Transport - Settings []Setting + Settings map[SettingID]uint32 + SettingsOrder []SettingID + // Settings []Setting InitialWindowSize uint32 // if nil, will use global initialWindowSize HeaderTableSize uint32 // if nil, will use global initialHeaderTableSize } func (t *Transport) maxHeaderListSize() uint32 { - if t.MaxHeaderListSize == 0 { + maxHeaderListSize, ok := t.Settings[SettingMaxHeaderListSize] + + if !ok { + maxHeaderListSize = 0 + } + + if maxHeaderListSize == 0 { return 10 << 20 } - if t.MaxHeaderListSize == 0xffffffff { + if maxHeaderListSize == 0xffffffff { return 0 } - return t.MaxHeaderListSize + return maxHeaderListSize } func (t *Transport) disableCompression() bool { @@ -235,12 +243,20 @@ func configureTransports(t1 *http.Transport) (*Transport, error) { // // TODO: also add this to x/net/http2.Configure Transport, behind // a +build go1.7 build tag: - if limit1 := t1.MaxResponseHeaderBytes; limit1 != 0 && t2.MaxHeaderListSize == 0 { + + maxHeaderListSize, ok := t2.Settings[SettingMaxHeaderListSize] + + if !ok { + // we specified in our custom map to not include SettingMaxHeaderListSize + return t2, nil + } + + if limit1 := t1.MaxResponseHeaderBytes; limit1 != 0 && maxHeaderListSize == 0 { const h2max = 1<<32 - 1 if limit1 >= h2max { - t2.MaxHeaderListSize = h2max + t2.Settings[SettingMaxHeaderListSize] = h2max } else { - t2.MaxHeaderListSize = uint32(limit1) + t2.Settings[SettingMaxHeaderListSize] = uint32(limit1) } } return t2, nil @@ -714,11 +730,15 @@ func (t *Transport) newClientConn(c net.Conn, addr string, singleUse bool) (*Cli cc.bw = bufio.NewWriter(stickyErrWriter{c, &cc.werr}) cc.br = bufio.NewReader(c) cc.fr = NewFramer(cc.bw, cc.br) - if t.HeaderTableSize != 0 { - cc.fr.ReadMetaHeaders = hpack.NewDecoder(t.HeaderTableSize, nil) + + customHeaderTableSize, ok := t.Settings[SettingHeaderTableSize] + + if ok { + cc.fr.ReadMetaHeaders = hpack.NewDecoder(customHeaderTableSize, nil) } else { cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil) } + cc.fr.MaxHeaderListSize = t.maxHeaderListSize() // TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on @@ -740,21 +760,42 @@ func (t *Transport) newClientConn(c net.Conn, addr string, singleUse bool) (*Cli if t.PushHandler != nil { pushEnabled = 1 } - initialSettings = append(initialSettings, Setting{ID: SettingEnablePush, Val: pushEnabled}) - setMaxHeader := false + //setMaxHeader := false if t.Settings != nil { - for _, setting := range t.Settings { - if setting.ID == SettingMaxHeaderListSize { - setMaxHeader = true + // we need to iterate over the slice here not the map because of the random range over a map + for _, settingId := range t.SettingsOrder { + settingValue := t.Settings[settingId] + + if settingId == SettingMaxHeaderListSize && settingValue != 0 { + // setMaxHeader = true + if settingValue != 0 { + initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: settingValue}) + continue + } + } - if setting.ID == SettingHeaderTableSize || setting.ID == SettingInitialWindowSize { - return nil, errSettingsIncludeIllegalSettings + if settingId == SettingHeaderTableSize || settingId == SettingInitialWindowSize { + // return nil, errSettingsIncludeIllegalSettings } - initialSettings = append(initialSettings, setting) + + initialSettings = append(initialSettings, Setting{ID: settingId, Val: settingValue}) } + } else { + // when we dont define a custom map on the transport we add Enable Push per default + initialSettings = append(initialSettings, Setting{ID: SettingEnablePush, Val: pushEnabled}) + } + + if _, ok := t.Settings[SettingInitialWindowSize]; !ok { + initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}) } - if t.InitialWindowSize != 0 { + + if _, ok := t.Settings[SettingHeaderTableSize]; !ok { + initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: initialHeaderTableSize}) + } + + // TODO: remove that + /*if t.InitialWindowSize != 0 { initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: t.InitialWindowSize}) } else { initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}) @@ -764,9 +805,12 @@ func (t *Transport) newClientConn(c net.Conn, addr string, singleUse bool) (*Cli } else { initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: initialHeaderTableSize}) } - if max := t.maxHeaderListSize(); max != 0 && !setMaxHeader { - initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max}) - } + */ + + /* + if max := t.maxHeaderListSize(); max != 0 && !setMaxHeader { + initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max}) + }*/ cc.bw.Write(clientPreface) cc.fr.WriteSettings(initialSettings...) diff --git a/transport.go b/transport.go index 851958d3..9cf91f04 100644 --- a/transport.go +++ b/transport.go @@ -14,9 +14,9 @@ import ( "container/list" "context" - tls "github.com/Carcraftz/utls" "errors" "fmt" + tls "github.com/Carcraftz/utls" "io" "log" "net" @@ -119,7 +119,6 @@ type Transport struct { // // If Proxy is nil or returns a nil *URL, no proxy is used. Proxy func(*Request) (*url.URL, error) - // DialContext specifies the dial function for creating unencrypted TCP connections. // If DialContext is nil (and the deprecated Dial below is also nil), // then the transport dials using package net. From 26d2bc4a17d3e2bc23b92b453854881c0e320366 Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Fri, 22 Apr 2022 21:45:18 +0200 Subject: [PATCH 03/74] fixed test; --- http2/fhttp_test.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/http2/fhttp_test.go b/http2/fhttp_test.go index b5388e4a..145dc369 100644 --- a/http2/fhttp_test.go +++ b/http2/fhttp_test.go @@ -2,12 +2,13 @@ package http2_test import ( "bytes" - tls "github.com/Carcraftz/utls" + gtls "crypto/tls" "crypto/x509" "errors" "fmt" "github.com/Carcraftz/fhttp/cookiejar" "github.com/Carcraftz/fhttp/httptest" + tls "github.com/Carcraftz/utls" "golang.org/x/net/publicsuffix" "log" ghttp "net/http" @@ -79,15 +80,25 @@ func compareSettings(ID http2.SettingID, output uint32, expected uint32) error { // Round trip test, makes sure that the changes made doesn't break the library func TestRoundTrip(t *testing.T) { - settings := []http2.Setting{ - {ID: http2.SettingHeaderTableSize, Val: 65536}, - {ID: http2.SettingMaxConcurrentStreams, Val: 1000}, - {ID: http2.SettingInitialWindowSize, Val: 6291456}, - {ID: http2.SettingMaxFrameSize, Val: 16384}, - {ID: http2.SettingMaxHeaderListSize, Val: 262144}, + settings := map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 65536, + http2.SettingMaxConcurrentStreams: 1000, + http2.SettingInitialWindowSize: 6291456, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: 262144, + } + + settingsOrder := []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, } + tr := http2.Transport{ - Settings: settings, + Settings: settings, + SettingsOrder: settingsOrder, } req, err := http.NewRequest("GET", "www.google.com", nil) if err != nil { @@ -214,7 +225,7 @@ func TestGClient_Load(t *testing.T) { Transport: &ghttp.Transport{ ForceAttemptHTTP2: true, Proxy: ghttp.ProxyURL(u), - TLSClientConfig: &tls.Config{ + TLSClientConfig: >ls.Config{ RootCAs: pool, }, }, From 99257bd4b7d56b73dfff2280ec484eacf1f4e39a Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Tue, 24 May 2022 23:31:58 +0200 Subject: [PATCH 04/74] reimplemented response body decompression; --- h2_bundle.go | 2 + http2/transport.go | 28 ++++--- transport.go | 195 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 11 deletions(-) diff --git a/h2_bundle.go b/h2_bundle.go index 2c1ad0ed..4223816d 100644 --- a/h2_bundle.go +++ b/h2_bundle.go @@ -8977,6 +8977,8 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http res.Body = http2transportResponseBody{cs} go cs.awaitRequestCancel(cs.req) + res.Body = DecompressBody(res) + return res, nil } diff --git a/http2/transport.go b/http2/transport.go index e721995f..a53e9914 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -328,14 +328,15 @@ type ClientConn struct { // clientStream is the state for a single HTTP/2 stream. One of these // is created for each Transport.RoundTrip call. type clientStream struct { - cc *ClientConn - req *http.Request - trace *httptrace.ClientTrace // or nil - ID uint32 - resc chan resAndError - bufPipe pipe // buffered pipe with the flow-controlled response payload - startedWrite bool // started request body write; guarded by cc.mu - on100 func() // optional code to run if get a 100 continue response + cc *ClientConn + req *http.Request + trace *httptrace.ClientTrace // or nil + ID uint32 + resc chan resAndError + requestedGzip bool + bufPipe pipe // buffered pipe with the flow-controlled response payload + startedWrite bool // started request body write; guarded by cc.mu + on100 func() // optional code to run if get a 100 continue response flow flow // guarded by cc.mu inflow flow // guarded by cc.mu @@ -1153,6 +1154,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf if err := checkConnHeaders(req); err != nil { return nil, false, err } + if cc.idleTimer != nil { cc.idleTimer.Stop() } @@ -1172,11 +1174,12 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf body := req.Body contentLen := actualContentLength(req) hasBody := contentLen != 0 + requestedGzip := cc.requestGzip(req) // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is // sent by writeRequestBody below, along with any Trailers, // again in form HEADERS{1}, CONTINUATION{0,}) - hdrs, err := cc.encodeHeaders(req, trailers, contentLen) + hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen) if err != nil { cc.mu.Unlock() return nil, false, err @@ -1185,6 +1188,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf cs := cc.newStream() cs.req = req cs.trace = httptrace.ContextClientTrace(req.Context()) + cs.requestedGzip = requestedGzip bodyWriter := cc.t.getBodyWriterState(cs, body) cs.on100 = bodyWriter.on100 @@ -1588,7 +1592,7 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) } // requires cc.mu be held. -func (cc *ClientConn) encodeHeaders(req *http.Request, trailers string, contentLength int64) ([]byte, error) { +func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { cc.hbuf.Reset() host := req.Host @@ -1691,7 +1695,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, trailers string, contentL } // Does not include accept-encoding header if its defined in req.Header - if _, ok := hdrs["accept-encoding"]; !ok { + if _, ok := hdrs["accept-encoding"]; !ok && addGzipHeader { hdrs["accept-encoding"] = []string{"gzip, deflate, br"} } @@ -2240,6 +2244,8 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra res.Body = transportResponseBody{cs} go cs.awaitRequestCancel(cs.req) + res.Body = http.DecompressBody(res) + return res, nil } diff --git a/transport.go b/transport.go index 9cf91f04..3e9a359d 100644 --- a/transport.go +++ b/transport.go @@ -11,6 +11,11 @@ package http import ( "bufio" + "bytes" + "compress/flate" + "compress/gzip" + "compress/zlib" + "github.com/andybalholm/brotli" "container/list" "context" @@ -2178,6 +2183,14 @@ func (pc *persistConn) readLoop() { resp.Body = body + if rc.addedGzip { + resp.Body = DecompressBody(resp) + resp.Header.Del("Content-Encoding") + resp.Header.Del("Content-Length") + resp.ContentLength = -1 + resp.Uncompressed = true + } + select { case rc.ch <- responseAndError{res: resp}: case <-rc.callerGone: @@ -2450,6 +2463,11 @@ type requestAndChan struct { cancelKey cancelKey ch chan responseAndError // unbuffered; always send in select on callerGone + // whether the Transport (as opposed to the user client code) + // added the Accept-Encoding gzip header. If the Transport + // set it, only then do we transparently decode the gzip. + addedGzip bool + // Optional blocking chan for Expect: 100-continue (for send). // If the request has an "Expect: 100-continue" header and // the server responds 100 Continue, readLoop send a value @@ -2523,6 +2541,27 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err // uncompress the gzip stream if we were the layer that // requested it. + requestedGzip := false + if !pc.t.DisableCompression && + req.Header.Get("Accept-Encoding") == "" && + req.Header.get("accept-encoding") == "" && + req.Header.Get("Range") == "" && + req.Method != "HEAD" { + // Request gzip, deflate, br if Accept-Encoding is + // not specified + // + // Note that we don't request this for HEAD requests, + // due to a bug in nginx: + // https://trac.nginx.org/nginx/ticket/358 + // https://golang.org/issue/5522 + // + // We don't request gzip if the request is for a range, since + // auto-decoding a portion of a gzipped document will just fail + // anyway. See https://golang.org/issue/8923 + requestedGzip = true + req.extraHeaders().Set("Accept-Encoding", "gzip, deflate, br") + } + var continueCh chan struct{} if req.ProtoAtLeast(1, 1) && req.Body != nil && req.expectsContinue() { continueCh = make(chan struct{}, 1) @@ -2557,6 +2596,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err req: req.Request, cancelKey: req.cancelKey, ch: resc, + addedGzip: requestedGzip, continueCh: continueCh, callerGone: gone, } @@ -2820,3 +2860,158 @@ func (cl *connLRU) remove(pc *persistConn) { func (cl *connLRU) len() int { return len(cl.m) } + +func DecompressBody(res *Response) io.ReadCloser { + ce := res.Header.Get("Content-Encoding") + res.ContentLength = -1 + res.Uncompressed = true + + switch ce { + case "gzip": + return &gzipReader{ + body: res.Body, + } + case "br": + return &brReader{ + body: res.Body, + } + case "deflate": + return identifyDeflate(res.Body) + default: + return res.Body + } +} + +// gzipReader wraps a response body so it can lazily +// call gzip.NewReader on the first call to Read +type gzipReader struct { + _ incomparable + body io.ReadCloser // underlying Response.Body + zr *gzip.Reader // lazily-initialized gzip reader + zerr error // sticky error +} + +func (gz *gzipReader) Read(p []byte) (n int, err error) { + if gz.zerr != nil { + return 0, gz.zerr + } + if gz.zr == nil { + gz.zr, err = gzip.NewReader(gz.body) + if err != nil { + gz.zerr = err + return 0, err + } + } + return gz.zr.Read(p) +} + +func (gz *gzipReader) Close() error { + return gz.body.Close() +} + +// brReader lazily wraps a response body into an +// io.ReadCloser, will call gzip.NewReader on first +// call to read +type brReader struct { + _ incomparable + body io.ReadCloser + zr *brotli.Reader + zerr error +} + +func (br *brReader) Read(p []byte) (n int, err error) { + if br.zerr != nil { + return 0, br.zerr + } + if br.zr == nil { + br.zr = brotli.NewReader(br.body) + } + return br.zr.Read(p) +} + +func (br *brReader) Close() error { + return br.body.Close() +} + +type zlibDeflateReader struct { + _ incomparable + body io.ReadCloser + zr io.ReadCloser + err error +} + +func (z *zlibDeflateReader) Read(p []byte) (n int, err error) { + if z.err != nil { + return 0, z.err + } + if z.zr == nil { + z.zr, err = zlib.NewReader(z.body) + if err != nil { + z.err = err + return 0, z.err + } + } + return z.zr.Read(p) +} + +func (z *zlibDeflateReader) Close() error { + return z.zr.Close() +} + +type deflateReader struct { + _ incomparable + body io.ReadCloser + r io.ReadCloser + err error +} + +func (dr *deflateReader) Read(p []byte) (n int, err error) { + if dr.err != nil { + return 0, dr.err + } + if dr.r == nil { + dr.r = flate.NewReader(dr.body) + } + return dr.r.Read(p) +} + +func (dr *deflateReader) Close() error { + return dr.r.Close() +} + +const ( + zlibMethodDeflate = 0x78 + zlibLevelDefault = 0x9C + zlibLevelLow = 0x01 + zlibLevelMedium = 0x5E + zlibLevelBest = 0xDA +) + +func identifyDeflate(body io.ReadCloser) io.ReadCloser { + var header [2]byte + _, err := io.ReadFull(body, header[:]) + if err != nil { + return body + } + + if header[0] == zlibMethodDeflate && + (header[1] == zlibLevelDefault || header[1] == zlibLevelLow || header[1] == zlibLevelMedium || header[1] == zlibLevelBest) { + return &zlibDeflateReader{ + body: prependBytesToReadCloser(header[:], body), + } + } else if header[0] == zlibMethodDeflate { + return &deflateReader{ + body: prependBytesToReadCloser(header[:], body), + } + } + return body +} + +func prependBytesToReadCloser(b []byte, r io.ReadCloser) io.ReadCloser { + w := new(bytes.Buffer) + w.Write(b) + io.Copy(w, r) + defer r.Close() + + return io.NopCloser(w) +} From 75232e8929628022e37010beaba60aae2e681379 Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Sat, 9 Jul 2022 23:10:16 +0200 Subject: [PATCH 05/74] configure pseudo header order on transport; --- h2_bundle.go | 6 ++++++ http2/transport.go | 15 ++++++++++++--- transport.go | 9 ++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/h2_bundle.go b/h2_bundle.go index 4223816d..a33b9887 100644 --- a/h2_bundle.go +++ b/h2_bundle.go @@ -8381,6 +8381,12 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail // [RFC3986]). pHeaderOrder, ok := req.Header[PHeaderOrderKey] + + if !ok { + pHeaderOrder = cc.t.t1.PseudoHeaderOrder + ok = true + } + m := req.Method if m == "" { m = MethodGet diff --git a/http2/transport.go b/http2/transport.go index a53e9914..bedab387 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -13,7 +13,6 @@ import ( "crypto/rand" "errors" "fmt" - tls "github.com/Carcraftz/utls" "io" "io/ioutil" "log" @@ -28,6 +27,8 @@ import ( "sync/atomic" "time" + tls "github.com/Carcraftz/utls" + http "github.com/Carcraftz/fhttp" "github.com/Carcraftz/fhttp/httptrace" @@ -144,8 +145,10 @@ type Transport struct { connPoolOrDef ClientConnPool // non-nil version of ConnPool // Settings should not include InitialWindowSize or HeaderTableSize, set that in Transport - Settings map[SettingID]uint32 - SettingsOrder []SettingID + Settings map[SettingID]uint32 + SettingsOrder []SettingID + PseudoHeaderOrder []string + // Settings []Setting InitialWindowSize uint32 // if nil, will use global initialWindowSize HeaderTableSize uint32 // if nil, will use global initialHeaderTableSize @@ -1648,6 +1651,12 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail // [RFC3986]). pHeaderOrder, ok := req.Header[http.PHeaderOrderKey] + + if !ok { + pHeaderOrder = cc.t.PseudoHeaderOrder + ok = true + } + m := req.Method if m == "" { m = http.MethodGet diff --git a/transport.go b/transport.go index 3e9a359d..6e5afbda 100644 --- a/transport.go +++ b/transport.go @@ -15,13 +15,10 @@ import ( "compress/flate" "compress/gzip" "compress/zlib" - "github.com/andybalholm/brotli" - "container/list" "context" "errors" "fmt" - tls "github.com/Carcraftz/utls" "io" "log" "net" @@ -34,6 +31,10 @@ import ( "sync/atomic" "time" + "github.com/andybalholm/brotli" + + tls "github.com/Carcraftz/utls" + "github.com/Carcraftz/fhttp/httptrace" "golang.org/x/net/http/httpguts" @@ -279,6 +280,8 @@ type Transport struct { H2transport h2Transport // non-nil if http2 wired up tlsNextProtoWasNil bool // whether TLSNextProto was nil when the Once fired + PseudoHeaderOrder []string + // ForceAttemptHTTP2 controls whether HTTP/2 is enabled when a non-zero // Dial, DialTLS, or DialContext func or TLSClientConfig is provided. // By default, use of any those fields conservatively disables HTTP/2. From e11869d56b2680d4621f0eea69643b820a6f99dc Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Mon, 11 Jul 2022 21:47:55 +0200 Subject: [PATCH 06/74] make ConnectionFlow configurable and prepare for custom tls client; --- go.mod | 12 +++++++++++- go.sum | 10 ++-------- http2/transport.go | 34 ++++++++++------------------------ transport.go | 1 + 4 files changed, 24 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index c44051a6..4d29c684 100644 --- a/go.mod +++ b/go.mod @@ -9,4 +9,14 @@ require ( golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 ) -replace github.com/Carcraftz/utls => ../utls +require ( + github.com/dsnet/compress v0.0.1 // indirect + gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect + gitlab.com/yawning/utls.git v0.0.12-1 // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/text v0.3.7 // indirect +) + +// replace github.com/Carcraftz/utls => ../utls +replace github.com/Carcraftz/utls => github.com/bogdanfinn/utls v0.0.1 diff --git a/go.sum b/go.sum index 2a84d5d4..b98add72 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/bogdanfinn/utls v0.0.1 h1:V5f+fk7TNBpacE/6FIeU/f4LNH5dYXrMkRkIYjyu1G0= +github.com/bogdanfinn/utls v0.0.1/go.mod h1:jtb6Ysg2H4hB0RT+nF0G2UWSA6L4diWUwrah9N1Ln3E= github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -15,22 +17,14 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220420153159-1850ba15e1be h1:yx80W7nvY5ySWpaU8UWaj5o9e23YgO9BRhQol7Lc+JI= golang.org/x/net v0.0.0-20220420153159-1850ba15e1be/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/http2/transport.go b/http2/transport.go index bedab387..094fd98d 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -148,6 +148,7 @@ type Transport struct { Settings map[SettingID]uint32 SettingsOrder []SettingID PseudoHeaderOrder []string + ConnectionFlow uint32 // Settings []Setting InitialWindowSize uint32 // if nil, will use global initialWindowSize @@ -790,35 +791,20 @@ func (t *Transport) newClientConn(c net.Conn, addr string, singleUse bool) (*Cli initialSettings = append(initialSettings, Setting{ID: SettingEnablePush, Val: pushEnabled}) } - if _, ok := t.Settings[SettingInitialWindowSize]; !ok { - initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}) - } - - if _, ok := t.Settings[SettingHeaderTableSize]; !ok { - initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: initialHeaderTableSize}) - } - - // TODO: remove that - /*if t.InitialWindowSize != 0 { - initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: t.InitialWindowSize}) - } else { - initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}) - } - if t.HeaderTableSize != 0 { - initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: t.HeaderTableSize}) - } else { - initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: initialHeaderTableSize}) - } - */ + /* if _, ok := t.Settings[SettingInitialWindowSize]; !ok { + initialSettings = append(initialSettings, Setting{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}) + } - /* - if max := t.maxHeaderListSize(); max != 0 && !setMaxHeader { - initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max}) + if _, ok := t.Settings[SettingHeaderTableSize]; !ok { + initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: initialHeaderTableSize}) }*/ cc.bw.Write(clientPreface) cc.fr.WriteSettings(initialSettings...) - cc.fr.WriteWindowUpdate(0, transportDefaultConnFlow) + + // + + cc.fr.WriteWindowUpdate(0, t.ConnectionFlow) cc.inflow.add(transportDefaultConnFlow + initialWindowSize) cc.bw.Flush() if cc.werr != nil { diff --git a/transport.go b/transport.go index 6e5afbda..c23bf2c4 100644 --- a/transport.go +++ b/transport.go @@ -281,6 +281,7 @@ type Transport struct { tlsNextProtoWasNil bool // whether TLSNextProto was nil when the Once fired PseudoHeaderOrder []string + ConnectionFlow uint32 // ForceAttemptHTTP2 controls whether HTTP/2 is enabled when a non-zero // Dial, DialTLS, or DialContext func or TLSClientConfig is provided. From 6ceccbb6054f21bc739d12cff571627ca82bcedf Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Tue, 12 Jul 2022 23:52:02 +0200 Subject: [PATCH 07/74] added http2 priority frames; --- go.mod | 4 ++-- go.sum | 4 ++-- http2/transport.go | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 4d29c684..a9f91fdc 100644 --- a/go.mod +++ b/go.mod @@ -18,5 +18,5 @@ require ( golang.org/x/text v0.3.7 // indirect ) -// replace github.com/Carcraftz/utls => ../utls -replace github.com/Carcraftz/utls => github.com/bogdanfinn/utls v0.0.1 +//replace github.com/Carcraftz/utls => ../utls +replace github.com/Carcraftz/utls => github.com/bogdanfinn/utls v0.0.2 diff --git a/go.sum b/go.sum index b98add72..0fbddcf6 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/bogdanfinn/utls v0.0.1 h1:V5f+fk7TNBpacE/6FIeU/f4LNH5dYXrMkRkIYjyu1G0= -github.com/bogdanfinn/utls v0.0.1/go.mod h1:jtb6Ysg2H4hB0RT+nF0G2UWSA6L4diWUwrah9N1Ln3E= +github.com/bogdanfinn/utls v0.0.2 h1:5iL1lK4gHiEMvcJzmZHDrvzC3j/1kivYn+JQ0On6/P4= +github.com/bogdanfinn/utls v0.0.2/go.mod h1:jtb6Ysg2H4hB0RT+nF0G2UWSA6L4diWUwrah9N1Ln3E= github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= diff --git a/http2/transport.go b/http2/transport.go index 094fd98d..7fcb2a12 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -147,6 +147,7 @@ type Transport struct { // Settings should not include InitialWindowSize or HeaderTableSize, set that in Transport Settings map[SettingID]uint32 SettingsOrder []SettingID + Priorities []Priority PseudoHeaderOrder []string ConnectionFlow uint32 @@ -155,6 +156,11 @@ type Transport struct { HeaderTableSize uint32 // if nil, will use global initialHeaderTableSize } +type Priority struct { + StreamID uint32 + PriorityParam PriorityParam +} + func (t *Transport) maxHeaderListSize() uint32 { maxHeaderListSize, ok := t.Settings[SettingMaxHeaderListSize] @@ -802,6 +808,9 @@ func (t *Transport) newClientConn(c net.Conn, addr string, singleUse bool) (*Cli cc.bw.Write(clientPreface) cc.fr.WriteSettings(initialSettings...) + for _, priority := range t.Priorities { + cc.fr.WritePriority(priority.StreamID, priority.PriorityParam) + } // cc.fr.WriteWindowUpdate(0, t.ConnectionFlow) From 41806f1633682d57afa2d91cd61e1167605f6473 Mon Sep 17 00:00:00 2001 From: Bogdan Finn Date: Wed, 20 Jul 2022 21:55:27 +0200 Subject: [PATCH 08/74] changed module name and bumdped version; --- README.md | 4 ++-- alpn_test.go | 7 ++++--- cgi/child.go | 5 +++-- cgi/child_test.go | 2 +- cgi/host.go | 2 +- cgi/host_test.go | 4 ++-- cgi/integration_test.go | 6 +++--- client.go | 3 ++- client_test.go | 9 +++++---- clientserver_test.go | 9 +++++---- cookiejar/dummy_publicsuffix_test.go | 2 +- cookiejar/example_test.go | 6 +++--- cookiejar/jar.go | 2 +- cookiejar/jar_test.go | 2 +- example_client_test.go | 7 ++++--- example_filesystem_test.go | 2 +- example_handle_test.go | 2 +- example_test.go | 2 +- fcgi/child.go | 4 ++-- fcgi/fcgi_test.go | 2 +- fs_test.go | 4 ++-- go.mod | 7 +++---- go.sum | 4 ++-- h2_bundle.go | 8 ++++---- header.go | 2 +- header_test.go | 2 +- http.go | 2 +- http2/client_conn_pool.go | 5 +++-- http2/fhttp_test.go | 13 +++++++------ http2/frame.go | 2 +- http2/frame_test.go | 2 +- http2/go111.go | 3 ++- http2/h2c/h2c.go | 6 +++--- http2/h2c/h2c_test.go | 4 ++-- http2/h2demo/h2demo.go | 5 +++-- http2/h2i/h2i.go | 8 +++++--- http2/header_order_test.go | 5 +++-- http2/headermap.go | 2 +- http2/http2.go | 5 +++-- http2/http2_test.go | 4 ++-- http2/not_go111.go | 4 +++- http2/push_consume.go | 2 +- http2/push_consume_test.go | 4 ++-- http2/server.go | 7 ++++--- http2/server_push_test.go | 2 +- http2/server_test.go | 7 ++++--- http2/transport.go | 8 ++++---- http2/transport_test.go | 11 ++++++----- http2/write.go | 4 ++-- http_test.go | 2 +- httptest/example_test.go | 4 ++-- httptest/httptest.go | 5 +++-- httptest/httptest_test.go | 5 +++-- httptest/recorder.go | 2 +- httptest/recorder_test.go | 2 +- httptest/server.go | 7 ++++--- httptest/server_test.go | 2 +- httptrace/example_test.go | 2 +- httptrace/trace.go | 5 +++-- httputil/dump.go | 2 +- httputil/dump_test.go | 2 +- httputil/example_test.go | 6 +++--- httputil/httputil.go | 2 +- httputil/persist.go | 2 +- httputil/reverseproxy.go | 2 +- httputil/reverseproxy_test.go | 4 ++-- internal/testenv/testenv.go | 2 +- main_test.go | 2 +- pprof/pprof.go | 4 ++-- pprof/pprof_test.go | 6 +++--- request.go | 5 +++-- request_test.go | 4 ++-- response.go | 3 ++- response_test.go | 2 +- serve_test.go | 13 +++++++------ server.go | 3 ++- sniff_test.go | 2 +- transfer.go | 4 ++-- transport.go | 4 ++-- transport_internal_test.go | 5 +++-- transport_test.go | 15 ++++++++------- triv.go | 3 ++- 82 files changed, 193 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index 07bab427..4c647bb5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@