// 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.
package http2 // import "golang.org/x/net/http2" import ( ) var ( VerboseLogs bool logFrameWrites bool logFrameReads bool inTests bool // Enabling extended CONNECT by causes browsers to attempt to use // WebSockets-over-HTTP/2. This results in problems when the server's websocket // package doesn't support extended CONNECT. // // Disable extended CONNECT by default for now. // // Issue #71128. disableExtendedConnectProtocol = true ) func () { := os.Getenv("GODEBUG") if strings.Contains(, "http2debug=1") { VerboseLogs = true } if strings.Contains(, "http2debug=2") { VerboseLogs = true logFrameWrites = true logFrameReads = true } if strings.Contains(, "http2xconnect=1") { disableExtendedConnectProtocol = false } } 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) } case SettingEnableConnectProtocol: if .Val != 1 && .Val != 0 { 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 SettingEnableConnectProtocol SettingID = 0x8 ) 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", SettingEnableConnectProtocol: "ENABLE_CONNECT_PROTOCOL", } 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 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 group synctestGroupInterface // immutable conn net.Conn // immutable bw *bufio.Writer // non-nil when data is buffered byteTimeout time.Duration // immutable, WriteByteTimeout } func ( synctestGroupInterface, net.Conn, time.Duration) *bufferedWriter { return &bufferedWriter{ group: , conn: , byteTimeout: , } } // 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((*bufferedWriterTimeoutWriter)()) .bw = } return .bw.Write() } func ( *bufferedWriter) () error { := .bw if == nil { return nil } := .Flush() .Reset(nil) bufWriterPool.Put() .bw = nil return } type bufferedWriterTimeoutWriter bufferedWriter func ( *bufferedWriterTimeoutWriter) ( []byte) ( int, error) { return writeWithByteTimeout(.group, .conn, .byteTimeout, ) } // writeWithByteTimeout writes to conn. // If more than timeout passes without any bytes being written to the connection, // the write fails. func ( synctestGroupInterface, net.Conn, time.Duration, []byte) ( int, error) { if <= 0 { return .Write() } for { var time.Time if == nil { = time.Now() } else { = .Now() } .SetWriteDeadline(.Add()) , := .Write([:]) += if == len() || == 0 || !errors.Is(, os.ErrDeadlineExceeded) { // Either we finished the write, made no progress, or hit the deadline. // Whichever it is, we're done now. .SetWriteDeadline(time.Time{}) 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 = } // 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() // synctestGroupInterface is the methods of synctestGroup used by Server and Transport. // It's defined as an interface here to let us keep synctestGroup entirely test-only // and not a part of non-test builds. type synctestGroupInterface interface { Join() Now() time.Time NewTimer(d time.Duration) timer AfterFunc(d time.Duration, f func()) timer ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) }