// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package http2 implements the HTTP/2 protocol. // // This package is low-level and intended to be used directly by very // few people. Most users will use it indirectly through the automatic // use by the net/http package (from Go 1.6 and later). // For use in earlier Go versions see ConfigureServer. (Transport support // requires Go 1.6 or later) // // See https://http2.github.io/ for more information on HTTP/2. // // See https://http2.golang.org/ for a test server running this code.
package http2 // import "golang.org/x/net/http2" import ( ) var ( VerboseLogs bool logFrameWrites bool logFrameReads bool inTests bool ) func () { := os.Getenv("GODEBUG") if strings.Contains(, "http2debug=1") { VerboseLogs = true } if strings.Contains(, "http2debug=2") { VerboseLogs = true logFrameWrites = true logFrameReads = true } } const ( // ClientPreface is the string that must be sent by new // connections from clients. ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" // SETTINGS_MAX_FRAME_SIZE default // https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2 initialMaxFrameSize = 16384 // NextProtoTLS is the NPN/ALPN protocol negotiated during // HTTP/2's TLS setup. NextProtoTLS = "h2" // https://httpwg.org/specs/rfc7540.html#SettingValues initialHeaderTableSize = 4096 initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size defaultMaxReadFrameSize = 1 << 20 ) var ( clientPreface = []byte(ClientPreface) ) type streamState int // HTTP/2 stream states. // // See http://tools.ietf.org/html/rfc7540#section-5.1. // // For simplicity, the server code merges "reserved (local)" into // "half-closed (remote)". This is one less state transition to track. // The only downside is that we send PUSH_PROMISEs slightly less // liberally than allowable. More discussion here: // https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html // // "reserved (remote)" is omitted since the client code does not // support server push. const ( stateIdle streamState = iota stateOpen stateHalfClosedLocal stateHalfClosedRemote stateClosed ) var stateName = [...]string{ stateIdle: "Idle", stateOpen: "Open", stateHalfClosedLocal: "HalfClosedLocal", stateHalfClosedRemote: "HalfClosedRemote", stateClosed: "Closed", } func ( streamState) () string { return stateName[] } // Setting is a setting parameter: which setting it is, and its value. type Setting struct { // ID is which setting is being set. // See https://httpwg.org/specs/rfc7540.html#SettingFormat ID SettingID // Val is the value. Val uint32 } func ( Setting) () string { return fmt.Sprintf("[%v = %d]", .ID, .Val) } // Valid reports whether the setting is valid. func ( Setting) () error { // Limits and error codes from 6.5.2 Defined SETTINGS Parameters switch .ID { case SettingEnablePush: if .Val != 1 && .Val != 0 { return ConnectionError(ErrCodeProtocol) } case SettingInitialWindowSize: if .Val > 1<<31-1 { return ConnectionError(ErrCodeFlowControl) } case SettingMaxFrameSize: if .Val < 16384 || .Val > 1<<24-1 { return ConnectionError(ErrCodeProtocol) } } return nil } // A SettingID is an HTTP/2 setting as defined in // https://httpwg.org/specs/rfc7540.html#iana-settings type SettingID uint16 const ( SettingHeaderTableSize SettingID = 0x1 SettingEnablePush SettingID = 0x2 SettingMaxConcurrentStreams SettingID = 0x3 SettingInitialWindowSize SettingID = 0x4 SettingMaxFrameSize SettingID = 0x5 SettingMaxHeaderListSize SettingID = 0x6 ) var settingName = map[SettingID]string{ SettingHeaderTableSize: "HEADER_TABLE_SIZE", SettingEnablePush: "ENABLE_PUSH", SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS", SettingInitialWindowSize: "INITIAL_WINDOW_SIZE", SettingMaxFrameSize: "MAX_FRAME_SIZE", SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE", } func ( SettingID) () string { if , := settingName[]; { return } return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16()) } // validWireHeaderFieldName reports whether v is a valid header field // name (key). See httpguts.ValidHeaderName for the base rules. // // Further, http2 says: // // "Just as in HTTP/1.x, header field names are strings of ASCII // characters that are compared in a case-insensitive // fashion. However, header field names MUST be converted to // lowercase prior to their encoding in HTTP/2. " func ( string) bool { if len() == 0 { return false } for , := range { if !httpguts.IsTokenRune() { return false } if 'A' <= && <= 'Z' { return false } } return true } func ( int) string { switch { case 200: return "200" case 404: return "404" } return strconv.Itoa() } // from pkg io type stringWriter interface { WriteString(s string) (n int, err error) } // A gate lets two goroutines coordinate their activities. type gate chan struct{} func ( gate) () { <- struct{}{} } func ( gate) () { <- } // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). type closeWaiter chan struct{} // Init makes a closeWaiter usable. // It exists because so a closeWaiter value can be placed inside a // larger struct and have the Mutex and Cond's memory in the same // allocation. func ( *closeWaiter) () { * = make(chan struct{}) } // Close marks the closeWaiter as closed and unblocks any waiters. func ( closeWaiter) () { close() } // Wait waits for the closeWaiter to become closed. func ( closeWaiter) () { <- } // bufferedWriter is a buffered writer that writes to w. // Its buffered writer is lazily allocated as needed, to minimize // idle memory usage with many connections. type bufferedWriter struct { _ incomparable w io.Writer // immutable bw *bufio.Writer // non-nil when data is buffered } func ( io.Writer) *bufferedWriter { return &bufferedWriter{w: } } // bufWriterPoolBufferSize is the size of bufio.Writer's // buffers created using bufWriterPool. // // TODO: pick a less arbitrary value? this is a bit under // (3 x typical 1500 byte MTU) at least. Other than that, // not much thought went into it. const bufWriterPoolBufferSize = 4 << 10 var bufWriterPool = sync.Pool{ New: func() interface{} { return bufio.NewWriterSize(nil, bufWriterPoolBufferSize) }, } func ( *bufferedWriter) () int { if .bw == nil { return bufWriterPoolBufferSize } return .bw.Available() } func ( *bufferedWriter) ( []byte) ( int, error) { if .bw == nil { := bufWriterPool.Get().(*bufio.Writer) .Reset(.w) .bw = } return .bw.Write() } func ( *bufferedWriter) () error { := .bw if == nil { return nil } := .Flush() .Reset(nil) bufWriterPool.Put() .bw = nil return } func ( int32) uint32 { if < 0 || > 2147483647 { panic("out of range") } return uint32() } // bodyAllowedForStatus reports whether a given response status code // permits a body. See RFC 7230, section 3.3. func ( int) bool { switch { case >= 100 && <= 199: return false case == 204: return false case == 304: return false } return true } type httpError struct { _ incomparable msg string timeout bool } func ( *httpError) () string { return .msg } func ( *httpError) () bool { return .timeout } func ( *httpError) () bool { return true } var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true} type connectionStater interface { ConnectionState() tls.ConnectionState } var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }} type sorter struct { v []string // owned by sorter } func ( *sorter) () int { return len(.v) } func ( *sorter) (, int) { .v[], .v[] = .v[], .v[] } func ( *sorter) (, int) bool { return .v[] < .v[] } // Keys returns the sorted keys of h. // // The returned slice is only valid until s used again or returned to // its pool. func ( *sorter) ( http.Header) []string { := .v[:0] for := range { = append(, ) } .v = sort.Sort() return } func ( *sorter) ( []string) { // Our sorter works on s.v, which sorter owns, so // stash it away while we sort the user's buffer. := .v .v = sort.Sort() .v = } // validPseudoPath reports whether v is a valid :path pseudo-header // value. It must be either: // // - a non-empty string starting with '/' // - the string '*', for OPTIONS requests. // // For now this is only used a quick check for deciding when to clean // up Opaque URLs before sending requests from the Transport. // See golang.org/issue/16847 // // We used to enforce that the path also didn't start with "//", but // Google's GFE accepts such paths and Chrome sends them, so ignore // that part of the spec. See golang.org/issue/19103. func ( string) bool { return (len() > 0 && [0] == '/') || == "*" } // incomparable is a zero-width, non-comparable type. Adding it to a struct // makes that struct also non-comparable, and generally doesn't add // any size (as long as it's first). type incomparable [0]func()