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