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