Matteo Scandolo | a428586 | 2020-12-01 18:10:10 -0800 | [diff] [blame] | 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 | "fmt" |
| 23 | "io" |
| 24 | "net/http" |
| 25 | "os" |
| 26 | "sort" |
| 27 | "strconv" |
| 28 | "strings" |
| 29 | "sync" |
| 30 | |
| 31 | "golang.org/x/net/http/httpguts" |
| 32 | ) |
| 33 | |
| 34 | var ( |
| 35 | VerboseLogs bool |
| 36 | logFrameWrites bool |
| 37 | logFrameReads bool |
| 38 | inTests bool |
| 39 | ) |
| 40 | |
| 41 | func init() { |
| 42 | e := os.Getenv("GODEBUG") |
| 43 | if strings.Contains(e, "http2debug=1") { |
| 44 | VerboseLogs = true |
| 45 | } |
| 46 | if strings.Contains(e, "http2debug=2") { |
| 47 | VerboseLogs = true |
| 48 | logFrameWrites = true |
| 49 | logFrameReads = true |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | const ( |
| 54 | // ClientPreface is the string that must be sent by new |
| 55 | // connections from clients. |
| 56 | ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" |
| 57 | |
| 58 | // SETTINGS_MAX_FRAME_SIZE default |
| 59 | // http://http2.github.io/http2-spec/#rfc.section.6.5.2 |
| 60 | initialMaxFrameSize = 16384 |
| 61 | |
| 62 | // NextProtoTLS is the NPN/ALPN protocol negotiated during |
| 63 | // HTTP/2's TLS setup. |
| 64 | NextProtoTLS = "h2" |
| 65 | |
| 66 | // http://http2.github.io/http2-spec/#SettingValues |
| 67 | initialHeaderTableSize = 4096 |
| 68 | |
| 69 | initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size |
| 70 | |
| 71 | defaultMaxReadFrameSize = 1 << 20 |
| 72 | ) |
| 73 | |
| 74 | var ( |
| 75 | clientPreface = []byte(ClientPreface) |
| 76 | ) |
| 77 | |
| 78 | type streamState int |
| 79 | |
| 80 | // HTTP/2 stream states. |
| 81 | // |
| 82 | // See http://tools.ietf.org/html/rfc7540#section-5.1. |
| 83 | // |
| 84 | // For simplicity, the server code merges "reserved (local)" into |
| 85 | // "half-closed (remote)". This is one less state transition to track. |
| 86 | // The only downside is that we send PUSH_PROMISEs slightly less |
| 87 | // liberally than allowable. More discussion here: |
| 88 | // https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html |
| 89 | // |
| 90 | // "reserved (remote)" is omitted since the client code does not |
| 91 | // support server push. |
| 92 | const ( |
| 93 | stateIdle streamState = iota |
| 94 | stateOpen |
| 95 | stateHalfClosedLocal |
| 96 | stateHalfClosedRemote |
| 97 | stateClosed |
| 98 | ) |
| 99 | |
| 100 | var stateName = [...]string{ |
| 101 | stateIdle: "Idle", |
| 102 | stateOpen: "Open", |
| 103 | stateHalfClosedLocal: "HalfClosedLocal", |
| 104 | stateHalfClosedRemote: "HalfClosedRemote", |
| 105 | stateClosed: "Closed", |
| 106 | } |
| 107 | |
| 108 | func (st streamState) String() string { |
| 109 | return stateName[st] |
| 110 | } |
| 111 | |
| 112 | // Setting is a setting parameter: which setting it is, and its value. |
| 113 | type Setting struct { |
| 114 | // ID is which setting is being set. |
| 115 | // See http://http2.github.io/http2-spec/#SettingValues |
| 116 | ID SettingID |
| 117 | |
| 118 | // Val is the value. |
| 119 | Val uint32 |
| 120 | } |
| 121 | |
| 122 | func (s Setting) String() string { |
| 123 | return fmt.Sprintf("[%v = %d]", s.ID, s.Val) |
| 124 | } |
| 125 | |
| 126 | // Valid reports whether the setting is valid. |
| 127 | func (s Setting) Valid() error { |
| 128 | // Limits and error codes from 6.5.2 Defined SETTINGS Parameters |
| 129 | switch s.ID { |
| 130 | case SettingEnablePush: |
| 131 | if s.Val != 1 && s.Val != 0 { |
| 132 | return ConnectionError(ErrCodeProtocol) |
| 133 | } |
| 134 | case SettingInitialWindowSize: |
| 135 | if s.Val > 1<<31-1 { |
| 136 | return ConnectionError(ErrCodeFlowControl) |
| 137 | } |
| 138 | case SettingMaxFrameSize: |
| 139 | if s.Val < 16384 || s.Val > 1<<24-1 { |
| 140 | return ConnectionError(ErrCodeProtocol) |
| 141 | } |
| 142 | } |
| 143 | return nil |
| 144 | } |
| 145 | |
| 146 | // A SettingID is an HTTP/2 setting as defined in |
| 147 | // http://http2.github.io/http2-spec/#iana-settings |
| 148 | type SettingID uint16 |
| 149 | |
| 150 | const ( |
| 151 | SettingHeaderTableSize SettingID = 0x1 |
| 152 | SettingEnablePush SettingID = 0x2 |
| 153 | SettingMaxConcurrentStreams SettingID = 0x3 |
| 154 | SettingInitialWindowSize SettingID = 0x4 |
| 155 | SettingMaxFrameSize SettingID = 0x5 |
| 156 | SettingMaxHeaderListSize SettingID = 0x6 |
| 157 | ) |
| 158 | |
| 159 | var settingName = map[SettingID]string{ |
| 160 | SettingHeaderTableSize: "HEADER_TABLE_SIZE", |
| 161 | SettingEnablePush: "ENABLE_PUSH", |
| 162 | SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS", |
| 163 | SettingInitialWindowSize: "INITIAL_WINDOW_SIZE", |
| 164 | SettingMaxFrameSize: "MAX_FRAME_SIZE", |
| 165 | SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE", |
| 166 | } |
| 167 | |
| 168 | func (s SettingID) String() string { |
| 169 | if v, ok := settingName[s]; ok { |
| 170 | return v |
| 171 | } |
| 172 | return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s)) |
| 173 | } |
| 174 | |
| 175 | // validWireHeaderFieldName reports whether v is a valid header field |
| 176 | // name (key). See httpguts.ValidHeaderName for the base rules. |
| 177 | // |
| 178 | // Further, http2 says: |
| 179 | // "Just as in HTTP/1.x, header field names are strings of ASCII |
| 180 | // characters that are compared in a case-insensitive |
| 181 | // fashion. However, header field names MUST be converted to |
| 182 | // lowercase prior to their encoding in HTTP/2. " |
| 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 | // from pkg io |
| 209 | type stringWriter interface { |
| 210 | WriteString(s string) (n int, err error) |
| 211 | } |
| 212 | |
| 213 | // A gate lets two goroutines coordinate their activities. |
| 214 | type gate chan struct{} |
| 215 | |
| 216 | func (g gate) Done() { g <- struct{}{} } |
| 217 | func (g gate) Wait() { <-g } |
| 218 | |
| 219 | // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). |
| 220 | type closeWaiter chan struct{} |
| 221 | |
| 222 | // Init makes a closeWaiter usable. |
| 223 | // It exists because so a closeWaiter value can be placed inside a |
| 224 | // larger struct and have the Mutex and Cond's memory in the same |
| 225 | // allocation. |
| 226 | func (cw *closeWaiter) Init() { |
| 227 | *cw = make(chan struct{}) |
| 228 | } |
| 229 | |
| 230 | // Close marks the closeWaiter as closed and unblocks any waiters. |
| 231 | func (cw closeWaiter) Close() { |
| 232 | close(cw) |
| 233 | } |
| 234 | |
| 235 | // Wait waits for the closeWaiter to become closed. |
| 236 | func (cw closeWaiter) Wait() { |
| 237 | <-cw |
| 238 | } |
| 239 | |
| 240 | // bufferedWriter is a buffered writer that writes to w. |
| 241 | // Its buffered writer is lazily allocated as needed, to minimize |
| 242 | // idle memory usage with many connections. |
| 243 | type bufferedWriter struct { |
| 244 | _ incomparable |
| 245 | w io.Writer // immutable |
| 246 | bw *bufio.Writer // non-nil when data is buffered |
| 247 | } |
| 248 | |
| 249 | func newBufferedWriter(w io.Writer) *bufferedWriter { |
| 250 | return &bufferedWriter{w: w} |
| 251 | } |
| 252 | |
| 253 | // bufWriterPoolBufferSize is the size of bufio.Writer's |
| 254 | // buffers created using bufWriterPool. |
| 255 | // |
| 256 | // TODO: pick a less arbitrary value? this is a bit under |
| 257 | // (3 x typical 1500 byte MTU) at least. Other than that, |
| 258 | // not much thought went into it. |
| 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 | // bodyAllowedForStatus reports whether a given response status code |
| 303 | // permits a body. See RFC 7230, section 3.3. |
| 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 // owned by sorter |
| 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 | // Keys returns the sorted keys of h. |
| 343 | // |
| 344 | // The returned slice is only valid until s used again or returned to |
| 345 | // its pool. |
| 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 | // Our sorter works on s.v, which sorter owns, so |
| 358 | // stash it away while we sort the user's buffer. |
| 359 | save := s.v |
| 360 | s.v = ss |
| 361 | sort.Sort(s) |
| 362 | s.v = save |
| 363 | } |
| 364 | |
| 365 | // validPseudoPath reports whether v is a valid :path pseudo-header |
| 366 | // value. It must be either: |
| 367 | // |
| 368 | // *) a non-empty string starting with '/' |
| 369 | // *) the string '*', for OPTIONS requests. |
| 370 | // |
| 371 | // For now this is only used a quick check for deciding when to clean |
| 372 | // up Opaque URLs before sending requests from the Transport. |
| 373 | // See golang.org/issue/16847 |
| 374 | // |
| 375 | // We used to enforce that the path also didn't start with "//", but |
| 376 | // Google's GFE accepts such paths and Chrome sends them, so ignore |
| 377 | // that part of the spec. See golang.org/issue/19103. |
| 378 | func validPseudoPath(v string) bool { |
| 379 | return (len(v) > 0 && v[0] == '/') || v == "*" |
| 380 | } |
| 381 | |
| 382 | // incomparable is a zero-width, non-comparable type. Adding it to a struct |
| 383 | // makes that struct also non-comparable, and generally doesn't add |
| 384 | // any size (as long as it's first). |
| 385 | type incomparable [0]func() |