|
|
// 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 ( "bufio" "crypto/tls" "errors" "fmt" "io" "net/http" "os" "sort" "strconv" "strings" "sync"
"golang.org/x/net/lex/httplex" )
var ( VerboseLogs bool logFrameWrites bool logFrameReads bool inTests bool )
func init() { e := os.Getenv("GODEBUG") if strings.Contains(e, "http2debug=1") { VerboseLogs = true } if strings.Contains(e, "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
// http://http2.github.io/http2-spec/#rfc.section.6.5.2
initialMaxFrameSize = 16384
// NextProtoTLS is the NPN/ALPN protocol negotiated during
// HTTP/2's TLS setup.
NextProtoTLS = "h2"
// http://http2.github.io/http2-spec/#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 (st streamState) String() string { return stateName[st] }
// Setting is a setting parameter: which setting it is, and its value.
type Setting struct { // ID is which setting is being set.
// See http://http2.github.io/http2-spec/#SettingValues
ID SettingID
// Val is the value.
Val uint32 }
func (s Setting) String() string { return fmt.Sprintf("[%v = %d]", s.ID, s.Val) }
// Valid reports whether the setting is valid.
func (s Setting) Valid() error { // Limits and error codes from 6.5.2 Defined SETTINGS Parameters
switch s.ID { case SettingEnablePush: if s.Val != 1 && s.Val != 0 { return ConnectionError(ErrCodeProtocol) } case SettingInitialWindowSize: if s.Val > 1<<31-1 { return ConnectionError(ErrCodeFlowControl) } case SettingMaxFrameSize: if s.Val < 16384 || s.Val > 1<<24-1 { return ConnectionError(ErrCodeProtocol) } } return nil }
// A SettingID is an HTTP/2 setting as defined in
// http://http2.github.io/http2-spec/#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 (s SettingID) String() string { if v, ok := settingName[s]; ok { return v } return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s)) }
var ( errInvalidHeaderFieldName = errors.New("http2: invalid header field name") errInvalidHeaderFieldValue = errors.New("http2: invalid header field value") )
// validWireHeaderFieldName reports whether v is a valid header field
// name (key). See httplex.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(v string) bool { if len(v) == 0 { return false } for _, r := range v { if !httplex.IsTokenRune(r) { return false } if 'A' <= r && r <= 'Z' { return false } } return true }
var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
func init() { for i := 100; i <= 999; i++ { if v := http.StatusText(i); v != "" { httpCodeStringCommon[i] = strconv.Itoa(i) } } }
func httpCodeString(code int) string { if s, ok := httpCodeStringCommon[code]; ok { return s } return strconv.Itoa(code) }
// 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 (g gate) Done() { g <- struct{}{} } func (g gate) Wait() { <-g }
// 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 (cw *closeWaiter) Init() { *cw = make(chan struct{}) }
// Close marks the closeWaiter as closed and unblocks any waiters.
func (cw closeWaiter) Close() { close(cw) }
// Wait waits for the closeWaiter to become closed.
func (cw closeWaiter) Wait() { <-cw }
// 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 { w io.Writer // immutable
bw *bufio.Writer // non-nil when data is buffered
}
func newBufferedWriter(w io.Writer) *bufferedWriter { return &bufferedWriter{w: 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 (w *bufferedWriter) Available() int { if w.bw == nil { return bufWriterPoolBufferSize } return w.bw.Available() }
func (w *bufferedWriter) Write(p []byte) (n int, err error) { if w.bw == nil { bw := bufWriterPool.Get().(*bufio.Writer) bw.Reset(w.w) w.bw = bw } return w.bw.Write(p) }
func (w *bufferedWriter) Flush() error { bw := w.bw if bw == nil { return nil } err := bw.Flush() bw.Reset(nil) bufWriterPool.Put(bw) w.bw = nil return err }
func mustUint31(v int32) uint32 { if v < 0 || v > 2147483647 { panic("out of range") } return uint32(v) }
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC 2616, section 4.4.
func bodyAllowedForStatus(status int) bool { switch { case status >= 100 && status <= 199: return false case status == 204: return false case status == 304: return false } return true }
type httpError struct { msg string timeout bool }
func (e *httpError) Error() string { return e.msg } func (e *httpError) Timeout() bool { return e.timeout } func (e *httpError) Temporary() 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 (s *sorter) Len() int { return len(s.v) } func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] } func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
// Keys returns the sorted keys of h.
//
// The returned slice is only valid until s used again or returned to
// its pool.
func (s *sorter) Keys(h http.Header) []string { keys := s.v[:0] for k := range h { keys = append(keys, k) } s.v = keys sort.Sort(s) return keys }
func (s *sorter) SortStrings(ss []string) { // Our sorter works on s.v, which sorter owns, so
// stash it away while we sort the user's buffer.
save := s.v s.v = ss sort.Sort(s) s.v = save }
// 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 validPseudoPath(v string) bool { return (len(v) > 0 && v[0] == '/') || v == "*" }
|