// 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 (VerboseLogsbool logFrameWrites bool logFrameReads 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 init() { := os.Getenv("GODEBUG")ifstrings.Contains(, "http2debug=1") {VerboseLogs = true }ifstrings.Contains(, "http2debug=2") {VerboseLogs = truelogFrameWrites = truelogFrameReads = true }ifstrings.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 {returnstateName[]}// Setting is a setting parameter: which setting it is, and its value.typeSettingstruct {// 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 {returnfmt.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 Parametersswitch .ID {caseSettingEnablePush:if .Val != 1 && .Val != 0 {returnConnectionError(ErrCodeProtocol) }caseSettingInitialWindowSize:if .Val > 1<<31-1 {returnConnectionError(ErrCodeFlowControl) }caseSettingMaxFrameSize:if .Val < 16384 || .Val > 1<<24-1 {returnConnectionError(ErrCodeProtocol) }caseSettingEnableConnectProtocol:if .Val != 1 && .Val != 0 {returnConnectionError(ErrCodeProtocol) } }returnnil}// A SettingID is an HTTP/2 setting as defined in// https://httpwg.org/specs/rfc7540.html#iana-settingstypeSettingIDuint16const (SettingHeaderTableSizeSettingID = 0x1SettingEnablePushSettingID = 0x2SettingMaxConcurrentStreamsSettingID = 0x3SettingInitialWindowSizeSettingID = 0x4SettingMaxFrameSizeSettingID = 0x5SettingMaxHeaderListSizeSettingID = 0x6SettingEnableConnectProtocolSettingID = 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 }returnfmt.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 validWireHeaderFieldName( string) bool {iflen() == 0 {returnfalse }for , := range {if !httpguts.IsTokenRune() {returnfalse }if'A' <= && <= 'Z' {returnfalse } }returntrue}func httpCodeString( int) string {switch {case200:return"200"case404:return"404" }returnstrconv.Itoa()}// from pkg iotype 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 chanstruct{}// 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(chanstruct{})}// 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 conn net.Conn// immutable bw *bufio.Writer// non-nil when data is buffered byteTimeout time.Duration// immutable, WriteByteTimeout}func newBufferedWriter( net.Conn, time.Duration) *bufferedWriter {return &bufferedWriter{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 << 10var bufWriterPool = sync.Pool{New: func() interface{} {returnbufio.NewWriterSize(nil, bufWriterPoolBufferSize) },}func ( *bufferedWriter) () int {if .bw == nil {returnbufWriterPoolBufferSize }return .bw.Available()}func ( *bufferedWriter) ( []byte) ( int, error) {if .bw == nil { := bufWriterPool.Get().(*bufio.Writer) .Reset((*bufferedWriterTimeoutWriter)()) .bw = }return .bw.Write()}func ( *bufferedWriter) () error { := .bwif == nil {returnnil } := .Flush() .Reset(nil)bufWriterPool.Put() .bw = nilreturn}type bufferedWriterTimeoutWriter bufferedWriterfunc ( *bufferedWriterTimeoutWriter) ( []byte) ( int, error) {returnwriteWithByteTimeout(.conn, .byteTimeout, )}// writeWithByteTimeout writes to conn.// If more than timeout passes without any bytes being written to the connection,// the write fails.func writeWithByteTimeout( net.Conn, time.Duration, []byte) ( int, error) {if <= 0 {return .Write() }for { .SetWriteDeadline(time.Now().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 mustUint31( int32) uint32 {if < 0 || > 2147483647 {panic("out of range") }returnuint32()}// bodyAllowedForStatus reports whether a given response status code// permits a body. See RFC 7230, section 3.3.func bodyAllowedForStatus( int) bool {switch {case >= 100 && <= 199:returnfalsecase == 204:returnfalsecase == 304:returnfalse }returntrue}type httpError struct { _ incomparable msg string timeout bool}func ( *httpError) () string { return .msg }func ( *httpError) () bool { return .timeout }func ( *httpError) () bool { returntrue }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{} { returnnew(sorter) }}type sorter struct { v []string// owned by sorter}func ( *sorter) () int { returnlen(.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()
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.