blob: 003e649f30c6cc1b39641e963719ea441b11963e [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001// 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.
William Kurkianea869482019-04-09 15:16:11 -040016package http2 // import "golang.org/x/net/http2"
17
18import (
19 "bufio"
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +053020 "context"
William Kurkianea869482019-04-09 15:16:11 -040021 "crypto/tls"
William Kurkianea869482019-04-09 15:16:11 -040022 "fmt"
23 "io"
24 "net/http"
25 "os"
26 "sort"
27 "strconv"
28 "strings"
29 "sync"
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +053030 "time"
William Kurkianea869482019-04-09 15:16:11 -040031
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
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +053060 // https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2
William Kurkianea869482019-04-09 15:16:11 -040061 initialMaxFrameSize = 16384
62
63 // NextProtoTLS is the NPN/ALPN protocol negotiated during
64 // HTTP/2's TLS setup.
65 NextProtoTLS = "h2"
66
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +053067 // https://httpwg.org/specs/rfc7540.html#SettingValues
William Kurkianea869482019-04-09 15:16:11 -040068 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.
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530116 // See https://httpwg.org/specs/rfc7540.html#SettingFormat
William Kurkianea869482019-04-09 15:16:11 -0400117 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
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530148// https://httpwg.org/specs/rfc7540.html#iana-settings
William Kurkianea869482019-04-09 15:16:11 -0400149type 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
William Kurkianea869482019-04-09 15:16:11 -0400176// validWireHeaderFieldName reports whether v is a valid header field
177// name (key). See httpguts.ValidHeaderName for the base rules.
178//
179// Further, http2 says:
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530180//
181// "Just as in HTTP/1.x, header field names are strings of ASCII
182// characters that are compared in a case-insensitive
183// fashion. However, header field names MUST be converted to
184// lowercase prior to their encoding in HTTP/2. "
William Kurkianea869482019-04-09 15:16:11 -0400185func validWireHeaderFieldName(v string) bool {
186 if len(v) == 0 {
187 return false
188 }
189 for _, r := range v {
190 if !httpguts.IsTokenRune(r) {
191 return false
192 }
193 if 'A' <= r && r <= 'Z' {
194 return false
195 }
196 }
197 return true
198}
199
200func httpCodeString(code int) string {
201 switch code {
202 case 200:
203 return "200"
204 case 404:
205 return "404"
206 }
207 return strconv.Itoa(code)
208}
209
210// from pkg io
211type stringWriter interface {
212 WriteString(s string) (n int, err error)
213}
214
William Kurkianea869482019-04-09 15:16:11 -0400215// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
216type closeWaiter chan struct{}
217
218// Init makes a closeWaiter usable.
219// It exists because so a closeWaiter value can be placed inside a
220// larger struct and have the Mutex and Cond's memory in the same
221// allocation.
222func (cw *closeWaiter) Init() {
223 *cw = make(chan struct{})
224}
225
226// Close marks the closeWaiter as closed and unblocks any waiters.
227func (cw closeWaiter) Close() {
228 close(cw)
229}
230
231// Wait waits for the closeWaiter to become closed.
232func (cw closeWaiter) Wait() {
233 <-cw
234}
235
236// bufferedWriter is a buffered writer that writes to w.
237// Its buffered writer is lazily allocated as needed, to minimize
238// idle memory usage with many connections.
239type bufferedWriter struct {
khenaidoo106c61a2021-08-11 18:05:46 -0400240 _ incomparable
William Kurkianea869482019-04-09 15:16:11 -0400241 w io.Writer // immutable
242 bw *bufio.Writer // non-nil when data is buffered
243}
244
245func newBufferedWriter(w io.Writer) *bufferedWriter {
246 return &bufferedWriter{w: w}
247}
248
249// bufWriterPoolBufferSize is the size of bufio.Writer's
250// buffers created using bufWriterPool.
251//
252// TODO: pick a less arbitrary value? this is a bit under
253// (3 x typical 1500 byte MTU) at least. Other than that,
254// not much thought went into it.
255const bufWriterPoolBufferSize = 4 << 10
256
257var bufWriterPool = sync.Pool{
258 New: func() interface{} {
259 return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
260 },
261}
262
263func (w *bufferedWriter) Available() int {
264 if w.bw == nil {
265 return bufWriterPoolBufferSize
266 }
267 return w.bw.Available()
268}
269
270func (w *bufferedWriter) Write(p []byte) (n int, err error) {
271 if w.bw == nil {
272 bw := bufWriterPool.Get().(*bufio.Writer)
273 bw.Reset(w.w)
274 w.bw = bw
275 }
276 return w.bw.Write(p)
277}
278
279func (w *bufferedWriter) Flush() error {
280 bw := w.bw
281 if bw == nil {
282 return nil
283 }
284 err := bw.Flush()
285 bw.Reset(nil)
286 bufWriterPool.Put(bw)
287 w.bw = nil
288 return err
289}
290
291func mustUint31(v int32) uint32 {
292 if v < 0 || v > 2147483647 {
293 panic("out of range")
294 }
295 return uint32(v)
296}
297
298// bodyAllowedForStatus reports whether a given response status code
299// permits a body. See RFC 7230, section 3.3.
300func bodyAllowedForStatus(status int) bool {
301 switch {
302 case status >= 100 && status <= 199:
303 return false
304 case status == 204:
305 return false
306 case status == 304:
307 return false
308 }
309 return true
310}
311
312type httpError struct {
khenaidoo106c61a2021-08-11 18:05:46 -0400313 _ incomparable
William Kurkianea869482019-04-09 15:16:11 -0400314 msg string
315 timeout bool
316}
317
318func (e *httpError) Error() string { return e.msg }
319func (e *httpError) Timeout() bool { return e.timeout }
320func (e *httpError) Temporary() bool { return true }
321
322var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
323
324type connectionStater interface {
325 ConnectionState() tls.ConnectionState
326}
327
328var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
329
330type sorter struct {
331 v []string // owned by sorter
332}
333
334func (s *sorter) Len() int { return len(s.v) }
335func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
336func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
337
338// Keys returns the sorted keys of h.
339//
340// The returned slice is only valid until s used again or returned to
341// its pool.
342func (s *sorter) Keys(h http.Header) []string {
343 keys := s.v[:0]
344 for k := range h {
345 keys = append(keys, k)
346 }
347 s.v = keys
348 sort.Sort(s)
349 return keys
350}
351
352func (s *sorter) SortStrings(ss []string) {
353 // Our sorter works on s.v, which sorter owns, so
354 // stash it away while we sort the user's buffer.
355 save := s.v
356 s.v = ss
357 sort.Sort(s)
358 s.v = save
359}
360
361// validPseudoPath reports whether v is a valid :path pseudo-header
362// value. It must be either:
363//
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530364// - a non-empty string starting with '/'
365// - the string '*', for OPTIONS requests.
William Kurkianea869482019-04-09 15:16:11 -0400366//
367// For now this is only used a quick check for deciding when to clean
368// up Opaque URLs before sending requests from the Transport.
369// See golang.org/issue/16847
370//
371// We used to enforce that the path also didn't start with "//", but
372// Google's GFE accepts such paths and Chrome sends them, so ignore
373// that part of the spec. See golang.org/issue/19103.
374func validPseudoPath(v string) bool {
375 return (len(v) > 0 && v[0] == '/') || v == "*"
376}
khenaidoo106c61a2021-08-11 18:05:46 -0400377
378// incomparable is a zero-width, non-comparable type. Adding it to a struct
379// makes that struct also non-comparable, and generally doesn't add
380// any size (as long as it's first).
381type incomparable [0]func()
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530382
383// synctestGroupInterface is the methods of synctestGroup used by Server and Transport.
384// It's defined as an interface here to let us keep synctestGroup entirely test-only
385// and not a part of non-test builds.
386type synctestGroupInterface interface {
387 Join()
388 Now() time.Time
389 NewTimer(d time.Duration) timer
390 AfterFunc(d time.Duration, f func()) timer
391 ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc)
392}