Source file
src/net/http/http2client.go
1
2
3
4
5
6
7 package http
8
9 import (
10 "context"
11 "crypto/tls"
12 "errors"
13 "net"
14 "net/http/internal/http2"
15 "time"
16
17 _ "unsafe"
18 )
19
20
21
22
23
24 const omitHTTP2Client = false
25
26 type http2Transport = http2.Transport
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 type http2ExternalTransportConfig interface {
42
43 HTTP2Config() HTTP2Config
44 DisableCompression() bool
45 MaxHeaderListSize() int64
46 IdleConnTimeout() time.Duration
47
48
49
50 ConnFromContext(context.Context) net.Conn
51
52
53
54
55 DialFromContext(ctx context.Context, network, addr string) (net.Conn, error)
56
57
58
59
60
61 ExternalRoundTrip() bool
62
63
64
65 RoundTrip(*Request) (*Response, error)
66
67
68 Registered(*Transport)
69 }
70
71 func (t *Transport) configureHTTP2(protocols Protocols) {
72 if t.TLSClientConfig == nil {
73 t.TLSClientConfig = &tls.Config{}
74 }
75 if t.HTTP2 == nil {
76 t.HTTP2 = &HTTP2Config{}
77 }
78 t2 := http2.NewTransport(transportConfig{t})
79 t.h2Transport = t2
80
81 t.registerProtocol("https", http2RoundTripper{t2, true})
82 if t.TLSNextProto == nil {
83 t.TLSNextProto = make(map[string]func(authority string, c *tls.Conn) RoundTripper)
84 }
85
86
87 t.TLSNextProto["h2"] = func(authority string, c *tls.Conn) RoundTripper {
88 return http2ErringRoundTripper{
89 errors.New("unexpected use of stub RoundTripper"),
90 }
91 }
92
93
94
95
96
97
98 t.TLSClientConfig.NextProtos = adjustNextProtos(t.TLSClientConfig.NextProtos, protocols)
99 }
100
101 type http2ErringRoundTripper struct{ err error }
102
103 func (rt http2ErringRoundTripper) RoundTripErr() error { return rt.err }
104 func (rt http2ErringRoundTripper) RoundTrip(*Request) (*Response, error) { return nil, rt.err }
105
106 func http2RoundTrip(req *Request, rt func(*http2.ClientRequest) (*http2.ClientResponse, error)) (*Response, error) {
107 resp := &Response{}
108 cresp, err := rt(&http2.ClientRequest{
109 Context: req.Context(),
110 Method: req.Method,
111 URL: req.URL,
112 Header: http2.Header(req.Header),
113 Trailer: http2.Header(req.Trailer),
114 Body: req.Body,
115 Host: req.Host,
116 GetBody: req.GetBody,
117 ContentLength: req.ContentLength,
118 Cancel: req.Cancel,
119 Close: req.Close,
120 ResTrailer: (*http2.Header)(&resp.Trailer),
121 })
122 if err != nil {
123 return nil, err
124 }
125 resp.Status = cresp.Status + " " + StatusText(cresp.StatusCode)
126 resp.StatusCode = cresp.StatusCode
127 resp.Proto = "HTTP/2.0"
128 resp.ProtoMajor = 2
129 resp.ProtoMinor = 0
130 resp.ContentLength = cresp.ContentLength
131 resp.Uncompressed = cresp.Uncompressed
132 resp.Header = Header(cresp.Header)
133 resp.Trailer = Header(cresp.Trailer)
134 resp.Body = cresp.Body
135 resp.TLS = cresp.TLS
136 resp.Request = req
137 return resp, nil
138 }
139
140
141 func (t *Transport) http2AddConn(scheme, authority string, nc net.Conn) (RoundTripper, error) {
142 if t.h2Transport == nil {
143 return nil, errors.ErrUnsupported
144 }
145 err := t.h2Transport.AddConn(scheme, authority, nc)
146 if err != nil {
147 return nil, err
148 }
149 return http2RoundTripper{t.h2Transport, false}, nil
150 }
151
152
153
154 func (t *Transport) http2NewClientConn(nc net.Conn, internalStateHook func()) (genericClientConn, error) {
155 if t.h2Transport == nil {
156 return nil, errors.ErrUnsupported
157 }
158 cc, err := t.h2Transport.NewClientConn(nc, internalStateHook)
159 if err != nil {
160 return nil, err
161 }
162 return http2ClientConn{cc}, nil
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 func (t *Transport) http2NewClientConnFromContext(ctx context.Context) (*ClientConn, error) {
179 if t.h2Config == nil {
180 return nil, errors.ErrUnsupported
181 }
182 nc := t.h2Config.ConnFromContext(ctx)
183 if nc == nil {
184 return nil, errors.ErrUnsupported
185 }
186 if t.h2Transport == nil {
187 return nil, errors.New("http: Transport does not support HTTP/2")
188 }
189 cc := &ClientConn{}
190 gc, err := t.http2NewClientConn(nc, cc.maybeRunStateHook)
191 if err != nil {
192 return nil, err
193 }
194 cc.stateHookMu.Lock()
195 defer cc.stateHookMu.Unlock()
196 cc.cc = gc
197 cc.lastAvailable = gc.Available()
198 return cc, nil
199 }
200
201
202
203
204
205
206
207
208 func (t *Transport) http2ExternalDial(ctx context.Context, cm connectMethod) (RoundTripper, error) {
209 if t.h2Config == nil {
210 return nil, errors.ErrUnsupported
211 }
212 nc, err := t.h2Config.DialFromContext(ctx, "tcp", cm.targetAddr)
213 if err != nil {
214 return nil, err
215 }
216 return t.http2AddConn(cm.targetScheme, cm.targetAddr, nc)
217 }
218
219 type http2RoundTripper struct {
220 t *http2.Transport
221 mapCachedConnErr bool
222 }
223
224 func (rt http2RoundTripper) RoundTrip(req *Request) (*Response, error) {
225 resp, err := http2RoundTrip(req, rt.t.RoundTrip)
226 if err != nil {
227 if rt.mapCachedConnErr && http2isNoCachedConnError(err) {
228 err = ErrSkipAltProtocol
229 }
230 return nil, err
231 }
232 return resp, nil
233 }
234
235 type http2ClientConn struct {
236 http2.NetHTTPClientConn
237 }
238
239 func (cc http2ClientConn) RoundTrip(req *Request) (*Response, error) {
240 return http2RoundTrip(req, cc.NetHTTPClientConn.RoundTrip)
241 }
242
243
244
245
246
247
248 type transportConfig struct {
249 t *Transport
250 }
251
252 func (t transportConfig) MaxResponseHeaderBytes() int64 { return t.t.MaxResponseHeaderBytes }
253 func (t transportConfig) DisableKeepAlives() bool { return t.t.DisableKeepAlives }
254 func (t transportConfig) ExpectContinueTimeout() time.Duration { return t.t.ExpectContinueTimeout }
255 func (t transportConfig) ResponseHeaderTimeout() time.Duration { return t.t.ResponseHeaderTimeout }
256
257 func (t transportConfig) MaxHeaderListSize() int64 {
258 if t.t.h2Config != nil {
259 return t.t.h2Config.MaxHeaderListSize()
260 }
261 return 0
262 }
263
264 func (t transportConfig) DisableCompression() bool {
265 if t.t.h2Config != nil && t.t.h2Config.DisableCompression() {
266 return true
267 }
268 return t.t.DisableCompression
269 }
270
271 func (t transportConfig) IdleConnTimeout() time.Duration {
272
273
274 if t.t.h2Config != nil {
275 if timeout := t.t.h2Config.IdleConnTimeout(); timeout != 0 {
276 return timeout
277 }
278 }
279 return t.t.IdleConnTimeout
280 }
281
282 func (t transportConfig) HTTP2Config() http2.Config {
283 return mergeHTTP2Config(t.t.HTTP2, t.t.h2Config)
284 }
285
286
287
288
289
290 func transportFromH1Transport(t *Transport) any {
291 t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
292 return t.h2Transport
293 }
294
View as plain text