]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | // Copyright 2014 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | // Package http2 implements the HTTP/2 protocol. | |
6 | // | |
7 | // This package is low-level and intended to be used directly by very | |
8 | // few people. Most users will use it indirectly through the automatic | |
9 | // use by the net/http package (from Go 1.6 and later). | |
10 | // For use in earlier Go versions see ConfigureServer. (Transport support | |
11 | // requires Go 1.6 or later) | |
12 | // | |
13 | // See https://http2.github.io/ for more information on HTTP/2. | |
14 | // | |
15 | // See https://http2.golang.org/ for a test server running this code. | |
16 | // | |
17 | package http2 // import "golang.org/x/net/http2" | |
18 | ||
19 | import ( | |
20 | "bufio" | |
21 | "crypto/tls" | |
22 | "errors" | |
23 | "fmt" | |
24 | "io" | |
25 | "net/http" | |
26 | "os" | |
27 | "sort" | |
28 | "strconv" | |
29 | "strings" | |
30 | "sync" | |
31 | ||
107c1cdb | 32 | "golang.org/x/net/http/httpguts" |
15c0b25d AP |
33 | ) |
34 | ||
35 | var ( | |
36 | VerboseLogs bool | |
37 | logFrameWrites bool | |
38 | logFrameReads bool | |
39 | inTests bool | |
40 | ) | |
41 | ||
42 | func init() { | |
43 | e := os.Getenv("GODEBUG") | |
44 | if strings.Contains(e, "http2debug=1") { | |
45 | VerboseLogs = true | |
46 | } | |
47 | if strings.Contains(e, "http2debug=2") { | |
48 | VerboseLogs = true | |
49 | logFrameWrites = true | |
50 | logFrameReads = true | |
51 | } | |
52 | } | |
53 | ||
54 | const ( | |
55 | // ClientPreface is the string that must be sent by new | |
56 | // connections from clients. | |
57 | ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" | |
58 | ||
59 | // SETTINGS_MAX_FRAME_SIZE default | |
60 | // http://http2.github.io/http2-spec/#rfc.section.6.5.2 | |
61 | initialMaxFrameSize = 16384 | |
62 | ||
63 | // NextProtoTLS is the NPN/ALPN protocol negotiated during | |
64 | // HTTP/2's TLS setup. | |
65 | NextProtoTLS = "h2" | |
66 | ||
67 | // http://http2.github.io/http2-spec/#SettingValues | |
68 | initialHeaderTableSize = 4096 | |
69 | ||
70 | initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size | |
71 | ||
72 | defaultMaxReadFrameSize = 1 << 20 | |
73 | ) | |
74 | ||
75 | var ( | |
76 | clientPreface = []byte(ClientPreface) | |
77 | ) | |
78 | ||
79 | type streamState int | |
80 | ||
81 | // HTTP/2 stream states. | |
82 | // | |
83 | // See http://tools.ietf.org/html/rfc7540#section-5.1. | |
84 | // | |
85 | // For simplicity, the server code merges "reserved (local)" into | |
86 | // "half-closed (remote)". This is one less state transition to track. | |
87 | // The only downside is that we send PUSH_PROMISEs slightly less | |
88 | // liberally than allowable. More discussion here: | |
89 | // https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html | |
90 | // | |
91 | // "reserved (remote)" is omitted since the client code does not | |
92 | // support server push. | |
93 | const ( | |
94 | stateIdle streamState = iota | |
95 | stateOpen | |
96 | stateHalfClosedLocal | |
97 | stateHalfClosedRemote | |
98 | stateClosed | |
99 | ) | |
100 | ||
101 | var stateName = [...]string{ | |
102 | stateIdle: "Idle", | |
103 | stateOpen: "Open", | |
104 | stateHalfClosedLocal: "HalfClosedLocal", | |
105 | stateHalfClosedRemote: "HalfClosedRemote", | |
106 | stateClosed: "Closed", | |
107 | } | |
108 | ||
109 | func (st streamState) String() string { | |
110 | return stateName[st] | |
111 | } | |
112 | ||
113 | // Setting is a setting parameter: which setting it is, and its value. | |
114 | type Setting struct { | |
115 | // ID is which setting is being set. | |
116 | // See http://http2.github.io/http2-spec/#SettingValues | |
117 | ID SettingID | |
118 | ||
119 | // Val is the value. | |
120 | Val uint32 | |
121 | } | |
122 | ||
123 | func (s Setting) String() string { | |
124 | return fmt.Sprintf("[%v = %d]", s.ID, s.Val) | |
125 | } | |
126 | ||
127 | // Valid reports whether the setting is valid. | |
128 | func (s Setting) Valid() error { | |
129 | // Limits and error codes from 6.5.2 Defined SETTINGS Parameters | |
130 | switch s.ID { | |
131 | case SettingEnablePush: | |
132 | if s.Val != 1 && s.Val != 0 { | |
133 | return ConnectionError(ErrCodeProtocol) | |
134 | } | |
135 | case SettingInitialWindowSize: | |
136 | if s.Val > 1<<31-1 { | |
137 | return ConnectionError(ErrCodeFlowControl) | |
138 | } | |
139 | case SettingMaxFrameSize: | |
140 | if s.Val < 16384 || s.Val > 1<<24-1 { | |
141 | return ConnectionError(ErrCodeProtocol) | |
142 | } | |
143 | } | |
144 | return nil | |
145 | } | |
146 | ||
147 | // A SettingID is an HTTP/2 setting as defined in | |
148 | // http://http2.github.io/http2-spec/#iana-settings | |
149 | type SettingID uint16 | |
150 | ||
151 | const ( | |
152 | SettingHeaderTableSize SettingID = 0x1 | |
153 | SettingEnablePush SettingID = 0x2 | |
154 | SettingMaxConcurrentStreams SettingID = 0x3 | |
155 | SettingInitialWindowSize SettingID = 0x4 | |
156 | SettingMaxFrameSize SettingID = 0x5 | |
157 | SettingMaxHeaderListSize SettingID = 0x6 | |
158 | ) | |
159 | ||
160 | var settingName = map[SettingID]string{ | |
161 | SettingHeaderTableSize: "HEADER_TABLE_SIZE", | |
162 | SettingEnablePush: "ENABLE_PUSH", | |
163 | SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS", | |
164 | SettingInitialWindowSize: "INITIAL_WINDOW_SIZE", | |
165 | SettingMaxFrameSize: "MAX_FRAME_SIZE", | |
166 | SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE", | |
167 | } | |
168 | ||
169 | func (s SettingID) String() string { | |
170 | if v, ok := settingName[s]; ok { | |
171 | return v | |
172 | } | |
173 | return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s)) | |
174 | } | |
175 | ||
176 | var ( | |
177 | errInvalidHeaderFieldName = errors.New("http2: invalid header field name") | |
178 | errInvalidHeaderFieldValue = errors.New("http2: invalid header field value") | |
179 | ) | |
180 | ||
181 | // validWireHeaderFieldName reports whether v is a valid header field | |
107c1cdb | 182 | // name (key). See httpguts.ValidHeaderName for the base rules. |
15c0b25d AP |
183 | // |
184 | // Further, http2 says: | |
185 | // "Just as in HTTP/1.x, header field names are strings of ASCII | |
186 | // characters that are compared in a case-insensitive | |
187 | // fashion. However, header field names MUST be converted to | |
188 | // lowercase prior to their encoding in HTTP/2. " | |
189 | func validWireHeaderFieldName(v string) bool { | |
190 | if len(v) == 0 { | |
191 | return false | |
192 | } | |
193 | for _, r := range v { | |
107c1cdb | 194 | if !httpguts.IsTokenRune(r) { |
15c0b25d AP |
195 | return false |
196 | } | |
197 | if 'A' <= r && r <= 'Z' { | |
198 | return false | |
199 | } | |
200 | } | |
201 | return true | |
202 | } | |
203 | ||
15c0b25d | 204 | func httpCodeString(code int) string { |
107c1cdb ND |
205 | switch code { |
206 | case 200: | |
207 | return "200" | |
208 | case 404: | |
209 | return "404" | |
15c0b25d AP |
210 | } |
211 | return strconv.Itoa(code) | |
212 | } | |
213 | ||
214 | // from pkg io | |
215 | type stringWriter interface { | |
216 | WriteString(s string) (n int, err error) | |
217 | } | |
218 | ||
219 | // A gate lets two goroutines coordinate their activities. | |
220 | type gate chan struct{} | |
221 | ||
222 | func (g gate) Done() { g <- struct{}{} } | |
223 | func (g gate) Wait() { <-g } | |
224 | ||
225 | // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). | |
226 | type closeWaiter chan struct{} | |
227 | ||
228 | // Init makes a closeWaiter usable. | |
229 | // It exists because so a closeWaiter value can be placed inside a | |
230 | // larger struct and have the Mutex and Cond's memory in the same | |
231 | // allocation. | |
232 | func (cw *closeWaiter) Init() { | |
233 | *cw = make(chan struct{}) | |
234 | } | |
235 | ||
236 | // Close marks the closeWaiter as closed and unblocks any waiters. | |
237 | func (cw closeWaiter) Close() { | |
238 | close(cw) | |
239 | } | |
240 | ||
241 | // Wait waits for the closeWaiter to become closed. | |
242 | func (cw closeWaiter) Wait() { | |
243 | <-cw | |
244 | } | |
245 | ||
246 | // bufferedWriter is a buffered writer that writes to w. | |
247 | // Its buffered writer is lazily allocated as needed, to minimize | |
248 | // idle memory usage with many connections. | |
249 | type bufferedWriter struct { | |
250 | w io.Writer // immutable | |
251 | bw *bufio.Writer // non-nil when data is buffered | |
252 | } | |
253 | ||
254 | func newBufferedWriter(w io.Writer) *bufferedWriter { | |
255 | return &bufferedWriter{w: w} | |
256 | } | |
257 | ||
258 | // bufWriterPoolBufferSize is the size of bufio.Writer's | |
259 | // buffers created using bufWriterPool. | |
260 | // | |
261 | // TODO: pick a less arbitrary value? this is a bit under | |
262 | // (3 x typical 1500 byte MTU) at least. Other than that, | |
263 | // not much thought went into it. | |
264 | const bufWriterPoolBufferSize = 4 << 10 | |
265 | ||
266 | var bufWriterPool = sync.Pool{ | |
267 | New: func() interface{} { | |
268 | return bufio.NewWriterSize(nil, bufWriterPoolBufferSize) | |
269 | }, | |
270 | } | |
271 | ||
272 | func (w *bufferedWriter) Available() int { | |
273 | if w.bw == nil { | |
274 | return bufWriterPoolBufferSize | |
275 | } | |
276 | return w.bw.Available() | |
277 | } | |
278 | ||
279 | func (w *bufferedWriter) Write(p []byte) (n int, err error) { | |
280 | if w.bw == nil { | |
281 | bw := bufWriterPool.Get().(*bufio.Writer) | |
282 | bw.Reset(w.w) | |
283 | w.bw = bw | |
284 | } | |
285 | return w.bw.Write(p) | |
286 | } | |
287 | ||
288 | func (w *bufferedWriter) Flush() error { | |
289 | bw := w.bw | |
290 | if bw == nil { | |
291 | return nil | |
292 | } | |
293 | err := bw.Flush() | |
294 | bw.Reset(nil) | |
295 | bufWriterPool.Put(bw) | |
296 | w.bw = nil | |
297 | return err | |
298 | } | |
299 | ||
300 | func mustUint31(v int32) uint32 { | |
301 | if v < 0 || v > 2147483647 { | |
302 | panic("out of range") | |
303 | } | |
304 | return uint32(v) | |
305 | } | |
306 | ||
307 | // bodyAllowedForStatus reports whether a given response status code | |
107c1cdb | 308 | // permits a body. See RFC 7230, section 3.3. |
15c0b25d AP |
309 | func bodyAllowedForStatus(status int) bool { |
310 | switch { | |
311 | case status >= 100 && status <= 199: | |
312 | return false | |
313 | case status == 204: | |
314 | return false | |
315 | case status == 304: | |
316 | return false | |
317 | } | |
318 | return true | |
319 | } | |
320 | ||
321 | type httpError struct { | |
322 | msg string | |
323 | timeout bool | |
324 | } | |
325 | ||
326 | func (e *httpError) Error() string { return e.msg } | |
327 | func (e *httpError) Timeout() bool { return e.timeout } | |
328 | func (e *httpError) Temporary() bool { return true } | |
329 | ||
330 | var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true} | |
331 | ||
332 | type connectionStater interface { | |
333 | ConnectionState() tls.ConnectionState | |
334 | } | |
335 | ||
336 | var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }} | |
337 | ||
338 | type sorter struct { | |
339 | v []string // owned by sorter | |
340 | } | |
341 | ||
342 | func (s *sorter) Len() int { return len(s.v) } | |
343 | func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] } | |
344 | func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] } | |
345 | ||
346 | // Keys returns the sorted keys of h. | |
347 | // | |
348 | // The returned slice is only valid until s used again or returned to | |
349 | // its pool. | |
350 | func (s *sorter) Keys(h http.Header) []string { | |
351 | keys := s.v[:0] | |
352 | for k := range h { | |
353 | keys = append(keys, k) | |
354 | } | |
355 | s.v = keys | |
356 | sort.Sort(s) | |
357 | return keys | |
358 | } | |
359 | ||
360 | func (s *sorter) SortStrings(ss []string) { | |
361 | // Our sorter works on s.v, which sorter owns, so | |
362 | // stash it away while we sort the user's buffer. | |
363 | save := s.v | |
364 | s.v = ss | |
365 | sort.Sort(s) | |
366 | s.v = save | |
367 | } | |
368 | ||
369 | // validPseudoPath reports whether v is a valid :path pseudo-header | |
370 | // value. It must be either: | |
371 | // | |
372 | // *) a non-empty string starting with '/' | |
373 | // *) the string '*', for OPTIONS requests. | |
374 | // | |
375 | // For now this is only used a quick check for deciding when to clean | |
376 | // up Opaque URLs before sending requests from the Transport. | |
377 | // See golang.org/issue/16847 | |
378 | // | |
379 | // We used to enforce that the path also didn't start with "//", but | |
380 | // Google's GFE accepts such paths and Chrome sends them, so ignore | |
381 | // that part of the spec. See golang.org/issue/19103. | |
382 | func validPseudoPath(v string) bool { | |
383 | return (len(v) > 0 && v[0] == '/') || v == "*" | |
384 | } |