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// 17package http2 // import "golang.org/x/net/http2" 18 19import ( 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 34var ( 35 VerboseLogs bool 36 logFrameWrites bool 37 logFrameReads bool 38 inTests bool 39) 40 41func 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 53const ( 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 74var ( 75 clientPreface = []byte(ClientPreface) 76) 77 78type 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. 92const ( 93 stateIdle streamState = iota 94 stateOpen 95 stateHalfClosedLocal 96 stateHalfClosedRemote 97 stateClosed 98) 99 100var stateName = [...]string{ 101 stateIdle: "Idle", 102 stateOpen: "Open", 103 stateHalfClosedLocal: "HalfClosedLocal", 104 stateHalfClosedRemote: "HalfClosedRemote", 105 stateClosed: "Closed", 106} 107 108func (st streamState) String() string { 109 return stateName[st] 110} 111 112// Setting is a setting parameter: which setting it is, and its value. 113type 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 122func (s Setting) String() string { 123 return fmt.Sprintf("[%v = %d]", s.ID, s.Val) 124} 125 126// Valid reports whether the setting is valid. 127func (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 148type SettingID uint16 149 150const ( 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 159var 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 168func (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. " 183func 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 198func 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 209type stringWriter interface { 210 WriteString(s string) (n int, err error) 211} 212 213// A gate lets two goroutines coordinate their activities. 214type gate chan struct{} 215 216func (g gate) Done() { g <- struct{}{} } 217func (g gate) Wait() { <-g } 218 219// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). 220type 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. 226func (cw *closeWaiter) Init() { 227 *cw = make(chan struct{}) 228} 229 230// Close marks the closeWaiter as closed and unblocks any waiters. 231func (cw closeWaiter) Close() { 232 close(cw) 233} 234 235// Wait waits for the closeWaiter to become closed. 236func (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. 243type bufferedWriter struct { 244 w io.Writer // immutable 245 bw *bufio.Writer // non-nil when data is buffered 246} 247 248func newBufferedWriter(w io.Writer) *bufferedWriter { 249 return &bufferedWriter{w: w} 250} 251 252// bufWriterPoolBufferSize is the size of bufio.Writer's 253// buffers created using bufWriterPool. 254// 255// TODO: pick a less arbitrary value? this is a bit under 256// (3 x typical 1500 byte MTU) at least. Other than that, 257// not much thought went into it. 258const bufWriterPoolBufferSize = 4 << 10 259 260var bufWriterPool = sync.Pool{ 261 New: func() interface{} { 262 return bufio.NewWriterSize(nil, bufWriterPoolBufferSize) 263 }, 264} 265 266func (w *bufferedWriter) Available() int { 267 if w.bw == nil { 268 return bufWriterPoolBufferSize 269 } 270 return w.bw.Available() 271} 272 273func (w *bufferedWriter) Write(p []byte) (n int, err error) { 274 if w.bw == nil { 275 bw := bufWriterPool.Get().(*bufio.Writer) 276 bw.Reset(w.w) 277 w.bw = bw 278 } 279 return w.bw.Write(p) 280} 281 282func (w *bufferedWriter) Flush() error { 283 bw := w.bw 284 if bw == nil { 285 return nil 286 } 287 err := bw.Flush() 288 bw.Reset(nil) 289 bufWriterPool.Put(bw) 290 w.bw = nil 291 return err 292} 293 294func mustUint31(v int32) uint32 { 295 if v < 0 || v > 2147483647 { 296 panic("out of range") 297 } 298 return uint32(v) 299} 300 301// bodyAllowedForStatus reports whether a given response status code 302// permits a body. See RFC 7230, section 3.3. 303func bodyAllowedForStatus(status int) bool { 304 switch { 305 case status >= 100 && status <= 199: 306 return false 307 case status == 204: 308 return false 309 case status == 304: 310 return false 311 } 312 return true 313} 314 315type httpError struct { 316 msg string 317 timeout bool 318} 319 320func (e *httpError) Error() string { return e.msg } 321func (e *httpError) Timeout() bool { return e.timeout } 322func (e *httpError) Temporary() bool { return true } 323 324var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true} 325 326type connectionStater interface { 327 ConnectionState() tls.ConnectionState 328} 329 330var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }} 331 332type sorter struct { 333 v []string // owned by sorter 334} 335 336func (s *sorter) Len() int { return len(s.v) } 337func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] } 338func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] } 339 340// Keys returns the sorted keys of h. 341// 342// The returned slice is only valid until s used again or returned to 343// its pool. 344func (s *sorter) Keys(h http.Header) []string { 345 keys := s.v[:0] 346 for k := range h { 347 keys = append(keys, k) 348 } 349 s.v = keys 350 sort.Sort(s) 351 return keys 352} 353 354func (s *sorter) SortStrings(ss []string) { 355 // Our sorter works on s.v, which sorter owns, so 356 // stash it away while we sort the user's buffer. 357 save := s.v 358 s.v = ss 359 sort.Sort(s) 360 s.v = save 361} 362 363// validPseudoPath reports whether v is a valid :path pseudo-header 364// value. It must be either: 365// 366// *) a non-empty string starting with '/' 367// *) the string '*', for OPTIONS requests. 368// 369// For now this is only used a quick check for deciding when to clean 370// up Opaque URLs before sending requests from the Transport. 371// See golang.org/issue/16847 372// 373// We used to enforce that the path also didn't start with "//", but 374// Google's GFE accepts such paths and Chrome sends them, so ignore 375// that part of the spec. See golang.org/issue/19103. 376func validPseudoPath(v string) bool { 377 return (len(v) > 0 && v[0] == '/') || v == "*" 378} 379