blob: 6c18ea230be09ba062cd8fe3270a0f67b9deec45 [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001// 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.
khenaidooac637102019-01-14 15:44:34 -050016package http2 // import "golang.org/x/net/http2"
17
18import (
19 "bufio"
mgouda64be8822025-05-30 10:44:00 +053020 "context"
khenaidooac637102019-01-14 15:44:34 -050021 "crypto/tls"
mgouda64be8822025-05-30 10:44:00 +053022 "errors"
khenaidooac637102019-01-14 15:44:34 -050023 "fmt"
mgouda64be8822025-05-30 10:44:00 +053024 "net"
khenaidooac637102019-01-14 15:44:34 -050025 "net/http"
26 "os"
27 "sort"
28 "strconv"
29 "strings"
30 "sync"
mgouda64be8822025-05-30 10:44:00 +053031 "time"
khenaidooac637102019-01-14 15:44:34 -050032
33 "golang.org/x/net/http/httpguts"
34)
35
36var (
37 VerboseLogs bool
38 logFrameWrites bool
39 logFrameReads bool
40 inTests bool
mgouda64be8822025-05-30 10:44:00 +053041
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
khenaidooac637102019-01-14 15:44:34 -050050)
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 }
mgouda64be8822025-05-30 10:44:00 +053062 if strings.Contains(e, "http2xconnect=1") {
63 disableExtendedConnectProtocol = false
64 }
khenaidooac637102019-01-14 15:44:34 -050065}
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
mgouda64be8822025-05-30 10:44:00 +053073 // https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2
khenaidooac637102019-01-14 15:44:34 -050074 initialMaxFrameSize = 16384
75
76 // NextProtoTLS is the NPN/ALPN protocol negotiated during
77 // HTTP/2's TLS setup.
78 NextProtoTLS = "h2"
79
mgouda64be8822025-05-30 10:44:00 +053080 // https://httpwg.org/specs/rfc7540.html#SettingValues
khenaidooac637102019-01-14 15:44:34 -050081 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.
mgouda64be8822025-05-30 10:44:00 +0530129 // See https://httpwg.org/specs/rfc7540.html#SettingFormat
khenaidooac637102019-01-14 15:44:34 -0500130 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 }
mgouda64be8822025-05-30 10:44:00 +0530156 case SettingEnableConnectProtocol:
157 if s.Val != 1 && s.Val != 0 {
158 return ConnectionError(ErrCodeProtocol)
159 }
khenaidooac637102019-01-14 15:44:34 -0500160 }
161 return nil
162}
163
164// A SettingID is an HTTP/2 setting as defined in
mgouda64be8822025-05-30 10:44:00 +0530165// https://httpwg.org/specs/rfc7540.html#iana-settings
khenaidooac637102019-01-14 15:44:34 -0500166type SettingID uint16
167
168const (
mgouda64be8822025-05-30 10:44:00 +0530169 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
khenaidooac637102019-01-14 15:44:34 -0500176)
177
178var settingName = map[SettingID]string{
mgouda64be8822025-05-30 10:44:00 +0530179 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",
khenaidooac637102019-01-14 15:44:34 -0500186}
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
khenaidooac637102019-01-14 15:44:34 -0500195// validWireHeaderFieldName reports whether v is a valid header field
196// name (key). See httpguts.ValidHeaderName for the base rules.
197//
198// Further, http2 says:
mgouda64be8822025-05-30 10:44:00 +0530199//
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. "
khenaidooac637102019-01-14 15:44:34 -0500204func 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
khenaidooac637102019-01-14 15:44:34 -0500234// 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 {
mgouda64be8822025-05-30 10:44:00 +0530259 _ 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
khenaidooac637102019-01-14 15:44:34 -0500264}
265
mgouda64be8822025-05-30 10:44:00 +0530266func newBufferedWriter(group synctestGroupInterface, conn net.Conn, timeout time.Duration) *bufferedWriter {
267 return &bufferedWriter{
268 group: group,
269 conn: conn,
270 byteTimeout: timeout,
271 }
khenaidooac637102019-01-14 15:44:34 -0500272}
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)
mgouda64be8822025-05-30 10:44:00 +0530298 bw.Reset((*bufferedWriterTimeoutWriter)(w))
khenaidooac637102019-01-14 15:44:34 -0500299 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
mgouda64be8822025-05-30 10:44:00 +0530316type 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
khenaidooac637102019-01-14 15:44:34 -0500348func 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 {
Andrea Campanella3614a922021-02-25 12:40:42 +0100370 _ incomparable
khenaidooac637102019-01-14 15:44:34 -0500371 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
Andrea Campanella3614a922021-02-25 12:40:42 +0100418// 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()
mgouda64be8822025-05-30 10:44:00 +0530422
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}