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 ContentLength: req.ContentLength,
117 Cancel: req.Cancel,
118 Close: req.Close,
119 ResTrailer: (*http2.Header)(&resp.Trailer),
120 })
121 if err != nil {
122 return nil, err
123 }
124 resp.Status = cresp.Status + " " + StatusText(cresp.StatusCode)
125 resp.StatusCode = cresp.StatusCode
126 resp.Proto = "HTTP/2.0"
127 resp.ProtoMajor = 2
128 resp.ProtoMinor = 0
129 resp.ContentLength = cresp.ContentLength
130 resp.Uncompressed = cresp.Uncompressed
131 resp.Header = Header(cresp.Header)
132 resp.Trailer = Header(cresp.Trailer)
133 resp.Body = cresp.Body
134 resp.TLS = cresp.TLS
135 resp.Request = req
136 return resp, nil
137 }
138
139
140 func (t *Transport) http2AddConn(scheme, authority string, nc net.Conn) (genericClientConn, error) {
141 if t.h2Transport == nil {
142 return nil, errors.ErrUnsupported
143 }
144 err := t.h2Transport.AddConn(scheme, authority, nc)
145 if err != nil {
146 return nil, err
147 }
148 return &altClientConn{
149 rt: http2RoundTripper{t.h2Transport, false},
150 proto: 2,
151 }, nil
152 }
153
154
155
156 func (t *Transport) http2NewClientConn(nc net.Conn, internalStateHook func()) (genericClientConn, error) {
157 if t.h2Transport == nil {
158 return nil, errors.ErrUnsupported
159 }
160 cc, err := t.h2Transport.NewClientConn(nc, internalStateHook)
161 if err != nil {
162 return nil, err
163 }
164 return externalHTTP2Conn{http2ClientConn{cc}}, nil
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 func (t *Transport) http2NewClientConnFromContext(ctx context.Context) (*ClientConn, error) {
181 if t.h2Config == nil {
182 return nil, errors.ErrUnsupported
183 }
184 nc := t.h2Config.ConnFromContext(ctx)
185 if nc == nil {
186 return nil, errors.ErrUnsupported
187 }
188 if t.h2Transport == nil {
189 return nil, errors.New("http: Transport does not support HTTP/2")
190 }
191 cc := &ClientConn{}
192 gc, err := t.http2NewClientConn(nc, cc.maybeRunStateHook)
193 if err != nil {
194 return nil, err
195 }
196 cc.stateHookMu.Lock()
197 defer cc.stateHookMu.Unlock()
198 cc.cc = gc
199 cc.lastAvailable = gc.Available()
200 return cc, nil
201 }
202
203
204
205
206
207
208
209
210 func (t *Transport) http2ExternalDial(ctx context.Context, cm connectMethod) (genericClientConn, error) {
211 if t.h2Config == nil {
212 return nil, errors.ErrUnsupported
213 }
214 nc, err := t.h2Config.DialFromContext(ctx, "tcp", cm.targetAddr)
215 if err != nil {
216 return nil, err
217 }
218 return t.http2AddConn(cm.targetScheme, cm.targetAddr, nc)
219 }
220
221 type http2RoundTripper struct {
222 t *http2.Transport
223 mapCachedConnErr bool
224 }
225
226 func (rt http2RoundTripper) RoundTrip(req *Request) (*Response, error) {
227 resp, err := http2RoundTrip(req, rt.t.RoundTrip)
228 if err != nil {
229 if rt.mapCachedConnErr && http2isNoCachedConnError(err) {
230 err = ErrSkipAltProtocol
231 }
232 return nil, err
233 }
234 return resp, nil
235 }
236
237 type http2ClientConn struct {
238 http2.NetHTTPClientConn
239 }
240
241 func (cc http2ClientConn) RoundTrip(req *Request) (*Response, error) {
242 return http2RoundTrip(req, cc.NetHTTPClientConn.RoundTrip)
243 }
244
245
246
247
248
249
250 type transportConfig struct {
251 t *Transport
252 }
253
254 func (t transportConfig) MaxResponseHeaderBytes() int64 { return t.t.MaxResponseHeaderBytes }
255 func (t transportConfig) DisableKeepAlives() bool { return t.t.DisableKeepAlives }
256 func (t transportConfig) ExpectContinueTimeout() time.Duration { return t.t.ExpectContinueTimeout }
257 func (t transportConfig) ResponseHeaderTimeout() time.Duration { return t.t.ResponseHeaderTimeout }
258
259 func (t transportConfig) MaxHeaderListSize() int64 {
260 if t.t.h2Config != nil {
261 return t.t.h2Config.MaxHeaderListSize()
262 }
263 return 0
264 }
265
266 func (t transportConfig) DisableCompression() bool {
267 if t.t.h2Config != nil && t.t.h2Config.DisableCompression() {
268 return true
269 }
270 return t.t.DisableCompression
271 }
272
273 func (t transportConfig) IdleConnTimeout() time.Duration {
274
275
276 if t.t.h2Config != nil {
277 if timeout := t.t.h2Config.IdleConnTimeout(); timeout != 0 {
278 return timeout
279 }
280 }
281 return t.t.IdleConnTimeout
282 }
283
284 func (t transportConfig) HTTP2Config() http2.Config {
285 return mergeHTTP2Config(t.t.HTTP2, t.t.h2Config)
286 }
287
288
289
290
291
292 func transportFromH1Transport(t *Transport) any {
293 t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
294 return t.h2Transport
295 }
296
View as plain text