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