1
2
3
4
5
6
7
8
9
10
11
12
13
14 package http2
15
16 import (
17 "bufio"
18 "crypto/tls"
19 "errors"
20 "fmt"
21 "net"
22 "os"
23 "slices"
24 "strconv"
25 "strings"
26 "sync"
27 "time"
28
29 "golang.org/x/net/http/httpguts"
30 )
31
32 var (
33 VerboseLogs bool
34 logFrameWrites bool
35 logFrameReads bool
36
37
38
39
40
41
42
43
44 disableExtendedConnectProtocol = true
45
46 inTests = false
47 )
48
49 func init() {
50 e := os.Getenv("GODEBUG")
51 if strings.Contains(e, "http2debug=1") {
52 VerboseLogs = true
53 }
54 if strings.Contains(e, "http2debug=2") {
55 VerboseLogs = true
56 logFrameWrites = true
57 logFrameReads = true
58 }
59 if strings.Contains(e, "http2xconnect=1") {
60 disableExtendedConnectProtocol = false
61 }
62 }
63
64 const (
65
66
67 ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
68
69
70
71 initialMaxFrameSize = 16384
72
73
74
75 NextProtoTLS = "h2"
76
77
78 initialHeaderTableSize = 4096
79
80 initialWindowSize = 65535
81
82 defaultMaxReadFrameSize = 1 << 20
83 )
84
85 var (
86 clientPreface = []byte(ClientPreface)
87 )
88
89 type streamState int
90
91
92
93
94
95
96
97
98
99
100
101
102
103 const (
104 stateIdle streamState = iota
105 stateOpen
106 stateHalfClosedLocal
107 stateHalfClosedRemote
108 stateClosed
109 )
110
111 var stateName = [...]string{
112 stateIdle: "Idle",
113 stateOpen: "Open",
114 stateHalfClosedLocal: "HalfClosedLocal",
115 stateHalfClosedRemote: "HalfClosedRemote",
116 stateClosed: "Closed",
117 }
118
119 func (st streamState) String() string {
120 return stateName[st]
121 }
122
123
124 type Setting struct {
125
126
127 ID SettingID
128
129
130 Val uint32
131 }
132
133 func (s Setting) String() string {
134 return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
135 }
136
137
138 func (s Setting) Valid() error {
139
140 switch s.ID {
141 case SettingEnablePush:
142 if s.Val != 1 && s.Val != 0 {
143 return ConnectionError(ErrCodeProtocol)
144 }
145 case SettingInitialWindowSize:
146 if s.Val > 1<<31-1 {
147 return ConnectionError(ErrCodeFlowControl)
148 }
149 case SettingMaxFrameSize:
150 if s.Val < 16384 || s.Val > 1<<24-1 {
151 return ConnectionError(ErrCodeProtocol)
152 }
153 case SettingEnableConnectProtocol:
154 if s.Val != 1 && s.Val != 0 {
155 return ConnectionError(ErrCodeProtocol)
156 }
157 }
158 return nil
159 }
160
161
162
163 type SettingID uint16
164
165 const (
166 SettingHeaderTableSize SettingID = 0x1
167 SettingEnablePush SettingID = 0x2
168 SettingMaxConcurrentStreams SettingID = 0x3
169 SettingInitialWindowSize SettingID = 0x4
170 SettingMaxFrameSize SettingID = 0x5
171 SettingMaxHeaderListSize SettingID = 0x6
172 SettingEnableConnectProtocol SettingID = 0x8
173 SettingNoRFC7540Priorities SettingID = 0x9
174 )
175
176 var settingName = map[SettingID]string{
177 SettingHeaderTableSize: "HEADER_TABLE_SIZE",
178 SettingEnablePush: "ENABLE_PUSH",
179 SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
180 SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
181 SettingMaxFrameSize: "MAX_FRAME_SIZE",
182 SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
183 SettingEnableConnectProtocol: "ENABLE_CONNECT_PROTOCOL",
184 SettingNoRFC7540Priorities: "NO_RFC7540_PRIORITIES",
185 }
186
187 func (s SettingID) String() string {
188 if v, ok := settingName[s]; ok {
189 return v
190 }
191 return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
192 }
193
194
195
196
197
198
199
200
201
202
203 func validWireHeaderFieldName(v string) bool {
204 if len(v) == 0 {
205 return false
206 }
207 for _, r := range v {
208 if !httpguts.IsTokenRune(r) {
209 return false
210 }
211 if 'A' <= r && r <= 'Z' {
212 return false
213 }
214 }
215 return true
216 }
217
218
219 func httpCodeString(code int) string {
220 switch code {
221 case 200:
222 return "200"
223 case 404:
224 return "404"
225 }
226 return strconv.Itoa(code)
227 }
228
229
230 type closeWaiter chan struct{}
231
232
233
234
235
236 func (cw *closeWaiter) Init() {
237 *cw = make(chan struct{})
238 }
239
240
241 func (cw closeWaiter) Close() {
242 close(cw)
243 }
244
245
246 func (cw closeWaiter) Wait() {
247 <-cw
248 }
249
250
251
252
253 type bufferedWriter struct {
254 _ incomparable
255 conn net.Conn
256 bw *bufio.Writer
257 byteTimeout time.Duration
258 werr error
259 }
260
261 func newBufferedWriter(conn net.Conn, timeout time.Duration) *bufferedWriter {
262 return &bufferedWriter{
263 conn: conn,
264 byteTimeout: timeout,
265 }
266 }
267
268
269
270
271
272
273
274 const bufWriterPoolBufferSize = 4 << 10
275
276 var bufWriterPool = sync.Pool{
277 New: func() any {
278 return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
279 },
280 }
281
282 func (w *bufferedWriter) Available() int {
283 if w.bw == nil {
284 return bufWriterPoolBufferSize
285 }
286 return w.bw.Available()
287 }
288
289 func (w *bufferedWriter) Write(p []byte) (n int, err error) {
290 if w.werr != nil {
291 return 0, w.werr
292 }
293 if w.bw == nil {
294 bw := bufWriterPool.Get().(*bufio.Writer)
295 bw.Reset((*bufferedWriterTimeoutWriter)(w))
296 w.bw = bw
297 }
298 n, w.werr = w.bw.Write(p)
299 return n, w.werr
300 }
301
302 func (w *bufferedWriter) Flush() error {
303 bw := w.bw
304 if bw == nil {
305 return nil
306 }
307 if w.werr != nil {
308 return w.werr
309 }
310 w.werr = bw.Flush()
311 bw.Reset(nil)
312 bufWriterPool.Put(bw)
313 w.bw = nil
314 return w.werr
315 }
316
317 type bufferedWriterTimeoutWriter bufferedWriter
318
319 func (w *bufferedWriterTimeoutWriter) Write(p []byte) (n int, err error) {
320 return writeWithByteTimeout(w.conn, w.byteTimeout, p)
321 }
322
323
324
325
326 func writeWithByteTimeout(conn net.Conn, timeout time.Duration, p []byte) (n int, err error) {
327 if timeout <= 0 {
328 return conn.Write(p)
329 }
330 for {
331 conn.SetWriteDeadline(time.Now().Add(timeout))
332 nn, err := conn.Write(p[n:])
333 n += nn
334 if n == len(p) || nn == 0 || !errors.Is(err, os.ErrDeadlineExceeded) {
335
336
337 conn.SetWriteDeadline(time.Time{})
338 return n, err
339 }
340 }
341 }
342
343 func mustUint31(v int32) uint32 {
344 if v < 0 || v > 2147483647 {
345 panic("out of range")
346 }
347 return uint32(v)
348 }
349
350
351
352 func bodyAllowedForStatus(status int) bool {
353 switch {
354 case status >= 100 && status <= 199:
355 return false
356 case status == 204:
357 return false
358 case status == 304:
359 return false
360 }
361 return true
362 }
363
364 type httpError struct {
365 _ incomparable
366 msg string
367 timeout bool
368 }
369
370 func (e *httpError) Error() string { return e.msg }
371 func (e *httpError) Timeout() bool { return e.timeout }
372 func (e *httpError) Temporary() bool { return true }
373
374 var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
375
376 type connectionStater interface {
377 ConnectionState() tls.ConnectionState
378 }
379
380 var sorterPool = sync.Pool{New: func() any { return new(sorter) }}
381
382 type sorter struct {
383 v []string
384 }
385
386
387
388
389
390 func (s *sorter) Keys(h Header) []string {
391 keys := s.v[:0]
392 for k := range h {
393 keys = append(keys, k)
394 }
395 s.v = keys
396 slices.Sort(s.v)
397 return keys
398 }
399
400
401
402
403 type incomparable [0]func()
404
View as plain text