http2.go

  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.
 16package http2 // import "golang.org/x/net/http2"
 17
 18import (
 19	"bufio"
 20	"context"
 21	"crypto/tls"
 22	"errors"
 23	"fmt"
 24	"net"
 25	"net/http"
 26	"os"
 27	"sort"
 28	"strconv"
 29	"strings"
 30	"sync"
 31	"time"
 32
 33	"golang.org/x/net/http/httpguts"
 34)
 35
 36var (
 37	VerboseLogs    bool
 38	logFrameWrites bool
 39	logFrameReads  bool
 40	inTests        bool
 41
 42	// Enabling extended CONNECT by causes browsers to attempt to use
 43	// WebSockets-over-HTTP/2. This results in problems when the server's websocket
 44	// package doesn't support extended CONNECT.
 45	//
 46	// Disable extended CONNECT by default for now.
 47	//
 48	// Issue #71128.
 49	disableExtendedConnectProtocol = true
 50)
 51
 52func init() {
 53	e := os.Getenv("GODEBUG")
 54	if strings.Contains(e, "http2debug=1") {
 55		VerboseLogs = true
 56	}
 57	if strings.Contains(e, "http2debug=2") {
 58		VerboseLogs = true
 59		logFrameWrites = true
 60		logFrameReads = true
 61	}
 62	if strings.Contains(e, "http2xconnect=1") {
 63		disableExtendedConnectProtocol = false
 64	}
 65}
 66
 67const (
 68	// ClientPreface is the string that must be sent by new
 69	// connections from clients.
 70	ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
 71
 72	// SETTINGS_MAX_FRAME_SIZE default
 73	// https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2
 74	initialMaxFrameSize = 16384
 75
 76	// NextProtoTLS is the NPN/ALPN protocol negotiated during
 77	// HTTP/2's TLS setup.
 78	NextProtoTLS = "h2"
 79
 80	// https://httpwg.org/specs/rfc7540.html#SettingValues
 81	initialHeaderTableSize = 4096
 82
 83	initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
 84
 85	defaultMaxReadFrameSize = 1 << 20
 86)
 87
 88var (
 89	clientPreface = []byte(ClientPreface)
 90)
 91
 92type streamState int
 93
 94// HTTP/2 stream states.
 95//
 96// See http://tools.ietf.org/html/rfc7540#section-5.1.
 97//
 98// For simplicity, the server code merges "reserved (local)" into
 99// "half-closed (remote)". This is one less state transition to track.
100// The only downside is that we send PUSH_PROMISEs slightly less
101// liberally than allowable. More discussion here:
102// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
103//
104// "reserved (remote)" is omitted since the client code does not
105// support server push.
106const (
107	stateIdle streamState = iota
108	stateOpen
109	stateHalfClosedLocal
110	stateHalfClosedRemote
111	stateClosed
112)
113
114var stateName = [...]string{
115	stateIdle:             "Idle",
116	stateOpen:             "Open",
117	stateHalfClosedLocal:  "HalfClosedLocal",
118	stateHalfClosedRemote: "HalfClosedRemote",
119	stateClosed:           "Closed",
120}
121
122func (st streamState) String() string {
123	return stateName[st]
124}
125
126// Setting is a setting parameter: which setting it is, and its value.
127type Setting struct {
128	// ID is which setting is being set.
129	// See https://httpwg.org/specs/rfc7540.html#SettingFormat
130	ID SettingID
131
132	// Val is the value.
133	Val uint32
134}
135
136func (s Setting) String() string {
137	return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
138}
139
140// Valid reports whether the setting is valid.
141func (s Setting) Valid() error {
142	// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
143	switch s.ID {
144	case SettingEnablePush:
145		if s.Val != 1 && s.Val != 0 {
146			return ConnectionError(ErrCodeProtocol)
147		}
148	case SettingInitialWindowSize:
149		if s.Val > 1<<31-1 {
150			return ConnectionError(ErrCodeFlowControl)
151		}
152	case SettingMaxFrameSize:
153		if s.Val < 16384 || s.Val > 1<<24-1 {
154			return ConnectionError(ErrCodeProtocol)
155		}
156	case SettingEnableConnectProtocol:
157		if s.Val != 1 && s.Val != 0 {
158			return ConnectionError(ErrCodeProtocol)
159		}
160	}
161	return nil
162}
163
164// A SettingID is an HTTP/2 setting as defined in
165// https://httpwg.org/specs/rfc7540.html#iana-settings
166type SettingID uint16
167
168const (
169	SettingHeaderTableSize       SettingID = 0x1
170	SettingEnablePush            SettingID = 0x2
171	SettingMaxConcurrentStreams  SettingID = 0x3
172	SettingInitialWindowSize     SettingID = 0x4
173	SettingMaxFrameSize          SettingID = 0x5
174	SettingMaxHeaderListSize     SettingID = 0x6
175	SettingEnableConnectProtocol SettingID = 0x8
176)
177
178var settingName = map[SettingID]string{
179	SettingHeaderTableSize:       "HEADER_TABLE_SIZE",
180	SettingEnablePush:            "ENABLE_PUSH",
181	SettingMaxConcurrentStreams:  "MAX_CONCURRENT_STREAMS",
182	SettingInitialWindowSize:     "INITIAL_WINDOW_SIZE",
183	SettingMaxFrameSize:          "MAX_FRAME_SIZE",
184	SettingMaxHeaderListSize:     "MAX_HEADER_LIST_SIZE",
185	SettingEnableConnectProtocol: "ENABLE_CONNECT_PROTOCOL",
186}
187
188func (s SettingID) String() string {
189	if v, ok := settingName[s]; ok {
190		return v
191	}
192	return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
193}
194
195// validWireHeaderFieldName reports whether v is a valid header field
196// name (key). See httpguts.ValidHeaderName for the base rules.
197//
198// Further, http2 says:
199//
200//	"Just as in HTTP/1.x, header field names are strings of ASCII
201//	characters that are compared in a case-insensitive
202//	fashion. However, header field names MUST be converted to
203//	lowercase prior to their encoding in HTTP/2. "
204func validWireHeaderFieldName(v string) bool {
205	if len(v) == 0 {
206		return false
207	}
208	for _, r := range v {
209		if !httpguts.IsTokenRune(r) {
210			return false
211		}
212		if 'A' <= r && r <= 'Z' {
213			return false
214		}
215	}
216	return true
217}
218
219func httpCodeString(code int) string {
220	switch code {
221	case 200:
222		return "200"
223	case 404:
224		return "404"
225	}
226	return strconv.Itoa(code)
227}
228
229// from pkg io
230type stringWriter interface {
231	WriteString(s string) (n int, err error)
232}
233
234// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
235type closeWaiter chan struct{}
236
237// Init makes a closeWaiter usable.
238// It exists because so a closeWaiter value can be placed inside a
239// larger struct and have the Mutex and Cond's memory in the same
240// allocation.
241func (cw *closeWaiter) Init() {
242	*cw = make(chan struct{})
243}
244
245// Close marks the closeWaiter as closed and unblocks any waiters.
246func (cw closeWaiter) Close() {
247	close(cw)
248}
249
250// Wait waits for the closeWaiter to become closed.
251func (cw closeWaiter) Wait() {
252	<-cw
253}
254
255// bufferedWriter is a buffered writer that writes to w.
256// Its buffered writer is lazily allocated as needed, to minimize
257// idle memory usage with many connections.
258type bufferedWriter struct {
259	_           incomparable
260	group       synctestGroupInterface // immutable
261	conn        net.Conn               // immutable
262	bw          *bufio.Writer          // non-nil when data is buffered
263	byteTimeout time.Duration          // immutable, WriteByteTimeout
264}
265
266func newBufferedWriter(group synctestGroupInterface, conn net.Conn, timeout time.Duration) *bufferedWriter {
267	return &bufferedWriter{
268		group:       group,
269		conn:        conn,
270		byteTimeout: timeout,
271	}
272}
273
274// bufWriterPoolBufferSize is the size of bufio.Writer's
275// buffers created using bufWriterPool.
276//
277// TODO: pick a less arbitrary value? this is a bit under
278// (3 x typical 1500 byte MTU) at least. Other than that,
279// not much thought went into it.
280const bufWriterPoolBufferSize = 4 << 10
281
282var bufWriterPool = sync.Pool{
283	New: func() interface{} {
284		return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
285	},
286}
287
288func (w *bufferedWriter) Available() int {
289	if w.bw == nil {
290		return bufWriterPoolBufferSize
291	}
292	return w.bw.Available()
293}
294
295func (w *bufferedWriter) Write(p []byte) (n int, err error) {
296	if w.bw == nil {
297		bw := bufWriterPool.Get().(*bufio.Writer)
298		bw.Reset((*bufferedWriterTimeoutWriter)(w))
299		w.bw = bw
300	}
301	return w.bw.Write(p)
302}
303
304func (w *bufferedWriter) Flush() error {
305	bw := w.bw
306	if bw == nil {
307		return nil
308	}
309	err := bw.Flush()
310	bw.Reset(nil)
311	bufWriterPool.Put(bw)
312	w.bw = nil
313	return err
314}
315
316type bufferedWriterTimeoutWriter bufferedWriter
317
318func (w *bufferedWriterTimeoutWriter) Write(p []byte) (n int, err error) {
319	return writeWithByteTimeout(w.group, w.conn, w.byteTimeout, p)
320}
321
322// writeWithByteTimeout writes to conn.
323// If more than timeout passes without any bytes being written to the connection,
324// the write fails.
325func writeWithByteTimeout(group synctestGroupInterface, conn net.Conn, timeout time.Duration, p []byte) (n int, err error) {
326	if timeout <= 0 {
327		return conn.Write(p)
328	}
329	for {
330		var now time.Time
331		if group == nil {
332			now = time.Now()
333		} else {
334			now = group.Now()
335		}
336		conn.SetWriteDeadline(now.Add(timeout))
337		nn, err := conn.Write(p[n:])
338		n += nn
339		if n == len(p) || nn == 0 || !errors.Is(err, os.ErrDeadlineExceeded) {
340			// Either we finished the write, made no progress, or hit the deadline.
341			// Whichever it is, we're done now.
342			conn.SetWriteDeadline(time.Time{})
343			return n, err
344		}
345	}
346}
347
348func mustUint31(v int32) uint32 {
349	if v < 0 || v > 2147483647 {
350		panic("out of range")
351	}
352	return uint32(v)
353}
354
355// bodyAllowedForStatus reports whether a given response status code
356// permits a body. See RFC 7230, section 3.3.
357func bodyAllowedForStatus(status int) bool {
358	switch {
359	case status >= 100 && status <= 199:
360		return false
361	case status == 204:
362		return false
363	case status == 304:
364		return false
365	}
366	return true
367}
368
369type httpError struct {
370	_       incomparable
371	msg     string
372	timeout bool
373}
374
375func (e *httpError) Error() string   { return e.msg }
376func (e *httpError) Timeout() bool   { return e.timeout }
377func (e *httpError) Temporary() bool { return true }
378
379var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
380
381type connectionStater interface {
382	ConnectionState() tls.ConnectionState
383}
384
385var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
386
387type sorter struct {
388	v []string // owned by sorter
389}
390
391func (s *sorter) Len() int           { return len(s.v) }
392func (s *sorter) Swap(i, j int)      { s.v[i], s.v[j] = s.v[j], s.v[i] }
393func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
394
395// Keys returns the sorted keys of h.
396//
397// The returned slice is only valid until s used again or returned to
398// its pool.
399func (s *sorter) Keys(h http.Header) []string {
400	keys := s.v[:0]
401	for k := range h {
402		keys = append(keys, k)
403	}
404	s.v = keys
405	sort.Sort(s)
406	return keys
407}
408
409func (s *sorter) SortStrings(ss []string) {
410	// Our sorter works on s.v, which sorter owns, so
411	// stash it away while we sort the user's buffer.
412	save := s.v
413	s.v = ss
414	sort.Sort(s)
415	s.v = save
416}
417
418// incomparable is a zero-width, non-comparable type. Adding it to a struct
419// makes that struct also non-comparable, and generally doesn't add
420// any size (as long as it's first).
421type incomparable [0]func()
422
423// synctestGroupInterface is the methods of synctestGroup used by Server and Transport.
424// It's defined as an interface here to let us keep synctestGroup entirely test-only
425// and not a part of non-test builds.
426type synctestGroupInterface interface {
427	Join()
428	Now() time.Time
429	NewTimer(d time.Duration) timer
430	AfterFunc(d time.Duration, f func()) timer
431	ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc)
432}