Matteo Scandolo | a6a3aee | 2019-11-26 13:30:14 -0700 | [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" |
Girish Gowdra | 161d27a | 2021-05-05 12:01:44 -0700 | [diff] [blame] | 22 | "errors" |
Matteo Scandolo | a6a3aee | 2019-11-26 13:30:14 -0700 | [diff] [blame] | 23 | "fmt" |
| 24 | "io" |
| 25 | "net/http" |
| 26 | "os" |
| 27 | "sort" |
| 28 | "strconv" |
| 29 | "strings" |
| 30 | "sync" |
| 31 | |
| 32 | "golang.org/x/net/http/httpguts" |
| 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 | |
Girish Gowdra | 161d27a | 2021-05-05 12:01:44 -0700 | [diff] [blame] | 176 | var ( |
| 177 | errInvalidHeaderFieldName = errors.New("http2: invalid header field name") |
| 178 | errInvalidHeaderFieldValue = errors.New("http2: invalid header field value") |
| 179 | ) |
| 180 | |
Matteo Scandolo | a6a3aee | 2019-11-26 13:30:14 -0700 | [diff] [blame] | 181 | // validWireHeaderFieldName reports whether v is a valid header field |
| 182 | // name (key). See httpguts.ValidHeaderName for the base rules. |
| 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 { |
| 194 | if !httpguts.IsTokenRune(r) { |
| 195 | return false |
| 196 | } |
| 197 | if 'A' <= r && r <= 'Z' { |
| 198 | return false |
| 199 | } |
| 200 | } |
| 201 | return true |
| 202 | } |
| 203 | |
| 204 | func httpCodeString(code int) string { |
| 205 | switch code { |
| 206 | case 200: |
| 207 | return "200" |
| 208 | case 404: |
| 209 | return "404" |
| 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 |
| 308 | // permits a body. See RFC 7230, section 3.3. |
| 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 | } |