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