2021-07-30 14:28:58 -07:00
//go:build !nethttpomithttp2
2020-01-02 15:05:27 -08:00
// +build !nethttpomithttp2
2017-06-08 19:02:12 +00:00
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
2020-01-02 15:05:27 -08:00
// $ bundle -o=h2_bundle.go -prefix=http2 -tags=!nethttpomithttp2 golang.org/x/net/http2
2016-02-03 21:58:02 +00:00
// Package http2 implements the HTTP/2 protocol.
//
// This package is low-level and intended to be used directly by very
// few people. Most users will use it indirectly through the automatic
// use by the net/http package (from Go 1.6 and later).
// For use in earlier Go versions see ConfigureServer. (Transport support
// requires Go 1.6 or later)
//
// See https://http2.github.io/ for more information on HTTP/2.
//
// See https://http2.golang.org/ for a test server running this code.
//
package http
import (
"bufio"
"bytes"
"compress/gzip"
2016-07-22 18:15:38 +00:00
"context"
2017-01-14 00:05:42 +00:00
"crypto/rand"
2016-02-03 21:58:02 +00:00
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
2016-09-10 13:14:00 +00:00
"math"
2018-01-09 01:23:08 +00:00
mathrand "math/rand"
2016-02-03 21:58:02 +00:00
"net"
2016-07-22 18:15:38 +00:00
"net/http/httptrace"
2016-02-03 21:58:02 +00:00
"net/textproto"
"net/url"
"os"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"sync"
2019-09-06 18:12:46 +00:00
"sync/atomic"
2016-02-03 21:58:02 +00:00
"time"
2016-07-22 18:15:38 +00:00
2019-09-06 18:12:46 +00:00
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/idna"
2016-02-03 21:58:02 +00:00
)
2022-02-11 14:53:56 -08:00
// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
// contains helper functions which may use Unicode-aware functions which would
// otherwise be unsafe and could introduce vulnerabilities if used improperly.
2021-07-30 14:28:58 -07:00
// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
// are equal, ASCII-case-insensitively.
func http2asciiEqualFold ( s , t string ) bool {
if len ( s ) != len ( t ) {
return false
}
for i := 0 ; i < len ( s ) ; i ++ {
if http2lower ( s [ i ] ) != http2lower ( t [ i ] ) {
return false
}
}
return true
}
// lower returns the ASCII lowercase version of b.
func http2lower ( b byte ) byte {
if 'A' <= b && b <= 'Z' {
return b + ( 'a' - 'A' )
}
return b
}
// isASCIIPrint returns whether s is ASCII and printable according to
// https://tools.ietf.org/html/rfc20#section-4.2.
func http2isASCIIPrint ( s string ) bool {
for i := 0 ; i < len ( s ) ; i ++ {
if s [ i ] < ' ' || s [ i ] > '~' {
return false
}
}
return true
}
// asciiToLower returns the lowercase version of s if s is ASCII and printable,
// and whether or not it was.
func http2asciiToLower ( s string ) ( lower string , ok bool ) {
if ! http2isASCIIPrint ( s ) {
return "" , false
}
return strings . ToLower ( s ) , true
}
2017-09-14 17:11:35 +00:00
// A list of the possible cipher suite ids. Taken from
2018-09-24 21:46:21 +00:00
// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt
2017-09-14 17:11:35 +00:00
const (
http2cipher_TLS_NULL_WITH_NULL_NULL uint16 = 0x0000
http2cipher_TLS_RSA_WITH_NULL_MD5 uint16 = 0x0001
http2cipher_TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
http2cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0003
http2cipher_TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
http2cipher_TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
http2cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x0006
http2cipher_TLS_RSA_WITH_IDEA_CBC_SHA uint16 = 0x0007
http2cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0008
http2cipher_TLS_RSA_WITH_DES_CBC_SHA uint16 = 0x0009
http2cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000A
http2cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000B
http2cipher_TLS_DH_DSS_WITH_DES_CBC_SHA uint16 = 0x000C
http2cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x000D
http2cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000E
http2cipher_TLS_DH_RSA_WITH_DES_CBC_SHA uint16 = 0x000F
http2cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0010
http2cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
http2cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA uint16 = 0x0012
http2cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x0013
http2cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
http2cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA uint16 = 0x0015
http2cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0016
http2cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0017
http2cipher_TLS_DH_anon_WITH_RC4_128_MD5 uint16 = 0x0018
http2cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
http2cipher_TLS_DH_anon_WITH_DES_CBC_SHA uint16 = 0x001A
http2cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0x001B
// Reserved uint16 = 0x001C-1D
http2cipher_TLS_KRB5_WITH_DES_CBC_SHA uint16 = 0x001E
http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA uint16 = 0x001F
http2cipher_TLS_KRB5_WITH_RC4_128_SHA uint16 = 0x0020
http2cipher_TLS_KRB5_WITH_IDEA_CBC_SHA uint16 = 0x0021
http2cipher_TLS_KRB5_WITH_DES_CBC_MD5 uint16 = 0x0022
http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5 uint16 = 0x0023
http2cipher_TLS_KRB5_WITH_RC4_128_MD5 uint16 = 0x0024
http2cipher_TLS_KRB5_WITH_IDEA_CBC_MD5 uint16 = 0x0025
http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA uint16 = 0x0026
http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA uint16 = 0x0027
http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA uint16 = 0x0028
http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 uint16 = 0x0029
http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x002A
http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5 uint16 = 0x002B
http2cipher_TLS_PSK_WITH_NULL_SHA uint16 = 0x002C
http2cipher_TLS_DHE_PSK_WITH_NULL_SHA uint16 = 0x002D
http2cipher_TLS_RSA_PSK_WITH_NULL_SHA uint16 = 0x002E
http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002F
http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0030
http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0031
http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0032
http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0033
http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA uint16 = 0x0034
http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0036
http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0037
http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0038
http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0039
http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA uint16 = 0x003A
http2cipher_TLS_RSA_WITH_NULL_SHA256 uint16 = 0x003B
http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003C
http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003D
http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x003E
http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003F
http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x0040
http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0041
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0042
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0043
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
// Reserved uint16 = 0x0047-4F
// Reserved uint16 = 0x0050-58
// Reserved uint16 = 0x0059-5C
// Unassigned uint16 = 0x005D-5F
// Reserved uint16 = 0x0060-66
http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x0068
http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x0069
http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
// Unassigned uint16 = 0x006E-83
http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0084
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0085
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0086
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0087
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0088
http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0089
http2cipher_TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008A
http2cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008B
http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008C
http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008D
http2cipher_TLS_DHE_PSK_WITH_RC4_128_SHA uint16 = 0x008E
http2cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008F
http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0090
http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0091
http2cipher_TLS_RSA_PSK_WITH_RC4_128_SHA uint16 = 0x0092
http2cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x0093
http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0094
http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0095
http2cipher_TLS_RSA_WITH_SEED_CBC_SHA uint16 = 0x0096
http2cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA uint16 = 0x0097
http2cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA uint16 = 0x0098
http2cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA uint16 = 0x0099
http2cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA uint16 = 0x009A
http2cipher_TLS_DH_anon_WITH_SEED_CBC_SHA uint16 = 0x009B
http2cipher_TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009C
http2cipher_TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009D
http2cipher_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009E
http2cipher_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009F
http2cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x00A0
http2cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x00A1
http2cipher_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A2
http2cipher_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A3
http2cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A4
http2cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A5
http2cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256 uint16 = 0x00A6
http2cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384 uint16 = 0x00A7
http2cipher_TLS_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00A8
http2cipher_TLS_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00A9
http2cipher_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AA
http2cipher_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AB
http2cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AC
http2cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AD
http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00AE
http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00AF
http2cipher_TLS_PSK_WITH_NULL_SHA256 uint16 = 0x00B0
http2cipher_TLS_PSK_WITH_NULL_SHA384 uint16 = 0x00B1
http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B2
http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B3
http2cipher_TLS_DHE_PSK_WITH_NULL_SHA256 uint16 = 0x00B4
http2cipher_TLS_DHE_PSK_WITH_NULL_SHA384 uint16 = 0x00B5
http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B6
http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B7
http2cipher_TLS_RSA_PSK_WITH_NULL_SHA256 uint16 = 0x00B8
http2cipher_TLS_RSA_PSK_WITH_NULL_SHA384 uint16 = 0x00B9
http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BA
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BB
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BC
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C0
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C1
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C2
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
// Unassigned uint16 = 0x00C6-FE
http2cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
// Unassigned uint16 = 0x01-55,*
http2cipher_TLS_FALLBACK_SCSV uint16 = 0x5600
// Unassigned uint16 = 0x5601 - 0xC000
http2cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA uint16 = 0xC001
http2cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA uint16 = 0xC002
http2cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC003
http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC004
http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC005
http2cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA uint16 = 0xC006
http2cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xC007
http2cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC008
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC009
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC00A
http2cipher_TLS_ECDH_RSA_WITH_NULL_SHA uint16 = 0xC00B
http2cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA uint16 = 0xC00C
http2cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC00D
http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC00E
http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC00F
http2cipher_TLS_ECDHE_RSA_WITH_NULL_SHA uint16 = 0xC010
http2cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xC011
http2cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC012
http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC013
http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC014
http2cipher_TLS_ECDH_anon_WITH_NULL_SHA uint16 = 0xC015
http2cipher_TLS_ECDH_anon_WITH_RC4_128_SHA uint16 = 0xC016
http2cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0xC017
http2cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA uint16 = 0xC018
http2cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA uint16 = 0xC019
http2cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01A
http2cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01B
http2cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01C
http2cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA uint16 = 0xC01D
http2cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC01E
http2cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA uint16 = 0xC01F
http2cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA uint16 = 0xC020
http2cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC021
http2cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA uint16 = 0xC022
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC023
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC024
http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC025
http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC026
http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC027
http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC028
http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC029
http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC02A
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02B
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02C
http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02D
http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02E
http2cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02F
http2cipher_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC030
http2cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC031
http2cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC032
http2cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA uint16 = 0xC033
http2cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0xC034
http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xC035
http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xC036
http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0xC037
http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0xC038
http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA uint16 = 0xC039
http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256 uint16 = 0xC03A
http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384 uint16 = 0xC03B
http2cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03C
http2cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03D
http2cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03E
http2cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03F
http2cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC040
http2cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC041
http2cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC042
http2cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC043
http2cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC044
http2cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC045
http2cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC046
http2cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC047
http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC048
http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC049
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04A
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04B
http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04C
http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04D
http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04E
http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04F
http2cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC050
http2cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC051
http2cipher_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC052
http2cipher_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC053
http2cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC054
http2cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC055
http2cipher_TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC056
http2cipher_TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC057
http2cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC058
http2cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC059
http2cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05A
http2cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05B
http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05C
http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05D
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05E
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05F
http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC060
http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC061
http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC062
http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC063
http2cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC064
http2cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC065
http2cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC066
http2cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC067
http2cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC068
http2cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC069
http2cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06A
http2cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06B
http2cipher_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06C
http2cipher_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06D
http2cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06E
http2cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06F
http2cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC070
http2cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC071
http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC074
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC075
http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC076
http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC077
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC078
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC079
http2cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07A
http2cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07B
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07C
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07D
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07E
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07F
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC080
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC081
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC082
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC083
http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC084
http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC085
http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC088
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC089
http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08A
http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08B
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08C
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08D
http2cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08E
http2cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08F
http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC090
http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC091
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC092
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC093
http2cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC094
http2cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC095
http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC096
http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC097
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC098
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC099
http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC09A
http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC09B
http2cipher_TLS_RSA_WITH_AES_128_CCM uint16 = 0xC09C
http2cipher_TLS_RSA_WITH_AES_256_CCM uint16 = 0xC09D
http2cipher_TLS_DHE_RSA_WITH_AES_128_CCM uint16 = 0xC09E
http2cipher_TLS_DHE_RSA_WITH_AES_256_CCM uint16 = 0xC09F
http2cipher_TLS_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A0
http2cipher_TLS_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A1
http2cipher_TLS_DHE_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A2
http2cipher_TLS_DHE_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A3
http2cipher_TLS_PSK_WITH_AES_128_CCM uint16 = 0xC0A4
http2cipher_TLS_PSK_WITH_AES_256_CCM uint16 = 0xC0A5
http2cipher_TLS_DHE_PSK_WITH_AES_128_CCM uint16 = 0xC0A6
http2cipher_TLS_DHE_PSK_WITH_AES_256_CCM uint16 = 0xC0A7
http2cipher_TLS_PSK_WITH_AES_128_CCM_8 uint16 = 0xC0A8
http2cipher_TLS_PSK_WITH_AES_256_CCM_8 uint16 = 0xC0A9
http2cipher_TLS_PSK_DHE_WITH_AES_128_CCM_8 uint16 = 0xC0AA
http2cipher_TLS_PSK_DHE_WITH_AES_256_CCM_8 uint16 = 0xC0AB
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM uint16 = 0xC0AC
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM uint16 = 0xC0AD
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 uint16 = 0xC0AE
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 uint16 = 0xC0AF
// Unassigned uint16 = 0xC0B0-FF
// Unassigned uint16 = 0xC1-CB,*
// Unassigned uint16 = 0xCC00-A7
http2cipher_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA8
http2cipher_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9
http2cipher_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAA
http2cipher_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAB
http2cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAC
http2cipher_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAD
http2cipher_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAE
)
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
// References:
// https://tools.ietf.org/html/rfc7540#appendix-A
// Reject cipher suites from Appendix A.
// "This list includes those cipher suites that do not
// offer an ephemeral key exchange and those that are
// based on the TLS null, stream or block cipher type"
func http2isBadCipher ( cipher uint16 ) bool {
switch cipher {
case http2cipher_TLS_NULL_WITH_NULL_NULL ,
http2cipher_TLS_RSA_WITH_NULL_MD5 ,
http2cipher_TLS_RSA_WITH_NULL_SHA ,
http2cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5 ,
http2cipher_TLS_RSA_WITH_RC4_128_MD5 ,
http2cipher_TLS_RSA_WITH_RC4_128_SHA ,
http2cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 ,
http2cipher_TLS_RSA_WITH_IDEA_CBC_SHA ,
http2cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA ,
http2cipher_TLS_RSA_WITH_DES_CBC_SHA ,
http2cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_DES_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_DES_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 ,
http2cipher_TLS_DH_anon_WITH_RC4_128_MD5 ,
http2cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_DES_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_KRB5_WITH_DES_CBC_SHA ,
http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_KRB5_WITH_RC4_128_SHA ,
http2cipher_TLS_KRB5_WITH_IDEA_CBC_SHA ,
http2cipher_TLS_KRB5_WITH_DES_CBC_MD5 ,
http2cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5 ,
http2cipher_TLS_KRB5_WITH_RC4_128_MD5 ,
http2cipher_TLS_KRB5_WITH_IDEA_CBC_MD5 ,
http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA ,
http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA ,
http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA ,
http2cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 ,
http2cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 ,
http2cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5 ,
http2cipher_TLS_PSK_WITH_NULL_SHA ,
http2cipher_TLS_DHE_PSK_WITH_NULL_SHA ,
http2cipher_TLS_RSA_PSK_WITH_NULL_SHA ,
http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_RSA_WITH_NULL_SHA256 ,
http2cipher_TLS_RSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_RSA_WITH_AES_256_CBC_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 ,
http2cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 ,
http2cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ,
http2cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 ,
http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA ,
http2cipher_TLS_PSK_WITH_RC4_128_SHA ,
http2cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_DHE_PSK_WITH_RC4_128_SHA ,
http2cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_RSA_PSK_WITH_RC4_128_SHA ,
http2cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_RSA_WITH_SEED_CBC_SHA ,
http2cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA ,
http2cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA ,
http2cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA ,
http2cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA ,
http2cipher_TLS_DH_anon_WITH_SEED_CBC_SHA ,
http2cipher_TLS_RSA_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_RSA_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_PSK_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_PSK_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_PSK_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_PSK_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_PSK_WITH_NULL_SHA256 ,
http2cipher_TLS_PSK_WITH_NULL_SHA384 ,
http2cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_DHE_PSK_WITH_NULL_SHA256 ,
http2cipher_TLS_DHE_PSK_WITH_NULL_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_NULL_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_NULL_SHA384 ,
http2cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 ,
http2cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 ,
http2cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 ,
http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 ,
http2cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV ,
http2cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA ,
http2cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA ,
http2cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA ,
http2cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA ,
http2cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_ECDH_RSA_WITH_NULL_SHA ,
http2cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA ,
http2cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_ECDHE_RSA_WITH_NULL_SHA ,
http2cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA ,
http2cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_ECDH_anon_WITH_NULL_SHA ,
http2cipher_TLS_ECDH_anon_WITH_RC4_128_SHA ,
http2cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 ,
http2cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 ,
http2cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA ,
http2cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA ,
http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA ,
http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA ,
http2cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA ,
http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256 ,
http2cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384 ,
http2cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 ,
http2cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 ,
http2cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 ,
http2cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 ,
http2cipher_TLS_RSA_WITH_AES_128_CCM ,
http2cipher_TLS_RSA_WITH_AES_256_CCM ,
http2cipher_TLS_RSA_WITH_AES_128_CCM_8 ,
http2cipher_TLS_RSA_WITH_AES_256_CCM_8 ,
http2cipher_TLS_PSK_WITH_AES_128_CCM ,
http2cipher_TLS_PSK_WITH_AES_256_CCM ,
http2cipher_TLS_PSK_WITH_AES_128_CCM_8 ,
http2cipher_TLS_PSK_WITH_AES_256_CCM_8 :
return true
default :
return false
}
}
2016-02-03 21:58:02 +00:00
// ClientConnPool manages a pool of HTTP/2 client connections.
type http2ClientConnPool interface {
2022-02-11 14:53:56 -08:00
// GetClientConn returns a specific HTTP/2 connection (usually
// a TLS-TCP connection) to an HTTP/2 server. On success, the
// returned ClientConn accounts for the upcoming RoundTrip
// call, so the caller should not omit it. If the caller needs
// to, ClientConn.RoundTrip can be called with a bogus
// new(http.Request) to release the stream reservation.
2016-02-03 21:58:02 +00:00
GetClientConn ( req * Request , addr string ) ( * http2ClientConn , error )
MarkDead ( * http2ClientConn )
}
2016-07-22 18:15:38 +00:00
// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
// implementations which can close their idle connections.
type http2clientConnPoolIdleCloser interface {
http2ClientConnPool
closeIdleConnections ( )
}
var (
_ http2clientConnPoolIdleCloser = ( * http2clientConnPool ) ( nil )
_ http2clientConnPoolIdleCloser = http2noDialClientConnPool { }
)
2016-02-03 21:58:02 +00:00
// TODO: use singleflight for dialing and addConnCalls?
type http2clientConnPool struct {
t * http2Transport
mu sync . Mutex // TODO: maybe switch to RWMutex
// TODO: add support for sharing conns based on cert names
// (e.g. share conn for googleapis.com and appspot.com)
conns map [ string ] [ ] * http2ClientConn // key is host:port
dialing map [ string ] * http2dialCall // currently in-flight dials
keys map [ * http2ClientConn ] [ ] string
2022-02-11 14:53:56 -08:00
addConnCalls map [ string ] * http2addConnCall // in-flight addConnIfNeeded calls
2016-02-03 21:58:02 +00:00
}
func ( p * http2clientConnPool ) GetClientConn ( req * Request , addr string ) ( * http2ClientConn , error ) {
return p . getClientConn ( req , addr , http2dialOnMiss )
}
const (
http2dialOnMiss = true
http2noDialOnMiss = false
)
2016-09-10 13:14:00 +00:00
func ( p * http2clientConnPool ) getClientConn ( req * Request , addr string , dialOnMiss bool ) ( * http2ClientConn , error ) {
2022-02-11 14:53:56 -08:00
// TODO(dneil): Dial a new connection when t.DisableKeepAlives is set?
2016-09-10 13:14:00 +00:00
if http2isConnectionCloseRequest ( req ) && dialOnMiss {
// It gets its own connection.
2018-09-24 21:46:21 +00:00
http2traceGetConn ( req , addr )
2016-09-10 13:14:00 +00:00
const singleUse = true
2021-07-30 14:28:58 -07:00
cc , err := p . t . dialClientConn ( req . Context ( ) , addr , singleUse )
2016-09-10 13:14:00 +00:00
if err != nil {
return nil , err
}
return cc , nil
}
2021-07-30 14:28:58 -07:00
for {
p . mu . Lock ( )
for _ , cc := range p . conns [ addr ] {
2022-02-11 14:53:56 -08:00
if cc . ReserveNewRequest ( ) {
// When a connection is presented to us by the net/http package,
// the GetConn hook has already been called.
// Don't call it a second time here.
if ! cc . getConnCalled {
2021-07-30 14:28:58 -07:00
http2traceGetConn ( req , addr )
}
2022-02-11 14:53:56 -08:00
cc . getConnCalled = false
2021-07-30 14:28:58 -07:00
p . mu . Unlock ( )
return cc , nil
2018-09-24 21:46:21 +00:00
}
2021-07-30 14:28:58 -07:00
}
if ! dialOnMiss {
2016-02-03 21:58:02 +00:00
p . mu . Unlock ( )
2021-07-30 14:28:58 -07:00
return nil , http2ErrNoCachedConn
2016-02-03 21:58:02 +00:00
}
2021-07-30 14:28:58 -07:00
http2traceGetConn ( req , addr )
call := p . getStartDialLocked ( req . Context ( ) , addr )
2016-02-03 21:58:02 +00:00
p . mu . Unlock ( )
2021-07-30 14:28:58 -07:00
<- call . done
if http2shouldRetryDial ( call , req ) {
continue
}
2022-02-11 14:53:56 -08:00
cc , err := call . res , call . err
if err != nil {
return nil , err
}
if cc . ReserveNewRequest ( ) {
return cc , nil
}
2016-02-03 21:58:02 +00:00
}
}
// dialCall is an in-flight Transport dial call to a host.
type http2dialCall struct {
2021-07-30 14:28:58 -07:00
_ http2incomparable
p * http2clientConnPool
// the context associated with the request
// that created this dialCall
ctx context . Context
2016-02-03 21:58:02 +00:00
done chan struct { } // closed when done
res * http2ClientConn // valid after done is closed
err error // valid after done is closed
}
// requires p.mu is held.
2021-07-30 14:28:58 -07:00
func ( p * http2clientConnPool ) getStartDialLocked ( ctx context . Context , addr string ) * http2dialCall {
2016-02-03 21:58:02 +00:00
if call , ok := p . dialing [ addr ] ; ok {
2017-09-14 17:11:35 +00:00
// A dial is already in-flight. Don't start another.
2016-02-03 21:58:02 +00:00
return call
}
2021-07-30 14:28:58 -07:00
call := & http2dialCall { p : p , done : make ( chan struct { } ) , ctx : ctx }
2016-02-03 21:58:02 +00:00
if p . dialing == nil {
p . dialing = make ( map [ string ] * http2dialCall )
}
p . dialing [ addr ] = call
2021-07-30 14:28:58 -07:00
go call . dial ( call . ctx , addr )
2016-02-03 21:58:02 +00:00
return call
}
// run in its own goroutine.
2021-07-30 14:28:58 -07:00
func ( c * http2dialCall ) dial ( ctx context . Context , addr string ) {
2016-09-10 13:14:00 +00:00
const singleUse = false // shared conn
2021-07-30 14:28:58 -07:00
c . res , c . err = c . p . t . dialClientConn ( ctx , addr , singleUse )
2016-02-03 21:58:02 +00:00
close ( c . done )
c . p . mu . Lock ( )
delete ( c . p . dialing , addr )
if c . err == nil {
c . p . addConnLocked ( addr , c . res )
}
c . p . mu . Unlock ( )
}
// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
// already exist. It coalesces concurrent calls with the same key.
// This is used by the http1 Transport code when it creates a new connection. Because
// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
// the protocol), it can get into a situation where it has multiple TLS connections.
// This code decides which ones live or die.
// The return value used is whether c was used.
// c is never closed.
func ( p * http2clientConnPool ) addConnIfNeeded ( key string , t * http2Transport , c * tls . Conn ) ( used bool , err error ) {
p . mu . Lock ( )
for _ , cc := range p . conns [ key ] {
if cc . CanTakeNewRequest ( ) {
p . mu . Unlock ( )
return false , nil
}
}
call , dup := p . addConnCalls [ key ]
if ! dup {
if p . addConnCalls == nil {
p . addConnCalls = make ( map [ string ] * http2addConnCall )
}
call = & http2addConnCall {
p : p ,
done : make ( chan struct { } ) ,
}
p . addConnCalls [ key ] = call
go call . run ( t , key , c )
}
p . mu . Unlock ( )
<- call . done
if call . err != nil {
return false , call . err
}
return ! dup , nil
}
type http2addConnCall struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
p * http2clientConnPool
done chan struct { } // closed when done
err error
}
func ( c * http2addConnCall ) run ( t * http2Transport , key string , tc * tls . Conn ) {
cc , err := t . NewClientConn ( tc )
p := c . p
p . mu . Lock ( )
if err != nil {
c . err = err
} else {
2022-02-11 14:53:56 -08:00
cc . getConnCalled = true // already called by the net/http package
2016-02-03 21:58:02 +00:00
p . addConnLocked ( key , cc )
}
delete ( p . addConnCalls , key )
p . mu . Unlock ( )
close ( c . done )
}
// p.mu must be held
func ( p * http2clientConnPool ) addConnLocked ( key string , cc * http2ClientConn ) {
for _ , v := range p . conns [ key ] {
if v == cc {
return
}
}
if p . conns == nil {
p . conns = make ( map [ string ] [ ] * http2ClientConn )
}
if p . keys == nil {
p . keys = make ( map [ * http2ClientConn ] [ ] string )
}
p . conns [ key ] = append ( p . conns [ key ] , cc )
p . keys [ cc ] = append ( p . keys [ cc ] , key )
}
func ( p * http2clientConnPool ) MarkDead ( cc * http2ClientConn ) {
p . mu . Lock ( )
defer p . mu . Unlock ( )
for _ , key := range p . keys [ cc ] {
vv , ok := p . conns [ key ]
if ! ok {
continue
}
newList := http2filterOutClientConn ( vv , cc )
if len ( newList ) > 0 {
p . conns [ key ] = newList
} else {
delete ( p . conns , key )
}
}
delete ( p . keys , cc )
}
func ( p * http2clientConnPool ) closeIdleConnections ( ) {
p . mu . Lock ( )
defer p . mu . Unlock ( )
2017-09-14 17:11:35 +00:00
// TODO: don't close a cc if it was just added to the pool
// milliseconds ago and has never been used. There's currently
// a small race window with the HTTP/1 Transport's integration
// where it can add an idle conn just before using it, and
// somebody else can concurrently call CloseIdleConns and
// break some caller's RoundTrip.
2016-02-03 21:58:02 +00:00
for _ , vv := range p . conns {
for _ , cc := range vv {
cc . closeIfIdle ( )
}
}
}
func http2filterOutClientConn ( in [ ] * http2ClientConn , exclude * http2ClientConn ) [ ] * http2ClientConn {
out := in [ : 0 ]
for _ , v := range in {
if v != exclude {
out = append ( out , v )
}
}
2017-09-14 17:11:35 +00:00
// If we filtered it out, zero out the last item to prevent
// the GC from seeing it.
2016-02-03 21:58:02 +00:00
if len ( in ) != len ( out ) {
in [ len ( in ) - 1 ] = nil
}
return out
}
2016-07-22 18:15:38 +00:00
// noDialClientConnPool is an implementation of http2.ClientConnPool
2017-09-14 17:11:35 +00:00
// which never dials. We let the HTTP/1.1 client dial and use its TLS
2016-07-22 18:15:38 +00:00
// connection instead.
type http2noDialClientConnPool struct { * http2clientConnPool }
func ( p http2noDialClientConnPool ) GetClientConn ( req * Request , addr string ) ( * http2ClientConn , error ) {
return p . getClientConn ( req , addr , http2noDialOnMiss )
}
2021-07-30 14:28:58 -07:00
// shouldRetryDial reports whether the current request should
// retry dialing after the call finished unsuccessfully, for example
// if the dial was canceled because of a context cancellation or
// deadline expiry.
func http2shouldRetryDial ( call * http2dialCall , req * Request ) bool {
if call . err == nil {
// No error, no need to retry
return false
}
if call . ctx == req . Context ( ) {
// If the call has the same context as the request, the dial
// should not be retried, since any cancellation will have come
// from this request.
return false
}
if ! errors . Is ( call . err , context . Canceled ) && ! errors . Is ( call . err , context . DeadlineExceeded ) {
// If the call error is not because of a context cancellation or a deadline expiry,
// the dial should not be retried.
return false
}
// Only retry if the error is a context cancellation error or deadline expiry
// and the context associated with the call was canceled or expired.
return call . ctx . Err ( ) != nil
}
2017-09-14 17:11:35 +00:00
// Buffer chunks are allocated from a pool to reduce pressure on GC.
// The maximum wasted space per dataBuffer is 2x the largest size class,
// which happens when the dataBuffer has multiple chunks and there is
// one unread byte in both the first and last chunks. We use a few size
// classes to minimize overheads for servers that typically receive very
// small request bodies.
//
// TODO: Benchmark to determine if the pools are necessary. The GC may have
// improved enough that we can instead allocate chunks like this:
// make([]byte, max(16<<10, expectedBytesRemaining))
var (
http2dataChunkSizeClasses = [ ] int {
1 << 10 ,
2 << 10 ,
4 << 10 ,
8 << 10 ,
16 << 10 ,
}
http2dataChunkPools = [ ... ] sync . Pool {
{ New : func ( ) interface { } { return make ( [ ] byte , 1 << 10 ) } } ,
{ New : func ( ) interface { } { return make ( [ ] byte , 2 << 10 ) } } ,
{ New : func ( ) interface { } { return make ( [ ] byte , 4 << 10 ) } } ,
{ New : func ( ) interface { } { return make ( [ ] byte , 8 << 10 ) } } ,
{ New : func ( ) interface { } { return make ( [ ] byte , 16 << 10 ) } } ,
}
)
func http2getDataBufferChunk ( size int64 ) [ ] byte {
i := 0
for ; i < len ( http2dataChunkSizeClasses ) - 1 ; i ++ {
if size <= int64 ( http2dataChunkSizeClasses [ i ] ) {
break
}
}
return http2dataChunkPools [ i ] . Get ( ) . ( [ ] byte )
}
func http2putDataBufferChunk ( p [ ] byte ) {
for i , n := range http2dataChunkSizeClasses {
if len ( p ) == n {
http2dataChunkPools [ i ] . Put ( p )
return
}
}
panic ( fmt . Sprintf ( "unexpected buffer len=%v" , len ( p ) ) )
}
// dataBuffer is an io.ReadWriter backed by a list of data chunks.
// Each dataBuffer is used to read DATA frames on a single stream.
// The buffer is divided into chunks so the server can limit the
// total memory used by a single connection without limiting the
// request body size on any single stream.
type http2dataBuffer struct {
chunks [ ] [ ] byte
r int // next byte to read is chunks[0][r]
w int // next byte to write is chunks[len(chunks)-1][w]
size int // total buffered bytes
expected int64 // we expect at least this many bytes in future Write calls (ignored if <= 0)
}
var http2errReadEmpty = errors . New ( "read from empty dataBuffer" )
// Read copies bytes from the buffer into p.
// It is an error to read when no data is available.
func ( b * http2dataBuffer ) Read ( p [ ] byte ) ( int , error ) {
if b . size == 0 {
return 0 , http2errReadEmpty
}
var ntotal int
for len ( p ) > 0 && b . size > 0 {
readFrom := b . bytesFromFirstChunk ( )
n := copy ( p , readFrom )
p = p [ n : ]
ntotal += n
b . r += n
b . size -= n
// If the first chunk has been consumed, advance to the next chunk.
if b . r == len ( b . chunks [ 0 ] ) {
http2putDataBufferChunk ( b . chunks [ 0 ] )
end := len ( b . chunks ) - 1
copy ( b . chunks [ : end ] , b . chunks [ 1 : ] )
b . chunks [ end ] = nil
b . chunks = b . chunks [ : end ]
b . r = 0
}
}
return ntotal , nil
}
func ( b * http2dataBuffer ) bytesFromFirstChunk ( ) [ ] byte {
if len ( b . chunks ) == 1 {
return b . chunks [ 0 ] [ b . r : b . w ]
}
return b . chunks [ 0 ] [ b . r : ]
}
// Len returns the number of bytes of the unread portion of the buffer.
func ( b * http2dataBuffer ) Len ( ) int {
return b . size
}
// Write appends p to the buffer.
func ( b * http2dataBuffer ) Write ( p [ ] byte ) ( int , error ) {
ntotal := len ( p )
for len ( p ) > 0 {
// If the last chunk is empty, allocate a new chunk. Try to allocate
// enough to fully copy p plus any additional bytes we expect to
// receive. However, this may allocate less than len(p).
want := int64 ( len ( p ) )
if b . expected > want {
want = b . expected
}
chunk := b . lastChunkOrAlloc ( want )
n := copy ( chunk [ b . w : ] , p )
p = p [ n : ]
b . w += n
b . size += n
b . expected -= int64 ( n )
}
return ntotal , nil
}
func ( b * http2dataBuffer ) lastChunkOrAlloc ( want int64 ) [ ] byte {
if len ( b . chunks ) != 0 {
last := b . chunks [ len ( b . chunks ) - 1 ]
if b . w < len ( last ) {
return last
}
}
chunk := http2getDataBufferChunk ( want )
b . chunks = append ( b . chunks , chunk )
b . w = 0
return chunk
}
2016-02-03 21:58:02 +00:00
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
type http2ErrCode uint32
const (
http2ErrCodeNo http2ErrCode = 0x0
http2ErrCodeProtocol http2ErrCode = 0x1
http2ErrCodeInternal http2ErrCode = 0x2
http2ErrCodeFlowControl http2ErrCode = 0x3
http2ErrCodeSettingsTimeout http2ErrCode = 0x4
http2ErrCodeStreamClosed http2ErrCode = 0x5
http2ErrCodeFrameSize http2ErrCode = 0x6
http2ErrCodeRefusedStream http2ErrCode = 0x7
http2ErrCodeCancel http2ErrCode = 0x8
http2ErrCodeCompression http2ErrCode = 0x9
http2ErrCodeConnect http2ErrCode = 0xa
http2ErrCodeEnhanceYourCalm http2ErrCode = 0xb
http2ErrCodeInadequateSecurity http2ErrCode = 0xc
http2ErrCodeHTTP11Required http2ErrCode = 0xd
)
var http2errCodeName = map [ http2ErrCode ] string {
http2ErrCodeNo : "NO_ERROR" ,
http2ErrCodeProtocol : "PROTOCOL_ERROR" ,
http2ErrCodeInternal : "INTERNAL_ERROR" ,
http2ErrCodeFlowControl : "FLOW_CONTROL_ERROR" ,
http2ErrCodeSettingsTimeout : "SETTINGS_TIMEOUT" ,
http2ErrCodeStreamClosed : "STREAM_CLOSED" ,
http2ErrCodeFrameSize : "FRAME_SIZE_ERROR" ,
http2ErrCodeRefusedStream : "REFUSED_STREAM" ,
http2ErrCodeCancel : "CANCEL" ,
http2ErrCodeCompression : "COMPRESSION_ERROR" ,
http2ErrCodeConnect : "CONNECT_ERROR" ,
http2ErrCodeEnhanceYourCalm : "ENHANCE_YOUR_CALM" ,
http2ErrCodeInadequateSecurity : "INADEQUATE_SECURITY" ,
http2ErrCodeHTTP11Required : "HTTP_1_1_REQUIRED" ,
}
func ( e http2ErrCode ) String ( ) string {
if s , ok := http2errCodeName [ e ] ; ok {
return s
}
return fmt . Sprintf ( "unknown error code 0x%x" , uint32 ( e ) )
}
2022-02-11 14:53:56 -08:00
func ( e http2ErrCode ) stringToken ( ) string {
if s , ok := http2errCodeName [ e ] ; ok {
return s
}
return fmt . Sprintf ( "ERR_UNKNOWN_%d" , uint32 ( e ) )
}
2016-02-03 21:58:02 +00:00
// ConnectionError is an error that results in the termination of the
// entire connection.
type http2ConnectionError http2ErrCode
func ( e http2ConnectionError ) Error ( ) string {
return fmt . Sprintf ( "connection error: %s" , http2ErrCode ( e ) )
}
// StreamError is an error that only affects one stream within an
// HTTP/2 connection.
type http2StreamError struct {
StreamID uint32
Code http2ErrCode
2016-09-10 13:14:00 +00:00
Cause error // optional additional detail
}
2022-02-11 14:53:56 -08:00
// errFromPeer is a sentinel error value for StreamError.Cause to
// indicate that the StreamError was sent from the peer over the wire
// and wasn't locally generated in the Transport.
var http2errFromPeer = errors . New ( "received from peer" )
2016-09-10 13:14:00 +00:00
func http2streamError ( id uint32 , code http2ErrCode ) http2StreamError {
return http2StreamError { StreamID : id , Code : code }
2016-02-03 21:58:02 +00:00
}
func ( e http2StreamError ) Error ( ) string {
2016-09-10 13:14:00 +00:00
if e . Cause != nil {
return fmt . Sprintf ( "stream error: stream ID %d; %v; %v" , e . StreamID , e . Code , e . Cause )
}
2016-02-03 21:58:02 +00:00
return fmt . Sprintf ( "stream error: stream ID %d; %v" , e . StreamID , e . Code )
}
// 6.9.1 The Flow Control Window
// "If a sender receives a WINDOW_UPDATE that causes a flow control
// window to exceed this maximum it MUST terminate either the stream
// or the connection, as appropriate. For streams, [...]; for the
// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
type http2goAwayFlowError struct { }
func ( http2goAwayFlowError ) Error ( ) string { return "connection exceeded flow control window size" }
2017-09-14 17:11:35 +00:00
// connError represents an HTTP/2 ConnectionError error code, along
// with a string (for debugging) explaining why.
//
2016-02-03 21:58:02 +00:00
// Errors of this type are only returned by the frame parser functions
2017-09-14 17:11:35 +00:00
// and converted into ConnectionError(Code), after stashing away
// the Reason into the Framer's errDetail field, accessible via
// the (*Framer).ErrorDetail method.
2016-02-03 21:58:02 +00:00
type http2connError struct {
2017-09-14 17:11:35 +00:00
Code http2ErrCode // the ConnectionError error code
Reason string // additional reason
2016-02-03 21:58:02 +00:00
}
func ( e http2connError ) Error ( ) string {
return fmt . Sprintf ( "http2: connection error: %v: %v" , e . Code , e . Reason )
}
2016-07-22 18:15:38 +00:00
type http2pseudoHeaderError string
func ( e http2pseudoHeaderError ) Error ( ) string {
return fmt . Sprintf ( "invalid pseudo-header %q" , string ( e ) )
}
type http2duplicatePseudoHeaderError string
func ( e http2duplicatePseudoHeaderError ) Error ( ) string {
return fmt . Sprintf ( "duplicate pseudo-header %q" , string ( e ) )
}
type http2headerFieldNameError string
func ( e http2headerFieldNameError ) Error ( ) string {
return fmt . Sprintf ( "invalid header field name %q" , string ( e ) )
}
type http2headerFieldValueError string
func ( e http2headerFieldValueError ) Error ( ) string {
return fmt . Sprintf ( "invalid header field value %q" , string ( e ) )
}
var (
http2errMixPseudoHeaderTypes = errors . New ( "mix of request and response pseudo headers" )
http2errPseudoAfterRegular = errors . New ( "pseudo header field after regular" )
)
2016-02-03 21:58:02 +00:00
// flow is the flow control window's size.
type http2flow struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
// n is the number of DATA bytes we're allowed to send.
// A flow is kept both on a conn and a per-stream.
n int32
// conn points to the shared connection-level flow that is
// shared by all streams on that conn. It is nil for the flow
// that's on the conn directly.
conn * http2flow
}
func ( f * http2flow ) setConnFlow ( cf * http2flow ) { f . conn = cf }
func ( f * http2flow ) available ( ) int32 {
n := f . n
if f . conn != nil && f . conn . n < n {
n = f . conn . n
}
return n
}
func ( f * http2flow ) take ( n int32 ) {
if n > f . available ( ) {
panic ( "internal error: took too much" )
}
f . n -= n
if f . conn != nil {
f . conn . n -= n
}
}
// add adds n bytes (positive or negative) to the flow control window.
// It returns false if the sum would exceed 2^31-1.
func ( f * http2flow ) add ( n int32 ) bool {
2018-09-24 21:46:21 +00:00
sum := f . n + n
if ( sum > n ) == ( f . n > 0 ) {
f . n = sum
return true
2016-02-03 21:58:02 +00:00
}
2018-09-24 21:46:21 +00:00
return false
2016-02-03 21:58:02 +00:00
}
const http2frameHeaderLen = 9
var http2padZeros = make ( [ ] byte , 255 ) // zeros for padding
// A FrameType is a registered frame type as defined in
// http://http2.github.io/http2-spec/#rfc.section.11.2
type http2FrameType uint8
const (
http2FrameData http2FrameType = 0x0
http2FrameHeaders http2FrameType = 0x1
http2FramePriority http2FrameType = 0x2
http2FrameRSTStream http2FrameType = 0x3
http2FrameSettings http2FrameType = 0x4
http2FramePushPromise http2FrameType = 0x5
http2FramePing http2FrameType = 0x6
http2FrameGoAway http2FrameType = 0x7
http2FrameWindowUpdate http2FrameType = 0x8
http2FrameContinuation http2FrameType = 0x9
)
var http2frameName = map [ http2FrameType ] string {
http2FrameData : "DATA" ,
http2FrameHeaders : "HEADERS" ,
http2FramePriority : "PRIORITY" ,
http2FrameRSTStream : "RST_STREAM" ,
http2FrameSettings : "SETTINGS" ,
http2FramePushPromise : "PUSH_PROMISE" ,
http2FramePing : "PING" ,
http2FrameGoAway : "GOAWAY" ,
http2FrameWindowUpdate : "WINDOW_UPDATE" ,
http2FrameContinuation : "CONTINUATION" ,
}
func ( t http2FrameType ) String ( ) string {
if s , ok := http2frameName [ t ] ; ok {
return s
}
return fmt . Sprintf ( "UNKNOWN_FRAME_TYPE_%d" , uint8 ( t ) )
}
// Flags is a bitmask of HTTP/2 flags.
// The meaning of flags varies depending on the frame type.
type http2Flags uint8
// Has reports whether f contains all (0 or more) flags in v.
func ( f http2Flags ) Has ( v http2Flags ) bool {
return ( f & v ) == v
}
// Frame-specific FrameHeader flag bits.
const (
// Data Frame
http2FlagDataEndStream http2Flags = 0x1
http2FlagDataPadded http2Flags = 0x8
// Headers Frame
http2FlagHeadersEndStream http2Flags = 0x1
http2FlagHeadersEndHeaders http2Flags = 0x4
http2FlagHeadersPadded http2Flags = 0x8
http2FlagHeadersPriority http2Flags = 0x20
// Settings Frame
http2FlagSettingsAck http2Flags = 0x1
// Ping Frame
http2FlagPingAck http2Flags = 0x1
// Continuation Frame
http2FlagContinuationEndHeaders http2Flags = 0x4
http2FlagPushPromiseEndHeaders http2Flags = 0x4
http2FlagPushPromisePadded http2Flags = 0x8
)
var http2flagName = map [ http2FrameType ] map [ http2Flags ] string {
http2FrameData : {
http2FlagDataEndStream : "END_STREAM" ,
http2FlagDataPadded : "PADDED" ,
} ,
http2FrameHeaders : {
http2FlagHeadersEndStream : "END_STREAM" ,
http2FlagHeadersEndHeaders : "END_HEADERS" ,
http2FlagHeadersPadded : "PADDED" ,
http2FlagHeadersPriority : "PRIORITY" ,
} ,
http2FrameSettings : {
http2FlagSettingsAck : "ACK" ,
} ,
http2FramePing : {
http2FlagPingAck : "ACK" ,
} ,
http2FrameContinuation : {
http2FlagContinuationEndHeaders : "END_HEADERS" ,
} ,
http2FramePushPromise : {
http2FlagPushPromiseEndHeaders : "END_HEADERS" ,
http2FlagPushPromisePadded : "PADDED" ,
} ,
}
// a frameParser parses a frame given its FrameHeader and payload
// bytes. The length of payload will always equal fh.Length (which
// might be 0).
2022-02-11 14:53:56 -08:00
type http2frameParser func ( fc * http2frameCache , fh http2FrameHeader , countError func ( string ) , payload [ ] byte ) ( http2Frame , error )
2016-02-03 21:58:02 +00:00
var http2frameParsers = map [ http2FrameType ] http2frameParser {
http2FrameData : http2parseDataFrame ,
http2FrameHeaders : http2parseHeadersFrame ,
http2FramePriority : http2parsePriorityFrame ,
http2FrameRSTStream : http2parseRSTStreamFrame ,
http2FrameSettings : http2parseSettingsFrame ,
http2FramePushPromise : http2parsePushPromise ,
http2FramePing : http2parsePingFrame ,
http2FrameGoAway : http2parseGoAwayFrame ,
http2FrameWindowUpdate : http2parseWindowUpdateFrame ,
http2FrameContinuation : http2parseContinuationFrame ,
}
func http2typeFrameParser ( t http2FrameType ) http2frameParser {
if f := http2frameParsers [ t ] ; f != nil {
return f
}
return http2parseUnknownFrame
}
// A FrameHeader is the 9 byte header of all HTTP/2 frames.
//
// See http://http2.github.io/http2-spec/#FrameHeader
type http2FrameHeader struct {
valid bool // caller can access []byte fields in the Frame
// Type is the 1 byte frame type. There are ten standard frame
// types, but extension frame types may be written by WriteRawFrame
// and will be returned by ReadFrame (as UnknownFrame).
Type http2FrameType
// Flags are the 1 byte of 8 potential bit flags per frame.
// They are specific to the frame type.
Flags http2Flags
// Length is the length of the frame, not including the 9 byte header.
// The maximum size is one byte less than 16MB (uint24), but only
// frames up to 16KB are allowed without peer agreement.
Length uint32
// StreamID is which stream this frame is for. Certain frames
// are not stream-specific, in which case this field is 0.
StreamID uint32
}
// Header returns h. It exists so FrameHeaders can be embedded in other
// specific frame types and implement the Frame interface.
func ( h http2FrameHeader ) Header ( ) http2FrameHeader { return h }
func ( h http2FrameHeader ) String ( ) string {
var buf bytes . Buffer
buf . WriteString ( "[FrameHeader " )
h . writeDebug ( & buf )
buf . WriteByte ( ']' )
return buf . String ( )
}
func ( h http2FrameHeader ) writeDebug ( buf * bytes . Buffer ) {
buf . WriteString ( h . Type . String ( ) )
if h . Flags != 0 {
buf . WriteString ( " flags=" )
set := 0
for i := uint8 ( 0 ) ; i < 8 ; i ++ {
if h . Flags & ( 1 << i ) == 0 {
continue
}
set ++
if set > 1 {
buf . WriteByte ( '|' )
}
name := http2flagName [ h . Type ] [ http2Flags ( 1 << i ) ]
if name != "" {
buf . WriteString ( name )
} else {
fmt . Fprintf ( buf , "0x%x" , 1 << i )
}
}
}
if h . StreamID != 0 {
fmt . Fprintf ( buf , " stream=%d" , h . StreamID )
}
fmt . Fprintf ( buf , " len=%d" , h . Length )
}
func ( h * http2FrameHeader ) checkValid ( ) {
if ! h . valid {
panic ( "Frame accessor called on non-owned Frame" )
}
}
func ( h * http2FrameHeader ) invalidate ( ) { h . valid = false }
// frame header bytes.
// Used only by ReadFrameHeader.
var http2fhBytes = sync . Pool {
New : func ( ) interface { } {
buf := make ( [ ] byte , http2frameHeaderLen )
return & buf
} ,
}
// ReadFrameHeader reads 9 bytes from r and returns a FrameHeader.
// Most users should use Framer.ReadFrame instead.
func http2ReadFrameHeader ( r io . Reader ) ( http2FrameHeader , error ) {
bufp := http2fhBytes . Get ( ) . ( * [ ] byte )
defer http2fhBytes . Put ( bufp )
return http2readFrameHeader ( * bufp , r )
}
func http2readFrameHeader ( buf [ ] byte , r io . Reader ) ( http2FrameHeader , error ) {
_ , err := io . ReadFull ( r , buf [ : http2frameHeaderLen ] )
if err != nil {
return http2FrameHeader { } , err
}
return http2FrameHeader {
Length : ( uint32 ( buf [ 0 ] ) << 16 | uint32 ( buf [ 1 ] ) << 8 | uint32 ( buf [ 2 ] ) ) ,
Type : http2FrameType ( buf [ 3 ] ) ,
Flags : http2Flags ( buf [ 4 ] ) ,
StreamID : binary . BigEndian . Uint32 ( buf [ 5 : ] ) & ( 1 << 31 - 1 ) ,
valid : true ,
} , nil
}
// A Frame is the base interface implemented by all frame types.
// Callers will generally type-assert the specific frame type:
// *HeadersFrame, *SettingsFrame, *WindowUpdateFrame, etc.
//
// Frames are only valid until the next call to Framer.ReadFrame.
type http2Frame interface {
Header ( ) http2FrameHeader
// invalidate is called by Framer.ReadFrame to make this
// frame's buffers as being invalid, since the subsequent
// frame will reuse them.
invalidate ( )
}
// A Framer reads and writes Frames.
type http2Framer struct {
r io . Reader
lastFrame http2Frame
2016-07-22 18:15:38 +00:00
errDetail error
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
// countError is a non-nil func that's called on a frame parse
// error with some unique error path token. It's initialized
// from Transport.CountError or Server.CountError.
countError func ( errToken string )
2016-02-03 21:58:02 +00:00
// lastHeaderStream is non-zero if the last frame was an
// unfinished HEADERS/CONTINUATION.
lastHeaderStream uint32
maxReadSize uint32
headerBuf [ http2frameHeaderLen ] byte
// TODO: let getReadBuf be configurable, and use a less memory-pinning
// allocator in server.go to minimize memory pinned for many idle conns.
// Will probably also need to make frame invalidation have a hook too.
getReadBuf func ( size uint32 ) [ ] byte
readBuf [ ] byte // cache for default getReadBuf
maxWriteSize uint32 // zero means unlimited; TODO: implement
w io . Writer
wbuf [ ] byte
// AllowIllegalWrites permits the Framer's Write methods to
// write frames that do not conform to the HTTP/2 spec. This
// permits using the Framer to test other HTTP/2
// implementations' conformance to the spec.
// If false, the Write methods will prefer to return an error
// rather than comply.
AllowIllegalWrites bool
// AllowIllegalReads permits the Framer's ReadFrame method
// to return non-compliant frames or frame orders.
// This is for testing and permits using the Framer to test
// other HTTP/2 implementations' conformance to the spec.
2016-07-22 18:15:38 +00:00
// It is not compatible with ReadMetaHeaders.
2016-02-03 21:58:02 +00:00
AllowIllegalReads bool
2016-07-22 18:15:38 +00:00
// ReadMetaHeaders if non-nil causes ReadFrame to merge
// HEADERS and CONTINUATION frames together and return
// MetaHeadersFrame instead.
ReadMetaHeaders * hpack . Decoder
// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
// It's used only if ReadMetaHeaders is set; 0 means a sane default
// (currently 16MB)
// If the limit is hit, MetaHeadersFrame.Truncated is set true.
MaxHeaderListSize uint32
2017-09-14 17:11:35 +00:00
// TODO: track which type of frame & with which flags was sent
// last. Then return an error (unless AllowIllegalWrites) if
// we're in the middle of a header block and a
// non-Continuation or Continuation on a different stream is
// attempted to be written.
2017-01-14 00:05:42 +00:00
logReads , logWrites bool
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
debugFramer * http2Framer // only use for logging written writes
debugFramerBuf * bytes . Buffer
debugReadLoggerf func ( string , ... interface { } )
debugWriteLoggerf func ( string , ... interface { } )
2017-09-14 17:11:35 +00:00
frameCache * http2frameCache // nil if frames aren't reused (default)
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
func ( fr * http2Framer ) maxHeaderListSize ( ) uint32 {
if fr . MaxHeaderListSize == 0 {
2017-09-14 17:11:35 +00:00
return 16 << 20 // sane default, per docs
2016-07-22 18:15:38 +00:00
}
return fr . MaxHeaderListSize
}
2016-02-03 21:58:02 +00:00
func ( f * http2Framer ) startWrite ( ftype http2FrameType , flags http2Flags , streamID uint32 ) {
2017-09-14 17:11:35 +00:00
// Write the FrameHeader.
2016-02-03 21:58:02 +00:00
f . wbuf = append ( f . wbuf [ : 0 ] ,
2017-09-14 17:11:35 +00:00
0 , // 3 bytes of length, filled in in endWrite
2016-02-03 21:58:02 +00:00
0 ,
0 ,
byte ( ftype ) ,
byte ( flags ) ,
byte ( streamID >> 24 ) ,
byte ( streamID >> 16 ) ,
byte ( streamID >> 8 ) ,
byte ( streamID ) )
}
func ( f * http2Framer ) endWrite ( ) error {
2017-09-14 17:11:35 +00:00
// Now that we know the final size, fill in the FrameHeader in
// the space previously reserved for it. Abuse append.
2016-02-03 21:58:02 +00:00
length := len ( f . wbuf ) - http2frameHeaderLen
if length >= ( 1 << 24 ) {
return http2ErrFrameTooLarge
}
_ = append ( f . wbuf [ : 0 ] ,
byte ( length >> 16 ) ,
byte ( length >> 8 ) ,
byte ( length ) )
2017-01-14 00:05:42 +00:00
if f . logWrites {
2016-02-03 21:58:02 +00:00
f . logWrite ( )
}
n , err := f . w . Write ( f . wbuf )
if err == nil && n != len ( f . wbuf ) {
err = io . ErrShortWrite
}
return err
}
func ( f * http2Framer ) logWrite ( ) {
if f . debugFramer == nil {
f . debugFramerBuf = new ( bytes . Buffer )
f . debugFramer = http2NewFramer ( nil , f . debugFramerBuf )
2017-09-14 17:11:35 +00:00
f . debugFramer . logReads = false // we log it ourselves, saying "wrote" below
// Let us read anything, even if we accidentally wrote it
// in the wrong order:
2016-02-03 21:58:02 +00:00
f . debugFramer . AllowIllegalReads = true
}
f . debugFramerBuf . Write ( f . wbuf )
fr , err := f . debugFramer . ReadFrame ( )
if err != nil {
2017-01-14 00:05:42 +00:00
f . debugWriteLoggerf ( "http2: Framer %p: failed to decode just-written frame" , f )
2016-02-03 21:58:02 +00:00
return
}
2017-01-14 00:05:42 +00:00
f . debugWriteLoggerf ( "http2: Framer %p: wrote %v" , f , http2summarizeFrame ( fr ) )
2016-02-03 21:58:02 +00:00
}
func ( f * http2Framer ) writeByte ( v byte ) { f . wbuf = append ( f . wbuf , v ) }
func ( f * http2Framer ) writeBytes ( v [ ] byte ) { f . wbuf = append ( f . wbuf , v ... ) }
func ( f * http2Framer ) writeUint16 ( v uint16 ) { f . wbuf = append ( f . wbuf , byte ( v >> 8 ) , byte ( v ) ) }
func ( f * http2Framer ) writeUint32 ( v uint32 ) {
f . wbuf = append ( f . wbuf , byte ( v >> 24 ) , byte ( v >> 16 ) , byte ( v >> 8 ) , byte ( v ) )
}
const (
http2minMaxFrameSize = 1 << 14
http2maxFrameSize = 1 << 24 - 1
)
2017-09-14 17:11:35 +00:00
// SetReuseFrames allows the Framer to reuse Frames.
// If called on a Framer, Frames returned by calls to ReadFrame are only
// valid until the next call to ReadFrame.
func ( fr * http2Framer ) SetReuseFrames ( ) {
if fr . frameCache != nil {
return
}
fr . frameCache = & http2frameCache { }
}
type http2frameCache struct {
dataFrame http2DataFrame
}
func ( fc * http2frameCache ) getDataFrame ( ) * http2DataFrame {
if fc == nil {
return & http2DataFrame { }
}
return & fc . dataFrame
}
2016-02-03 21:58:02 +00:00
// NewFramer returns a Framer that writes frames to w and reads them from r.
func http2NewFramer ( w io . Writer , r io . Reader ) * http2Framer {
fr := & http2Framer {
2017-01-14 00:05:42 +00:00
w : w ,
r : r ,
2022-02-11 14:53:56 -08:00
countError : func ( string ) { } ,
2017-01-14 00:05:42 +00:00
logReads : http2logFrameReads ,
logWrites : http2logFrameWrites ,
debugReadLoggerf : log . Printf ,
debugWriteLoggerf : log . Printf ,
2016-02-03 21:58:02 +00:00
}
fr . getReadBuf = func ( size uint32 ) [ ] byte {
if cap ( fr . readBuf ) >= int ( size ) {
return fr . readBuf [ : size ]
}
fr . readBuf = make ( [ ] byte , size )
return fr . readBuf
}
fr . SetMaxReadFrameSize ( http2maxFrameSize )
return fr
}
// SetMaxReadFrameSize sets the maximum size of a frame
// that will be read by a subsequent call to ReadFrame.
// It is the caller's responsibility to advertise this
// limit with a SETTINGS frame.
func ( fr * http2Framer ) SetMaxReadFrameSize ( v uint32 ) {
if v > http2maxFrameSize {
v = http2maxFrameSize
}
fr . maxReadSize = v
}
2016-07-22 18:15:38 +00:00
// ErrorDetail returns a more detailed error of the last error
// returned by Framer.ReadFrame. For instance, if ReadFrame
// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
// will say exactly what was invalid. ErrorDetail is not guaranteed
// to return a non-nil value and like the rest of the http2 package,
// its return value is not protected by an API compatibility promise.
// ErrorDetail is reset after the next call to ReadFrame.
func ( fr * http2Framer ) ErrorDetail ( ) error {
return fr . errDetail
}
2016-02-03 21:58:02 +00:00
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
// sends a frame that is larger than declared with SetMaxReadFrameSize.
var http2ErrFrameTooLarge = errors . New ( "http2: frame too large" )
// terminalReadFrameError reports whether err is an unrecoverable
// error from ReadFrame and no other frames should be read.
func http2terminalReadFrameError ( err error ) bool {
if _ , ok := err . ( http2StreamError ) ; ok {
return false
}
return err != nil
}
// ReadFrame reads a single frame. The returned Frame is only valid
// until the next call to ReadFrame.
//
// If the frame is larger than previously set with SetMaxReadFrameSize, the
// returned error is ErrFrameTooLarge. Other errors may be of type
2016-07-22 18:15:38 +00:00
// ConnectionError, StreamError, or anything else from the underlying
2016-02-03 21:58:02 +00:00
// reader.
func ( fr * http2Framer ) ReadFrame ( ) ( http2Frame , error ) {
2016-07-22 18:15:38 +00:00
fr . errDetail = nil
2016-02-03 21:58:02 +00:00
if fr . lastFrame != nil {
fr . lastFrame . invalidate ( )
}
fh , err := http2readFrameHeader ( fr . headerBuf [ : ] , fr . r )
if err != nil {
return nil , err
}
if fh . Length > fr . maxReadSize {
return nil , http2ErrFrameTooLarge
}
payload := fr . getReadBuf ( fh . Length )
if _ , err := io . ReadFull ( fr . r , payload ) ; err != nil {
return nil , err
}
2022-02-11 14:53:56 -08:00
f , err := http2typeFrameParser ( fh . Type ) ( fr . frameCache , fh , fr . countError , payload )
2016-02-03 21:58:02 +00:00
if err != nil {
if ce , ok := err . ( http2connError ) ; ok {
return nil , fr . connError ( ce . Code , ce . Reason )
}
return nil , err
}
if err := fr . checkFrameOrder ( f ) ; err != nil {
return nil , err
}
if fr . logReads {
2017-01-14 00:05:42 +00:00
fr . debugReadLoggerf ( "http2: Framer %p: read %v" , fr , http2summarizeFrame ( f ) )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
if fh . Type == http2FrameHeaders && fr . ReadMetaHeaders != nil {
return fr . readMetaFrame ( f . ( * http2HeadersFrame ) )
}
2016-02-03 21:58:02 +00:00
return f , nil
}
// connError returns ConnectionError(code) but first
// stashes away a public reason to the caller can optionally relay it
// to the peer before hanging up on them. This might help others debug
// their implementations.
func ( fr * http2Framer ) connError ( code http2ErrCode , reason string ) error {
2016-07-22 18:15:38 +00:00
fr . errDetail = errors . New ( reason )
2016-02-03 21:58:02 +00:00
return http2ConnectionError ( code )
}
// checkFrameOrder reports an error if f is an invalid frame to return
// next from ReadFrame. Mostly it checks whether HEADERS and
// CONTINUATION frames are contiguous.
func ( fr * http2Framer ) checkFrameOrder ( f http2Frame ) error {
last := fr . lastFrame
fr . lastFrame = f
if fr . AllowIllegalReads {
return nil
}
fh := f . Header ( )
if fr . lastHeaderStream != 0 {
if fh . Type != http2FrameContinuation {
return fr . connError ( http2ErrCodeProtocol ,
fmt . Sprintf ( "got %s for stream %d; expected CONTINUATION following %s for stream %d" ,
fh . Type , fh . StreamID ,
last . Header ( ) . Type , fr . lastHeaderStream ) )
}
if fh . StreamID != fr . lastHeaderStream {
return fr . connError ( http2ErrCodeProtocol ,
fmt . Sprintf ( "got CONTINUATION for stream %d; expected stream %d" ,
fh . StreamID , fr . lastHeaderStream ) )
}
} else if fh . Type == http2FrameContinuation {
return fr . connError ( http2ErrCodeProtocol , fmt . Sprintf ( "unexpected CONTINUATION for stream %d" , fh . StreamID ) )
}
switch fh . Type {
case http2FrameHeaders , http2FrameContinuation :
if fh . Flags . Has ( http2FlagHeadersEndHeaders ) {
fr . lastHeaderStream = 0
} else {
fr . lastHeaderStream = fh . StreamID
}
}
return nil
}
// A DataFrame conveys arbitrary, variable-length sequences of octets
// associated with a stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.1
type http2DataFrame struct {
http2FrameHeader
data [ ] byte
}
func ( f * http2DataFrame ) StreamEnded ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagDataEndStream )
}
// Data returns the frame's data octets, not including any padding
// size byte or padding suffix bytes.
// The caller must not retain the returned memory past the next
// call to ReadFrame.
func ( f * http2DataFrame ) Data ( ) [ ] byte {
f . checkValid ( )
return f . data
}
2022-02-11 14:53:56 -08:00
func http2parseDataFrame ( fc * http2frameCache , fh http2FrameHeader , countError func ( string ) , payload [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if fh . StreamID == 0 {
2017-09-14 17:11:35 +00:00
// DATA frames MUST be associated with a stream. If a
// DATA frame is received whose stream identifier
// field is 0x0, the recipient MUST respond with a
// connection error (Section 5.4.1) of type
// PROTOCOL_ERROR.
2022-02-11 14:53:56 -08:00
countError ( "frame_data_stream_0" )
2016-02-03 21:58:02 +00:00
return nil , http2connError { http2ErrCodeProtocol , "DATA frame with stream ID 0" }
}
2017-09-14 17:11:35 +00:00
f := fc . getDataFrame ( )
f . http2FrameHeader = fh
2016-02-03 21:58:02 +00:00
var padSize byte
if fh . Flags . Has ( http2FlagDataPadded ) {
var err error
payload , padSize , err = http2readByte ( payload )
if err != nil {
2022-02-11 14:53:56 -08:00
countError ( "frame_data_pad_byte_short" )
2016-02-03 21:58:02 +00:00
return nil , err
}
}
if int ( padSize ) > len ( payload ) {
2017-09-14 17:11:35 +00:00
// If the length of the padding is greater than the
// length of the frame payload, the recipient MUST
// treat this as a connection error.
// Filed: https://github.com/http2/http2-spec/issues/610
2022-02-11 14:53:56 -08:00
countError ( "frame_data_pad_too_big" )
2016-02-03 21:58:02 +00:00
return nil , http2connError { http2ErrCodeProtocol , "pad size larger than data payload" }
}
f . data = payload [ : len ( payload ) - int ( padSize ) ]
return f , nil
}
2016-07-22 18:15:38 +00:00
var (
http2errStreamID = errors . New ( "invalid stream ID" )
http2errDepStreamID = errors . New ( "invalid dependent stream ID" )
2016-09-10 13:14:00 +00:00
http2errPadLength = errors . New ( "pad length too large" )
2017-09-14 17:11:35 +00:00
http2errPadBytes = errors . New ( "padding bytes must all be zeros unless AllowIllegalWrites is enabled" )
2016-07-22 18:15:38 +00:00
)
func http2validStreamIDOrZero ( streamID uint32 ) bool {
return streamID & ( 1 << 31 ) == 0
}
2016-02-03 21:58:02 +00:00
func http2validStreamID ( streamID uint32 ) bool {
return streamID != 0 && streamID & ( 1 << 31 ) == 0
}
// WriteData writes a DATA frame.
//
// It will perform exactly one Write to the underlying Writer.
2016-09-10 13:14:00 +00:00
// It is the caller's responsibility not to violate the maximum frame size
// and to not call other Write methods concurrently.
2016-02-03 21:58:02 +00:00
func ( f * http2Framer ) WriteData ( streamID uint32 , endStream bool , data [ ] byte ) error {
2016-09-10 13:14:00 +00:00
return f . WriteDataPadded ( streamID , endStream , data , nil )
}
2016-02-03 21:58:02 +00:00
2019-09-06 18:12:46 +00:00
// WriteDataPadded writes a DATA frame with optional padding.
2016-09-10 13:14:00 +00:00
//
// If pad is nil, the padding bit is not sent.
// The length of pad must not exceed 255 bytes.
2017-09-14 17:11:35 +00:00
// The bytes of pad must all be zero, unless f.AllowIllegalWrites is set.
2016-09-10 13:14:00 +00:00
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility not to violate the maximum frame size
// and to not call other Write methods concurrently.
func ( f * http2Framer ) WriteDataPadded ( streamID uint32 , endStream bool , data , pad [ ] byte ) error {
2016-02-03 21:58:02 +00:00
if ! http2validStreamID ( streamID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
2017-09-14 17:11:35 +00:00
if len ( pad ) > 0 {
if len ( pad ) > 255 {
return http2errPadLength
}
if ! f . AllowIllegalWrites {
for _ , b := range pad {
if b != 0 {
// "Padding octets MUST be set to zero when sending."
return http2errPadBytes
}
}
}
2016-09-10 13:14:00 +00:00
}
2016-02-03 21:58:02 +00:00
var flags http2Flags
if endStream {
flags |= http2FlagDataEndStream
}
2016-09-10 13:14:00 +00:00
if pad != nil {
flags |= http2FlagDataPadded
}
2016-02-03 21:58:02 +00:00
f . startWrite ( http2FrameData , flags , streamID )
2016-09-10 13:14:00 +00:00
if pad != nil {
f . wbuf = append ( f . wbuf , byte ( len ( pad ) ) )
}
2016-02-03 21:58:02 +00:00
f . wbuf = append ( f . wbuf , data ... )
2016-09-10 13:14:00 +00:00
f . wbuf = append ( f . wbuf , pad ... )
2016-02-03 21:58:02 +00:00
return f . endWrite ( )
}
// A SettingsFrame conveys configuration parameters that affect how
// endpoints communicate, such as preferences and constraints on peer
// behavior.
//
// See http://http2.github.io/http2-spec/#SETTINGS
type http2SettingsFrame struct {
http2FrameHeader
p [ ] byte
}
2022-02-11 14:53:56 -08:00
func http2parseSettingsFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if fh . Flags . Has ( http2FlagSettingsAck ) && fh . Length > 0 {
2017-09-14 17:11:35 +00:00
// When this (ACK 0x1) bit is set, the payload of the
// SETTINGS frame MUST be empty. Receipt of a
// SETTINGS frame with the ACK flag set and a length
// field value other than 0 MUST be treated as a
// connection error (Section 5.4.1) of type
// FRAME_SIZE_ERROR.
2022-02-11 14:53:56 -08:00
countError ( "frame_settings_ack_with_length" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFrameSize )
}
if fh . StreamID != 0 {
2017-09-14 17:11:35 +00:00
// SETTINGS frames always apply to a connection,
// never a single stream. The stream identifier for a
// SETTINGS frame MUST be zero (0x0). If an endpoint
// receives a SETTINGS frame whose stream identifier
// field is anything other than 0x0, the endpoint MUST
// respond with a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR.
2022-02-11 14:53:56 -08:00
countError ( "frame_settings_has_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
if len ( p ) % 6 != 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_settings_mod_6" )
2017-09-14 17:11:35 +00:00
// Expecting even number of 6 byte settings.
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFrameSize )
}
f := & http2SettingsFrame { http2FrameHeader : fh , p : p }
if v , ok := f . Value ( http2SettingInitialWindowSize ) ; ok && v > ( 1 << 31 ) - 1 {
2022-02-11 14:53:56 -08:00
countError ( "frame_settings_window_size_too_big" )
2017-09-14 17:11:35 +00:00
// Values above the maximum flow control window size of 2^31 - 1 MUST
// be treated as a connection error (Section 5.4.1) of type
// FLOW_CONTROL_ERROR.
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFlowControl )
}
return f , nil
}
func ( f * http2SettingsFrame ) IsAck ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagSettingsAck )
}
2018-09-24 21:46:21 +00:00
func ( f * http2SettingsFrame ) Value ( id http2SettingID ) ( v uint32 , ok bool ) {
2016-02-03 21:58:02 +00:00
f . checkValid ( )
2018-09-24 21:46:21 +00:00
for i := 0 ; i < f . NumSettings ( ) ; i ++ {
if s := f . Setting ( i ) ; s . ID == id {
return s . Val , true
2016-02-03 21:58:02 +00:00
}
}
return 0 , false
}
2018-09-24 21:46:21 +00:00
// Setting returns the setting from the frame at the given 0-based index.
// The index must be >= 0 and less than f.NumSettings().
func ( f * http2SettingsFrame ) Setting ( i int ) http2Setting {
buf := f . p
return http2Setting {
ID : http2SettingID ( binary . BigEndian . Uint16 ( buf [ i * 6 : i * 6 + 2 ] ) ) ,
Val : binary . BigEndian . Uint32 ( buf [ i * 6 + 2 : i * 6 + 6 ] ) ,
}
}
func ( f * http2SettingsFrame ) NumSettings ( ) int { return len ( f . p ) / 6 }
// HasDuplicates reports whether f contains any duplicate setting IDs.
func ( f * http2SettingsFrame ) HasDuplicates ( ) bool {
num := f . NumSettings ( )
if num == 0 {
return false
}
// If it's small enough (the common case), just do the n^2
// thing and avoid a map allocation.
if num < 10 {
for i := 0 ; i < num ; i ++ {
idi := f . Setting ( i ) . ID
for j := i + 1 ; j < num ; j ++ {
idj := f . Setting ( j ) . ID
if idi == idj {
return true
}
}
}
return false
}
seen := map [ http2SettingID ] bool { }
for i := 0 ; i < num ; i ++ {
id := f . Setting ( i ) . ID
if seen [ id ] {
return true
}
seen [ id ] = true
}
return false
}
2016-02-03 21:58:02 +00:00
// ForeachSetting runs fn for each setting.
// It stops and returns the first error.
func ( f * http2SettingsFrame ) ForeachSetting ( fn func ( http2Setting ) error ) error {
f . checkValid ( )
2018-09-24 21:46:21 +00:00
for i := 0 ; i < f . NumSettings ( ) ; i ++ {
if err := fn ( f . Setting ( i ) ) ; err != nil {
2016-02-03 21:58:02 +00:00
return err
}
}
return nil
}
// WriteSettings writes a SETTINGS frame with zero or more settings
// specified and the ACK bit not set.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WriteSettings ( settings ... http2Setting ) error {
f . startWrite ( http2FrameSettings , 0 , 0 )
for _ , s := range settings {
f . writeUint16 ( uint16 ( s . ID ) )
f . writeUint32 ( s . Val )
}
return f . endWrite ( )
}
2017-01-14 00:05:42 +00:00
// WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set.
2016-02-03 21:58:02 +00:00
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WriteSettingsAck ( ) error {
f . startWrite ( http2FrameSettings , http2FlagSettingsAck , 0 )
return f . endWrite ( )
}
// A PingFrame is a mechanism for measuring a minimal round trip time
// from the sender, as well as determining whether an idle connection
// is still functional.
// See http://http2.github.io/http2-spec/#rfc.section.6.7
type http2PingFrame struct {
http2FrameHeader
Data [ 8 ] byte
}
func ( f * http2PingFrame ) IsAck ( ) bool { return f . Flags . Has ( http2FlagPingAck ) }
2022-02-11 14:53:56 -08:00
func http2parsePingFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , payload [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if len ( payload ) != 8 {
2022-02-11 14:53:56 -08:00
countError ( "frame_ping_length" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFrameSize )
}
if fh . StreamID != 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_ping_has_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
f := & http2PingFrame { http2FrameHeader : fh }
copy ( f . Data [ : ] , payload )
return f , nil
}
func ( f * http2Framer ) WritePing ( ack bool , data [ 8 ] byte ) error {
var flags http2Flags
if ack {
flags = http2FlagPingAck
}
f . startWrite ( http2FramePing , flags , 0 )
f . writeBytes ( data [ : ] )
return f . endWrite ( )
}
// A GoAwayFrame informs the remote peer to stop creating streams on this connection.
// See http://http2.github.io/http2-spec/#rfc.section.6.8
type http2GoAwayFrame struct {
http2FrameHeader
LastStreamID uint32
ErrCode http2ErrCode
debugData [ ] byte
}
// DebugData returns any debug data in the GOAWAY frame. Its contents
// are not defined.
// The caller must not retain the returned memory past the next
// call to ReadFrame.
func ( f * http2GoAwayFrame ) DebugData ( ) [ ] byte {
f . checkValid ( )
return f . debugData
}
2022-02-11 14:53:56 -08:00
func http2parseGoAwayFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if fh . StreamID != 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_goaway_has_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
if len ( p ) < 8 {
2022-02-11 14:53:56 -08:00
countError ( "frame_goaway_short" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFrameSize )
}
return & http2GoAwayFrame {
http2FrameHeader : fh ,
LastStreamID : binary . BigEndian . Uint32 ( p [ : 4 ] ) & ( 1 << 31 - 1 ) ,
ErrCode : http2ErrCode ( binary . BigEndian . Uint32 ( p [ 4 : 8 ] ) ) ,
debugData : p [ 8 : ] ,
} , nil
}
func ( f * http2Framer ) WriteGoAway ( maxStreamID uint32 , code http2ErrCode , debugData [ ] byte ) error {
f . startWrite ( http2FrameGoAway , 0 , 0 )
f . writeUint32 ( maxStreamID & ( 1 << 31 - 1 ) )
f . writeUint32 ( uint32 ( code ) )
f . writeBytes ( debugData )
return f . endWrite ( )
}
// An UnknownFrame is the frame type returned when the frame type is unknown
// or no specific frame type parser exists.
type http2UnknownFrame struct {
http2FrameHeader
p [ ] byte
}
// Payload returns the frame's payload (after the header). It is not
// valid to call this method after a subsequent call to
// Framer.ReadFrame, nor is it valid to retain the returned slice.
// The memory is owned by the Framer and is invalidated when the next
// frame is read.
func ( f * http2UnknownFrame ) Payload ( ) [ ] byte {
f . checkValid ( )
return f . p
}
2022-02-11 14:53:56 -08:00
func http2parseUnknownFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
return & http2UnknownFrame { fh , p } , nil
}
// A WindowUpdateFrame is used to implement flow control.
// See http://http2.github.io/http2-spec/#rfc.section.6.9
type http2WindowUpdateFrame struct {
http2FrameHeader
Increment uint32 // never read with high bit set
}
2022-02-11 14:53:56 -08:00
func http2parseWindowUpdateFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if len ( p ) != 4 {
2022-02-11 14:53:56 -08:00
countError ( "frame_windowupdate_bad_len" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFrameSize )
}
2017-09-14 17:11:35 +00:00
inc := binary . BigEndian . Uint32 ( p [ : 4 ] ) & 0x7fffffff // mask off high reserved bit
2016-02-03 21:58:02 +00:00
if inc == 0 {
2017-09-14 17:11:35 +00:00
// A receiver MUST treat the receipt of a
// WINDOW_UPDATE frame with an flow control window
// increment of 0 as a stream error (Section 5.4.2) of
// type PROTOCOL_ERROR; errors on the connection flow
// control window MUST be treated as a connection
// error (Section 5.4.1).
2016-02-03 21:58:02 +00:00
if fh . StreamID == 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_windowupdate_zero_inc_conn" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
2022-02-11 14:53:56 -08:00
countError ( "frame_windowupdate_zero_inc_stream" )
2016-09-10 13:14:00 +00:00
return nil , http2streamError ( fh . StreamID , http2ErrCodeProtocol )
2016-02-03 21:58:02 +00:00
}
return & http2WindowUpdateFrame {
http2FrameHeader : fh ,
Increment : inc ,
} , nil
}
// WriteWindowUpdate writes a WINDOW_UPDATE frame.
// The increment value must be between 1 and 2,147,483,647, inclusive.
// If the Stream ID is zero, the window update applies to the
// connection as a whole.
func ( f * http2Framer ) WriteWindowUpdate ( streamID , incr uint32 ) error {
2017-09-14 17:11:35 +00:00
// "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets."
2016-02-03 21:58:02 +00:00
if ( incr < 1 || incr > 2147483647 ) && ! f . AllowIllegalWrites {
return errors . New ( "illegal window increment value" )
}
f . startWrite ( http2FrameWindowUpdate , 0 , streamID )
f . writeUint32 ( incr )
return f . endWrite ( )
}
// A HeadersFrame is used to open a stream and additionally carries a
// header block fragment.
type http2HeadersFrame struct {
http2FrameHeader
// Priority is set if FlagHeadersPriority is set in the FrameHeader.
Priority http2PriorityParam
headerFragBuf [ ] byte // not owned
}
func ( f * http2HeadersFrame ) HeaderBlockFragment ( ) [ ] byte {
f . checkValid ( )
return f . headerFragBuf
}
func ( f * http2HeadersFrame ) HeadersEnded ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagHeadersEndHeaders )
}
func ( f * http2HeadersFrame ) StreamEnded ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagHeadersEndStream )
}
func ( f * http2HeadersFrame ) HasPriority ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagHeadersPriority )
}
2022-02-11 14:53:56 -08:00
func http2parseHeadersFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( _ http2Frame , err error ) {
2016-02-03 21:58:02 +00:00
hf := & http2HeadersFrame {
http2FrameHeader : fh ,
}
if fh . StreamID == 0 {
2017-09-14 17:11:35 +00:00
// HEADERS frames MUST be associated with a stream. If a HEADERS frame
// is received whose stream identifier field is 0x0, the recipient MUST
// respond with a connection error (Section 5.4.1) of type
// PROTOCOL_ERROR.
2022-02-11 14:53:56 -08:00
countError ( "frame_headers_zero_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2connError { http2ErrCodeProtocol , "HEADERS frame with stream ID 0" }
}
var padLength uint8
if fh . Flags . Has ( http2FlagHeadersPadded ) {
if p , padLength , err = http2readByte ( p ) ; err != nil {
2022-02-11 14:53:56 -08:00
countError ( "frame_headers_pad_short" )
2016-02-03 21:58:02 +00:00
return
}
}
if fh . Flags . Has ( http2FlagHeadersPriority ) {
var v uint32
p , v , err = http2readUint32 ( p )
if err != nil {
2022-02-11 14:53:56 -08:00
countError ( "frame_headers_prio_short" )
2016-02-03 21:58:02 +00:00
return nil , err
}
hf . Priority . StreamDep = v & 0x7fffffff
2017-09-14 17:11:35 +00:00
hf . Priority . Exclusive = ( v != hf . Priority . StreamDep ) // high bit was set
2016-02-03 21:58:02 +00:00
p , hf . Priority . Weight , err = http2readByte ( p )
if err != nil {
2022-02-11 14:53:56 -08:00
countError ( "frame_headers_prio_weight_short" )
2016-02-03 21:58:02 +00:00
return nil , err
}
}
2022-02-11 14:53:56 -08:00
if len ( p ) - int ( padLength ) < 0 {
countError ( "frame_headers_pad_too_big" )
2016-09-10 13:14:00 +00:00
return nil , http2streamError ( fh . StreamID , http2ErrCodeProtocol )
2016-02-03 21:58:02 +00:00
}
hf . headerFragBuf = p [ : len ( p ) - int ( padLength ) ]
return hf , nil
}
// HeadersFrameParam are the parameters for writing a HEADERS frame.
type http2HeadersFrameParam struct {
// StreamID is the required Stream ID to initiate.
StreamID uint32
// BlockFragment is part (or all) of a Header Block.
BlockFragment [ ] byte
// EndStream indicates that the header block is the last that
// the endpoint will send for the identified stream. Setting
// this flag causes the stream to enter one of "half closed"
// states.
EndStream bool
// EndHeaders indicates that this frame contains an entire
// header block and is not followed by any
// CONTINUATION frames.
EndHeaders bool
// PadLength is the optional number of bytes of zeros to add
// to this frame.
PadLength uint8
// Priority, if non-zero, includes stream priority information
// in the HEADER frame.
Priority http2PriorityParam
}
// WriteHeaders writes a single HEADERS frame.
//
// This is a low-level header writing method. Encoding headers and
// splitting them into any necessary CONTINUATION frames is handled
// elsewhere.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WriteHeaders ( p http2HeadersFrameParam ) error {
if ! http2validStreamID ( p . StreamID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
var flags http2Flags
if p . PadLength != 0 {
flags |= http2FlagHeadersPadded
}
if p . EndStream {
flags |= http2FlagHeadersEndStream
}
if p . EndHeaders {
flags |= http2FlagHeadersEndHeaders
}
if ! p . Priority . IsZero ( ) {
flags |= http2FlagHeadersPriority
}
f . startWrite ( http2FrameHeaders , flags , p . StreamID )
if p . PadLength != 0 {
f . writeByte ( p . PadLength )
}
if ! p . Priority . IsZero ( ) {
v := p . Priority . StreamDep
2016-07-22 18:15:38 +00:00
if ! http2validStreamIDOrZero ( v ) && ! f . AllowIllegalWrites {
return http2errDepStreamID
2016-02-03 21:58:02 +00:00
}
if p . Priority . Exclusive {
v |= 1 << 31
}
f . writeUint32 ( v )
f . writeByte ( p . Priority . Weight )
}
f . wbuf = append ( f . wbuf , p . BlockFragment ... )
f . wbuf = append ( f . wbuf , http2padZeros [ : p . PadLength ] ... )
return f . endWrite ( )
}
// A PriorityFrame specifies the sender-advised priority of a stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.3
type http2PriorityFrame struct {
http2FrameHeader
http2PriorityParam
}
// PriorityParam are the stream prioritzation parameters.
type http2PriorityParam struct {
// StreamDep is a 31-bit stream identifier for the
// stream that this stream depends on. Zero means no
// dependency.
StreamDep uint32
// Exclusive is whether the dependency is exclusive.
Exclusive bool
// Weight is the stream's zero-indexed weight. It should be
2017-09-14 17:11:35 +00:00
// set together with StreamDep, or neither should be set. Per
2016-02-03 21:58:02 +00:00
// the spec, "Add one to the value to obtain a weight between
// 1 and 256."
Weight uint8
}
func ( p http2PriorityParam ) IsZero ( ) bool {
return p == http2PriorityParam { }
}
2022-02-11 14:53:56 -08:00
func http2parsePriorityFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , payload [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if fh . StreamID == 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_priority_zero_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2connError { http2ErrCodeProtocol , "PRIORITY frame with stream ID 0" }
}
if len ( payload ) != 5 {
2022-02-11 14:53:56 -08:00
countError ( "frame_priority_bad_length" )
2016-02-03 21:58:02 +00:00
return nil , http2connError { http2ErrCodeFrameSize , fmt . Sprintf ( "PRIORITY frame payload size was %d; want 5" , len ( payload ) ) }
}
v := binary . BigEndian . Uint32 ( payload [ : 4 ] )
2017-09-14 17:11:35 +00:00
streamID := v & 0x7fffffff // mask off high bit
2016-02-03 21:58:02 +00:00
return & http2PriorityFrame {
http2FrameHeader : fh ,
http2PriorityParam : http2PriorityParam {
Weight : payload [ 4 ] ,
StreamDep : streamID ,
2017-09-14 17:11:35 +00:00
Exclusive : streamID != v , // was high bit set?
2016-02-03 21:58:02 +00:00
} ,
} , nil
}
// WritePriority writes a PRIORITY frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WritePriority ( streamID uint32 , p http2PriorityParam ) error {
if ! http2validStreamID ( streamID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
2016-07-22 18:15:38 +00:00
if ! http2validStreamIDOrZero ( p . StreamDep ) {
return http2errDepStreamID
}
2016-02-03 21:58:02 +00:00
f . startWrite ( http2FramePriority , 0 , streamID )
v := p . StreamDep
if p . Exclusive {
v |= 1 << 31
}
f . writeUint32 ( v )
f . writeByte ( p . Weight )
return f . endWrite ( )
}
// A RSTStreamFrame allows for abnormal termination of a stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.4
type http2RSTStreamFrame struct {
http2FrameHeader
ErrCode http2ErrCode
}
2022-02-11 14:53:56 -08:00
func http2parseRSTStreamFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if len ( p ) != 4 {
2022-02-11 14:53:56 -08:00
countError ( "frame_rststream_bad_len" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeFrameSize )
}
if fh . StreamID == 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_rststream_zero_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
return & http2RSTStreamFrame { fh , http2ErrCode ( binary . BigEndian . Uint32 ( p [ : 4 ] ) ) } , nil
}
// WriteRSTStream writes a RST_STREAM frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WriteRSTStream ( streamID uint32 , code http2ErrCode ) error {
if ! http2validStreamID ( streamID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
f . startWrite ( http2FrameRSTStream , 0 , streamID )
f . writeUint32 ( uint32 ( code ) )
return f . endWrite ( )
}
// A ContinuationFrame is used to continue a sequence of header block fragments.
// See http://http2.github.io/http2-spec/#rfc.section.6.10
type http2ContinuationFrame struct {
http2FrameHeader
headerFragBuf [ ] byte
}
2022-02-11 14:53:56 -08:00
func http2parseContinuationFrame ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( http2Frame , error ) {
2016-02-03 21:58:02 +00:00
if fh . StreamID == 0 {
2022-02-11 14:53:56 -08:00
countError ( "frame_continuation_zero_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2connError { http2ErrCodeProtocol , "CONTINUATION frame with stream ID 0" }
}
return & http2ContinuationFrame { fh , p } , nil
}
func ( f * http2ContinuationFrame ) HeaderBlockFragment ( ) [ ] byte {
f . checkValid ( )
return f . headerFragBuf
}
func ( f * http2ContinuationFrame ) HeadersEnded ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagContinuationEndHeaders )
}
// WriteContinuation writes a CONTINUATION frame.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WriteContinuation ( streamID uint32 , endHeaders bool , headerBlockFragment [ ] byte ) error {
if ! http2validStreamID ( streamID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
var flags http2Flags
if endHeaders {
flags |= http2FlagContinuationEndHeaders
}
f . startWrite ( http2FrameContinuation , flags , streamID )
f . wbuf = append ( f . wbuf , headerBlockFragment ... )
return f . endWrite ( )
}
// A PushPromiseFrame is used to initiate a server stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.6
type http2PushPromiseFrame struct {
http2FrameHeader
PromiseID uint32
headerFragBuf [ ] byte // not owned
}
func ( f * http2PushPromiseFrame ) HeaderBlockFragment ( ) [ ] byte {
f . checkValid ( )
return f . headerFragBuf
}
func ( f * http2PushPromiseFrame ) HeadersEnded ( ) bool {
return f . http2FrameHeader . Flags . Has ( http2FlagPushPromiseEndHeaders )
}
2022-02-11 14:53:56 -08:00
func http2parsePushPromise ( _ * http2frameCache , fh http2FrameHeader , countError func ( string ) , p [ ] byte ) ( _ http2Frame , err error ) {
2016-02-03 21:58:02 +00:00
pp := & http2PushPromiseFrame {
http2FrameHeader : fh ,
}
if pp . StreamID == 0 {
2017-09-14 17:11:35 +00:00
// PUSH_PROMISE frames MUST be associated with an existing,
// peer-initiated stream. The stream identifier of a
// PUSH_PROMISE frame indicates the stream it is associated
// with. If the stream identifier field specifies the value
// 0x0, a recipient MUST respond with a connection error
// (Section 5.4.1) of type PROTOCOL_ERROR.
2022-02-11 14:53:56 -08:00
countError ( "frame_pushpromise_zero_stream" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
// The PUSH_PROMISE frame includes optional padding.
// Padding fields and flags are identical to those defined for DATA frames
var padLength uint8
if fh . Flags . Has ( http2FlagPushPromisePadded ) {
if p , padLength , err = http2readByte ( p ) ; err != nil {
2022-02-11 14:53:56 -08:00
countError ( "frame_pushpromise_pad_short" )
2016-02-03 21:58:02 +00:00
return
}
}
p , pp . PromiseID , err = http2readUint32 ( p )
if err != nil {
2022-02-11 14:53:56 -08:00
countError ( "frame_pushpromise_promiseid_short" )
2016-02-03 21:58:02 +00:00
return
}
pp . PromiseID = pp . PromiseID & ( 1 << 31 - 1 )
if int ( padLength ) > len ( p ) {
2017-09-14 17:11:35 +00:00
// like the DATA frame, error out if padding is longer than the body.
2022-02-11 14:53:56 -08:00
countError ( "frame_pushpromise_pad_too_big" )
2016-02-03 21:58:02 +00:00
return nil , http2ConnectionError ( http2ErrCodeProtocol )
}
pp . headerFragBuf = p [ : len ( p ) - int ( padLength ) ]
return pp , nil
}
// PushPromiseParam are the parameters for writing a PUSH_PROMISE frame.
type http2PushPromiseParam struct {
// StreamID is the required Stream ID to initiate.
StreamID uint32
// PromiseID is the required Stream ID which this
// Push Promises
PromiseID uint32
// BlockFragment is part (or all) of a Header Block.
BlockFragment [ ] byte
// EndHeaders indicates that this frame contains an entire
// header block and is not followed by any
// CONTINUATION frames.
EndHeaders bool
// PadLength is the optional number of bytes of zeros to add
// to this frame.
PadLength uint8
}
// WritePushPromise writes a single PushPromise Frame.
//
// As with Header Frames, This is the low level call for writing
// individual frames. Continuation frames are handled elsewhere.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
func ( f * http2Framer ) WritePushPromise ( p http2PushPromiseParam ) error {
if ! http2validStreamID ( p . StreamID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
var flags http2Flags
if p . PadLength != 0 {
flags |= http2FlagPushPromisePadded
}
if p . EndHeaders {
flags |= http2FlagPushPromiseEndHeaders
}
f . startWrite ( http2FramePushPromise , flags , p . StreamID )
if p . PadLength != 0 {
f . writeByte ( p . PadLength )
}
if ! http2validStreamID ( p . PromiseID ) && ! f . AllowIllegalWrites {
return http2errStreamID
}
f . writeUint32 ( p . PromiseID )
f . wbuf = append ( f . wbuf , p . BlockFragment ... )
f . wbuf = append ( f . wbuf , http2padZeros [ : p . PadLength ] ... )
return f . endWrite ( )
}
// WriteRawFrame writes a raw frame. This can be used to write
// extension frames unknown to this package.
func ( f * http2Framer ) WriteRawFrame ( t http2FrameType , flags http2Flags , streamID uint32 , payload [ ] byte ) error {
f . startWrite ( t , flags , streamID )
f . writeBytes ( payload )
return f . endWrite ( )
}
func http2readByte ( p [ ] byte ) ( remain [ ] byte , b byte , err error ) {
if len ( p ) == 0 {
return nil , 0 , io . ErrUnexpectedEOF
}
return p [ 1 : ] , p [ 0 ] , nil
}
func http2readUint32 ( p [ ] byte ) ( remain [ ] byte , v uint32 , err error ) {
if len ( p ) < 4 {
return nil , 0 , io . ErrUnexpectedEOF
}
return p [ 4 : ] , binary . BigEndian . Uint32 ( p [ : 4 ] ) , nil
}
type http2streamEnder interface {
StreamEnded ( ) bool
}
type http2headersEnder interface {
HeadersEnded ( ) bool
}
2016-07-22 18:15:38 +00:00
type http2headersOrContinuation interface {
http2headersEnder
HeaderBlockFragment ( ) [ ] byte
}
// A MetaHeadersFrame is the representation of one HEADERS frame and
// zero or more contiguous CONTINUATION frames and the decoding of
// their HPACK-encoded contents.
//
// This type of frame does not appear on the wire and is only returned
// by the Framer when Framer.ReadMetaHeaders is set.
type http2MetaHeadersFrame struct {
* http2HeadersFrame
// Fields are the fields contained in the HEADERS and
// CONTINUATION frames. The underlying slice is owned by the
// Framer and must not be retained after the next call to
// ReadFrame.
//
// Fields are guaranteed to be in the correct http2 order and
// not have unknown pseudo header fields or invalid header
// field names or values. Required pseudo header fields may be
// missing, however. Use the MetaHeadersFrame.Pseudo accessor
// method access pseudo headers.
Fields [ ] hpack . HeaderField
// Truncated is whether the max header list size limit was hit
// and Fields is incomplete. The hpack decoder state is still
// valid, however.
Truncated bool
}
// PseudoValue returns the given pseudo header field's value.
// The provided pseudo field should not contain the leading colon.
func ( mh * http2MetaHeadersFrame ) PseudoValue ( pseudo string ) string {
for _ , hf := range mh . Fields {
if ! hf . IsPseudo ( ) {
return ""
}
if hf . Name [ 1 : ] == pseudo {
return hf . Value
}
}
return ""
}
// RegularFields returns the regular (non-pseudo) header fields of mh.
// The caller does not own the returned slice.
func ( mh * http2MetaHeadersFrame ) RegularFields ( ) [ ] hpack . HeaderField {
for i , hf := range mh . Fields {
if ! hf . IsPseudo ( ) {
return mh . Fields [ i : ]
}
}
return nil
}
// PseudoFields returns the pseudo header fields of mh.
// The caller does not own the returned slice.
func ( mh * http2MetaHeadersFrame ) PseudoFields ( ) [ ] hpack . HeaderField {
for i , hf := range mh . Fields {
if ! hf . IsPseudo ( ) {
return mh . Fields [ : i ]
}
}
return mh . Fields
}
func ( mh * http2MetaHeadersFrame ) checkPseudos ( ) error {
var isRequest , isResponse bool
pf := mh . PseudoFields ( )
for i , hf := range pf {
switch hf . Name {
case ":method" , ":path" , ":scheme" , ":authority" :
isRequest = true
case ":status" :
isResponse = true
default :
return http2pseudoHeaderError ( hf . Name )
}
2017-09-14 17:11:35 +00:00
// Check for duplicates.
// This would be a bad algorithm, but N is 4.
// And this doesn't allocate.
2016-07-22 18:15:38 +00:00
for _ , hf2 := range pf [ : i ] {
if hf . Name == hf2 . Name {
return http2duplicatePseudoHeaderError ( hf . Name )
}
}
}
if isRequest && isResponse {
return http2errMixPseudoHeaderTypes
}
return nil
}
func ( fr * http2Framer ) maxHeaderStringLen ( ) int {
v := fr . maxHeaderListSize ( )
if uint32 ( int ( v ) ) == v {
return int ( v )
}
2017-09-14 17:11:35 +00:00
// They had a crazy big number for MaxHeaderBytes anyway,
// so give them unlimited header lengths:
2016-07-22 18:15:38 +00:00
return 0
}
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
2019-01-18 19:04:36 +00:00
// merge them into the provided hf and returns a MetaHeadersFrame
2016-07-22 18:15:38 +00:00
// with the decoded hpack values.
func ( fr * http2Framer ) readMetaFrame ( hf * http2HeadersFrame ) ( * http2MetaHeadersFrame , error ) {
if fr . AllowIllegalReads {
return nil , errors . New ( "illegal use of AllowIllegalReads with ReadMetaHeaders" )
}
mh := & http2MetaHeadersFrame {
http2HeadersFrame : hf ,
}
var remainSize = fr . maxHeaderListSize ( )
var sawRegular bool
var invalid error // pseudo header field errors
hdec := fr . ReadMetaHeaders
hdec . SetEmitEnabled ( true )
hdec . SetMaxStringLength ( fr . maxHeaderStringLen ( ) )
hdec . SetEmitFunc ( func ( hf hpack . HeaderField ) {
2017-01-14 00:05:42 +00:00
if http2VerboseLogs && fr . logReads {
fr . debugReadLoggerf ( "http2: decoded hpack field %+v" , hf )
2016-09-10 13:14:00 +00:00
}
2018-09-24 21:46:21 +00:00
if ! httpguts . ValidHeaderFieldValue ( hf . Value ) {
2016-07-22 18:15:38 +00:00
invalid = http2headerFieldValueError ( hf . Value )
}
isPseudo := strings . HasPrefix ( hf . Name , ":" )
if isPseudo {
if sawRegular {
invalid = http2errPseudoAfterRegular
}
} else {
sawRegular = true
if ! http2validWireHeaderFieldName ( hf . Name ) {
invalid = http2headerFieldNameError ( hf . Name )
}
}
if invalid != nil {
hdec . SetEmitEnabled ( false )
return
}
size := hf . Size ( )
if size > remainSize {
hdec . SetEmitEnabled ( false )
mh . Truncated = true
return
}
remainSize -= size
mh . Fields = append ( mh . Fields , hf )
} )
2017-09-14 17:11:35 +00:00
// Lose reference to MetaHeadersFrame:
2016-07-22 18:15:38 +00:00
defer hdec . SetEmitFunc ( func ( hf hpack . HeaderField ) { } )
var hc http2headersOrContinuation = hf
for {
frag := hc . HeaderBlockFragment ( )
if _ , err := hdec . Write ( frag ) ; err != nil {
return nil , http2ConnectionError ( http2ErrCodeCompression )
}
if hc . HeadersEnded ( ) {
break
}
if f , err := fr . ReadFrame ( ) ; err != nil {
return nil , err
} else {
2017-09-14 17:11:35 +00:00
hc = f . ( * http2ContinuationFrame ) // guaranteed by checkFrameOrder
2016-07-22 18:15:38 +00:00
}
}
mh . http2HeadersFrame . headerFragBuf = nil
mh . http2HeadersFrame . invalidate ( )
if err := hdec . Close ( ) ; err != nil {
return nil , http2ConnectionError ( http2ErrCodeCompression )
}
if invalid != nil {
fr . errDetail = invalid
2016-09-10 13:14:00 +00:00
if http2VerboseLogs {
log . Printf ( "http2: invalid header: %v" , invalid )
}
return nil , http2StreamError { mh . StreamID , http2ErrCodeProtocol , invalid }
2016-07-22 18:15:38 +00:00
}
if err := mh . checkPseudos ( ) ; err != nil {
fr . errDetail = err
2016-09-10 13:14:00 +00:00
if http2VerboseLogs {
log . Printf ( "http2: invalid pseudo headers: %v" , err )
}
return nil , http2StreamError { mh . StreamID , http2ErrCodeProtocol , err }
2016-07-22 18:15:38 +00:00
}
return mh , nil
}
2016-02-03 21:58:02 +00:00
func http2summarizeFrame ( f http2Frame ) string {
var buf bytes . Buffer
f . Header ( ) . writeDebug ( & buf )
switch f := f . ( type ) {
case * http2SettingsFrame :
n := 0
f . ForeachSetting ( func ( s http2Setting ) error {
n ++
if n == 1 {
buf . WriteString ( ", settings:" )
}
fmt . Fprintf ( & buf , " %v=%v," , s . ID , s . Val )
return nil
} )
if n > 0 {
2017-09-14 17:11:35 +00:00
buf . Truncate ( buf . Len ( ) - 1 ) // remove trailing comma
2016-02-03 21:58:02 +00:00
}
case * http2DataFrame :
data := f . Data ( )
const max = 256
if len ( data ) > max {
data = data [ : max ]
}
fmt . Fprintf ( & buf , " data=%q" , data )
if len ( f . Data ( ) ) > max {
fmt . Fprintf ( & buf , " (%d bytes omitted)" , len ( f . Data ( ) ) - max )
}
case * http2WindowUpdateFrame :
if f . StreamID == 0 {
buf . WriteString ( " (conn)" )
}
fmt . Fprintf ( & buf , " incr=%v" , f . Increment )
case * http2PingFrame :
fmt . Fprintf ( & buf , " ping=%q" , f . Data [ : ] )
case * http2GoAwayFrame :
fmt . Fprintf ( & buf , " LastStreamID=%v ErrCode=%v Debug=%q" ,
f . LastStreamID , f . ErrCode , f . debugData )
case * http2RSTStreamFrame :
fmt . Fprintf ( & buf , " ErrCode=%v" , f . ErrCode )
}
return buf . String ( )
}
2019-01-18 19:04:36 +00:00
func http2traceHasWroteHeaderField ( trace * httptrace . ClientTrace ) bool {
2018-09-24 21:46:21 +00:00
return trace != nil && trace . WroteHeaderField != nil
}
2019-01-18 19:04:36 +00:00
func http2traceWroteHeaderField ( trace * httptrace . ClientTrace , k , v string ) {
2018-09-24 21:46:21 +00:00
if trace != nil && trace . WroteHeaderField != nil {
trace . WroteHeaderField ( k , [ ] string { v } )
}
}
2019-01-18 19:04:36 +00:00
func http2traceGot1xxResponseFunc ( trace * httptrace . ClientTrace ) func ( int , textproto . MIMEHeader ) error {
2018-09-24 21:46:21 +00:00
if trace != nil {
return trace . Got1xxResponse
}
return nil
}
2021-07-30 14:28:58 -07:00
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func ( t * http2Transport ) dialTLSWithContext ( ctx context . Context , network , addr string , cfg * tls . Config ) ( * tls . Conn , error ) {
dialer := & tls . Dialer {
Config : cfg ,
}
cn , err := dialer . DialContext ( ctx , network , addr )
if err != nil {
return nil , err
}
tlsCn := cn . ( * tls . Conn ) // DialContext comment promises this will always succeed
return tlsCn , nil
}
2016-02-03 21:58:02 +00:00
var http2DebugGoroutines = os . Getenv ( "DEBUG_HTTP2_GOROUTINES" ) == "1"
type http2goroutineLock uint64
func http2newGoroutineLock ( ) http2goroutineLock {
if ! http2DebugGoroutines {
return 0
}
return http2goroutineLock ( http2curGoroutineID ( ) )
}
func ( g http2goroutineLock ) check ( ) {
if ! http2DebugGoroutines {
return
}
if http2curGoroutineID ( ) != uint64 ( g ) {
panic ( "running on the wrong goroutine" )
}
}
func ( g http2goroutineLock ) checkNotOn ( ) {
if ! http2DebugGoroutines {
return
}
if http2curGoroutineID ( ) == uint64 ( g ) {
panic ( "running on the wrong goroutine" )
}
}
var http2goroutineSpace = [ ] byte ( "goroutine " )
func http2curGoroutineID ( ) uint64 {
bp := http2littleBuf . Get ( ) . ( * [ ] byte )
defer http2littleBuf . Put ( bp )
b := * bp
b = b [ : runtime . Stack ( b , false ) ]
2017-09-14 17:11:35 +00:00
// Parse the 4707 out of "goroutine 4707 ["
2016-02-03 21:58:02 +00:00
b = bytes . TrimPrefix ( b , http2goroutineSpace )
i := bytes . IndexByte ( b , ' ' )
if i < 0 {
panic ( fmt . Sprintf ( "No space found in %q" , b ) )
}
b = b [ : i ]
n , err := http2parseUintBytes ( b , 10 , 64 )
if err != nil {
panic ( fmt . Sprintf ( "Failed to parse goroutine ID out of %q: %v" , b , err ) )
}
return n
}
var http2littleBuf = sync . Pool {
New : func ( ) interface { } {
buf := make ( [ ] byte , 64 )
return & buf
} ,
}
// parseUintBytes is like strconv.ParseUint, but using a []byte.
func http2parseUintBytes ( s [ ] byte , base int , bitSize int ) ( n uint64 , err error ) {
var cutoff , maxVal uint64
if bitSize == 0 {
bitSize = int ( strconv . IntSize )
}
s0 := s
switch {
case len ( s ) < 1 :
err = strconv . ErrSyntax
goto Error
case 2 <= base && base <= 36 :
2017-09-14 17:11:35 +00:00
// valid base; nothing to do
2016-02-03 21:58:02 +00:00
case base == 0 :
2017-09-14 17:11:35 +00:00
// Look for octal, hex prefix.
2016-02-03 21:58:02 +00:00
switch {
case s [ 0 ] == '0' && len ( s ) > 1 && ( s [ 1 ] == 'x' || s [ 1 ] == 'X' ) :
base = 16
s = s [ 2 : ]
if len ( s ) < 1 {
err = strconv . ErrSyntax
goto Error
}
case s [ 0 ] == '0' :
base = 8
default :
base = 10
}
default :
err = errors . New ( "invalid base " + strconv . Itoa ( base ) )
goto Error
}
n = 0
cutoff = http2cutoff64 ( base )
maxVal = 1 << uint ( bitSize ) - 1
for i := 0 ; i < len ( s ) ; i ++ {
var v byte
d := s [ i ]
switch {
case '0' <= d && d <= '9' :
v = d - '0'
case 'a' <= d && d <= 'z' :
v = d - 'a' + 10
case 'A' <= d && d <= 'Z' :
v = d - 'A' + 10
default :
n = 0
err = strconv . ErrSyntax
goto Error
}
if int ( v ) >= base {
n = 0
err = strconv . ErrSyntax
goto Error
}
if n >= cutoff {
2017-09-14 17:11:35 +00:00
// n*base overflows
2016-02-03 21:58:02 +00:00
n = 1 << 64 - 1
err = strconv . ErrRange
goto Error
}
n *= uint64 ( base )
n1 := n + uint64 ( v )
if n1 < n || n1 > maxVal {
2017-09-14 17:11:35 +00:00
// n+v overflows
2016-02-03 21:58:02 +00:00
n = 1 << 64 - 1
err = strconv . ErrRange
goto Error
}
n = n1
}
return n , nil
Error :
return n , & strconv . NumError { Func : "ParseUint" , Num : string ( s0 ) , Err : err }
}
// Return the first number n such that n*base >= 1<<64.
func http2cutoff64 ( base int ) uint64 {
if base < 2 {
return 0
}
return ( 1 << 64 - 1 ) / uint64 ( base ) + 1
}
var (
2019-01-18 19:04:36 +00:00
http2commonBuildOnce sync . Once
http2commonLowerHeader map [ string ] string // Go-Canonical-Case -> lower-case
http2commonCanonHeader map [ string ] string // lower-case -> Go-Canonical-Case
2016-02-03 21:58:02 +00:00
)
2019-01-18 19:04:36 +00:00
func http2buildCommonHeaderMapsOnce ( ) {
http2commonBuildOnce . Do ( http2buildCommonHeaderMaps )
}
func http2buildCommonHeaderMaps ( ) {
common := [ ] string {
2016-02-03 21:58:02 +00:00
"accept" ,
"accept-charset" ,
"accept-encoding" ,
"accept-language" ,
"accept-ranges" ,
"age" ,
"access-control-allow-origin" ,
"allow" ,
"authorization" ,
"cache-control" ,
"content-disposition" ,
"content-encoding" ,
"content-language" ,
"content-length" ,
"content-location" ,
"content-range" ,
"content-type" ,
"cookie" ,
"date" ,
"etag" ,
"expect" ,
"expires" ,
"from" ,
"host" ,
"if-match" ,
"if-modified-since" ,
"if-none-match" ,
"if-unmodified-since" ,
"last-modified" ,
"link" ,
"location" ,
"max-forwards" ,
"proxy-authenticate" ,
"proxy-authorization" ,
"range" ,
"referer" ,
"refresh" ,
"retry-after" ,
"server" ,
"set-cookie" ,
"strict-transport-security" ,
"trailer" ,
"transfer-encoding" ,
"user-agent" ,
"vary" ,
"via" ,
"www-authenticate" ,
2019-01-18 19:04:36 +00:00
}
http2commonLowerHeader = make ( map [ string ] string , len ( common ) )
http2commonCanonHeader = make ( map [ string ] string , len ( common ) )
for _ , v := range common {
2016-02-03 21:58:02 +00:00
chk := CanonicalHeaderKey ( v )
http2commonLowerHeader [ chk ] = v
http2commonCanonHeader [ v ] = chk
}
}
2021-07-30 14:28:58 -07:00
func http2lowerHeader ( v string ) ( lower string , ascii bool ) {
2019-01-18 19:04:36 +00:00
http2buildCommonHeaderMapsOnce ( )
2016-02-03 21:58:02 +00:00
if s , ok := http2commonLowerHeader [ v ] ; ok {
2021-07-30 14:28:58 -07:00
return s , true
2016-02-03 21:58:02 +00:00
}
2021-07-30 14:28:58 -07:00
return http2asciiToLower ( v )
2016-02-03 21:58:02 +00:00
}
var (
http2VerboseLogs bool
http2logFrameWrites bool
http2logFrameReads bool
2017-01-14 00:05:42 +00:00
http2inTests bool
2016-02-03 21:58:02 +00:00
)
func init ( ) {
e := os . Getenv ( "GODEBUG" )
if strings . Contains ( e , "http2debug=1" ) {
http2VerboseLogs = true
}
if strings . Contains ( e , "http2debug=2" ) {
http2VerboseLogs = true
http2logFrameWrites = true
http2logFrameReads = true
}
}
const (
// ClientPreface is the string that must be sent by new
// connections from clients.
http2ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
// SETTINGS_MAX_FRAME_SIZE default
// http://http2.github.io/http2-spec/#rfc.section.6.5.2
http2initialMaxFrameSize = 16384
// NextProtoTLS is the NPN/ALPN protocol negotiated during
// HTTP/2's TLS setup.
http2NextProtoTLS = "h2"
// http://http2.github.io/http2-spec/#SettingValues
http2initialHeaderTableSize = 4096
http2initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
http2defaultMaxReadFrameSize = 1 << 20
)
var (
http2clientPreface = [ ] byte ( http2ClientPreface )
)
type http2streamState int
2017-01-14 00:05:42 +00:00
// HTTP/2 stream states.
//
// See http://tools.ietf.org/html/rfc7540#section-5.1.
//
// For simplicity, the server code merges "reserved (local)" into
// "half-closed (remote)". This is one less state transition to track.
// The only downside is that we send PUSH_PROMISEs slightly less
// liberally than allowable. More discussion here:
// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
//
// "reserved (remote)" is omitted since the client code does not
// support server push.
2016-02-03 21:58:02 +00:00
const (
http2stateIdle http2streamState = iota
http2stateOpen
http2stateHalfClosedLocal
http2stateHalfClosedRemote
http2stateClosed
)
var http2stateName = [ ... ] string {
http2stateIdle : "Idle" ,
http2stateOpen : "Open" ,
http2stateHalfClosedLocal : "HalfClosedLocal" ,
http2stateHalfClosedRemote : "HalfClosedRemote" ,
http2stateClosed : "Closed" ,
}
func ( st http2streamState ) String ( ) string {
return http2stateName [ st ]
}
// Setting is a setting parameter: which setting it is, and its value.
type http2Setting struct {
// ID is which setting is being set.
// See http://http2.github.io/http2-spec/#SettingValues
ID http2SettingID
// Val is the value.
Val uint32
}
func ( s http2Setting ) String ( ) string {
return fmt . Sprintf ( "[%v = %d]" , s . ID , s . Val )
}
// Valid reports whether the setting is valid.
func ( s http2Setting ) Valid ( ) error {
2017-09-14 17:11:35 +00:00
// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
2016-02-03 21:58:02 +00:00
switch s . ID {
case http2SettingEnablePush :
if s . Val != 1 && s . Val != 0 {
return http2ConnectionError ( http2ErrCodeProtocol )
}
case http2SettingInitialWindowSize :
if s . Val > 1 << 31 - 1 {
return http2ConnectionError ( http2ErrCodeFlowControl )
}
case http2SettingMaxFrameSize :
if s . Val < 16384 || s . Val > 1 << 24 - 1 {
return http2ConnectionError ( http2ErrCodeProtocol )
}
}
return nil
}
// A SettingID is an HTTP/2 setting as defined in
// http://http2.github.io/http2-spec/#iana-settings
type http2SettingID uint16
const (
http2SettingHeaderTableSize http2SettingID = 0x1
http2SettingEnablePush http2SettingID = 0x2
http2SettingMaxConcurrentStreams http2SettingID = 0x3
http2SettingInitialWindowSize http2SettingID = 0x4
http2SettingMaxFrameSize http2SettingID = 0x5
http2SettingMaxHeaderListSize http2SettingID = 0x6
)
var http2settingName = map [ http2SettingID ] string {
http2SettingHeaderTableSize : "HEADER_TABLE_SIZE" ,
http2SettingEnablePush : "ENABLE_PUSH" ,
http2SettingMaxConcurrentStreams : "MAX_CONCURRENT_STREAMS" ,
http2SettingInitialWindowSize : "INITIAL_WINDOW_SIZE" ,
http2SettingMaxFrameSize : "MAX_FRAME_SIZE" ,
http2SettingMaxHeaderListSize : "MAX_HEADER_LIST_SIZE" ,
}
func ( s http2SettingID ) String ( ) string {
if v , ok := http2settingName [ s ] ; ok {
return v
}
return fmt . Sprintf ( "UNKNOWN_SETTING_%d" , uint16 ( s ) )
}
2016-07-22 18:15:38 +00:00
// validWireHeaderFieldName reports whether v is a valid header field
2018-09-24 21:46:21 +00:00
// name (key). See httpguts.ValidHeaderName for the base rules.
2016-07-22 18:15:38 +00:00
//
2016-02-03 21:58:02 +00:00
// Further, http2 says:
// "Just as in HTTP/1.x, header field names are strings of ASCII
// characters that are compared in a case-insensitive
// fashion. However, header field names MUST be converted to
// lowercase prior to their encoding in HTTP/2. "
2016-07-22 18:15:38 +00:00
func http2validWireHeaderFieldName ( v string ) bool {
2016-02-03 21:58:02 +00:00
if len ( v ) == 0 {
return false
}
for _ , r := range v {
2018-09-24 21:46:21 +00:00
if ! httpguts . IsTokenRune ( r ) {
2016-02-03 21:58:02 +00:00
return false
}
2016-07-22 18:15:38 +00:00
if 'A' <= r && r <= 'Z' {
2016-02-03 21:58:02 +00:00
return false
}
}
return true
}
func http2httpCodeString ( code int ) string {
2019-01-18 19:04:36 +00:00
switch code {
case 200 :
return "200"
case 404 :
return "404"
2016-02-03 21:58:02 +00:00
}
return strconv . Itoa ( code )
}
// from pkg io
type http2stringWriter interface {
WriteString ( s string ) ( n int , err error )
}
// A gate lets two goroutines coordinate their activities.
type http2gate chan struct { }
func ( g http2gate ) Done ( ) { g <- struct { } { } }
func ( g http2gate ) Wait ( ) { <- g }
// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
type http2closeWaiter chan struct { }
// Init makes a closeWaiter usable.
// It exists because so a closeWaiter value can be placed inside a
// larger struct and have the Mutex and Cond's memory in the same
// allocation.
func ( cw * http2closeWaiter ) Init ( ) {
* cw = make ( chan struct { } )
}
// Close marks the closeWaiter as closed and unblocks any waiters.
func ( cw http2closeWaiter ) Close ( ) {
close ( cw )
}
// Wait waits for the closeWaiter to become closed.
func ( cw http2closeWaiter ) Wait ( ) {
<- cw
}
// bufferedWriter is a buffered writer that writes to w.
// Its buffered writer is lazily allocated as needed, to minimize
// idle memory usage with many connections.
type http2bufferedWriter struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
w io . Writer // immutable
bw * bufio . Writer // non-nil when data is buffered
}
func http2newBufferedWriter ( w io . Writer ) * http2bufferedWriter {
return & http2bufferedWriter { w : w }
}
2017-01-14 00:05:42 +00:00
// bufWriterPoolBufferSize is the size of bufio.Writer's
// buffers created using bufWriterPool.
//
// TODO: pick a less arbitrary value? this is a bit under
// (3 x typical 1500 byte MTU) at least. Other than that,
// not much thought went into it.
const http2bufWriterPoolBufferSize = 4 << 10
2016-02-03 21:58:02 +00:00
var http2bufWriterPool = sync . Pool {
New : func ( ) interface { } {
2017-01-14 00:05:42 +00:00
return bufio . NewWriterSize ( nil , http2bufWriterPoolBufferSize )
2016-02-03 21:58:02 +00:00
} ,
}
2017-01-14 00:05:42 +00:00
func ( w * http2bufferedWriter ) Available ( ) int {
if w . bw == nil {
return http2bufWriterPoolBufferSize
}
return w . bw . Available ( )
}
2016-02-03 21:58:02 +00:00
func ( w * http2bufferedWriter ) Write ( p [ ] byte ) ( n int , err error ) {
if w . bw == nil {
bw := http2bufWriterPool . Get ( ) . ( * bufio . Writer )
bw . Reset ( w . w )
w . bw = bw
}
return w . bw . Write ( p )
}
func ( w * http2bufferedWriter ) Flush ( ) error {
bw := w . bw
if bw == nil {
return nil
}
err := bw . Flush ( )
bw . Reset ( nil )
http2bufWriterPool . Put ( bw )
w . bw = nil
return err
}
func http2mustUint31 ( v int32 ) uint32 {
if v < 0 || v > 2147483647 {
panic ( "out of range" )
}
return uint32 ( v )
}
// bodyAllowedForStatus reports whether a given response status code
2018-09-24 21:46:21 +00:00
// permits a body. See RFC 7230, section 3.3.
2016-02-03 21:58:02 +00:00
func http2bodyAllowedForStatus ( status int ) bool {
switch {
case status >= 100 && status <= 199 :
return false
case status == 204 :
return false
case status == 304 :
return false
}
return true
}
type http2httpError struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
msg string
timeout bool
}
func ( e * http2httpError ) Error ( ) string { return e . msg }
func ( e * http2httpError ) Timeout ( ) bool { return e . timeout }
func ( e * http2httpError ) Temporary ( ) bool { return true }
var http2errTimeout error = & http2httpError { msg : "http2: timeout awaiting response headers" , timeout : true }
2016-02-18 05:56:46 +00:00
type http2connectionStater interface {
ConnectionState ( ) tls . ConnectionState
}
2016-07-22 18:15:38 +00:00
var http2sorterPool = sync . Pool { New : func ( ) interface { } { return new ( http2sorter ) } }
type http2sorter struct {
v [ ] string // owned by sorter
}
func ( s * http2sorter ) Len ( ) int { return len ( s . v ) }
func ( s * http2sorter ) Swap ( i , j int ) { s . v [ i ] , s . v [ j ] = s . v [ j ] , s . v [ i ] }
func ( s * http2sorter ) Less ( i , j int ) bool { return s . v [ i ] < s . v [ j ] }
// Keys returns the sorted keys of h.
//
// The returned slice is only valid until s used again or returned to
// its pool.
func ( s * http2sorter ) Keys ( h Header ) [ ] string {
keys := s . v [ : 0 ]
for k := range h {
keys = append ( keys , k )
}
s . v = keys
sort . Sort ( s )
return keys
}
func ( s * http2sorter ) SortStrings ( ss [ ] string ) {
2017-09-14 17:11:35 +00:00
// Our sorter works on s.v, which sorter owns, so
// stash it away while we sort the user's buffer.
2016-07-22 18:15:38 +00:00
save := s . v
s . v = ss
sort . Sort ( s )
s . v = save
}
2017-01-14 00:05:42 +00:00
// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
2017-09-14 17:11:35 +00:00
// *) a non-empty string starting with '/'
2017-01-14 00:05:42 +00:00
// *) the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
2017-09-14 17:11:35 +00:00
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
2017-01-14 00:05:42 +00:00
func http2validPseudoPath ( v string ) bool {
2017-09-14 17:11:35 +00:00
return ( len ( v ) > 0 && v [ 0 ] == '/' ) || v == "*"
2017-01-14 00:05:42 +00:00
}
2020-07-27 22:27:54 -07:00
// incomparable is a zero-width, non-comparable type. Adding it to a struct
// makes that struct also non-comparable, and generally doesn't add
// any size (as long as it's first).
type http2incomparable [ 0 ] func ( )
2017-09-14 17:11:35 +00:00
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
2016-02-03 21:58:02 +00:00
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
// underlying buffer is an interface. (io.Pipe is always unbuffered)
type http2pipe struct {
mu sync . Mutex
2017-09-14 17:11:35 +00:00
c sync . Cond // c.L lazily initialized to &p.mu
b http2pipeBuffer // nil when done reading
2020-01-02 15:05:27 -08:00
unread int // bytes unread when done
2017-09-14 17:11:35 +00:00
err error // read error once empty. non-nil means closed.
breakErr error // immediate read error (caller doesn't see rest of b)
donec chan struct { } // closed on error
readFn func ( ) // optional code to run in Read before error
2016-02-03 21:58:02 +00:00
}
type http2pipeBuffer interface {
Len ( ) int
io . Writer
io . Reader
}
2022-02-11 14:53:56 -08:00
// setBuffer initializes the pipe buffer.
// It has no effect if the pipe is already closed.
func ( p * http2pipe ) setBuffer ( b http2pipeBuffer ) {
p . mu . Lock ( )
defer p . mu . Unlock ( )
if p . err != nil || p . breakErr != nil {
return
}
p . b = b
}
2016-07-22 18:15:38 +00:00
func ( p * http2pipe ) Len ( ) int {
p . mu . Lock ( )
defer p . mu . Unlock ( )
2017-09-14 17:11:35 +00:00
if p . b == nil {
2020-01-02 15:05:27 -08:00
return p . unread
2017-09-14 17:11:35 +00:00
}
2016-07-22 18:15:38 +00:00
return p . b . Len ( )
}
2016-02-03 21:58:02 +00:00
// Read waits until data is available and copies bytes
// from the buffer into p.
func ( p * http2pipe ) Read ( d [ ] byte ) ( n int , err error ) {
p . mu . Lock ( )
defer p . mu . Unlock ( )
if p . c . L == nil {
p . c . L = & p . mu
}
for {
if p . breakErr != nil {
return 0 , p . breakErr
}
2017-09-14 17:11:35 +00:00
if p . b != nil && p . b . Len ( ) > 0 {
2016-02-03 21:58:02 +00:00
return p . b . Read ( d )
}
if p . err != nil {
if p . readFn != nil {
2017-09-14 17:11:35 +00:00
p . readFn ( ) // e.g. copy trailers
p . readFn = nil // not sticky like p.err
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
p . b = nil
2016-02-03 21:58:02 +00:00
return 0 , p . err
}
p . c . Wait ( )
}
}
var http2errClosedPipeWrite = errors . New ( "write on closed buffer" )
// Write copies bytes from p into the buffer and wakes a reader.
// It is an error to write more data than the buffer can hold.
func ( p * http2pipe ) Write ( d [ ] byte ) ( n int , err error ) {
p . mu . Lock ( )
defer p . mu . Unlock ( )
if p . c . L == nil {
p . c . L = & p . mu
}
defer p . c . Signal ( )
if p . err != nil {
return 0 , http2errClosedPipeWrite
}
2017-09-14 17:11:35 +00:00
if p . breakErr != nil {
2020-01-02 15:05:27 -08:00
p . unread += len ( d )
2017-09-14 17:11:35 +00:00
return len ( d ) , nil // discard when there is no reader
}
2016-02-03 21:58:02 +00:00
return p . b . Write ( d )
}
// CloseWithError causes the next Read (waking up a current blocked
// Read if needed) to return the provided err after all data has been
// read.
//
// The error must be non-nil.
func ( p * http2pipe ) CloseWithError ( err error ) { p . closeWithError ( & p . err , err , nil ) }
// BreakWithError causes the next Read (waking up a current blocked
// Read if needed) to return the provided err immediately, without
// waiting for unread data.
func ( p * http2pipe ) BreakWithError ( err error ) { p . closeWithError ( & p . breakErr , err , nil ) }
// closeWithErrorAndCode is like CloseWithError but also sets some code to run
// in the caller's goroutine before returning the error.
func ( p * http2pipe ) closeWithErrorAndCode ( err error , fn func ( ) ) { p . closeWithError ( & p . err , err , fn ) }
func ( p * http2pipe ) closeWithError ( dst * error , err error , fn func ( ) ) {
if err == nil {
panic ( "err must be non-nil" )
}
p . mu . Lock ( )
defer p . mu . Unlock ( )
if p . c . L == nil {
p . c . L = & p . mu
}
defer p . c . Signal ( )
if * dst != nil {
2017-09-14 17:11:35 +00:00
// Already been done.
2016-02-03 21:58:02 +00:00
return
}
p . readFn = fn
2017-09-14 17:11:35 +00:00
if dst == & p . breakErr {
2020-01-02 15:05:27 -08:00
if p . b != nil {
p . unread += p . b . Len ( )
}
2017-09-14 17:11:35 +00:00
p . b = nil
}
2016-02-03 21:58:02 +00:00
* dst = err
p . closeDoneLocked ( )
}
// requires p.mu be held.
func ( p * http2pipe ) closeDoneLocked ( ) {
if p . donec == nil {
return
}
2017-09-14 17:11:35 +00:00
// Close if unclosed. This isn't racy since we always
// hold p.mu while closing.
2016-02-03 21:58:02 +00:00
select {
case <- p . donec :
default :
close ( p . donec )
}
}
// Err returns the error (if any) first set by BreakWithError or CloseWithError.
func ( p * http2pipe ) Err ( ) error {
p . mu . Lock ( )
defer p . mu . Unlock ( )
if p . breakErr != nil {
return p . breakErr
}
return p . err
}
// Done returns a channel which is closed if and when this pipe is closed
// with CloseWithError.
func ( p * http2pipe ) Done ( ) <- chan struct { } {
p . mu . Lock ( )
defer p . mu . Unlock ( )
if p . donec == nil {
p . donec = make ( chan struct { } )
if p . err != nil || p . breakErr != nil {
2017-09-14 17:11:35 +00:00
// Already hit an error.
2016-02-03 21:58:02 +00:00
p . closeDoneLocked ( )
}
}
return p . donec
}
const (
2019-09-12 23:22:53 +00:00
http2prefaceTimeout = 10 * time . Second
http2firstSettingsTimeout = 2 * time . Second // should be in-flight with preface anyway
http2handlerChunkWriteSize = 4 << 10
http2defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
http2maxQueuedControlFrames = 10000
2016-02-03 21:58:02 +00:00
)
var (
http2errClientDisconnected = errors . New ( "client disconnected" )
http2errClosedBody = errors . New ( "body closed by handler" )
http2errHandlerComplete = errors . New ( "http2: request body closed due to handler exiting" )
http2errStreamClosed = errors . New ( "http2: stream closed" )
)
var http2responseWriterStatePool = sync . Pool {
New : func ( ) interface { } {
rws := & http2responseWriterState { }
rws . bw = bufio . NewWriterSize ( http2chunkWriter { rws } , http2handlerChunkWriteSize )
return rws
} ,
}
// Test hooks.
var (
http2testHookOnConn func ( )
http2testHookGetServerConn func ( * http2serverConn )
http2testHookOnPanicMu * sync . Mutex // nil except in tests
http2testHookOnPanic func ( sc * http2serverConn , panicVal interface { } ) ( rePanic bool )
)
// Server is an HTTP/2 server.
type http2Server struct {
// MaxHandlers limits the number of http.Handler ServeHTTP goroutines
// which may run at a time over all connections.
// Negative or zero no limit.
// TODO: implement
MaxHandlers int
// MaxConcurrentStreams optionally specifies the number of
// concurrent streams that each client may have open at a
// time. This is unrelated to the number of http.Handler goroutines
// which may be active globally, which is MaxHandlers.
// If zero, MaxConcurrentStreams defaults to at least 100, per
// the HTTP/2 spec's recommendations.
MaxConcurrentStreams uint32
// MaxReadFrameSize optionally specifies the largest frame
// this server is willing to read. A valid value is between
// 16k and 16M, inclusive. If zero or otherwise invalid, a
// default value is used.
MaxReadFrameSize uint32
// PermitProhibitedCipherSuites, if true, permits the use of
// cipher suites prohibited by the HTTP/2 spec.
PermitProhibitedCipherSuites bool
2017-01-14 00:05:42 +00:00
// IdleTimeout specifies how long until idle clients should be
// closed with a GOAWAY frame. PING frames are not considered
// activity for the purposes of IdleTimeout.
IdleTimeout time . Duration
2017-09-14 17:11:35 +00:00
// MaxUploadBufferPerConnection is the size of the initial flow
// control window for each connections. The HTTP/2 spec does not
// allow this to be smaller than 65535 or larger than 2^32-1.
// If the value is outside this range, a default value will be
// used instead.
MaxUploadBufferPerConnection int32
// MaxUploadBufferPerStream is the size of the initial flow control
// window for each stream. The HTTP/2 spec does not allow this to
// be larger than 2^32-1. If the value is zero or larger than the
// maximum, a default value will be used instead.
MaxUploadBufferPerStream int32
2017-01-14 00:05:42 +00:00
// NewWriteScheduler constructs a write scheduler for a connection.
// If nil, a default scheduler is chosen.
NewWriteScheduler func ( ) http2WriteScheduler
2017-09-14 17:11:35 +00:00
2022-02-11 14:53:56 -08:00
// CountError, if non-nil, is called on HTTP/2 server errors.
// It's intended to increment a metric for monitoring, such
// as an expvar or Prometheus metric.
// The errType consists of only ASCII word characters.
CountError func ( errType string )
2017-09-14 17:11:35 +00:00
// Internal state. This is a pointer (rather than embedded directly)
// so that we don't embed a Mutex in this struct, which will make the
// struct non-copyable, which might break some callers.
state * http2serverInternalState
}
func ( s * http2Server ) initialConnRecvWindowSize ( ) int32 {
if s . MaxUploadBufferPerConnection > http2initialWindowSize {
return s . MaxUploadBufferPerConnection
}
return 1 << 20
}
func ( s * http2Server ) initialStreamRecvWindowSize ( ) int32 {
if s . MaxUploadBufferPerStream > 0 {
return s . MaxUploadBufferPerStream
}
return 1 << 20
2016-02-03 21:58:02 +00:00
}
func ( s * http2Server ) maxReadFrameSize ( ) uint32 {
if v := s . MaxReadFrameSize ; v >= http2minMaxFrameSize && v <= http2maxFrameSize {
return v
}
return http2defaultMaxReadFrameSize
}
func ( s * http2Server ) maxConcurrentStreams ( ) uint32 {
if v := s . MaxConcurrentStreams ; v > 0 {
return v
}
return http2defaultMaxStreams
}
2019-09-12 23:22:53 +00:00
// maxQueuedControlFrames is the maximum number of control frames like
// SETTINGS, PING and RST_STREAM that will be queued for writing before
// the connection is closed to prevent memory exhaustion attacks.
func ( s * http2Server ) maxQueuedControlFrames ( ) int {
// TODO: if anybody asks, add a Server field, and remember to define the
// behavior of negative values.
return http2maxQueuedControlFrames
}
2017-09-14 17:11:35 +00:00
type http2serverInternalState struct {
mu sync . Mutex
activeConns map [ * http2serverConn ] struct { }
}
func ( s * http2serverInternalState ) registerConn ( sc * http2serverConn ) {
if s == nil {
return // if the Server was used without calling ConfigureServer
}
s . mu . Lock ( )
s . activeConns [ sc ] = struct { } { }
s . mu . Unlock ( )
}
func ( s * http2serverInternalState ) unregisterConn ( sc * http2serverConn ) {
if s == nil {
return // if the Server was used without calling ConfigureServer
}
s . mu . Lock ( )
delete ( s . activeConns , sc )
s . mu . Unlock ( )
}
func ( s * http2serverInternalState ) startGracefulShutdown ( ) {
if s == nil {
return // if the Server was used without calling ConfigureServer
}
s . mu . Lock ( )
for sc := range s . activeConns {
sc . startGracefulShutdown ( )
}
s . mu . Unlock ( )
}
2016-02-03 21:58:02 +00:00
// ConfigureServer adds HTTP/2 support to a net/http Server.
//
// The configuration conf may be nil.
//
// ConfigureServer must be called before s begins serving.
func http2ConfigureServer ( s * Server , conf * http2Server ) error {
2017-01-14 00:05:42 +00:00
if s == nil {
panic ( "nil *http.Server" )
}
2016-02-03 21:58:02 +00:00
if conf == nil {
conf = new ( http2Server )
}
2017-09-14 17:11:35 +00:00
conf . state = & http2serverInternalState { activeConns : make ( map [ * http2serverConn ] struct { } ) }
2019-01-18 19:04:36 +00:00
if h1 , h2 := s , conf ; h2 . IdleTimeout == 0 {
if h1 . IdleTimeout != 0 {
h2 . IdleTimeout = h1 . IdleTimeout
} else {
h2 . IdleTimeout = h1 . ReadTimeout
}
2017-09-14 17:11:35 +00:00
}
2019-01-18 19:04:36 +00:00
s . RegisterOnShutdown ( conf . state . startGracefulShutdown )
2016-02-03 21:58:02 +00:00
if s . TLSConfig == nil {
s . TLSConfig = new ( tls . Config )
2021-07-30 14:28:58 -07:00
} else if s . TLSConfig . CipherSuites != nil && s . TLSConfig . MinVersion < tls . VersionTLS13 {
// If they already provided a TLS 1.0– 1.2 CipherSuite list, return an
// error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or
// ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
2016-02-03 21:58:02 +00:00
haveRequired := false
2021-07-30 14:28:58 -07:00
for _ , cs := range s . TLSConfig . CipherSuites {
2018-01-09 01:23:08 +00:00
switch cs {
case tls . TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ,
// Alternative MTI cipher to not discourage ECDSA-only servers.
// See http://golang.org/cl/30721 for further information.
tls . TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :
2016-02-03 21:58:02 +00:00
haveRequired = true
}
}
if ! haveRequired {
2021-07-30 14:28:58 -07:00
return fmt . Errorf ( "http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)" )
2016-02-03 21:58:02 +00:00
}
}
2017-09-14 17:11:35 +00:00
// Note: not setting MinVersion to tls.VersionTLS12,
// as we don't want to interfere with HTTP/1.1 traffic
// on the user's server. We enforce TLS 1.2 later once
// we accept a connection. Ideally this should be done
// during next-proto selection, but using TLS <1.2 with
// HTTP/2 is still the client's bug.
2016-02-03 21:58:02 +00:00
s . TLSConfig . PreferServerCipherSuites = true
2022-02-11 14:53:56 -08:00
if ! http2strSliceContains ( s . TLSConfig . NextProtos , http2NextProtoTLS ) {
2016-02-03 21:58:02 +00:00
s . TLSConfig . NextProtos = append ( s . TLSConfig . NextProtos , http2NextProtoTLS )
}
2022-02-11 14:53:56 -08:00
if ! http2strSliceContains ( s . TLSConfig . NextProtos , "http/1.1" ) {
s . TLSConfig . NextProtos = append ( s . TLSConfig . NextProtos , "http/1.1" )
}
2016-02-03 21:58:02 +00:00
if s . TLSNextProto == nil {
s . TLSNextProto = map [ string ] func ( * Server , * tls . Conn , Handler ) { }
}
protoHandler := func ( hs * Server , c * tls . Conn , h Handler ) {
if http2testHookOnConn != nil {
http2testHookOnConn ( )
}
2019-09-06 18:12:46 +00:00
// The TLSNextProto interface predates contexts, so
// the net/http package passes down its per-connection
// base context via an exported but unadvertised
// method on the Handler. This is for internal
// net/http<=>http2 use only.
var ctx context . Context
type baseContexter interface {
BaseContext ( ) context . Context
}
if bc , ok := h . ( baseContexter ) ; ok {
ctx = bc . BaseContext ( )
}
2016-02-18 05:56:46 +00:00
conf . ServeConn ( c , & http2ServeConnOpts {
2019-09-06 18:12:46 +00:00
Context : ctx ,
2016-02-18 05:56:46 +00:00
Handler : h ,
BaseConfig : hs ,
} )
2016-02-03 21:58:02 +00:00
}
s . TLSNextProto [ http2NextProtoTLS ] = protoHandler
return nil
}
2016-02-18 05:56:46 +00:00
// ServeConnOpts are options for the Server.ServeConn method.
type http2ServeConnOpts struct {
2019-09-06 18:12:46 +00:00
// Context is the base context to use.
// If nil, context.Background is used.
Context context . Context
2016-02-18 05:56:46 +00:00
// BaseConfig optionally sets the base configuration
// for values. If nil, defaults are used.
BaseConfig * Server
// Handler specifies which handler to use for processing
// requests. If nil, BaseConfig.Handler is used. If BaseConfig
// or BaseConfig.Handler is nil, http.DefaultServeMux is used.
Handler Handler
}
2019-09-06 18:12:46 +00:00
func ( o * http2ServeConnOpts ) context ( ) context . Context {
2020-01-02 15:05:27 -08:00
if o != nil && o . Context != nil {
2019-09-06 18:12:46 +00:00
return o . Context
}
return context . Background ( )
}
2016-02-18 05:56:46 +00:00
func ( o * http2ServeConnOpts ) baseConfig ( ) * Server {
if o != nil && o . BaseConfig != nil {
return o . BaseConfig
}
return new ( Server )
}
func ( o * http2ServeConnOpts ) handler ( ) Handler {
if o != nil {
if o . Handler != nil {
return o . Handler
}
if o . BaseConfig != nil && o . BaseConfig . Handler != nil {
return o . BaseConfig . Handler
}
}
return DefaultServeMux
}
// ServeConn serves HTTP/2 requests on the provided connection and
// blocks until the connection is no longer readable.
//
// ServeConn starts speaking HTTP/2 assuming that c has not had any
// reads or writes. It writes its initial settings frame and expects
// to be able to read the preface and settings frame from the
// client. If c has a ConnectionState method like a *tls.Conn, the
// ConnectionState is used to verify the TLS ciphersuite and to set
// the Request.TLS field in Handlers.
//
// ServeConn does not support h2c by itself. Any h2c support must be
// implemented in terms of providing a suitably-behaving net.Conn.
//
// The opts parameter is optional. If nil, default values are used.
func ( s * http2Server ) ServeConn ( c net . Conn , opts * http2ServeConnOpts ) {
2016-07-22 18:15:38 +00:00
baseCtx , cancel := http2serverConnBaseContext ( c , opts )
defer cancel ( )
2016-02-03 21:58:02 +00:00
sc := & http2serverConn {
2017-09-14 17:11:35 +00:00
srv : s ,
hs : opts . baseConfig ( ) ,
conn : c ,
baseCtx : baseCtx ,
remoteAddrStr : c . RemoteAddr ( ) . String ( ) ,
bw : http2newBufferedWriter ( c ) ,
handler : opts . handler ( ) ,
streams : make ( map [ uint32 ] * http2stream ) ,
readFrameCh : make ( chan http2readFrameResult ) ,
wantWriteFrameCh : make ( chan http2FrameWriteRequest , 8 ) ,
serveMsgCh : make ( chan interface { } , 8 ) ,
wroteFrameCh : make ( chan http2frameWriteResult , 1 ) , // buffered; one send in writeFrameAsync
bodyReadCh : make ( chan http2bodyReadMsg ) , // buffering doesn't matter either way
doneServing : make ( chan struct { } ) ,
clientMaxStreams : math . MaxUint32 , // Section 6.5.2: "Initially, there is no limit to this value"
advMaxStreams : s . maxConcurrentStreams ( ) ,
initialStreamSendWindowSize : http2initialWindowSize ,
maxFrameSize : http2initialMaxFrameSize ,
headerTableSize : http2initialHeaderTableSize ,
serveG : http2newGoroutineLock ( ) ,
pushEnabled : true ,
}
s . state . registerConn ( sc )
defer s . state . unregisterConn ( sc )
// The net/http package sets the write deadline from the
// http.Server.WriteTimeout during the TLS handshake, but then
// passes the connection off to us with the deadline already set.
// Write deadlines are set per stream in serverConn.newStream.
// Disarm the net.Conn write deadline here.
2017-01-14 00:05:42 +00:00
if sc . hs . WriteTimeout != 0 {
sc . conn . SetWriteDeadline ( time . Time { } )
}
if s . NewWriteScheduler != nil {
sc . writeSched = s . NewWriteScheduler ( )
} else {
sc . writeSched = http2NewRandomWriteScheduler ( )
}
2017-09-14 17:11:35 +00:00
// These start at the RFC-specified defaults. If there is a higher
// configured value for inflow, that will be updated when we send a
// WINDOW_UPDATE shortly after sending SETTINGS.
2016-02-03 21:58:02 +00:00
sc . flow . add ( http2initialWindowSize )
sc . inflow . add ( http2initialWindowSize )
sc . hpackEncoder = hpack . NewEncoder ( & sc . headerWriteBuf )
fr := http2NewFramer ( sc . bw , c )
2022-02-11 14:53:56 -08:00
if s . CountError != nil {
fr . countError = s . CountError
}
2016-07-22 18:15:38 +00:00
fr . ReadMetaHeaders = hpack . NewDecoder ( http2initialHeaderTableSize , nil )
fr . MaxHeaderListSize = sc . maxHeaderListSize ( )
2016-02-18 05:56:46 +00:00
fr . SetMaxReadFrameSize ( s . maxReadFrameSize ( ) )
2016-02-03 21:58:02 +00:00
sc . framer = fr
2016-02-18 05:56:46 +00:00
if tc , ok := c . ( http2connectionStater ) ; ok {
2016-02-03 21:58:02 +00:00
sc . tlsState = new ( tls . ConnectionState )
* sc . tlsState = tc . ConnectionState ( )
2017-09-14 17:11:35 +00:00
// 9.2 Use of TLS Features
// An implementation of HTTP/2 over TLS MUST use TLS
// 1.2 or higher with the restrictions on feature set
// and cipher suite described in this section. Due to
// implementation limitations, it might not be
// possible to fail TLS negotiation. An endpoint MUST
// immediately terminate an HTTP/2 connection that
// does not meet the TLS requirements described in
// this section with a connection error (Section
// 5.4.1) of type INADEQUATE_SECURITY.
2016-02-03 21:58:02 +00:00
if sc . tlsState . Version < tls . VersionTLS12 {
sc . rejectConn ( http2ErrCodeInadequateSecurity , "TLS version too low" )
return
}
if sc . tlsState . ServerName == "" {
2017-09-14 17:11:35 +00:00
// Client must use SNI, but we don't enforce that anymore,
// since it was causing problems when connecting to bare IP
// addresses during development.
//
// TODO: optionally enforce? Or enforce at the time we receive
2018-09-24 21:46:21 +00:00
// a new request, and verify the ServerName matches the :authority?
2017-09-14 17:11:35 +00:00
// But that precludes proxy situations, perhaps.
//
// So for now, do nothing here again.
2016-02-03 21:58:02 +00:00
}
2016-02-18 05:56:46 +00:00
if ! s . PermitProhibitedCipherSuites && http2isBadCipher ( sc . tlsState . CipherSuite ) {
2017-09-14 17:11:35 +00:00
// "Endpoints MAY choose to generate a connection error
// (Section 5.4.1) of type INADEQUATE_SECURITY if one of
// the prohibited cipher suites are negotiated."
//
// We choose that. In my opinion, the spec is weak
// here. It also says both parties must support at least
// TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 so there's no
// excuses here. If we really must, we could allow an
// "AllowInsecureWeakCiphers" option on the server later.
// Let's see how it plays out first.
2016-02-03 21:58:02 +00:00
sc . rejectConn ( http2ErrCodeInadequateSecurity , fmt . Sprintf ( "Prohibited TLS 1.2 Cipher Suite: %x" , sc . tlsState . CipherSuite ) )
return
}
}
if hook := http2testHookGetServerConn ; hook != nil {
hook ( sc )
}
sc . serve ( )
}
2019-01-18 19:04:36 +00:00
func http2serverConnBaseContext ( c net . Conn , opts * http2ServeConnOpts ) ( ctx context . Context , cancel func ( ) ) {
2019-09-06 18:12:46 +00:00
ctx , cancel = context . WithCancel ( opts . context ( ) )
2019-01-18 19:04:36 +00:00
ctx = context . WithValue ( ctx , LocalAddrContextKey , c . LocalAddr ( ) )
if hs := opts . baseConfig ( ) ; hs != nil {
ctx = context . WithValue ( ctx , ServerContextKey , hs )
}
return
}
2016-02-03 21:58:02 +00:00
func ( sc * http2serverConn ) rejectConn ( err http2ErrCode , debug string ) {
sc . vlogf ( "http2: server rejecting conn: %v, %s" , err , debug )
2017-09-14 17:11:35 +00:00
// ignoring errors. hanging up anyway.
2016-02-03 21:58:02 +00:00
sc . framer . WriteGoAway ( 0 , err , [ ] byte ( debug ) )
sc . bw . Flush ( )
sc . conn . Close ( )
}
type http2serverConn struct {
// Immutable:
srv * http2Server
hs * Server
conn net . Conn
bw * http2bufferedWriter // writing to conn
handler Handler
2019-01-18 19:04:36 +00:00
baseCtx context . Context
2016-02-03 21:58:02 +00:00
framer * http2Framer
2017-01-14 00:05:42 +00:00
doneServing chan struct { } // closed when serverConn.serve ends
readFrameCh chan http2readFrameResult // written by serverConn.readFrames
wantWriteFrameCh chan http2FrameWriteRequest // from handlers -> serve
wroteFrameCh chan http2frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
bodyReadCh chan http2bodyReadMsg // from handlers -> serve
2017-09-14 17:11:35 +00:00
serveMsgCh chan interface { } // misc messages & code to send to / run on the serve loop
2017-01-14 00:05:42 +00:00
flow http2flow // conn-wide (not stream-specific) outbound flow control
inflow http2flow // conn-wide inbound flow control
tlsState * tls . ConnectionState // shared by all handlers, like net/http
2016-02-03 21:58:02 +00:00
remoteAddrStr string
2017-01-14 00:05:42 +00:00
writeSched http2WriteScheduler
2016-02-03 21:58:02 +00:00
// Everything following is owned by the serve loop; use serveG.check():
2017-09-14 17:11:35 +00:00
serveG http2goroutineLock // used to verify funcs are on serve()
pushEnabled bool
sawFirstSettings bool // got the initial SETTINGS frame after the preface
needToSendSettingsAck bool
unackedSettings int // how many SETTINGS have we sent without ACKs?
2019-09-12 23:22:53 +00:00
queuedControlFrames int // control frames in the writeSched queue
2017-09-14 17:11:35 +00:00
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
curClientStreams uint32 // number of open streams initiated by the client
curPushedStreams uint32 // number of open streams initiated by server push
maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
streams map [ uint32 ] * http2stream
initialStreamSendWindowSize int32
maxFrameSize int32
headerTableSize uint32
peerMaxHeaderListSize uint32 // zero means unknown (default)
canonHeader map [ string ] string // http2-lower-case -> Go-Canonical-Case
writingFrame bool // started writing a frame (on serve goroutine or separate)
writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh
needsFrameFlush bool // last frame write wasn't a flush
inGoAway bool // we've started to or sent GOAWAY
inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
needToSendGoAway bool // we need to schedule a GOAWAY frame write
goAwayCode http2ErrCode
shutdownTimer * time . Timer // nil until used
idleTimer * time . Timer // nil if unused
2016-02-03 21:58:02 +00:00
// Owned by the writeFrameAsync goroutine:
headerWriteBuf bytes . Buffer
hpackEncoder * hpack . Encoder
2017-09-14 17:11:35 +00:00
// Used by startGracefulShutdown.
shutdownOnce sync . Once
2016-02-03 21:58:02 +00:00
}
func ( sc * http2serverConn ) maxHeaderListSize ( ) uint32 {
n := sc . hs . MaxHeaderBytes
if n <= 0 {
n = DefaultMaxHeaderBytes
}
// http2's count is in a slightly different unit and includes 32 bytes per pair.
// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
const perFieldOverhead = 32 // per http2 spec
const typicalHeaders = 10 // conservative
return uint32 ( n + typicalHeaders * perFieldOverhead )
}
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) curOpenStreams ( ) uint32 {
sc . serveG . check ( )
return sc . curClientStreams + sc . curPushedStreams
}
2016-02-03 21:58:02 +00:00
// stream represents a stream. This is the minimal metadata needed by
// the serve goroutine. Most of the actual stream state is owned by
// the http.Handler's goroutine in the responseWriter. Because the
// responseWriter's responseWriterState is recycled at the end of a
// handler, this struct intentionally has no pointer to the
// *responseWriter{,State} itself, as the Handler ending nils out the
// responseWriter's state field.
type http2stream struct {
// immutable:
2016-07-22 18:15:38 +00:00
sc * http2serverConn
id uint32
body * http2pipe // non-nil if expecting DATA frames
cw http2closeWaiter // closed wait stream transitions to closed state
2019-01-18 19:04:36 +00:00
ctx context . Context
2016-07-22 18:15:38 +00:00
cancelCtx func ( )
2016-02-03 21:58:02 +00:00
// owned by serverConn's serve loop:
2020-07-27 22:27:54 -07:00
bodyBytes int64 // body bytes seen so far
declBodyBytes int64 // or -1 if undeclared
flow http2flow // limits writing from Handler to client
inflow http2flow // what the client is allowed to POST/etc to us
2016-02-03 21:58:02 +00:00
state http2streamState
2017-09-14 17:11:35 +00:00
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
gotTrailerHeader bool // HEADER frame for trailers was seen
wroteHeaders bool // whether we wrote headers (not status 100)
writeDeadline * time . Timer // nil if unused
2016-02-03 21:58:02 +00:00
trailer Header // accumulated trailers
reqTrailer Header // handler's Request.Trailer
}
func ( sc * http2serverConn ) Framer ( ) * http2Framer { return sc . framer }
func ( sc * http2serverConn ) CloseConn ( ) error { return sc . conn . Close ( ) }
func ( sc * http2serverConn ) Flush ( ) error { return sc . bw . Flush ( ) }
func ( sc * http2serverConn ) HeaderEncoder ( ) ( * hpack . Encoder , * bytes . Buffer ) {
return sc . hpackEncoder , & sc . headerWriteBuf
}
func ( sc * http2serverConn ) state ( streamID uint32 ) ( http2streamState , * http2stream ) {
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-5.1
2016-02-03 21:58:02 +00:00
if st , ok := sc . streams [ streamID ] ; ok {
return st . state , st
}
2017-09-14 17:11:35 +00:00
// "The first use of a new stream identifier implicitly closes all
// streams in the "idle" state that might have been initiated by
// that peer with a lower-valued stream identifier. For example, if
// a client sends a HEADERS frame on stream 7 without ever sending a
// frame on stream 5, then stream 5 transitions to the "closed"
// state when the first frame for stream 7 is sent or received."
2017-01-14 00:05:42 +00:00
if streamID % 2 == 1 {
if streamID <= sc . maxClientStreamID {
return http2stateClosed , nil
}
} else {
if streamID <= sc . maxPushPromiseID {
return http2stateClosed , nil
}
2016-02-03 21:58:02 +00:00
}
return http2stateIdle , nil
}
// setConnState calls the net/http ConnState hook for this connection, if configured.
// Note that the net/http package does StateNew and StateClosed for us.
// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
func ( sc * http2serverConn ) setConnState ( state ConnState ) {
if sc . hs . ConnState != nil {
sc . hs . ConnState ( sc . conn , state )
}
}
func ( sc * http2serverConn ) vlogf ( format string , args ... interface { } ) {
if http2VerboseLogs {
sc . logf ( format , args ... )
}
}
func ( sc * http2serverConn ) logf ( format string , args ... interface { } ) {
if lg := sc . hs . ErrorLog ; lg != nil {
lg . Printf ( format , args ... )
} else {
log . Printf ( format , args ... )
}
}
// errno returns v's underlying uintptr, else 0.
//
// TODO: remove this helper function once http2 can use build
// tags. See comment in isClosedConnError.
func http2errno ( v error ) uintptr {
if rv := reflect . ValueOf ( v ) ; rv . Kind ( ) == reflect . Uintptr {
return uintptr ( rv . Uint ( ) )
}
return 0
}
// isClosedConnError reports whether err is an error from use of a closed
// network connection.
func http2isClosedConnError ( err error ) bool {
if err == nil {
return false
}
2017-09-14 17:11:35 +00:00
// TODO: remove this string search and be more like the Windows
// case below. That might involve modifying the standard library
// to return better error types.
2016-02-03 21:58:02 +00:00
str := err . Error ( )
if strings . Contains ( str , "use of closed network connection" ) {
return true
}
2017-09-14 17:11:35 +00:00
// TODO(bradfitz): x/tools/cmd/bundle doesn't really support
// build tags, so I can't make an http2_windows.go file with
// Windows-specific stuff. Fix that and move this, once we
// have a way to bundle this into std's net/http somehow.
2016-02-03 21:58:02 +00:00
if runtime . GOOS == "windows" {
if oe , ok := err . ( * net . OpError ) ; ok && oe . Op == "read" {
if se , ok := oe . Err . ( * os . SyscallError ) ; ok && se . Syscall == "wsarecv" {
const WSAECONNABORTED = 10053
const WSAECONNRESET = 10054
if n := http2errno ( se . Err ) ; n == WSAECONNRESET || n == WSAECONNABORTED {
return true
}
}
}
}
return false
}
func ( sc * http2serverConn ) condlogf ( err error , format string , args ... interface { } ) {
if err == nil {
return
}
2018-01-09 01:23:08 +00:00
if err == io . EOF || err == io . ErrUnexpectedEOF || http2isClosedConnError ( err ) || err == http2errPrefaceTimeout {
2017-09-14 17:11:35 +00:00
// Boring, expected errors.
2016-02-03 21:58:02 +00:00
sc . vlogf ( format , args ... )
} else {
sc . logf ( format , args ... )
}
}
2016-07-22 18:15:38 +00:00
func ( sc * http2serverConn ) canonicalHeader ( v string ) string {
2016-02-03 21:58:02 +00:00
sc . serveG . check ( )
2019-01-18 19:04:36 +00:00
http2buildCommonHeaderMapsOnce ( )
2016-07-22 18:15:38 +00:00
cv , ok := http2commonCanonHeader [ v ]
if ok {
return cv
2016-02-03 21:58:02 +00:00
}
cv , ok = sc . canonHeader [ v ]
if ok {
return cv
}
if sc . canonHeader == nil {
sc . canonHeader = make ( map [ string ] string )
}
cv = CanonicalHeaderKey ( v )
2022-02-11 14:53:56 -08:00
// maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of
// entries in the canonHeader cache. This should be larger than the number
// of unique, uncommon header keys likely to be sent by the peer, while not
// so high as to permit unreaasonable memory usage if the peer sends an unbounded
// number of unique header keys.
const maxCachedCanonicalHeaders = 32
if len ( sc . canonHeader ) < maxCachedCanonicalHeaders {
sc . canonHeader [ v ] = cv
}
2016-02-03 21:58:02 +00:00
return cv
}
type http2readFrameResult struct {
f http2Frame // valid until readMore is called
err error
// readMore should be called once the consumer no longer needs or
// retains f. After readMore, f is invalid and more frames can be
// read.
readMore func ( )
}
// readFrames is the loop that reads incoming frames.
// It takes care to only read one frame at a time, blocking until the
// consumer is done with the frame.
// It's run on its own goroutine.
func ( sc * http2serverConn ) readFrames ( ) {
gate := make ( http2gate )
2016-07-22 18:15:38 +00:00
gateDone := gate . Done
2016-02-03 21:58:02 +00:00
for {
f , err := sc . framer . ReadFrame ( )
select {
2016-07-22 18:15:38 +00:00
case sc . readFrameCh <- http2readFrameResult { f , err , gateDone } :
2016-02-03 21:58:02 +00:00
case <- sc . doneServing :
return
}
select {
case <- gate :
case <- sc . doneServing :
return
}
if http2terminalReadFrameError ( err ) {
return
}
}
}
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
type http2frameWriteResult struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2017-01-14 00:05:42 +00:00
wr http2FrameWriteRequest // what was written (or attempted)
err error // result of the writeFrame call
2016-02-03 21:58:02 +00:00
}
// writeFrameAsync runs in its own goroutine and writes a single frame
// and then reports when it's done.
// At most one goroutine can be running writeFrameAsync at a time per
// serverConn.
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) writeFrameAsync ( wr http2FrameWriteRequest ) {
err := wr . write . writeFrame ( sc )
2020-07-27 22:27:54 -07:00
sc . wroteFrameCh <- http2frameWriteResult { wr : wr , err : err }
2016-02-03 21:58:02 +00:00
}
func ( sc * http2serverConn ) closeAllStreamsOnConnClose ( ) {
sc . serveG . check ( )
for _ , st := range sc . streams {
sc . closeStream ( st , http2errClientDisconnected )
}
}
func ( sc * http2serverConn ) stopShutdownTimer ( ) {
sc . serveG . check ( )
if t := sc . shutdownTimer ; t != nil {
t . Stop ( )
}
}
func ( sc * http2serverConn ) notePanic ( ) {
2017-09-14 17:11:35 +00:00
// Note: this is for serverConn.serve panicking, not http.Handler code.
2016-02-03 21:58:02 +00:00
if http2testHookOnPanicMu != nil {
http2testHookOnPanicMu . Lock ( )
defer http2testHookOnPanicMu . Unlock ( )
}
if http2testHookOnPanic != nil {
if e := recover ( ) ; e != nil {
if http2testHookOnPanic ( sc , e ) {
panic ( e )
}
}
}
}
func ( sc * http2serverConn ) serve ( ) {
sc . serveG . check ( )
defer sc . notePanic ( )
defer sc . conn . Close ( )
defer sc . closeAllStreamsOnConnClose ( )
defer sc . stopShutdownTimer ( )
2017-09-14 17:11:35 +00:00
defer close ( sc . doneServing ) // unblocks handlers trying to send
2016-02-03 21:58:02 +00:00
if http2VerboseLogs {
sc . vlogf ( "http2: server connection from %v on %p" , sc . conn . RemoteAddr ( ) , sc . hs )
}
2017-01-14 00:05:42 +00:00
sc . writeFrame ( http2FrameWriteRequest {
2016-02-03 21:58:02 +00:00
write : http2writeSettings {
{ http2SettingMaxFrameSize , sc . srv . maxReadFrameSize ( ) } ,
{ http2SettingMaxConcurrentStreams , sc . advMaxStreams } ,
{ http2SettingMaxHeaderListSize , sc . maxHeaderListSize ( ) } ,
2017-09-14 17:11:35 +00:00
{ http2SettingInitialWindowSize , uint32 ( sc . srv . initialStreamRecvWindowSize ( ) ) } ,
2016-02-03 21:58:02 +00:00
} ,
} )
sc . unackedSettings ++
2022-02-11 14:53:56 -08:00
// Each connection starts with initialWindowSize inflow tokens.
2017-09-14 17:11:35 +00:00
// If a higher value is configured, we add more tokens.
if diff := sc . srv . initialConnRecvWindowSize ( ) - http2initialWindowSize ; diff > 0 {
sc . sendWindowUpdate ( nil , int ( diff ) )
}
2016-02-03 21:58:02 +00:00
if err := sc . readPreface ( ) ; err != nil {
sc . condlogf ( err , "http2: server: error reading preface from client %v: %v" , sc . conn . RemoteAddr ( ) , err )
return
}
2017-09-14 17:11:35 +00:00
// Now that we've got the preface, get us out of the
// "StateNew" state. We can't go directly to idle, though.
// Active means we read some data and anticipate a request. We'll
// do another Active when we get a HEADERS frame.
2016-02-03 21:58:02 +00:00
sc . setConnState ( StateActive )
sc . setConnState ( StateIdle )
2017-01-14 00:05:42 +00:00
if sc . srv . IdleTimeout != 0 {
2017-09-14 17:11:35 +00:00
sc . idleTimer = time . AfterFunc ( sc . srv . IdleTimeout , sc . onIdleTimer )
2017-01-14 00:05:42 +00:00
defer sc . idleTimer . Stop ( )
}
2017-09-14 17:11:35 +00:00
go sc . readFrames ( ) // closed by defer sc.conn.Close above
2017-01-14 00:05:42 +00:00
2017-09-14 17:11:35 +00:00
settingsTimer := time . AfterFunc ( http2firstSettingsTimeout , sc . onSettingsTimer )
defer settingsTimer . Stop ( )
2016-02-03 21:58:02 +00:00
loopNum := 0
for {
loopNum ++
select {
2017-01-14 00:05:42 +00:00
case wr := <- sc . wantWriteFrameCh :
2017-09-14 17:11:35 +00:00
if se , ok := wr . write . ( http2StreamError ) ; ok {
sc . resetStream ( se )
break
}
2017-01-14 00:05:42 +00:00
sc . writeFrame ( wr )
2016-02-03 21:58:02 +00:00
case res := <- sc . wroteFrameCh :
sc . wroteFrame ( res )
case res := <- sc . readFrameCh :
2021-09-16 16:09:35 -07:00
// Process any written frames before reading new frames from the client since a
// written frame could have triggered a new stream to be started.
if sc . writingFrameAsync {
select {
case wroteRes := <- sc . wroteFrameCh :
sc . wroteFrame ( wroteRes )
default :
}
}
2016-02-03 21:58:02 +00:00
if ! sc . processFrameFromReader ( res ) {
return
}
res . readMore ( )
2017-09-14 17:11:35 +00:00
if settingsTimer != nil {
2016-02-03 21:58:02 +00:00
settingsTimer . Stop ( )
2017-09-14 17:11:35 +00:00
settingsTimer = nil
2016-02-03 21:58:02 +00:00
}
case m := <- sc . bodyReadCh :
sc . noteBodyRead ( m . st , m . n )
2017-09-14 17:11:35 +00:00
case msg := <- sc . serveMsgCh :
switch v := msg . ( type ) {
case func ( int ) :
v ( loopNum ) // for testing
case * http2serverMessage :
switch v {
case http2settingsTimerMsg :
sc . logf ( "timeout waiting for SETTINGS frames from %v" , sc . conn . RemoteAddr ( ) )
return
case http2idleTimerMsg :
sc . vlogf ( "connection is idle" )
sc . goAway ( http2ErrCodeNo )
case http2shutdownTimerMsg :
sc . vlogf ( "GOAWAY close timer fired; closing conn from %v" , sc . conn . RemoteAddr ( ) )
return
case http2gracefulShutdownMsg :
sc . startGracefulShutdownInternal ( )
default :
panic ( "unknown timer" )
}
case * http2startPushRequest :
sc . startPush ( v )
default :
panic ( fmt . Sprintf ( "unexpected type %T" , v ) )
}
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
2019-09-12 23:22:53 +00:00
// If the peer is causing us to generate a lot of control frames,
// but not reading them from us, assume they are trying to make us
// run out of memory.
if sc . queuedControlFrames > sc . srv . maxQueuedControlFrames ( ) {
sc . vlogf ( "http2: too many control frames in send queue, closing connection" )
return
}
2018-01-09 01:23:08 +00:00
// Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
// with no error code (graceful shutdown), don't start the timer until
// all open streams have been completed.
sentGoAway := sc . inGoAway && ! sc . needToSendGoAway && ! sc . writingFrame
gracefulShutdownComplete := sc . goAwayCode == http2ErrCodeNo && sc . curOpenStreams ( ) == 0
if sentGoAway && sc . shutdownTimer == nil && ( sc . goAwayCode != http2ErrCodeNo || gracefulShutdownComplete ) {
sc . shutDownIn ( http2goAwayTimeout )
2017-01-14 00:05:42 +00:00
}
2016-02-03 21:58:02 +00:00
}
}
2017-06-08 19:02:12 +00:00
func ( sc * http2serverConn ) awaitGracefulShutdown ( sharedCh <- chan struct { } , privateCh chan struct { } ) {
select {
case <- sc . doneServing :
case <- sharedCh :
close ( privateCh )
}
}
2017-09-14 17:11:35 +00:00
type http2serverMessage int
// Message values sent to serveMsgCh.
var (
http2settingsTimerMsg = new ( http2serverMessage )
http2idleTimerMsg = new ( http2serverMessage )
http2shutdownTimerMsg = new ( http2serverMessage )
http2gracefulShutdownMsg = new ( http2serverMessage )
)
func ( sc * http2serverConn ) onSettingsTimer ( ) { sc . sendServeMsg ( http2settingsTimerMsg ) }
func ( sc * http2serverConn ) onIdleTimer ( ) { sc . sendServeMsg ( http2idleTimerMsg ) }
func ( sc * http2serverConn ) onShutdownTimer ( ) { sc . sendServeMsg ( http2shutdownTimerMsg ) }
func ( sc * http2serverConn ) sendServeMsg ( msg interface { } ) {
sc . serveG . checkNotOn ( ) // NOT
select {
case sc . serveMsgCh <- msg :
case <- sc . doneServing :
}
}
2018-01-09 01:23:08 +00:00
var http2errPrefaceTimeout = errors . New ( "timeout waiting for client preface" )
// readPreface reads the ClientPreface greeting from the peer or
// returns errPrefaceTimeout on timeout, or an error if the greeting
// is invalid.
2016-02-03 21:58:02 +00:00
func ( sc * http2serverConn ) readPreface ( ) error {
errc := make ( chan error , 1 )
go func ( ) {
2017-09-14 17:11:35 +00:00
// Read the client preface
2016-02-03 21:58:02 +00:00
buf := make ( [ ] byte , len ( http2ClientPreface ) )
if _ , err := io . ReadFull ( sc . conn , buf ) ; err != nil {
errc <- err
} else if ! bytes . Equal ( buf , http2clientPreface ) {
errc <- fmt . Errorf ( "bogus greeting %q" , buf )
} else {
errc <- nil
}
} ( )
2017-09-14 17:11:35 +00:00
timer := time . NewTimer ( http2prefaceTimeout ) // TODO: configurable on *Server?
2016-02-03 21:58:02 +00:00
defer timer . Stop ( )
select {
case <- timer . C :
2018-01-09 01:23:08 +00:00
return http2errPrefaceTimeout
2016-02-03 21:58:02 +00:00
case err := <- errc :
if err == nil {
if http2VerboseLogs {
sc . vlogf ( "http2: server: client %v said hello" , sc . conn . RemoteAddr ( ) )
}
}
return err
}
}
var http2errChanPool = sync . Pool {
New : func ( ) interface { } { return make ( chan error , 1 ) } ,
}
var http2writeDataPool = sync . Pool {
New : func ( ) interface { } { return new ( http2writeData ) } ,
}
// writeDataFromHandler writes DATA response frames from a handler on
// the given stream.
func ( sc * http2serverConn ) writeDataFromHandler ( stream * http2stream , data [ ] byte , endStream bool ) error {
ch := http2errChanPool . Get ( ) . ( chan error )
writeArg := http2writeDataPool . Get ( ) . ( * http2writeData )
* writeArg = http2writeData { stream . id , data , endStream }
2017-01-14 00:05:42 +00:00
err := sc . writeFrameFromHandler ( http2FrameWriteRequest {
2016-02-03 21:58:02 +00:00
write : writeArg ,
stream : stream ,
done : ch ,
} )
if err != nil {
return err
}
var frameWriteDone bool // the frame write is done (successfully or not)
select {
case err = <- ch :
frameWriteDone = true
case <- sc . doneServing :
return http2errClientDisconnected
case <- stream . cw :
2017-09-14 17:11:35 +00:00
// If both ch and stream.cw were ready (as might
// happen on the final Write after an http.Handler
// ends), prefer the write result. Otherwise this
// might just be us successfully closing the stream.
// The writeFrameAsync and serve goroutines guarantee
// that the ch send will happen before the stream.cw
// close.
2016-02-03 21:58:02 +00:00
select {
case err = <- ch :
frameWriteDone = true
default :
return http2errStreamClosed
}
}
http2errChanPool . Put ( ch )
if frameWriteDone {
http2writeDataPool . Put ( writeArg )
}
return err
}
2017-01-14 00:05:42 +00:00
// writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts
2016-02-03 21:58:02 +00:00
// if the connection has gone away.
//
// This must not be run from the serve goroutine itself, else it might
// deadlock writing to sc.wantWriteFrameCh (which is only mildly
// buffered and is read by serve itself). If you're on the serve
// goroutine, call writeFrame instead.
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) writeFrameFromHandler ( wr http2FrameWriteRequest ) error {
2017-09-14 17:11:35 +00:00
sc . serveG . checkNotOn ( ) // NOT
2016-02-03 21:58:02 +00:00
select {
2017-01-14 00:05:42 +00:00
case sc . wantWriteFrameCh <- wr :
2016-02-03 21:58:02 +00:00
return nil
case <- sc . doneServing :
2017-09-14 17:11:35 +00:00
// Serve loop is gone.
// Client has closed their connection to the server.
2016-02-03 21:58:02 +00:00
return http2errClientDisconnected
}
}
// writeFrame schedules a frame to write and sends it if there's nothing
// already being written.
//
// There is no pushback here (the serve goroutine never blocks). It's
// the http.Handlers that block, waiting for their previous frames to
// make it onto the wire
//
// If you're not on the serve goroutine, use writeFrameFromHandler instead.
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) writeFrame ( wr http2FrameWriteRequest ) {
2016-02-03 21:58:02 +00:00
sc . serveG . check ( )
2016-07-22 18:15:38 +00:00
2017-01-14 00:05:42 +00:00
// If true, wr will not be written and wr.done will not be signaled.
2016-07-22 18:15:38 +00:00
var ignoreWrite bool
2017-09-14 17:11:35 +00:00
// We are not allowed to write frames on closed streams. RFC 7540 Section
// 5.1.1 says: "An endpoint MUST NOT send frames other than PRIORITY on
// a closed stream." Our server never sends PRIORITY, so that exception
// does not apply.
//
// The serverConn might close an open stream while the stream's handler
// is still running. For example, the server might close a stream when it
// receives bad data from the client. If this happens, the handler might
// attempt to write a frame after the stream has been closed (since the
// handler hasn't yet been notified of the close). In this case, we simply
// ignore the frame. The handler will notice that the stream is closed when
// it waits for the frame to be written.
//
// As an exception to this rule, we allow sending RST_STREAM after close.
// This allows us to immediately reject new streams without tracking any
// state for those streams (except for the queued RST_STREAM frame). This
// may result in duplicate RST_STREAMs in some cases, but the client should
// ignore those.
2017-01-14 00:05:42 +00:00
if wr . StreamID ( ) != 0 {
_ , isReset := wr . write . ( http2StreamError )
if state , _ := sc . state ( wr . StreamID ( ) ) ; state == http2stateClosed && ! isReset {
ignoreWrite = true
}
}
2017-09-14 17:11:35 +00:00
// Don't send a 100-continue response if we've already sent headers.
// See golang.org/issue/14030.
2017-01-14 00:05:42 +00:00
switch wr . write . ( type ) {
2016-07-22 18:15:38 +00:00
case * http2writeResHeaders :
2017-01-14 00:05:42 +00:00
wr . stream . wroteHeaders = true
2016-07-22 18:15:38 +00:00
case http2write100ContinueHeadersFrame :
2017-01-14 00:05:42 +00:00
if wr . stream . wroteHeaders {
2017-09-14 17:11:35 +00:00
// We do not need to notify wr.done because this frame is
// never written with wr.done != nil.
2017-01-14 00:05:42 +00:00
if wr . done != nil {
panic ( "wr.done != nil for write100ContinueHeadersFrame" )
}
2016-07-22 18:15:38 +00:00
ignoreWrite = true
}
}
if ! ignoreWrite {
2019-09-12 23:22:53 +00:00
if wr . isControl ( ) {
sc . queuedControlFrames ++
// For extra safety, detect wraparounds, which should not happen,
// and pull the plug.
if sc . queuedControlFrames < 0 {
sc . conn . Close ( )
}
}
2017-01-14 00:05:42 +00:00
sc . writeSched . Push ( wr )
2016-07-22 18:15:38 +00:00
}
2016-02-03 21:58:02 +00:00
sc . scheduleFrameWrite ( )
}
2017-01-14 00:05:42 +00:00
// startFrameWrite starts a goroutine to write wr (in a separate
2016-02-03 21:58:02 +00:00
// goroutine since that might block on the network), and updates the
2017-01-14 00:05:42 +00:00
// serve goroutine's state about the world, updated from info in wr.
func ( sc * http2serverConn ) startFrameWrite ( wr http2FrameWriteRequest ) {
2016-02-03 21:58:02 +00:00
sc . serveG . check ( )
if sc . writingFrame {
panic ( "internal error: can only be writing one frame at a time" )
}
2017-01-14 00:05:42 +00:00
st := wr . stream
2016-02-03 21:58:02 +00:00
if st != nil {
switch st . state {
case http2stateHalfClosedLocal :
2017-01-14 00:05:42 +00:00
switch wr . write . ( type ) {
case http2StreamError , http2handlerPanicRST , http2writeWindowUpdate :
2017-09-14 17:11:35 +00:00
// RFC 7540 Section 5.1 allows sending RST_STREAM, PRIORITY, and WINDOW_UPDATE
// in this state. (We never send PRIORITY from the server, so that is not checked.)
2017-01-14 00:05:42 +00:00
default :
panic ( fmt . Sprintf ( "internal error: attempt to send frame on a half-closed-local stream: %v" , wr ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
case http2stateClosed :
panic ( fmt . Sprintf ( "internal error: attempt to send frame on a closed stream: %v" , wr ) )
}
}
if wpp , ok := wr . write . ( * http2writePushPromise ) ; ok {
var err error
wpp . promisedID , err = wpp . allocatePromisedID ( )
if err != nil {
sc . writingFrameAsync = false
wr . replyToWriter ( err )
return
2016-02-03 21:58:02 +00:00
}
}
sc . writingFrame = true
sc . needsFrameFlush = true
2017-01-14 00:05:42 +00:00
if wr . write . staysWithinBuffer ( sc . bw . Available ( ) ) {
sc . writingFrameAsync = false
err := wr . write . writeFrame ( sc )
2020-07-27 22:27:54 -07:00
sc . wroteFrame ( http2frameWriteResult { wr : wr , err : err } )
2017-01-14 00:05:42 +00:00
} else {
sc . writingFrameAsync = true
go sc . writeFrameAsync ( wr )
}
2016-02-03 21:58:02 +00:00
}
// errHandlerPanicked is the error given to any callers blocked in a read from
// Request.Body when the main goroutine panics. Since most handlers read in the
2019-01-18 19:04:36 +00:00
// main ServeHTTP goroutine, this will show up rarely.
2016-02-03 21:58:02 +00:00
var http2errHandlerPanicked = errors . New ( "http2: handler panicked" )
// wroteFrame is called on the serve goroutine with the result of
// whatever happened on writeFrameAsync.
func ( sc * http2serverConn ) wroteFrame ( res http2frameWriteResult ) {
sc . serveG . check ( )
if ! sc . writingFrame {
panic ( "internal error: expected to be already writing a frame" )
}
sc . writingFrame = false
2017-01-14 00:05:42 +00:00
sc . writingFrameAsync = false
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
wr := res . wr
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
if http2writeEndsStream ( wr . write ) {
st := wr . stream
2016-02-03 21:58:02 +00:00
if st == nil {
panic ( "internal error: expecting non-nil stream" )
}
switch st . state {
case http2stateOpen :
2017-09-14 17:11:35 +00:00
// Here we would go to stateHalfClosedLocal in
// theory, but since our handler is done and
// the net/http package provides no mechanism
// for closing a ResponseWriter while still
// reading data (see possible TODO at top of
// this file), we go into closed state here
// anyway, after telling the peer we're
// hanging up on them. We'll transition to
// stateClosed after the RST_STREAM frame is
// written.
2016-02-03 21:58:02 +00:00
st . state = http2stateHalfClosedLocal
2017-09-14 17:11:35 +00:00
// Section 8.1: a server MAY request that the client abort
// transmission of a request without error by sending a
// RST_STREAM with an error code of NO_ERROR after sending
// a complete response.
sc . resetStream ( http2streamError ( st . id , http2ErrCodeNo ) )
2016-02-03 21:58:02 +00:00
case http2stateHalfClosedRemote :
sc . closeStream ( st , http2errHandlerComplete )
}
2017-01-14 00:05:42 +00:00
} else {
switch v := wr . write . ( type ) {
case http2StreamError :
2017-09-14 17:11:35 +00:00
// st may be unknown if the RST_STREAM was generated to reject bad input.
2017-01-14 00:05:42 +00:00
if st , ok := sc . streams [ v . StreamID ] ; ok {
sc . closeStream ( st , v )
}
case http2handlerPanicRST :
sc . closeStream ( wr . stream , http2errHandlerPanicked )
}
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// Reply (if requested) to unblock the ServeHTTP goroutine.
2017-01-14 00:05:42 +00:00
wr . replyToWriter ( res . err )
2016-02-03 21:58:02 +00:00
sc . scheduleFrameWrite ( )
}
// scheduleFrameWrite tickles the frame writing scheduler.
//
// If a frame is already being written, nothing happens. This will be called again
// when the frame is done being written.
//
2019-09-12 23:22:53 +00:00
// If a frame isn't being written and we need to send one, the best frame
// to send is selected by writeSched.
2016-02-03 21:58:02 +00:00
//
// If a frame isn't being written and there's nothing else to send, we
// flush the write buffer.
func ( sc * http2serverConn ) scheduleFrameWrite ( ) {
sc . serveG . check ( )
2017-01-14 00:05:42 +00:00
if sc . writingFrame || sc . inFrameScheduleLoop {
2016-02-03 21:58:02 +00:00
return
}
2017-01-14 00:05:42 +00:00
sc . inFrameScheduleLoop = true
for ! sc . writingFrameAsync {
if sc . needToSendGoAway {
sc . needToSendGoAway = false
sc . startFrameWrite ( http2FrameWriteRequest {
write : & http2writeGoAway {
maxStreamID : sc . maxClientStreamID ,
code : sc . goAwayCode ,
} ,
} )
continue
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if sc . needToSendSettingsAck {
sc . needToSendSettingsAck = false
sc . startFrameWrite ( http2FrameWriteRequest { write : http2writeSettingsAck { } } )
continue
}
if ! sc . inGoAway || sc . goAwayCode == http2ErrCodeNo {
if wr , ok := sc . writeSched . Pop ( ) ; ok {
2019-09-12 23:22:53 +00:00
if wr . isControl ( ) {
sc . queuedControlFrames --
}
2017-01-14 00:05:42 +00:00
sc . startFrameWrite ( wr )
continue
}
}
if sc . needsFrameFlush {
sc . startFrameWrite ( http2FrameWriteRequest { write : http2flushFrameWriter { } } )
2017-09-14 17:11:35 +00:00
sc . needsFrameFlush = false // after startFrameWrite, since it sets this true
2017-01-14 00:05:42 +00:00
continue
}
break
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
sc . inFrameScheduleLoop = false
}
2017-09-14 17:11:35 +00:00
// startGracefulShutdown gracefully shuts down a connection. This
// sends GOAWAY with ErrCodeNo to tell the client we're gracefully
// shutting down. The connection isn't closed until all current
// streams are done.
//
// startGracefulShutdown returns immediately; it does not wait until
// the connection has shut down.
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) startGracefulShutdown ( ) {
2017-09-14 17:11:35 +00:00
sc . serveG . checkNotOn ( ) // NOT
sc . shutdownOnce . Do ( func ( ) { sc . sendServeMsg ( http2gracefulShutdownMsg ) } )
}
2021-07-30 14:28:58 -07:00
// After sending GOAWAY with an error code (non-graceful shutdown), the
// connection will close after goAwayTimeout.
//
2018-01-09 01:23:08 +00:00
// If we close the connection immediately after sending GOAWAY, there may
// be unsent data in our kernel receive buffer, which will cause the kernel
// to send a TCP RST on close() instead of a FIN. This RST will abort the
// connection immediately, whether or not the client had received the GOAWAY.
//
// Ideally we should delay for at least 1 RTT + epsilon so the client has
// a chance to read the GOAWAY and stop sending messages. Measuring RTT
// is hard, so we approximate with 1 second. See golang.org/issue/18701.
//
// This is a var so it can be shorter in tests, where all requests uses the
// loopback interface making the expected RTT very small.
//
// TODO: configurable?
var http2goAwayTimeout = 1 * time . Second
2017-09-14 17:11:35 +00:00
func ( sc * http2serverConn ) startGracefulShutdownInternal ( ) {
2018-01-09 01:23:08 +00:00
sc . goAway ( http2ErrCodeNo )
2016-02-03 21:58:02 +00:00
}
func ( sc * http2serverConn ) goAway ( code http2ErrCode ) {
2017-01-14 00:05:42 +00:00
sc . serveG . check ( )
if sc . inGoAway {
return
}
2016-02-03 21:58:02 +00:00
sc . inGoAway = true
sc . needToSendGoAway = true
sc . goAwayCode = code
sc . scheduleFrameWrite ( )
}
func ( sc * http2serverConn ) shutDownIn ( d time . Duration ) {
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
sc . shutdownTimer = time . AfterFunc ( d , sc . onShutdownTimer )
2016-02-03 21:58:02 +00:00
}
func ( sc * http2serverConn ) resetStream ( se http2StreamError ) {
sc . serveG . check ( )
2017-01-14 00:05:42 +00:00
sc . writeFrame ( http2FrameWriteRequest { write : se } )
2016-02-03 21:58:02 +00:00
if st , ok := sc . streams [ se . StreamID ] ; ok {
2017-01-14 00:05:42 +00:00
st . resetQueued = true
2016-02-03 21:58:02 +00:00
}
}
// processFrameFromReader processes the serve loop's read from readFrameCh from the
// frame-reading goroutine.
2019-02-26 01:00:39 +00:00
// processFrameFromReader returns whether the connection should be kept open.
2016-02-03 21:58:02 +00:00
func ( sc * http2serverConn ) processFrameFromReader ( res http2readFrameResult ) bool {
sc . serveG . check ( )
err := res . err
if err != nil {
if err == http2ErrFrameTooLarge {
sc . goAway ( http2ErrCodeFrameSize )
2017-09-14 17:11:35 +00:00
return true // goAway will close the loop
2016-02-03 21:58:02 +00:00
}
clientGone := err == io . EOF || err == io . ErrUnexpectedEOF || http2isClosedConnError ( err )
if clientGone {
2017-09-14 17:11:35 +00:00
// TODO: could we also get into this state if
// the peer does a half close
// (e.g. CloseWrite) because they're done
// sending frames but they're still wanting
// our open replies? Investigate.
// TODO: add CloseWrite to crypto/tls.Conn first
// so we have a way to test this? I suppose
// just for testing we could have a non-TLS mode.
2016-02-03 21:58:02 +00:00
return false
}
} else {
f := res . f
if http2VerboseLogs {
sc . vlogf ( "http2: server read frame %v" , http2summarizeFrame ( f ) )
}
err = sc . processFrame ( f )
if err == nil {
return true
}
}
switch ev := err . ( type ) {
case http2StreamError :
sc . resetStream ( ev )
return true
case http2goAwayFlowError :
sc . goAway ( http2ErrCodeFlowControl )
return true
case http2ConnectionError :
sc . logf ( "http2: server connection error from %v: %v" , sc . conn . RemoteAddr ( ) , ev )
sc . goAway ( http2ErrCode ( ev ) )
2017-09-14 17:11:35 +00:00
return true // goAway will handle shutdown
2016-02-03 21:58:02 +00:00
default :
if res . err != nil {
sc . vlogf ( "http2: server closing client connection; error reading frame from client %s: %v" , sc . conn . RemoteAddr ( ) , err )
} else {
sc . logf ( "http2: server closing client connection: %v" , err )
}
return false
}
}
func ( sc * http2serverConn ) processFrame ( f http2Frame ) error {
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
// First frame received must be SETTINGS.
2016-02-03 21:58:02 +00:00
if ! sc . sawFirstSettings {
if _ , ok := f . ( * http2SettingsFrame ) ; ! ok {
2022-02-11 14:53:56 -08:00
return sc . countError ( "first_settings" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
sc . sawFirstSettings = true
}
switch f := f . ( type ) {
case * http2SettingsFrame :
return sc . processSettings ( f )
2016-07-22 18:15:38 +00:00
case * http2MetaHeadersFrame :
2016-02-03 21:58:02 +00:00
return sc . processHeaders ( f )
case * http2WindowUpdateFrame :
return sc . processWindowUpdate ( f )
case * http2PingFrame :
return sc . processPing ( f )
case * http2DataFrame :
return sc . processData ( f )
case * http2RSTStreamFrame :
return sc . processResetStream ( f )
case * http2PriorityFrame :
return sc . processPriority ( f )
2017-01-14 00:05:42 +00:00
case * http2GoAwayFrame :
return sc . processGoAway ( f )
2016-02-03 21:58:02 +00:00
case * http2PushPromiseFrame :
2017-09-14 17:11:35 +00:00
// A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
// frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
2022-02-11 14:53:56 -08:00
return sc . countError ( "push_promise" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
default :
sc . vlogf ( "http2: server ignoring frame: %v" , f . Header ( ) )
return nil
}
}
func ( sc * http2serverConn ) processPing ( f * http2PingFrame ) error {
sc . serveG . check ( )
if f . IsAck ( ) {
2017-09-14 17:11:35 +00:00
// 6.7 PING: " An endpoint MUST NOT respond to PING frames
// containing this flag."
2016-02-03 21:58:02 +00:00
return nil
}
if f . StreamID != 0 {
2017-09-14 17:11:35 +00:00
// "PING frames are not associated with any individual
// stream. If a PING frame is received with a stream
// identifier field value other than 0x0, the recipient MUST
// respond with a connection error (Section 5.4.1) of type
// PROTOCOL_ERROR."
2022-02-11 14:53:56 -08:00
return sc . countError ( "ping_on_stream" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if sc . inGoAway && sc . goAwayCode != http2ErrCodeNo {
return nil
}
sc . writeFrame ( http2FrameWriteRequest { write : http2writePingAck { f } } )
2016-02-03 21:58:02 +00:00
return nil
}
func ( sc * http2serverConn ) processWindowUpdate ( f * http2WindowUpdateFrame ) error {
sc . serveG . check ( )
switch {
2017-09-14 17:11:35 +00:00
case f . StreamID != 0 : // stream-level flow control
2017-01-14 00:05:42 +00:00
state , st := sc . state ( f . StreamID )
if state == http2stateIdle {
2017-09-14 17:11:35 +00:00
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
2022-02-11 14:53:56 -08:00
return sc . countError ( "stream_idle" , http2ConnectionError ( http2ErrCodeProtocol ) )
2017-01-14 00:05:42 +00:00
}
2016-02-03 21:58:02 +00:00
if st == nil {
2017-09-14 17:11:35 +00:00
// "WINDOW_UPDATE can be sent by a peer that has sent a
// frame bearing the END_STREAM flag. This means that a
// receiver could receive a WINDOW_UPDATE frame on a "half
// closed (remote)" or "closed" stream. A receiver MUST
// NOT treat this as an error, see Section 5.1."
2016-02-03 21:58:02 +00:00
return nil
}
if ! st . flow . add ( int32 ( f . Increment ) ) {
2022-02-11 14:53:56 -08:00
return sc . countError ( "bad_flow" , http2streamError ( f . StreamID , http2ErrCodeFlowControl ) )
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
default : // connection-level flow control
2016-02-03 21:58:02 +00:00
if ! sc . flow . add ( int32 ( f . Increment ) ) {
return http2goAwayFlowError { }
}
}
sc . scheduleFrameWrite ( )
return nil
}
func ( sc * http2serverConn ) processResetStream ( f * http2RSTStreamFrame ) error {
sc . serveG . check ( )
state , st := sc . state ( f . StreamID )
if state == http2stateIdle {
2017-09-14 17:11:35 +00:00
// 6.4 "RST_STREAM frames MUST NOT be sent for a
// stream in the "idle" state. If a RST_STREAM frame
// identifying an idle stream is received, the
// recipient MUST treat this as a connection error
// (Section 5.4.1) of type PROTOCOL_ERROR.
2022-02-11 14:53:56 -08:00
return sc . countError ( "reset_idle_stream" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
if st != nil {
2016-07-22 18:15:38 +00:00
st . cancelCtx ( )
2016-09-10 13:14:00 +00:00
sc . closeStream ( st , http2streamError ( f . StreamID , f . ErrCode ) )
2016-02-03 21:58:02 +00:00
}
return nil
}
func ( sc * http2serverConn ) closeStream ( st * http2stream , err error ) {
sc . serveG . check ( )
if st . state == http2stateIdle || st . state == http2stateClosed {
panic ( fmt . Sprintf ( "invariant; can't close stream in state %v" , st . state ) )
}
st . state = http2stateClosed
2017-09-14 17:11:35 +00:00
if st . writeDeadline != nil {
st . writeDeadline . Stop ( )
}
2017-01-14 00:05:42 +00:00
if st . isPushed ( ) {
sc . curPushedStreams --
} else {
sc . curClientStreams --
2016-02-03 21:58:02 +00:00
}
delete ( sc . streams , st . id )
2017-01-14 00:05:42 +00:00
if len ( sc . streams ) == 0 {
sc . setConnState ( StateIdle )
if sc . srv . IdleTimeout != 0 {
sc . idleTimer . Reset ( sc . srv . IdleTimeout )
}
if http2h1ServerKeepAlivesDisabled ( sc . hs ) {
2017-09-14 17:11:35 +00:00
sc . startGracefulShutdownInternal ( )
2017-01-14 00:05:42 +00:00
}
}
2016-02-03 21:58:02 +00:00
if p := st . body ; p != nil {
2017-09-14 17:11:35 +00:00
// Return any buffered unread bytes worth of conn-level flow control.
// See golang.org/issue/16481
2016-09-10 13:14:00 +00:00
sc . sendWindowUpdate ( nil , p . Len ( ) )
2016-02-03 21:58:02 +00:00
p . CloseWithError ( err )
}
2017-09-14 17:11:35 +00:00
st . cw . Close ( ) // signals Handler's CloseNotifier, unblocks writes, etc
2017-01-14 00:05:42 +00:00
sc . writeSched . CloseStream ( st . id )
2016-02-03 21:58:02 +00:00
}
func ( sc * http2serverConn ) processSettings ( f * http2SettingsFrame ) error {
sc . serveG . check ( )
if f . IsAck ( ) {
sc . unackedSettings --
if sc . unackedSettings < 0 {
2017-09-14 17:11:35 +00:00
// Why is the peer ACKing settings we never sent?
// The spec doesn't mention this case, but
// hang up on them anyway.
2022-02-11 14:53:56 -08:00
return sc . countError ( "ack_mystery" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
return nil
}
2018-09-24 21:46:21 +00:00
if f . NumSettings ( ) > 100 || f . HasDuplicates ( ) {
// This isn't actually in the spec, but hang up on
// suspiciously large settings frames or those with
// duplicate entries.
2022-02-11 14:53:56 -08:00
return sc . countError ( "settings_big_or_dups" , http2ConnectionError ( http2ErrCodeProtocol ) )
2018-09-24 21:46:21 +00:00
}
2016-02-03 21:58:02 +00:00
if err := f . ForeachSetting ( sc . processSetting ) ; err != nil {
return err
}
2019-09-12 23:22:53 +00:00
// TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
// acknowledged individually, even if multiple are received before the ACK.
2016-02-03 21:58:02 +00:00
sc . needToSendSettingsAck = true
sc . scheduleFrameWrite ( )
return nil
}
func ( sc * http2serverConn ) processSetting ( s http2Setting ) error {
sc . serveG . check ( )
if err := s . Valid ( ) ; err != nil {
return err
}
if http2VerboseLogs {
sc . vlogf ( "http2: server processing setting %v" , s )
}
switch s . ID {
case http2SettingHeaderTableSize :
sc . headerTableSize = s . Val
sc . hpackEncoder . SetMaxDynamicTableSize ( s . Val )
case http2SettingEnablePush :
sc . pushEnabled = s . Val != 0
case http2SettingMaxConcurrentStreams :
sc . clientMaxStreams = s . Val
case http2SettingInitialWindowSize :
return sc . processSettingInitialWindowSize ( s . Val )
case http2SettingMaxFrameSize :
2017-09-14 17:11:35 +00:00
sc . maxFrameSize = int32 ( s . Val ) // the maximum valid s.Val is < 2^31
2016-02-03 21:58:02 +00:00
case http2SettingMaxHeaderListSize :
sc . peerMaxHeaderListSize = s . Val
default :
2017-09-14 17:11:35 +00:00
// Unknown setting: "An endpoint that receives a SETTINGS
// frame with any unknown or unsupported identifier MUST
// ignore that setting."
2016-02-03 21:58:02 +00:00
if http2VerboseLogs {
sc . vlogf ( "http2: server ignoring unknown setting %v" , s )
}
}
return nil
}
func ( sc * http2serverConn ) processSettingInitialWindowSize ( val uint32 ) error {
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
// Note: val already validated to be within range by
// processSetting's Valid call.
// "A SETTINGS frame can alter the initial flow control window
// size for all current streams. When the value of
// SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST
// adjust the size of all stream flow control windows that it
// maintains by the difference between the new value and the
// old value."
old := sc . initialStreamSendWindowSize
sc . initialStreamSendWindowSize = int32 ( val )
growth := int32 ( val ) - old // may be negative
2016-02-03 21:58:02 +00:00
for _ , st := range sc . streams {
if ! st . flow . add ( growth ) {
2017-09-14 17:11:35 +00:00
// 6.9.2 Initial Flow Control Window Size
// "An endpoint MUST treat a change to
// SETTINGS_INITIAL_WINDOW_SIZE that causes any flow
// control window to exceed the maximum size as a
// connection error (Section 5.4.1) of type
// FLOW_CONTROL_ERROR."
2022-02-11 14:53:56 -08:00
return sc . countError ( "setting_win_size" , http2ConnectionError ( http2ErrCodeFlowControl ) )
2016-02-03 21:58:02 +00:00
}
}
return nil
}
func ( sc * http2serverConn ) processData ( f * http2DataFrame ) error {
sc . serveG . check ( )
2021-07-30 14:28:58 -07:00
id := f . Header ( ) . StreamID
if sc . inGoAway && ( sc . goAwayCode != http2ErrCodeNo || id > sc . maxClientStreamID ) {
// Discard all DATA frames if the GOAWAY is due to an
// error, or:
//
// Section 6.8: After sending a GOAWAY frame, the sender
// can discard frames for streams initiated by the
// receiver with identifiers higher than the identified
// last stream.
2017-01-14 00:05:42 +00:00
return nil
}
2016-02-03 21:58:02 +00:00
2021-07-30 14:28:58 -07:00
data := f . Data ( )
2017-01-14 00:05:42 +00:00
state , st := sc . state ( id )
if id == 0 || state == http2stateIdle {
2021-07-30 14:28:58 -07:00
// Section 6.1: "DATA frames MUST be associated with a
// stream. If a DATA frame is received whose stream
// identifier field is 0x0, the recipient MUST respond
// with a connection error (Section 5.4.1) of type
// PROTOCOL_ERROR."
//
2017-09-14 17:11:35 +00:00
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
2022-02-11 14:53:56 -08:00
return sc . countError ( "data_on_idle" , http2ConnectionError ( http2ErrCodeProtocol ) )
2017-01-14 00:05:42 +00:00
}
2021-07-30 14:28:58 -07:00
// "If a DATA frame is received whose stream is not in "open"
// or "half closed (local)" state, the recipient MUST respond
// with a stream error (Section 5.4.2) of type STREAM_CLOSED."
2017-01-14 00:05:42 +00:00
if st == nil || state != http2stateOpen || st . gotTrailerHeader || st . resetQueued {
2017-09-14 17:11:35 +00:00
// This includes sending a RST_STREAM if the stream is
// in stateHalfClosedLocal (which currently means that
// the http.Handler returned, so it's done reading &
// done writing). Try to stop the client from sending
// more DATA.
// But still enforce their connection-level flow control,
// and return any flow control bytes since we're not going
// to consume them.
2016-09-10 13:14:00 +00:00
if sc . inflow . available ( ) < int32 ( f . Length ) {
2022-02-11 14:53:56 -08:00
return sc . countError ( "data_flow" , http2streamError ( id , http2ErrCodeFlowControl ) )
2016-09-10 13:14:00 +00:00
}
2017-09-14 17:11:35 +00:00
// Deduct the flow control from inflow, since we're
// going to immediately add it back in
// sendWindowUpdate, which also schedules sending the
// frames.
2016-09-10 13:14:00 +00:00
sc . inflow . take ( int32 ( f . Length ) )
2017-09-14 17:11:35 +00:00
sc . sendWindowUpdate ( nil , int ( f . Length ) ) // conn-level
2016-09-10 13:14:00 +00:00
2017-01-14 00:05:42 +00:00
if st != nil && st . resetQueued {
2017-09-14 17:11:35 +00:00
// Already have a stream error in flight. Don't send another.
2017-01-14 00:05:42 +00:00
return nil
}
2022-02-11 14:53:56 -08:00
return sc . countError ( "closed" , http2streamError ( id , http2ErrCodeStreamClosed ) )
2016-02-03 21:58:02 +00:00
}
if st . body == nil {
panic ( "internal error: should have a body in this state" )
}
2017-09-14 17:11:35 +00:00
// Sender sending more than they'd declared?
2016-02-03 21:58:02 +00:00
if st . declBodyBytes != - 1 && st . bodyBytes + int64 ( len ( data ) ) > st . declBodyBytes {
st . body . CloseWithError ( fmt . Errorf ( "sender tried to send more than declared Content-Length of %d bytes" , st . declBodyBytes ) )
2018-09-24 21:46:21 +00:00
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
// value of a content-length header field does not equal the sum of the
// DATA frame payload lengths that form the body.
2022-02-11 14:53:56 -08:00
return sc . countError ( "send_too_much" , http2streamError ( id , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2016-09-10 13:14:00 +00:00
if f . Length > 0 {
2017-09-14 17:11:35 +00:00
// Check whether the client has flow control quota.
2016-09-10 13:14:00 +00:00
if st . inflow . available ( ) < int32 ( f . Length ) {
2022-02-11 14:53:56 -08:00
return sc . countError ( "flow_on_data_length" , http2streamError ( id , http2ErrCodeFlowControl ) )
2016-02-03 21:58:02 +00:00
}
2016-09-10 13:14:00 +00:00
st . inflow . take ( int32 ( f . Length ) )
if len ( data ) > 0 {
wrote , err := st . body . Write ( data )
if err != nil {
2020-11-07 07:25:23 -08:00
sc . sendWindowUpdate ( nil , int ( f . Length ) - wrote )
2022-02-11 14:53:56 -08:00
return sc . countError ( "body_write_err" , http2streamError ( id , http2ErrCodeStreamClosed ) )
2016-09-10 13:14:00 +00:00
}
if wrote != len ( data ) {
panic ( "internal error: bad Writer" )
}
st . bodyBytes += int64 ( len ( data ) )
2016-02-03 21:58:02 +00:00
}
2016-09-10 13:14:00 +00:00
2017-09-14 17:11:35 +00:00
// Return any padded flow control now, since we won't
// refund it later on body reads.
2016-09-10 13:14:00 +00:00
if pad := int32 ( f . Length ) - int32 ( len ( data ) ) ; pad > 0 {
sc . sendWindowUpdate32 ( nil , pad )
sc . sendWindowUpdate32 ( st , pad )
2016-02-03 21:58:02 +00:00
}
}
if f . StreamEnded ( ) {
st . endStream ( )
}
return nil
}
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) processGoAway ( f * http2GoAwayFrame ) error {
sc . serveG . check ( )
if f . ErrCode != http2ErrCodeNo {
sc . logf ( "http2: received GOAWAY %+v, starting graceful shutdown" , f )
} else {
sc . vlogf ( "http2: received GOAWAY %+v, starting graceful shutdown" , f )
}
2017-09-14 17:11:35 +00:00
sc . startGracefulShutdownInternal ( )
// http://tools.ietf.org/html/rfc7540#section-6.8
// We should not create any new streams, which means we should disable push.
2017-01-14 00:05:42 +00:00
sc . pushEnabled = false
return nil
}
// isPushed reports whether the stream is server-initiated.
func ( st * http2stream ) isPushed ( ) bool {
return st . id % 2 == 0
}
2016-02-03 21:58:02 +00:00
// endStream closes a Request.Body's pipe. It is called when a DATA
// frame says a request body is over (or after trailers).
func ( st * http2stream ) endStream ( ) {
sc := st . sc
sc . serveG . check ( )
if st . declBodyBytes != - 1 && st . declBodyBytes != st . bodyBytes {
st . body . CloseWithError ( fmt . Errorf ( "request declared a Content-Length of %d but only wrote %d bytes" ,
st . declBodyBytes , st . bodyBytes ) )
} else {
st . body . closeWithErrorAndCode ( io . EOF , st . copyTrailersToHandlerRequest )
st . body . CloseWithError ( io . EOF )
}
st . state = http2stateHalfClosedRemote
}
// copyTrailersToHandlerRequest is run in the Handler's goroutine in
// its Request.Body.Read just before it gets io.EOF.
func ( st * http2stream ) copyTrailersToHandlerRequest ( ) {
for k , vv := range st . trailer {
if _ , ok := st . reqTrailer [ k ] ; ok {
2017-09-14 17:11:35 +00:00
// Only copy it over it was pre-declared.
2016-02-03 21:58:02 +00:00
st . reqTrailer [ k ] = vv
}
}
}
2017-09-14 17:11:35 +00:00
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
// when the stream's WriteTimeout has fired.
func ( st * http2stream ) onWriteTimeout ( ) {
st . sc . writeFrameFromHandler ( http2FrameWriteRequest { write : http2streamError ( st . id , http2ErrCodeInternal ) } )
}
2016-07-22 18:15:38 +00:00
func ( sc * http2serverConn ) processHeaders ( f * http2MetaHeadersFrame ) error {
2016-02-03 21:58:02 +00:00
sc . serveG . check ( )
2017-01-14 00:05:42 +00:00
id := f . StreamID
2016-02-03 21:58:02 +00:00
if sc . inGoAway {
2017-09-14 17:11:35 +00:00
// Ignore.
2016-02-03 21:58:02 +00:00
return nil
}
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-5.1.1
// Streams initiated by a client MUST use odd-numbered stream
// identifiers. [...] An endpoint that receives an unexpected
// stream identifier MUST respond with a connection error
// (Section 5.4.1) of type PROTOCOL_ERROR.
2016-02-03 21:58:02 +00:00
if id % 2 != 1 {
2022-02-11 14:53:56 -08:00
return sc . countError ( "headers_even" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// A HEADERS frame can be used to create a new stream or
// send a trailer for an open one. If we already have a stream
// open, let it process its own HEADERS frame (trailers at this
// point, if it's valid).
2017-01-14 00:05:42 +00:00
if st := sc . streams [ f . StreamID ] ; st != nil {
if st . resetQueued {
2017-09-14 17:11:35 +00:00
// We're sending RST_STREAM to close the stream, so don't bother
// processing this frame.
2017-01-14 00:05:42 +00:00
return nil
}
2018-09-24 21:46:21 +00:00
// RFC 7540, sec 5.1: If an endpoint receives additional frames, other than
// WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream that is in
// this state, it MUST respond with a stream error (Section 5.4.2) of
// type STREAM_CLOSED.
if st . state == http2stateHalfClosedRemote {
2022-02-11 14:53:56 -08:00
return sc . countError ( "headers_half_closed" , http2streamError ( id , http2ErrCodeStreamClosed ) )
2018-09-24 21:46:21 +00:00
}
2016-02-03 21:58:02 +00:00
return st . processTrailerHeaders ( f )
}
2017-09-14 17:11:35 +00:00
// [...] The identifier of a newly established stream MUST be
// numerically greater than all streams that the initiating
// endpoint has opened or reserved. [...] An endpoint that
// receives an unexpected stream identifier MUST respond with
// a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
2017-01-14 00:05:42 +00:00
if id <= sc . maxClientStreamID {
2022-02-11 14:53:56 -08:00
return sc . countError ( "stream_went_down" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
sc . maxClientStreamID = id
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
if sc . idleTimer != nil {
sc . idleTimer . Stop ( )
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-5.1.2
// [...] Endpoints MUST NOT exceed the limit set by their peer. An
// endpoint that receives a HEADERS frame that causes their
// advertised concurrent stream limit to be exceeded MUST treat
// this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR
// or REFUSED_STREAM.
2017-01-14 00:05:42 +00:00
if sc . curClientStreams + 1 > sc . advMaxStreams {
if sc . unackedSettings == 0 {
2017-09-14 17:11:35 +00:00
// They should know better.
2022-02-11 14:53:56 -08:00
return sc . countError ( "over_max_streams" , http2streamError ( id , http2ErrCodeProtocol ) )
2017-01-14 00:05:42 +00:00
}
2017-09-14 17:11:35 +00:00
// Assume it's a network race, where they just haven't
// received our last SETTINGS update. But actually
// this can't happen yet, because we don't yet provide
// a way for users to adjust server parameters at
// runtime.
2022-02-11 14:53:56 -08:00
return sc . countError ( "over_max_streams_race" , http2streamError ( id , http2ErrCodeRefusedStream ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
initialState := http2stateOpen
if f . StreamEnded ( ) {
initialState = http2stateHalfClosedRemote
}
st := sc . newStream ( id , 0 , initialState )
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
if f . HasPriority ( ) {
2022-02-11 14:53:56 -08:00
if err := sc . checkPriority ( f . StreamID , f . Priority ) ; err != nil {
2017-01-14 00:05:42 +00:00
return err
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
sc . writeSched . AdjustStream ( st . id , f . Priority )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
rw , req , err := sc . newWriterAndRequest ( st , f )
2016-02-03 21:58:02 +00:00
if err != nil {
return err
}
st . reqTrailer = req . Trailer
if st . reqTrailer != nil {
st . trailer = make ( Header )
}
2017-09-14 17:11:35 +00:00
st . body = req . Body . ( * http2requestBody ) . pipe // may be nil
2016-02-03 21:58:02 +00:00
st . declBodyBytes = req . ContentLength
handler := sc . handler . ServeHTTP
2016-07-22 18:15:38 +00:00
if f . Truncated {
2017-09-14 17:11:35 +00:00
// Their header list was too long. Send a 431 error.
2016-02-03 21:58:02 +00:00
handler = http2handleHeaderListTooLong
2017-01-14 00:05:42 +00:00
} else if err := http2checkValidHTTP2RequestHeaders ( req . Header ) ; err != nil {
2016-07-22 18:15:38 +00:00
handler = http2new400Handler ( err )
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// The net/http package sets the read deadline from the
// http.Server.ReadTimeout during the TLS handshake, but then
// passes the connection off to us with the deadline already
// set. Disarm it here after the request headers are read,
// similar to how the http1 server works. Here it's
// technically more like the http1 Server's ReadHeaderTimeout
// (in Go 1.8), though. That's a more sane option anyway.
2017-01-14 00:05:42 +00:00
if sc . hs . ReadTimeout != 0 {
sc . conn . SetReadDeadline ( time . Time { } )
}
2016-02-03 21:58:02 +00:00
go sc . runHandler ( rw , req , handler )
return nil
}
2016-07-22 18:15:38 +00:00
func ( st * http2stream ) processTrailerHeaders ( f * http2MetaHeadersFrame ) error {
2016-02-03 21:58:02 +00:00
sc := st . sc
sc . serveG . check ( )
2016-07-22 18:15:38 +00:00
if st . gotTrailerHeader {
2022-02-11 14:53:56 -08:00
return sc . countError ( "dup_trailers" , http2ConnectionError ( http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
st . gotTrailerHeader = true
if ! f . StreamEnded ( ) {
2022-02-11 14:53:56 -08:00
return sc . countError ( "trailers_not_ended" , http2streamError ( st . id , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
if len ( f . PseudoFields ( ) ) > 0 {
2022-02-11 14:53:56 -08:00
return sc . countError ( "trailers_pseudo" , http2streamError ( st . id , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
if st . trailer != nil {
for _ , hf := range f . RegularFields ( ) {
key := sc . canonicalHeader ( hf . Name )
2018-09-24 21:46:21 +00:00
if ! httpguts . ValidTrailerHeader ( key ) {
2017-09-14 17:11:35 +00:00
// TODO: send more details to the peer somehow. But http2 has
// no way to send debug data at a stream level. Discuss with
// HTTP folk.
2022-02-11 14:53:56 -08:00
return sc . countError ( "trailers_bogus" , http2streamError ( st . id , http2ErrCodeProtocol ) )
2016-07-22 18:15:38 +00:00
}
st . trailer [ key ] = append ( st . trailer [ key ] , hf . Value )
}
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
st . endStream ( )
2016-02-03 21:58:02 +00:00
return nil
}
2022-02-11 14:53:56 -08:00
func ( sc * http2serverConn ) checkPriority ( streamID uint32 , p http2PriorityParam ) error {
2017-01-14 00:05:42 +00:00
if streamID == p . StreamDep {
2017-09-14 17:11:35 +00:00
// Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat
// this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
// Section 5.3.3 says that a stream can depend on one of its dependencies,
// so it's only self-dependencies that are forbidden.
2022-02-11 14:53:56 -08:00
return sc . countError ( "priority" , http2streamError ( streamID , http2ErrCodeProtocol ) )
2017-01-14 00:05:42 +00:00
}
2016-02-03 21:58:02 +00:00
return nil
}
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) processPriority ( f * http2PriorityFrame ) error {
if sc . inGoAway {
return nil
}
2022-02-11 14:53:56 -08:00
if err := sc . checkPriority ( f . StreamID , f . http2PriorityParam ) ; err != nil {
2017-01-14 00:05:42 +00:00
return err
}
sc . writeSched . AdjustStream ( f . StreamID , f . http2PriorityParam )
return nil
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) newStream ( id , pusherID uint32 , state http2streamState ) * http2stream {
sc . serveG . check ( )
if id == 0 {
panic ( "internal error: cannot create stream with id 0" )
2016-02-03 21:58:02 +00:00
}
2019-01-18 19:04:36 +00:00
ctx , cancelCtx := context . WithCancel ( sc . baseCtx )
2017-01-14 00:05:42 +00:00
st := & http2stream {
sc : sc ,
id : id ,
state : state ,
ctx : ctx ,
cancelCtx : cancelCtx ,
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
st . cw . Init ( )
2017-09-14 17:11:35 +00:00
st . flow . conn = & sc . flow // link to conn-level counter
st . flow . add ( sc . initialStreamSendWindowSize )
st . inflow . conn = & sc . inflow // link to conn-level counter
st . inflow . add ( sc . srv . initialStreamRecvWindowSize ( ) )
if sc . hs . WriteTimeout != 0 {
st . writeDeadline = time . AfterFunc ( sc . hs . WriteTimeout , st . onWriteTimeout )
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
sc . streams [ id ] = st
sc . writeSched . OpenStream ( st . id , http2OpenStreamOptions { PusherID : pusherID } )
if st . isPushed ( ) {
sc . curPushedStreams ++
} else {
sc . curClientStreams ++
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if sc . curOpenStreams ( ) == 1 {
sc . setConnState ( StateActive )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
return st
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
func ( sc * http2serverConn ) newWriterAndRequest ( st * http2stream , f * http2MetaHeadersFrame ) ( * http2responseWriter , * Request , error ) {
2016-02-03 21:58:02 +00:00
sc . serveG . check ( )
2017-01-14 00:05:42 +00:00
rp := http2requestParam {
method : f . PseudoValue ( "method" ) ,
scheme : f . PseudoValue ( "scheme" ) ,
authority : f . PseudoValue ( "authority" ) ,
path : f . PseudoValue ( "path" ) ,
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
isConnect := rp . method == "CONNECT"
2016-02-03 21:58:02 +00:00
if isConnect {
2017-01-14 00:05:42 +00:00
if rp . path != "" || rp . scheme != "" || rp . authority == "" {
2022-02-11 14:53:56 -08:00
return nil , nil , sc . countError ( "bad_connect" , http2streamError ( f . StreamID , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
} else if rp . method == "" || rp . path == "" || ( rp . scheme != "https" && rp . scheme != "http" ) {
2017-09-14 17:11:35 +00:00
// See 8.1.2.6 Malformed Requests and Responses:
//
// Malformed requests or responses that are detected
// MUST be treated as a stream error (Section 5.4.2)
// of type PROTOCOL_ERROR."
//
// 8.1.2.3 Request Pseudo-Header Fields
// "All HTTP/2 requests MUST include exactly one valid
// value for the :method, :scheme, and :path
// pseudo-header fields"
2022-02-11 14:53:56 -08:00
return nil , nil , sc . countError ( "bad_path_method" , http2streamError ( f . StreamID , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
bodyOpen := ! f . StreamEnded ( )
2017-01-14 00:05:42 +00:00
if rp . method == "HEAD" && bodyOpen {
2017-09-14 17:11:35 +00:00
// HEAD requests can't have bodies
2022-02-11 14:53:56 -08:00
return nil , nil , sc . countError ( "head_body" , http2streamError ( f . StreamID , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
rp . header = make ( Header )
for _ , hf := range f . RegularFields ( ) {
rp . header . Add ( sc . canonicalHeader ( hf . Name ) , hf . Value )
}
if rp . authority == "" {
rp . authority = rp . header . Get ( "Host" )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
2017-01-14 00:05:42 +00:00
rw , req , err := sc . newWriterAndRequestNoBody ( st , rp )
if err != nil {
return nil , nil , err
}
if bodyOpen {
if vv , ok := rp . header [ "Content-Length" ] ; ok {
2020-12-23 09:57:37 -08:00
if cl , err := strconv . ParseUint ( vv [ 0 ] , 10 , 63 ) ; err == nil {
req . ContentLength = int64 ( cl )
} else {
req . ContentLength = 0
}
2017-01-14 00:05:42 +00:00
} else {
req . ContentLength = - 1
}
2017-09-14 17:11:35 +00:00
req . Body . ( * http2requestBody ) . pipe = & http2pipe {
b : & http2dataBuffer { expected : req . ContentLength } ,
}
2016-07-22 18:15:38 +00:00
}
2017-01-14 00:05:42 +00:00
return rw , req , nil
}
type http2requestParam struct {
method string
scheme , authority , path string
header Header
}
2016-07-22 18:15:38 +00:00
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) newWriterAndRequestNoBody ( st * http2stream , rp http2requestParam ) ( * http2responseWriter , * Request , error ) {
sc . serveG . check ( )
var tlsState * tls . ConnectionState // nil if not scheme https
if rp . scheme == "https" {
tlsState = sc . tlsState
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
needsContinue := rp . header . Get ( "Expect" ) == "100-continue"
2016-02-03 21:58:02 +00:00
if needsContinue {
2017-01-14 00:05:42 +00:00
rp . header . Del ( "Expect" )
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// Merge Cookie headers into one "; "-delimited value.
2017-01-14 00:05:42 +00:00
if cookies := rp . header [ "Cookie" ] ; len ( cookies ) > 1 {
rp . header . Set ( "Cookie" , strings . Join ( cookies , "; " ) )
2016-02-03 21:58:02 +00:00
}
// Setup Trailers
var trailer Header
2017-01-14 00:05:42 +00:00
for _ , v := range rp . header [ "Trailer" ] {
2016-02-03 21:58:02 +00:00
for _ , key := range strings . Split ( v , "," ) {
2020-12-23 09:57:37 -08:00
key = CanonicalHeaderKey ( textproto . TrimString ( key ) )
2016-02-03 21:58:02 +00:00
switch key {
case "Transfer-Encoding" , "Trailer" , "Content-Length" :
2017-09-14 17:11:35 +00:00
// Bogus. (copy of http1 rules)
// Ignore.
2016-02-03 21:58:02 +00:00
default :
if trailer == nil {
trailer = make ( Header )
}
trailer [ key ] = nil
}
}
}
2017-01-14 00:05:42 +00:00
delete ( rp . header , "Trailer" )
2016-02-03 21:58:02 +00:00
var url_ * url . URL
var requestURI string
2017-01-14 00:05:42 +00:00
if rp . method == "CONNECT" {
url_ = & url . URL { Host : rp . authority }
2017-09-14 17:11:35 +00:00
requestURI = rp . authority // mimic HTTP/1 server behavior
2016-02-03 21:58:02 +00:00
} else {
var err error
2017-01-14 00:05:42 +00:00
url_ , err = url . ParseRequestURI ( rp . path )
2016-02-03 21:58:02 +00:00
if err != nil {
2022-02-11 14:53:56 -08:00
return nil , nil , sc . countError ( "bad_path" , http2streamError ( st . id , http2ErrCodeProtocol ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
requestURI = rp . path
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
body := & http2requestBody {
conn : sc ,
stream : st ,
needsContinue : needsContinue ,
}
req := & Request {
Method : rp . method ,
URL : url_ ,
RemoteAddr : sc . remoteAddrStr ,
Header : rp . header ,
2016-02-03 21:58:02 +00:00
RequestURI : requestURI ,
Proto : "HTTP/2.0" ,
ProtoMajor : 2 ,
ProtoMinor : 0 ,
TLS : tlsState ,
2017-01-14 00:05:42 +00:00
Host : rp . authority ,
2016-02-03 21:58:02 +00:00
Body : body ,
Trailer : trailer ,
}
2019-01-18 19:04:36 +00:00
req = req . WithContext ( st . ctx )
2016-02-03 21:58:02 +00:00
rws := http2responseWriterStatePool . Get ( ) . ( * http2responseWriterState )
bwSave := rws . bw
2017-09-14 17:11:35 +00:00
* rws = http2responseWriterState { } // zero all the fields
2016-02-03 21:58:02 +00:00
rws . conn = sc
rws . bw = bwSave
rws . bw . Reset ( http2chunkWriter { rws } )
2016-07-22 18:15:38 +00:00
rws . stream = st
2016-02-03 21:58:02 +00:00
rws . req = req
rws . body = body
rw := & http2responseWriter { rws : rws }
return rw , req , nil
}
// Run on its own goroutine.
func ( sc * http2serverConn ) runHandler ( rw * http2responseWriter , req * Request , handler func ( ResponseWriter , * Request ) ) {
didPanic := true
defer func ( ) {
2016-07-22 18:15:38 +00:00
rw . rws . stream . cancelCtx ( )
2016-02-03 21:58:02 +00:00
if didPanic {
e := recover ( )
2017-01-14 00:05:42 +00:00
sc . writeFrameFromHandler ( http2FrameWriteRequest {
2016-02-03 21:58:02 +00:00
write : http2handlerPanicRST { rw . rws . stream . id } ,
stream : rw . rws . stream ,
} )
2017-09-14 17:11:35 +00:00
// Same as net/http:
2019-01-18 19:04:36 +00:00
if e != nil && e != ErrAbortHandler {
2017-01-14 00:05:42 +00:00
const size = 64 << 10
buf := make ( [ ] byte , size )
buf = buf [ : runtime . Stack ( buf , false ) ]
sc . logf ( "http2: panic serving %v: %v\n%s" , sc . conn . RemoteAddr ( ) , e , buf )
}
2016-02-03 21:58:02 +00:00
return
}
rw . handlerDone ( )
} ( )
handler ( rw , req )
didPanic = false
}
func http2handleHeaderListTooLong ( w ResponseWriter , r * Request ) {
// 10.5.1 Limits on Header Block Size:
// .. "A server that receives a larger header block than it is
// willing to handle can send an HTTP 431 (Request Header Fields Too
// Large) status code"
const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+
w . WriteHeader ( statusRequestHeaderFieldsTooLarge )
io . WriteString ( w , "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>" )
}
// called from handler goroutines.
// h may be nil.
func ( sc * http2serverConn ) writeHeaders ( st * http2stream , headerData * http2writeResHeaders ) error {
2017-09-14 17:11:35 +00:00
sc . serveG . checkNotOn ( ) // NOT on
2016-02-03 21:58:02 +00:00
var errc chan error
if headerData . h != nil {
2017-09-14 17:11:35 +00:00
// If there's a header map (which we don't own), so we have to block on
// waiting for this frame to be written, so an http.Flush mid-handler
// writes out the correct value of keys, before a handler later potentially
// mutates it.
2016-02-03 21:58:02 +00:00
errc = http2errChanPool . Get ( ) . ( chan error )
}
2017-01-14 00:05:42 +00:00
if err := sc . writeFrameFromHandler ( http2FrameWriteRequest {
2016-02-03 21:58:02 +00:00
write : headerData ,
stream : st ,
done : errc ,
} ) ; err != nil {
return err
}
if errc != nil {
select {
case err := <- errc :
http2errChanPool . Put ( errc )
return err
case <- sc . doneServing :
return http2errClientDisconnected
case <- st . cw :
return http2errStreamClosed
}
}
return nil
}
// called from handler goroutines.
func ( sc * http2serverConn ) write100ContinueHeaders ( st * http2stream ) {
2017-01-14 00:05:42 +00:00
sc . writeFrameFromHandler ( http2FrameWriteRequest {
2016-02-03 21:58:02 +00:00
write : http2write100ContinueHeadersFrame { st . id } ,
stream : st ,
} )
}
// A bodyReadMsg tells the server loop that the http.Handler read n
// bytes of the DATA from the client on the given stream.
type http2bodyReadMsg struct {
st * http2stream
n int
}
// called from handler goroutines.
// Notes that the handler for the given stream ID read n bytes of its body
// and schedules flow control tokens to be sent.
2017-01-14 00:05:42 +00:00
func ( sc * http2serverConn ) noteBodyReadFromHandler ( st * http2stream , n int , err error ) {
2017-09-14 17:11:35 +00:00
sc . serveG . checkNotOn ( ) // NOT on
2017-01-14 00:05:42 +00:00
if n > 0 {
select {
case sc . bodyReadCh <- http2bodyReadMsg { st , n } :
case <- sc . doneServing :
}
}
2016-02-03 21:58:02 +00:00
}
func ( sc * http2serverConn ) noteBodyRead ( st * http2stream , n int ) {
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
sc . sendWindowUpdate ( nil , n ) // conn-level
2016-02-03 21:58:02 +00:00
if st . state != http2stateHalfClosedRemote && st . state != http2stateClosed {
2017-09-14 17:11:35 +00:00
// Don't send this WINDOW_UPDATE if the stream is closed
// remotely.
2016-02-03 21:58:02 +00:00
sc . sendWindowUpdate ( st , n )
}
}
// st may be nil for conn-level
func ( sc * http2serverConn ) sendWindowUpdate ( st * http2stream , n int ) {
sc . serveG . check ( )
// "The legal range for the increment to the flow control
// window is 1 to 2^31-1 (2,147,483,647) octets."
// A Go Read call on 64-bit machines could in theory read
// a larger Read than this. Very unlikely, but we handle it here
// rather than elsewhere for now.
const maxUint31 = 1 << 31 - 1
for n >= maxUint31 {
sc . sendWindowUpdate32 ( st , maxUint31 )
n -= maxUint31
}
sc . sendWindowUpdate32 ( st , int32 ( n ) )
}
// st may be nil for conn-level
func ( sc * http2serverConn ) sendWindowUpdate32 ( st * http2stream , n int32 ) {
sc . serveG . check ( )
if n == 0 {
return
}
if n < 0 {
panic ( "negative update" )
}
var streamID uint32
if st != nil {
streamID = st . id
}
2017-01-14 00:05:42 +00:00
sc . writeFrame ( http2FrameWriteRequest {
2016-02-03 21:58:02 +00:00
write : http2writeWindowUpdate { streamID : streamID , n : uint32 ( n ) } ,
stream : st ,
} )
var ok bool
if st == nil {
ok = sc . inflow . add ( n )
} else {
ok = st . inflow . add ( n )
}
if ! ok {
panic ( "internal error; sent too many window updates without decrements?" )
}
}
2017-01-14 00:05:42 +00:00
// requestBody is the Handler's Request.Body type.
// Read and Close may be called concurrently.
2016-02-03 21:58:02 +00:00
type http2requestBody struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
stream * http2stream
conn * http2serverConn
2017-01-14 00:05:42 +00:00
closed bool // for use by Close only
sawEOF bool // for use by Read only
2016-02-03 21:58:02 +00:00
pipe * http2pipe // non-nil if we have a HTTP entity message body
needsContinue bool // need to send a 100-continue
}
func ( b * http2requestBody ) Close ( ) error {
2017-01-14 00:05:42 +00:00
if b . pipe != nil && ! b . closed {
2016-07-22 18:15:38 +00:00
b . pipe . BreakWithError ( http2errClosedBody )
2016-02-03 21:58:02 +00:00
}
b . closed = true
return nil
}
func ( b * http2requestBody ) Read ( p [ ] byte ) ( n int , err error ) {
if b . needsContinue {
b . needsContinue = false
b . conn . write100ContinueHeaders ( b . stream )
}
2017-01-14 00:05:42 +00:00
if b . pipe == nil || b . sawEOF {
2016-02-03 21:58:02 +00:00
return 0 , io . EOF
}
n , err = b . pipe . Read ( p )
2017-01-14 00:05:42 +00:00
if err == io . EOF {
b . sawEOF = true
}
if b . conn == nil && http2inTests {
return
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
b . conn . noteBodyReadFromHandler ( b . stream , n , err )
2016-02-03 21:58:02 +00:00
return
}
2017-09-14 17:11:35 +00:00
// responseWriter is the http.ResponseWriter implementation. It's
// intentionally small (1 pointer wide) to minimize garbage. The
2016-02-03 21:58:02 +00:00
// responseWriterState pointer inside is zeroed at the end of a
// request (in handlerDone) and calls on the responseWriter thereafter
// simply crash (caller's mistake), but the much larger responseWriterState
// and buffers are reused between multiple requests.
type http2responseWriter struct {
rws * http2responseWriterState
}
// Optional http.ResponseWriter interfaces implemented.
var (
_ CloseNotifier = ( * http2responseWriter ) ( nil )
_ Flusher = ( * http2responseWriter ) ( nil )
_ http2stringWriter = ( * http2responseWriter ) ( nil )
)
type http2responseWriterState struct {
// immutable within a request:
stream * http2stream
req * Request
body * http2requestBody // to close at end of request, if DATA frames didn't
conn * http2serverConn
// TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc
bw * bufio . Writer // writing to a chunkWriter{this *responseWriterState}
// mutated by http.Handler goroutine:
handlerHeader Header // nil until called
snapHeader Header // snapshot of handlerHeader at WriteHeader time
trailers [ ] string // set in writeChunk
status int // status code passed to WriteHeader
wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
sentHeader bool // have we sent the header frame?
handlerDone bool // handler has finished
2017-09-14 17:11:35 +00:00
dirty bool // a Write failed; don't reuse this responseWriterState
2016-02-03 21:58:02 +00:00
sentContentLen int64 // non-zero if handler set a Content-Length header
wroteBytes int64
closeNotifierMu sync . Mutex // guards closeNotifierCh
closeNotifierCh chan bool // nil until first used
}
type http2chunkWriter struct { rws * http2responseWriterState }
func ( cw http2chunkWriter ) Write ( p [ ] byte ) ( n int , err error ) { return cw . rws . writeChunk ( p ) }
2019-09-06 18:12:46 +00:00
func ( rws * http2responseWriterState ) hasTrailers ( ) bool { return len ( rws . trailers ) > 0 }
func ( rws * http2responseWriterState ) hasNonemptyTrailers ( ) bool {
for _ , trailer := range rws . trailers {
if _ , ok := rws . handlerHeader [ trailer ] ; ok {
return true
}
}
return false
}
2016-02-03 21:58:02 +00:00
// declareTrailer is called for each Trailer header when the
// response header is written. It notes that a header will need to be
// written in the trailers at the end of the response.
func ( rws * http2responseWriterState ) declareTrailer ( k string ) {
k = CanonicalHeaderKey ( k )
2018-09-24 21:46:21 +00:00
if ! httpguts . ValidTrailerHeader ( k ) {
// Forbidden by RFC 7230, section 4.1.2.
2016-07-22 18:15:38 +00:00
rws . conn . logf ( "ignoring invalid trailer %q" , k )
2016-02-03 21:58:02 +00:00
return
}
2016-02-18 05:56:46 +00:00
if ! http2strSliceContains ( rws . trailers , k ) {
rws . trailers = append ( rws . trailers , k )
}
2016-02-03 21:58:02 +00:00
}
// writeChunk writes chunks from the bufio.Writer. But because
// bufio.Writer may bypass its chunking, sometimes p may be
// arbitrarily large.
//
// writeChunk is also responsible (on the first chunk) for sending the
// HEADER response.
func ( rws * http2responseWriterState ) writeChunk ( p [ ] byte ) ( n int , err error ) {
if ! rws . wroteHeader {
rws . writeHeader ( 200 )
}
isHeadResp := rws . req . Method == "HEAD"
if ! rws . sentHeader {
rws . sentHeader = true
var ctype , clen string
if clen = rws . snapHeader . Get ( "Content-Length" ) ; clen != "" {
rws . snapHeader . Del ( "Content-Length" )
2020-12-23 09:57:37 -08:00
if cl , err := strconv . ParseUint ( clen , 10 , 63 ) ; err == nil {
rws . sentContentLen = int64 ( cl )
2016-02-03 21:58:02 +00:00
} else {
clen = ""
}
}
if clen == "" && rws . handlerDone && http2bodyAllowedForStatus ( rws . status ) && ( len ( p ) > 0 || ! isHeadResp ) {
clen = strconv . Itoa ( len ( p ) )
}
_ , hasContentType := rws . snapHeader [ "Content-Type" ]
2020-01-02 15:05:27 -08:00
// If the Content-Encoding is non-blank, we shouldn't
// sniff the body. See Issue golang.org/issue/31753.
ce := rws . snapHeader . Get ( "Content-Encoding" )
hasCE := len ( ce ) > 0
if ! hasCE && ! hasContentType && http2bodyAllowedForStatus ( rws . status ) && len ( p ) > 0 {
2016-02-03 21:58:02 +00:00
ctype = DetectContentType ( p )
}
var date string
if _ , ok := rws . snapHeader [ "Date" ] ; ! ok {
2017-09-14 17:11:35 +00:00
// TODO(bradfitz): be faster here, like net/http? measure.
2016-02-03 21:58:02 +00:00
date = time . Now ( ) . UTC ( ) . Format ( TimeFormat )
}
for _ , v := range rws . snapHeader [ "Trailer" ] {
http2foreachHeaderElement ( v , rws . declareTrailer )
}
2018-09-24 21:46:21 +00:00
// "Connection" headers aren't allowed in HTTP/2 (RFC 7540, 8.1.2.2),
// but respect "Connection" == "close" to mean sending a GOAWAY and tearing
// down the TCP connection when idle, like we do for HTTP/1.
// TODO: remove more Connection-specific header fields here, in addition
// to "Connection".
if _ , ok := rws . snapHeader [ "Connection" ] ; ok {
v := rws . snapHeader . Get ( "Connection" )
delete ( rws . snapHeader , "Connection" )
if v == "close" {
rws . conn . startGracefulShutdown ( )
}
}
2016-02-03 21:58:02 +00:00
endStream := ( rws . handlerDone && ! rws . hasTrailers ( ) && len ( p ) == 0 ) || isHeadResp
err = rws . conn . writeHeaders ( rws . stream , & http2writeResHeaders {
streamID : rws . stream . id ,
httpResCode : rws . status ,
h : rws . snapHeader ,
endStream : endStream ,
contentType : ctype ,
contentLength : clen ,
date : date ,
} )
if err != nil {
2017-09-14 17:11:35 +00:00
rws . dirty = true
2016-02-03 21:58:02 +00:00
return 0 , err
}
if endStream {
return 0 , nil
}
}
if isHeadResp {
return len ( p ) , nil
}
if len ( p ) == 0 && ! rws . handlerDone {
return 0 , nil
}
2016-02-18 05:56:46 +00:00
if rws . handlerDone {
rws . promoteUndeclaredTrailers ( )
}
2019-09-06 18:12:46 +00:00
// only send trailers if they have actually been defined by the
// server handler.
hasNonemptyTrailers := rws . hasNonemptyTrailers ( )
endStream := rws . handlerDone && ! hasNonemptyTrailers
2016-02-03 21:58:02 +00:00
if len ( p ) > 0 || endStream {
2017-09-14 17:11:35 +00:00
// only send a 0 byte DATA frame if we're ending the stream.
2016-02-03 21:58:02 +00:00
if err := rws . conn . writeDataFromHandler ( rws . stream , p , endStream ) ; err != nil {
2017-09-14 17:11:35 +00:00
rws . dirty = true
2016-02-03 21:58:02 +00:00
return 0 , err
}
}
2019-09-06 18:12:46 +00:00
if rws . handlerDone && hasNonemptyTrailers {
2016-02-03 21:58:02 +00:00
err = rws . conn . writeHeaders ( rws . stream , & http2writeResHeaders {
streamID : rws . stream . id ,
h : rws . handlerHeader ,
trailers : rws . trailers ,
endStream : true ,
} )
2017-09-14 17:11:35 +00:00
if err != nil {
rws . dirty = true
}
2016-02-03 21:58:02 +00:00
return len ( p ) , err
}
return len ( p ) , nil
}
2016-02-18 05:56:46 +00:00
// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
// that, if present, signals that the map entry is actually for
// the response trailers, and not the response headers. The prefix
// is stripped after the ServeHTTP call finishes and the values are
// sent in the trailers.
//
// This mechanism is intended only for trailers that are not known
// prior to the headers being written. If the set of trailers is fixed
// or known before the header is written, the normal Go trailers mechanism
// is preferred:
// https://golang.org/pkg/net/http/#ResponseWriter
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
const http2TrailerPrefix = "Trailer:"
// promoteUndeclaredTrailers permits http.Handlers to set trailers
// after the header has already been flushed. Because the Go
// ResponseWriter interface has no way to set Trailers (only the
// Header), and because we didn't want to expand the ResponseWriter
2018-09-24 21:46:21 +00:00
// interface, and because nobody used trailers, and because RFC 7230
2016-02-18 05:56:46 +00:00
// says you SHOULD (but not must) predeclare any trailers in the
// header, the official ResponseWriter rules said trailers in Go must
// be predeclared, and then we reuse the same ResponseWriter.Header()
2017-09-14 17:11:35 +00:00
// map to mean both Headers and Trailers. When it's time to write the
2016-02-18 05:56:46 +00:00
// Trailers, we pick out the fields of Headers that were declared as
// trailers. That worked for a while, until we found the first major
// user of Trailers in the wild: gRPC (using them only over http2),
// and gRPC libraries permit setting trailers mid-stream without
2020-01-02 15:05:27 -08:00
// predeclaring them. So: change of plans. We still permit the old
2016-02-18 05:56:46 +00:00
// way, but we also permit this hack: if a Header() key begins with
// "Trailer:", the suffix of that key is a Trailer. Because ':' is an
// invalid token byte anyway, there is no ambiguity. (And it's already
// filtered out) It's mildly hacky, but not terrible.
//
// This method runs after the Handler is done and promotes any Header
// fields to be trailers.
func ( rws * http2responseWriterState ) promoteUndeclaredTrailers ( ) {
for k , vv := range rws . handlerHeader {
if ! strings . HasPrefix ( k , http2TrailerPrefix ) {
continue
}
trailerKey := strings . TrimPrefix ( k , http2TrailerPrefix )
rws . declareTrailer ( trailerKey )
rws . handlerHeader [ CanonicalHeaderKey ( trailerKey ) ] = vv
}
2016-07-22 18:15:38 +00:00
if len ( rws . trailers ) > 1 {
sorter := http2sorterPool . Get ( ) . ( * http2sorter )
sorter . SortStrings ( rws . trailers )
http2sorterPool . Put ( sorter )
}
2016-02-18 05:56:46 +00:00
}
2016-02-03 21:58:02 +00:00
func ( w * http2responseWriter ) Flush ( ) {
rws := w . rws
if rws == nil {
panic ( "Header called after Handler finished" )
}
if rws . bw . Buffered ( ) > 0 {
if err := rws . bw . Flush ( ) ; err != nil {
2017-09-14 17:11:35 +00:00
// Ignore the error. The frame writer already knows.
2016-02-03 21:58:02 +00:00
return
}
} else {
2017-09-14 17:11:35 +00:00
// The bufio.Writer won't call chunkWriter.Write
// (writeChunk with zero bytes, so we have to do it
// ourselves to force the HTTP response header and/or
// final DATA frame (with END_STREAM) to be sent.
2016-02-03 21:58:02 +00:00
rws . writeChunk ( nil )
}
}
func ( w * http2responseWriter ) CloseNotify ( ) <- chan bool {
rws := w . rws
if rws == nil {
panic ( "CloseNotify called after Handler finished" )
}
rws . closeNotifierMu . Lock ( )
ch := rws . closeNotifierCh
if ch == nil {
ch = make ( chan bool , 1 )
rws . closeNotifierCh = ch
2017-01-14 00:05:42 +00:00
cw := rws . stream . cw
2016-02-03 21:58:02 +00:00
go func ( ) {
2017-09-14 17:11:35 +00:00
cw . Wait ( ) // wait for close
2016-02-03 21:58:02 +00:00
ch <- true
} ( )
}
rws . closeNotifierMu . Unlock ( )
return ch
}
func ( w * http2responseWriter ) Header ( ) Header {
rws := w . rws
if rws == nil {
panic ( "Header called after Handler finished" )
}
if rws . handlerHeader == nil {
rws . handlerHeader = make ( Header )
}
return rws . handlerHeader
}
2018-01-09 01:23:08 +00:00
// checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode.
func http2checkWriteHeaderCode ( code int ) {
// Issue 22880: require valid WriteHeader status codes.
// For now we only enforce that it's three digits.
// In the future we might block things over 599 (600 and above aren't defined
// at http://httpwg.org/specs/rfc7231.html#status.codes)
// and we might block under 200 (once we have more mature 1xx support).
// But for now any three digits.
//
// We used to send "HTTP/1.1 000 0" on the wire in responses but there's
// no equivalent bogus thing we can realistically send in HTTP/2,
// so we'll consistently panic instead and help people find their bugs
// early. (We can't return an error from WriteHeader even if we wanted to.)
if code < 100 || code > 999 {
panic ( fmt . Sprintf ( "invalid WriteHeader code %v" , code ) )
}
}
2016-02-03 21:58:02 +00:00
func ( w * http2responseWriter ) WriteHeader ( code int ) {
rws := w . rws
if rws == nil {
panic ( "WriteHeader called after Handler finished" )
}
rws . writeHeader ( code )
}
func ( rws * http2responseWriterState ) writeHeader ( code int ) {
if ! rws . wroteHeader {
2018-01-17 14:20:29 +00:00
http2checkWriteHeaderCode ( code )
2016-02-03 21:58:02 +00:00
rws . wroteHeader = true
rws . status = code
if len ( rws . handlerHeader ) > 0 {
rws . snapHeader = http2cloneHeader ( rws . handlerHeader )
}
}
}
func http2cloneHeader ( h Header ) Header {
h2 := make ( Header , len ( h ) )
for k , vv := range h {
vv2 := make ( [ ] string , len ( vv ) )
copy ( vv2 , vv )
h2 [ k ] = vv2
}
return h2
}
// The Life Of A Write is like this:
//
// * Handler calls w.Write or w.WriteString ->
// * -> rws.bw (*bufio.Writer) ->
2017-09-14 17:11:35 +00:00
// * (Handler might call Flush)
2016-02-03 21:58:02 +00:00
// * -> chunkWriter{rws}
// * -> responseWriterState.writeChunk(p []byte)
// * -> responseWriterState.writeChunk (most of the magic; see comment there)
func ( w * http2responseWriter ) Write ( p [ ] byte ) ( n int , err error ) {
return w . write ( len ( p ) , p , "" )
}
func ( w * http2responseWriter ) WriteString ( s string ) ( n int , err error ) {
return w . write ( len ( s ) , nil , s )
}
// either dataB or dataS is non-zero.
func ( w * http2responseWriter ) write ( lenData int , dataB [ ] byte , dataS string ) ( n int , err error ) {
rws := w . rws
if rws == nil {
panic ( "Write called after Handler finished" )
}
if ! rws . wroteHeader {
w . WriteHeader ( 200 )
}
if ! http2bodyAllowedForStatus ( rws . status ) {
return 0 , ErrBodyNotAllowed
}
2017-09-14 17:11:35 +00:00
rws . wroteBytes += int64 ( len ( dataB ) ) + int64 ( len ( dataS ) ) // only one can be set
2016-02-03 21:58:02 +00:00
if rws . sentContentLen != 0 && rws . wroteBytes > rws . sentContentLen {
2017-09-14 17:11:35 +00:00
// TODO: send a RST_STREAM
2016-02-03 21:58:02 +00:00
return 0 , errors . New ( "http2: handler wrote more than declared Content-Length" )
}
if dataB != nil {
return rws . bw . Write ( dataB )
} else {
return rws . bw . WriteString ( dataS )
}
}
func ( w * http2responseWriter ) handlerDone ( ) {
rws := w . rws
2017-09-14 17:11:35 +00:00
dirty := rws . dirty
2016-02-03 21:58:02 +00:00
rws . handlerDone = true
w . Flush ( )
w . rws = nil
2017-09-14 17:11:35 +00:00
if ! dirty {
// Only recycle the pool if all prior Write calls to
// the serverConn goroutine completed successfully. If
// they returned earlier due to resets from the peer
// there might still be write goroutines outstanding
// from the serverConn referencing the rws memory. See
// issue 20704.
http2responseWriterStatePool . Put ( rws )
}
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
// Push errors.
var (
http2ErrRecursivePush = errors . New ( "http2: recursive push not allowed" )
http2ErrPushLimitReached = errors . New ( "http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS" )
)
2019-01-18 19:04:36 +00:00
var _ Pusher = ( * http2responseWriter ) ( nil )
2017-01-14 00:05:42 +00:00
2019-01-18 19:04:36 +00:00
func ( w * http2responseWriter ) Push ( target string , opts * PushOptions ) error {
2017-01-14 00:05:42 +00:00
st := w . rws . stream
sc := st . sc
sc . serveG . checkNotOn ( )
2017-09-14 17:11:35 +00:00
// No recursive pushes: "PUSH_PROMISE frames MUST only be sent on a peer-initiated stream."
// http://tools.ietf.org/html/rfc7540#section-6.6
2017-01-14 00:05:42 +00:00
if st . isPushed ( ) {
return http2ErrRecursivePush
}
2019-01-18 19:04:36 +00:00
if opts == nil {
opts = new ( PushOptions )
}
2017-09-14 17:11:35 +00:00
// Default options.
2017-01-14 00:05:42 +00:00
if opts . Method == "" {
opts . Method = "GET"
}
if opts . Header == nil {
opts . Header = Header { }
}
wantScheme := "http"
if w . rws . req . TLS != nil {
wantScheme = "https"
}
2017-09-14 17:11:35 +00:00
// Validate the request.
2017-01-14 00:05:42 +00:00
u , err := url . Parse ( target )
if err != nil {
return err
}
if u . Scheme == "" {
if ! strings . HasPrefix ( target , "/" ) {
return fmt . Errorf ( "target must be an absolute URL or an absolute path: %q" , target )
}
u . Scheme = wantScheme
u . Host = w . rws . req . Host
} else {
if u . Scheme != wantScheme {
return fmt . Errorf ( "cannot push URL with scheme %q from request with scheme %q" , u . Scheme , wantScheme )
}
if u . Host == "" {
return errors . New ( "URL must have a host" )
}
}
for k := range opts . Header {
if strings . HasPrefix ( k , ":" ) {
return fmt . Errorf ( "promised request headers cannot include pseudo header %q" , k )
}
2017-09-14 17:11:35 +00:00
// These headers are meaningful only if the request has a body,
// but PUSH_PROMISE requests cannot have a body.
// http://tools.ietf.org/html/rfc7540#section-8.2
// Also disallow Host, since the promised URL must be absolute.
2021-07-30 14:28:58 -07:00
if http2asciiEqualFold ( k , "content-length" ) ||
http2asciiEqualFold ( k , "content-encoding" ) ||
http2asciiEqualFold ( k , "trailer" ) ||
http2asciiEqualFold ( k , "te" ) ||
http2asciiEqualFold ( k , "expect" ) ||
http2asciiEqualFold ( k , "host" ) {
2017-01-14 00:05:42 +00:00
return fmt . Errorf ( "promised request headers cannot include %q" , k )
}
}
if err := http2checkValidHTTP2RequestHeaders ( opts . Header ) ; err != nil {
return err
}
2017-09-14 17:11:35 +00:00
// The RFC effectively limits promised requests to GET and HEAD:
// "Promised requests MUST be cacheable [GET, HEAD, or POST], and MUST be safe [GET or HEAD]"
// http://tools.ietf.org/html/rfc7540#section-8.2
2017-01-14 00:05:42 +00:00
if opts . Method != "GET" && opts . Method != "HEAD" {
return fmt . Errorf ( "method %q must be GET or HEAD" , opts . Method )
}
2017-09-14 17:11:35 +00:00
msg := & http2startPushRequest {
2017-01-14 00:05:42 +00:00
parent : st ,
method : opts . Method ,
url : u ,
header : http2cloneHeader ( opts . Header ) ,
done : http2errChanPool . Get ( ) . ( chan error ) ,
}
select {
case <- sc . doneServing :
return http2errClientDisconnected
case <- st . cw :
return http2errStreamClosed
2017-09-14 17:11:35 +00:00
case sc . serveMsgCh <- msg :
2017-01-14 00:05:42 +00:00
}
select {
case <- sc . doneServing :
return http2errClientDisconnected
case <- st . cw :
return http2errStreamClosed
case err := <- msg . done :
http2errChanPool . Put ( msg . done )
return err
}
}
type http2startPushRequest struct {
parent * http2stream
method string
url * url . URL
header Header
done chan error
}
2017-09-14 17:11:35 +00:00
func ( sc * http2serverConn ) startPush ( msg * http2startPushRequest ) {
2017-01-14 00:05:42 +00:00
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-6.6.
// PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that
// is in either the "open" or "half-closed (remote)" state.
2017-01-14 00:05:42 +00:00
if msg . parent . state != http2stateOpen && msg . parent . state != http2stateHalfClosedRemote {
2020-01-02 15:05:27 -08:00
// responseWriter.Push checks that the stream is peer-initiated.
2017-01-14 00:05:42 +00:00
msg . done <- http2errStreamClosed
return
}
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-6.6.
2017-01-14 00:05:42 +00:00
if ! sc . pushEnabled {
msg . done <- ErrNotSupported
return
}
2017-09-14 17:11:35 +00:00
// PUSH_PROMISE frames must be sent in increasing order by stream ID, so
// we allocate an ID for the promised stream lazily, when the PUSH_PROMISE
// is written. Once the ID is allocated, we start the request handler.
2017-01-14 00:05:42 +00:00
allocatePromisedID := func ( ) ( uint32 , error ) {
sc . serveG . check ( )
2017-09-14 17:11:35 +00:00
// Check this again, just in case. Technically, we might have received
// an updated SETTINGS by the time we got around to writing this frame.
2017-01-14 00:05:42 +00:00
if ! sc . pushEnabled {
return 0 , ErrNotSupported
}
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-6.5.2.
2017-01-14 00:05:42 +00:00
if sc . curPushedStreams + 1 > sc . clientMaxStreams {
return 0 , http2ErrPushLimitReached
}
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-5.1.1.
// Streams initiated by the server MUST use even-numbered identifiers.
// A server that is unable to establish a new stream identifier can send a GOAWAY
// frame so that the client is forced to open a new connection for new streams.
2017-01-14 00:05:42 +00:00
if sc . maxPushPromiseID + 2 >= 1 << 31 {
2017-09-14 17:11:35 +00:00
sc . startGracefulShutdownInternal ( )
2017-01-14 00:05:42 +00:00
return 0 , http2ErrPushLimitReached
}
sc . maxPushPromiseID += 2
promisedID := sc . maxPushPromiseID
2017-09-14 17:11:35 +00:00
// http://tools.ietf.org/html/rfc7540#section-8.2.
// Strictly speaking, the new stream should start in "reserved (local)", then
// transition to "half closed (remote)" after sending the initial HEADERS, but
// we start in "half closed (remote)" for simplicity.
// See further comments at the definition of stateHalfClosedRemote.
2017-01-14 00:05:42 +00:00
promised := sc . newStream ( promisedID , msg . parent . id , http2stateHalfClosedRemote )
rw , req , err := sc . newWriterAndRequestNoBody ( promised , http2requestParam {
method : msg . method ,
scheme : msg . url . Scheme ,
authority : msg . url . Host ,
path : msg . url . RequestURI ( ) ,
2017-09-14 17:11:35 +00:00
header : http2cloneHeader ( msg . header ) , // clone since handler runs concurrently with writing the PUSH_PROMISE
2017-01-14 00:05:42 +00:00
} )
if err != nil {
2017-09-14 17:11:35 +00:00
// Should not happen, since we've already validated msg.url.
2017-01-14 00:05:42 +00:00
panic ( fmt . Sprintf ( "newWriterAndRequestNoBody(%+v): %v" , msg . url , err ) )
}
go sc . runHandler ( rw , req , sc . handler . ServeHTTP )
return promisedID , nil
}
sc . writeFrame ( http2FrameWriteRequest {
write : & http2writePushPromise {
streamID : msg . parent . id ,
method : msg . method ,
url : msg . url ,
h : msg . header ,
allocatePromisedID : allocatePromisedID ,
} ,
stream : msg . parent ,
done : msg . done ,
} )
}
2016-02-03 21:58:02 +00:00
// foreachHeaderElement splits v according to the "#rule" construction
2018-09-24 21:46:21 +00:00
// in RFC 7230 section 7 and calls fn for each non-empty element.
2016-02-03 21:58:02 +00:00
func http2foreachHeaderElement ( v string , fn func ( string ) ) {
v = textproto . TrimString ( v )
if v == "" {
return
}
if ! strings . Contains ( v , "," ) {
fn ( v )
return
}
for _ , f := range strings . Split ( v , "," ) {
if f = textproto . TrimString ( f ) ; f != "" {
fn ( f )
}
}
}
2016-07-22 18:15:38 +00:00
// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2
var http2connHeaders = [ ] string {
"Connection" ,
"Keep-Alive" ,
"Proxy-Connection" ,
"Transfer-Encoding" ,
"Upgrade" ,
}
2017-01-14 00:05:42 +00:00
// checkValidHTTP2RequestHeaders checks whether h is a valid HTTP/2 request,
2016-07-22 18:15:38 +00:00
// per RFC 7540 Section 8.1.2.2.
// The returned error is reported to users.
2017-01-14 00:05:42 +00:00
func http2checkValidHTTP2RequestHeaders ( h Header ) error {
for _ , k := range http2connHeaders {
if _ , ok := h [ k ] ; ok {
return fmt . Errorf ( "request header %q is not valid in HTTP/2" , k )
2016-07-22 18:15:38 +00:00
}
}
2017-01-14 00:05:42 +00:00
te := h [ "Te" ]
2016-07-22 18:15:38 +00:00
if len ( te ) > 0 && ( len ( te ) > 1 || ( te [ 0 ] != "trailers" && te [ 0 ] != "" ) ) {
return errors . New ( ` request header "TE" may only be "trailers" in HTTP/2 ` )
}
return nil
}
func http2new400Handler ( err error ) HandlerFunc {
return func ( w ResponseWriter , r * Request ) {
Error ( w , err . Error ( ) , StatusBadRequest )
}
}
2017-01-14 00:05:42 +00:00
// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
// disabled. See comments on h1ServerShutdownChan above for why
// the code is written this way.
func http2h1ServerKeepAlivesDisabled ( hs * Server ) bool {
var x interface { } = hs
type I interface {
doKeepAlives ( ) bool
}
if hs , ok := x . ( I ) ; ok {
return ! hs . doKeepAlives ( )
}
return false
}
2022-02-11 14:53:56 -08:00
func ( sc * http2serverConn ) countError ( name string , err error ) error {
if sc == nil || sc . srv == nil {
return err
}
f := sc . srv . CountError
if f == nil {
return err
}
var typ string
var code http2ErrCode
switch e := err . ( type ) {
case http2ConnectionError :
typ = "conn"
code = http2ErrCode ( e )
case http2StreamError :
typ = "stream"
code = http2ErrCode ( e . Code )
default :
return err
}
codeStr := http2errCodeName [ code ]
if codeStr == "" {
codeStr = strconv . Itoa ( int ( code ) )
}
f ( fmt . Sprintf ( "%s_%s_%s" , typ , codeStr , name ) )
return err
}
2016-02-03 21:58:02 +00:00
const (
// transportDefaultConnFlow is how many connection-level flow control
// tokens we give the server at start-up, past the default 64k.
http2transportDefaultConnFlow = 1 << 30
// transportDefaultStreamFlow is how many stream-level flow
// control tokens we announce to the peer, and how many bytes
// we buffer per stream.
http2transportDefaultStreamFlow = 4 << 20
// transportDefaultStreamMinRefresh is the minimum number of bytes we'll send
// a stream-level WINDOW_UPDATE for at a time.
http2transportDefaultStreamMinRefresh = 4 << 10
http2defaultUserAgent = "Go-http-client/2.0"
2022-02-11 14:53:56 -08:00
// initialMaxConcurrentStreams is a connections maxConcurrentStreams until
// it's received servers initial SETTINGS frame, which corresponds with the
// spec's minimum recommended value.
http2initialMaxConcurrentStreams = 100
// defaultMaxConcurrentStreams is a connections default maxConcurrentStreams
// if the server doesn't include one in its initial SETTINGS frame.
http2defaultMaxConcurrentStreams = 1000
2016-02-03 21:58:02 +00:00
)
// Transport is an HTTP/2 Transport.
//
// A Transport internally caches connections to servers. It is safe
// for concurrent use by multiple goroutines.
type http2Transport struct {
// DialTLS specifies an optional dial function for creating
// TLS connections for requests.
//
// If DialTLS is nil, tls.Dial is used.
//
// If the returned net.Conn has a ConnectionState method like tls.Conn,
// it will be used to set http.Response.TLS.
DialTLS func ( network , addr string , cfg * tls . Config ) ( net . Conn , error )
// TLSClientConfig specifies the TLS configuration to use with
// tls.Client. If nil, the default configuration is used.
TLSClientConfig * tls . Config
// ConnPool optionally specifies an alternate connection pool to use.
// If nil, the default is used.
ConnPool http2ClientConnPool
// DisableCompression, if true, prevents the Transport from
// requesting compression with an "Accept-Encoding: gzip"
// request header when the Request contains no existing
// Accept-Encoding value. If the Transport requests gzip on
// its own and gets a gzipped response, it's transparently
// decoded in the Response.Body. However, if the user
// explicitly requested gzip it is not automatically
// uncompressed.
DisableCompression bool
2016-07-22 18:15:38 +00:00
// AllowHTTP, if true, permits HTTP/2 requests using the insecure,
// plain-text "http" scheme. Note that this does not enable h2c support.
AllowHTTP bool
2016-02-03 21:58:02 +00:00
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
// send in the initial settings frame. It is how many bytes
2018-01-09 01:23:08 +00:00
// of response headers are allowed. Unlike the http2 spec, zero here
2016-02-03 21:58:02 +00:00
// means to use a default limit (currently 10MB). If you actually
2020-07-27 22:27:54 -07:00
// want to advertise an unlimited value to the peer, Transport
2016-02-03 21:58:02 +00:00
// interprets the highest possible value here (0xffffffff or 1<<32-1)
// to mean no limit.
MaxHeaderListSize uint32
2019-01-18 19:04:36 +00:00
// StrictMaxConcurrentStreams controls whether the server's
// SETTINGS_MAX_CONCURRENT_STREAMS should be respected
// globally. If false, new TCP connections are created to the
// server as needed to keep each under the per-connection
// SETTINGS_MAX_CONCURRENT_STREAMS limit. If true, the
// server's SETTINGS_MAX_CONCURRENT_STREAMS is interpreted as
// a global limit and callers of RoundTrip block when needed,
// waiting for their turn.
StrictMaxConcurrentStreams bool
2020-12-23 09:57:37 -08:00
// ReadIdleTimeout is the timeout after which a health check using ping
// frame will be carried out if no frame is received on the connection.
// Note that a ping response will is considered a received frame, so if
// there is no other traffic on the connection, the health check will
// be performed every ReadIdleTimeout interval.
// If zero, no health check is performed.
ReadIdleTimeout time . Duration
// PingTimeout is the timeout after which the connection will be closed
// if a response to Ping is not received.
// Defaults to 15s.
PingTimeout time . Duration
2022-02-11 14:53:56 -08:00
// WriteByteTimeout is the timeout after which the connection will be
// closed no data can be written to it. The timeout begins when data is
// available to write, and is extended whenever any bytes are written.
WriteByteTimeout time . Duration
// CountError, if non-nil, is called on HTTP/2 transport errors.
// It's intended to increment a metric for monitoring, such
// as an expvar or Prometheus metric.
// The errType consists of only ASCII word characters.
CountError func ( errType string )
2016-02-03 21:58:02 +00:00
// t1, if non-nil, is the standard library Transport using
// this transport. Its settings are used (but not its
// RoundTrip method, etc).
t1 * Transport
connPoolOnce sync . Once
connPoolOrDef http2ClientConnPool // non-nil version of ConnPool
}
func ( t * http2Transport ) maxHeaderListSize ( ) uint32 {
if t . MaxHeaderListSize == 0 {
return 10 << 20
}
if t . MaxHeaderListSize == 0xffffffff {
return 0
}
return t . MaxHeaderListSize
}
func ( t * http2Transport ) disableCompression ( ) bool {
return t . DisableCompression || ( t . t1 != nil && t . t1 . DisableCompression )
}
2020-12-23 09:57:37 -08:00
func ( t * http2Transport ) pingTimeout ( ) time . Duration {
if t . PingTimeout == 0 {
return 15 * time . Second
}
return t . PingTimeout
}
2016-02-03 21:58:02 +00:00
// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
2019-01-18 19:04:36 +00:00
// It returns an error if t1 has already been HTTP/2-enabled.
2020-12-23 09:57:37 -08:00
//
// Use ConfigureTransports instead to configure the HTTP/2 Transport.
2016-02-03 21:58:02 +00:00
func http2ConfigureTransport ( t1 * Transport ) error {
2020-12-23 09:57:37 -08:00
_ , err := http2ConfigureTransports ( t1 )
2016-02-03 21:58:02 +00:00
return err
}
2020-12-23 09:57:37 -08:00
// ConfigureTransports configures a net/http HTTP/1 Transport to use HTTP/2.
// It returns a new HTTP/2 Transport for further configuration.
// It returns an error if t1 has already been HTTP/2-enabled.
func http2ConfigureTransports ( t1 * Transport ) ( * http2Transport , error ) {
return http2configureTransports ( t1 )
}
func http2configureTransports ( t1 * Transport ) ( * http2Transport , error ) {
2019-01-18 19:04:36 +00:00
connPool := new ( http2clientConnPool )
t2 := & http2Transport {
ConnPool : http2noDialClientConnPool { connPool } ,
t1 : t1 ,
}
connPool . t = t2
if err := http2registerHTTPSProtocol ( t1 , http2noDialH2RoundTripper { t2 } ) ; err != nil {
return nil , err
}
if t1 . TLSClientConfig == nil {
t1 . TLSClientConfig = new ( tls . Config )
}
if ! http2strSliceContains ( t1 . TLSClientConfig . NextProtos , "h2" ) {
t1 . TLSClientConfig . NextProtos = append ( [ ] string { "h2" } , t1 . TLSClientConfig . NextProtos ... )
}
if ! http2strSliceContains ( t1 . TLSClientConfig . NextProtos , "http/1.1" ) {
t1 . TLSClientConfig . NextProtos = append ( t1 . TLSClientConfig . NextProtos , "http/1.1" )
}
upgradeFn := func ( authority string , c * tls . Conn ) RoundTripper {
addr := http2authorityAddr ( "https" , authority )
if used , err := connPool . addConnIfNeeded ( addr , t2 , c ) ; err != nil {
go c . Close ( )
return http2erringRoundTripper { err }
} else if ! used {
// Turns out we don't need this c.
// For example, two goroutines made requests to the same host
// at the same time, both kicking off TCP dials. (since protocol
// was unknown)
go c . Close ( )
}
return t2
}
if m := t1 . TLSNextProto ; len ( m ) == 0 {
t1 . TLSNextProto = map [ string ] func ( string , * tls . Conn ) RoundTripper {
"h2" : upgradeFn ,
}
} else {
m [ "h2" ] = upgradeFn
}
return t2 , nil
}
2016-02-03 21:58:02 +00:00
func ( t * http2Transport ) connPool ( ) http2ClientConnPool {
t . connPoolOnce . Do ( t . initConnPool )
return t . connPoolOrDef
}
func ( t * http2Transport ) initConnPool ( ) {
if t . ConnPool != nil {
t . connPoolOrDef = t . ConnPool
} else {
t . connPoolOrDef = & http2clientConnPool { t : t }
}
}
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
type http2ClientConn struct {
2022-02-11 14:53:56 -08:00
t * http2Transport
tconn net . Conn // usually *tls.Conn, except specialized impls
tlsState * tls . ConnectionState // nil only for specialized impls
reused uint32 // whether conn is being reused; atomic
singleUse bool // whether being used for a single http.Request
getConnCalled bool // used by clientConnPool
2016-02-03 21:58:02 +00:00
// readLoop goroutine fields:
readerDone chan struct { } // closed on error
readerErr error // set before readerDone is closed
2017-01-14 00:05:42 +00:00
idleTimeout time . Duration // or 0 for never
idleTimer * time . Timer
2016-09-10 13:14:00 +00:00
mu sync . Mutex // guards following
cond * sync . Cond // hold mu; broadcast on flow/closed changes
flow http2flow // our conn-level flow control quota (cs.flow is per stream)
inflow http2flow // peer's conn-level flow control
2022-02-11 14:53:56 -08:00
doNotReuse bool // whether conn is marked to not be reused for any future requests
2018-09-24 21:46:21 +00:00
closing bool
2016-09-10 13:14:00 +00:00
closed bool
2022-02-11 14:53:56 -08:00
seenSettings bool // true if we've seen a settings frame, false otherwise
2016-09-10 13:14:00 +00:00
wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
goAway * http2GoAwayFrame // if non-nil, the GoAwayFrame we received
goAwayDebug string // goAway frame's debug data, retained as a string
streams map [ uint32 ] * http2clientStream // client-initiated
2022-02-11 14:53:56 -08:00
streamsReserved int // incr by ReserveNewRequest; decr on RoundTrip
2016-09-10 13:14:00 +00:00
nextStreamID uint32
2018-01-09 01:23:08 +00:00
pendingRequests int // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams
2017-01-14 00:05:42 +00:00
pings map [ [ 8 ] byte ] chan struct { } // in flight ping data to notification channel
2016-09-10 13:14:00 +00:00
br * bufio . Reader
lastActive time . Time
2020-01-02 15:05:27 -08:00
lastIdle time . Time // time last idle
2022-02-11 14:53:56 -08:00
// Settings from peer: (also guarded by wmu)
2018-01-09 01:23:08 +00:00
maxFrameSize uint32
maxConcurrentStreams uint32
peerMaxHeaderListSize uint64
initialWindowSize uint32
2016-09-10 13:14:00 +00:00
2022-02-11 14:53:56 -08:00
// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
// Write to reqHeaderMu to lock it, read from it to unlock.
// Lock reqmu BEFORE mu or wmu.
reqHeaderMu chan struct { }
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
// wmu is held while writing.
// Acquire BEFORE mu when holding both, to avoid blocking mu on network writes.
// Only acquire both at the same time when changing peer settings.
wmu sync . Mutex
bw * bufio . Writer
fr * http2Framer
werr error // first write error that has occurred
hbuf bytes . Buffer // HPACK encoder writes into this
henc * hpack . Encoder
2016-02-03 21:58:02 +00:00
}
// clientStream is the state for a single HTTP/2 stream. One of these
// is created for each Transport.RoundTrip call.
type http2clientStream struct {
2022-02-11 14:53:56 -08:00
cc * http2ClientConn
// Fields of Request that we may access even after the response body is closed.
ctx context . Context
reqCancel <- chan struct { }
2019-01-18 19:04:36 +00:00
trace * httptrace . ClientTrace // or nil
2016-02-03 21:58:02 +00:00
ID uint32
bufPipe http2pipe // buffered pipe with the flow-controlled response payload
requestedGzip bool
2022-02-11 14:53:56 -08:00
isHead bool
abortOnce sync . Once
abort chan struct { } // closed to signal stream should end immediately
abortErr error // set if abort is closed
peerClosed chan struct { } // closed when the peer sends an END_STREAM flag
donec chan struct { } // closed after the stream is in the closed state
on100 chan struct { } // buffered; written to if a 100 is received
respHeaderRecv chan struct { } // closed when headers are received
res * Response // set if respHeaderRecv is closed
2016-02-03 21:58:02 +00:00
flow http2flow // guarded by cc.mu
inflow http2flow // guarded by cc.mu
bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read
readErr error // sticky read error; owned by transportResponseBody.Read
2022-02-11 14:53:56 -08:00
reqBody io . ReadCloser
reqBodyContentLength int64 // -1 means unknown
reqBodyClosed bool // body has been closed; guarded by cc.mu
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
// owned by writeRequest:
sentEndStream bool // sent an END_STREAM flag to the peer
sentHeaders bool
2016-02-03 21:58:02 +00:00
// owned by clientConnReadLoop:
2018-09-24 21:46:21 +00:00
firstByte bool // got the first response byte
pastHeaders bool // got first MetaHeadersFrame (actual headers)
pastTrailers bool // got optional second MetaHeadersFrame (trailers)
num1xx uint8 // number of 1xx responses seen
2022-02-11 14:53:56 -08:00
readClosed bool // peer sent an END_STREAM flag
readAborted bool // read loop reset the stream
2016-02-03 21:58:02 +00:00
trailer Header // accumulated trailers
resTrailer * Header // client's Response.Trailer
}
2018-09-24 21:46:21 +00:00
var http2got1xxFuncForTests func ( int , textproto . MIMEHeader ) error
// get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func,
// if any. It returns nil if not set or if the Go version is too old.
func ( cs * http2clientStream ) get1xxTraceFunc ( ) func ( int , textproto . MIMEHeader ) error {
if fn := http2got1xxFuncForTests ; fn != nil {
return fn
}
return http2traceGot1xxResponseFunc ( cs . trace )
}
2022-02-11 14:53:56 -08:00
func ( cs * http2clientStream ) abortStream ( err error ) {
cs . cc . mu . Lock ( )
defer cs . cc . mu . Unlock ( )
cs . abortStreamLocked ( err )
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
func ( cs * http2clientStream ) abortStreamLocked ( err error ) {
cs . abortOnce . Do ( func ( ) {
cs . abortErr = err
close ( cs . abort )
} )
if cs . reqBody != nil && ! cs . reqBodyClosed {
cs . reqBody . Close ( )
cs . reqBodyClosed = true
2017-01-14 00:05:42 +00:00
}
2022-02-11 14:53:56 -08:00
// TODO(dneil): Clean up tests where cs.cc.cond is nil.
if cs . cc . cond != nil {
// Wake up writeRequestBody if it is waiting on flow control.
cs . cc . cond . Broadcast ( )
2016-02-03 21:58:02 +00:00
}
}
2022-02-11 14:53:56 -08:00
func ( cs * http2clientStream ) abortRequestBodyWrite ( ) {
2018-01-09 01:23:08 +00:00
cc := cs . cc
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
2022-02-11 14:53:56 -08:00
if cs . reqBody != nil && ! cs . reqBodyClosed {
cs . reqBody . Close ( )
cs . reqBodyClosed = true
cc . cond . Broadcast ( )
2016-02-03 21:58:02 +00:00
}
}
type http2stickyErrWriter struct {
2022-02-11 14:53:56 -08:00
conn net . Conn
timeout time . Duration
err * error
2016-02-03 21:58:02 +00:00
}
func ( sew http2stickyErrWriter ) Write ( p [ ] byte ) ( n int , err error ) {
if * sew . err != nil {
return 0 , * sew . err
}
2022-02-11 14:53:56 -08:00
for {
if sew . timeout != 0 {
sew . conn . SetWriteDeadline ( time . Now ( ) . Add ( sew . timeout ) )
}
nn , err := sew . conn . Write ( p [ n : ] )
n += nn
if n < len ( p ) && nn > 0 && errors . Is ( err , os . ErrDeadlineExceeded ) {
// Keep extending the deadline so long as we're making progress.
continue
}
if sew . timeout != 0 {
sew . conn . SetWriteDeadline ( time . Time { } )
}
* sew . err = err
return n , err
}
2016-02-03 21:58:02 +00:00
}
2018-09-24 21:46:21 +00:00
// noCachedConnError is the concrete type of ErrNoCachedConn, which
// needs to be detected by net/http regardless of whether it's its
// bundled version (in h2_bundle.go with a rewritten type name) or
// from a user's x/net/http2. As such, as it has a unique method name
// (IsHTTP2NoCachedConnError) that net/http sniffs for via func
// isNoCachedConnError.
2018-01-17 14:20:29 +00:00
type http2noCachedConnError struct { }
func ( http2noCachedConnError ) IsHTTP2NoCachedConnError ( ) { }
func ( http2noCachedConnError ) Error ( ) string { return "http2: no cached connection was available" }
// isNoCachedConnError reports whether err is of type noCachedConnError
// or its equivalent renamed type in net/http2's h2_bundle.go. Both types
// may coexist in the same running program.
func http2isNoCachedConnError ( err error ) bool {
2018-09-24 21:46:21 +00:00
_ , ok := err . ( interface { IsHTTP2NoCachedConnError ( ) } )
2018-01-17 14:20:29 +00:00
return ok
}
var http2ErrNoCachedConn error = http2noCachedConnError { }
2016-02-03 21:58:02 +00:00
// RoundTripOpt are options for the Transport.RoundTripOpt method.
type http2RoundTripOpt struct {
// OnlyCachedConn controls whether RoundTripOpt may
// create a new TCP connection. If set true and
// no cached connection is available, RoundTripOpt
// will return ErrNoCachedConn.
OnlyCachedConn bool
}
func ( t * http2Transport ) RoundTrip ( req * Request ) ( * Response , error ) {
return t . RoundTripOpt ( req , http2RoundTripOpt { } )
}
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
2016-07-22 18:15:38 +00:00
func http2authorityAddr ( scheme string , authority string ) ( addr string ) {
2017-01-14 00:05:42 +00:00
host , port , err := net . SplitHostPort ( authority )
2017-09-14 17:11:35 +00:00
if err != nil { // authority didn't have a port
2017-01-14 00:05:42 +00:00
port = "443"
if scheme == "http" {
port = "80"
}
host = authority
}
if a , err := idna . ToASCII ( host ) ; err == nil {
host = a
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// IPv6 address literal, without a port:
2017-01-14 00:05:42 +00:00
if strings . HasPrefix ( host , "[" ) && strings . HasSuffix ( host , "]" ) {
return host + ":" + port
2016-07-22 18:15:38 +00:00
}
2017-01-14 00:05:42 +00:00
return net . JoinHostPort ( host , port )
2016-02-03 21:58:02 +00:00
}
// RoundTripOpt is like RoundTrip, but takes options.
func ( t * http2Transport ) RoundTripOpt ( req * Request , opt http2RoundTripOpt ) ( * Response , error ) {
2016-07-22 18:15:38 +00:00
if ! ( req . URL . Scheme == "https" || ( req . URL . Scheme == "http" && t . AllowHTTP ) ) {
2016-02-03 21:58:02 +00:00
return nil , errors . New ( "http2: unsupported scheme" )
}
2016-07-22 18:15:38 +00:00
addr := http2authorityAddr ( req . URL . Scheme , req . URL . Host )
2018-01-09 01:23:08 +00:00
for retry := 0 ; ; retry ++ {
2016-02-03 21:58:02 +00:00
cc , err := t . connPool ( ) . GetClientConn ( req , addr )
if err != nil {
t . vlogf ( "http2: Transport failed to get client conn for %s: %v" , addr , err )
return nil , err
}
2019-09-06 18:12:46 +00:00
reused := ! atomic . CompareAndSwapUint32 ( & cc . reused , 0 , 1 )
http2traceGotConn ( req , cc , reused )
2022-02-11 14:53:56 -08:00
res , err := cc . RoundTrip ( req )
2018-01-09 01:23:08 +00:00
if err != nil && retry <= 6 {
2022-02-11 14:53:56 -08:00
if req , err = http2shouldRetryRequest ( req , err ) ; err == nil {
2018-01-09 01:23:08 +00:00
// After the first retry, do exponential backoff with 10% jitter.
if retry == 0 {
continue
}
backoff := float64 ( uint ( 1 ) << ( uint ( retry ) - 1 ) )
backoff += backoff * ( 0.1 * mathrand . Float64 ( ) )
select {
case <- time . After ( time . Second * time . Duration ( backoff ) ) :
continue
2019-01-18 19:04:36 +00:00
case <- req . Context ( ) . Done ( ) :
2022-02-11 14:53:56 -08:00
err = req . Context ( ) . Err ( )
2018-01-09 01:23:08 +00:00
}
2017-01-14 00:05:42 +00:00
}
2016-02-03 21:58:02 +00:00
}
if err != nil {
t . vlogf ( "RoundTrip failure: %v" , err )
return nil , err
}
return res , nil
}
}
// CloseIdleConnections closes any connections which were previously
// connected from previous requests but are now sitting idle.
// It does not interrupt any connections currently in use.
func ( t * http2Transport ) CloseIdleConnections ( ) {
2016-07-22 18:15:38 +00:00
if cp , ok := t . connPool ( ) . ( http2clientConnPoolIdleCloser ) ; ok {
2016-02-03 21:58:02 +00:00
cp . closeIdleConnections ( )
}
}
var (
2018-01-09 01:23:08 +00:00
http2errClientConnClosed = errors . New ( "http2: client conn is closed" )
http2errClientConnUnusable = errors . New ( "http2: client conn not usable" )
http2errClientConnGotGoAway = errors . New ( "http2: Transport received Server's graceful shutdown GOAWAY" )
2016-02-03 21:58:02 +00:00
)
2017-01-14 00:05:42 +00:00
// shouldRetryRequest is called by RoundTrip when a request fails to get
// response headers. It is always called with a non-nil error.
// It returns either a request to retry (either the same request, or a
// modified clone), or an error if the request can't be replayed.
2022-02-11 14:53:56 -08:00
func http2shouldRetryRequest ( req * Request , err error ) ( * Request , error ) {
2018-01-09 01:23:08 +00:00
if ! http2canRetryError ( err ) {
2017-01-14 00:05:42 +00:00
return nil , err
2018-01-09 01:23:08 +00:00
}
// If the Body is nil (or http.NoBody), it's safe to reuse
// this request and its Body.
2019-01-18 19:04:36 +00:00
if req . Body == nil || req . Body == NoBody {
2018-01-09 01:23:08 +00:00
return req , nil
}
2018-09-24 21:46:21 +00:00
// If the request body can be reset back to its original
// state via the optional req.GetBody, do that.
2019-01-18 19:04:36 +00:00
if req . GetBody != nil {
body , err := req . GetBody ( )
2018-09-24 21:46:21 +00:00
if err != nil {
return nil , err
}
newReq := * req
newReq . Body = body
return & newReq , nil
2018-01-09 01:23:08 +00:00
}
2018-09-24 21:46:21 +00:00
// The Request.Body can't reset back to the beginning, but we
// don't seem to have started to read from it yet, so reuse
2022-02-11 14:53:56 -08:00
// the request directly.
if err == http2errClientConnUnusable {
2018-09-24 21:46:21 +00:00
return req , nil
2018-01-09 01:23:08 +00:00
}
2018-09-24 21:46:21 +00:00
return nil , fmt . Errorf ( "http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error" , err )
2018-01-09 01:23:08 +00:00
}
func http2canRetryError ( err error ) bool {
if err == http2errClientConnUnusable || err == http2errClientConnGotGoAway {
return true
}
if se , ok := err . ( http2StreamError ) ; ok {
2022-02-11 14:53:56 -08:00
if se . Code == http2ErrCodeProtocol && se . Cause == http2errFromPeer {
// See golang/go#47635, golang/go#42777
return true
}
2018-01-09 01:23:08 +00:00
return se . Code == http2ErrCodeRefusedStream
}
return false
2016-02-03 21:58:02 +00:00
}
2021-07-30 14:28:58 -07:00
func ( t * http2Transport ) dialClientConn ( ctx context . Context , addr string , singleUse bool ) ( * http2ClientConn , error ) {
2016-02-03 21:58:02 +00:00
host , _ , err := net . SplitHostPort ( addr )
if err != nil {
return nil , err
}
2021-07-30 14:28:58 -07:00
tconn , err := t . dialTLS ( ctx ) ( "tcp" , addr , t . newTLSConfig ( host ) )
2016-02-03 21:58:02 +00:00
if err != nil {
return nil , err
}
2016-09-10 13:14:00 +00:00
return t . newClientConn ( tconn , singleUse )
2016-02-03 21:58:02 +00:00
}
func ( t * http2Transport ) newTLSConfig ( host string ) * tls . Config {
cfg := new ( tls . Config )
if t . TLSClientConfig != nil {
2019-01-18 19:04:36 +00:00
* cfg = * t . TLSClientConfig . Clone ( )
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
if ! http2strSliceContains ( cfg . NextProtos , http2NextProtoTLS ) {
cfg . NextProtos = append ( [ ] string { http2NextProtoTLS } , cfg . NextProtos ... )
}
if cfg . ServerName == "" {
cfg . ServerName = host
}
2016-02-03 21:58:02 +00:00
return cfg
}
2021-07-30 14:28:58 -07:00
func ( t * http2Transport ) dialTLS ( ctx context . Context ) func ( string , string , * tls . Config ) ( net . Conn , error ) {
2016-02-03 21:58:02 +00:00
if t . DialTLS != nil {
return t . DialTLS
}
2021-07-30 14:28:58 -07:00
return func ( network , addr string , cfg * tls . Config ) ( net . Conn , error ) {
tlsCn , err := t . dialTLSWithContext ( ctx , network , addr , cfg )
if err != nil {
2016-02-03 21:58:02 +00:00
return nil , err
}
2021-07-30 14:28:58 -07:00
state := tlsCn . ConnectionState ( )
if p := state . NegotiatedProtocol ; p != http2NextProtoTLS {
return nil , fmt . Errorf ( "http2: unexpected ALPN protocol %q; want %q" , p , http2NextProtoTLS )
}
if ! state . NegotiatedProtocolIsMutual {
return nil , errors . New ( "http2: could not negotiate protocol mutually" )
}
return tlsCn , nil
2016-02-03 21:58:02 +00:00
}
}
// disableKeepAlives reports whether connections should be closed as
// soon as possible after handling the first request.
func ( t * http2Transport ) disableKeepAlives ( ) bool {
return t . t1 != nil && t . t1 . DisableKeepAlives
}
2016-07-22 18:15:38 +00:00
func ( t * http2Transport ) expectContinueTimeout ( ) time . Duration {
if t . t1 == nil {
return 0
}
2019-01-18 19:04:36 +00:00
return t . t1 . ExpectContinueTimeout
2016-07-22 18:15:38 +00:00
}
2016-02-03 21:58:02 +00:00
func ( t * http2Transport ) NewClientConn ( c net . Conn ) ( * http2ClientConn , error ) {
2020-01-02 15:05:27 -08:00
return t . newClientConn ( c , t . disableKeepAlives ( ) )
2016-09-10 13:14:00 +00:00
}
2016-02-03 21:58:02 +00:00
2016-09-10 13:14:00 +00:00
func ( t * http2Transport ) newClientConn ( c net . Conn , singleUse bool ) ( * http2ClientConn , error ) {
2016-02-03 21:58:02 +00:00
cc := & http2ClientConn {
2018-01-09 01:23:08 +00:00
t : t ,
tconn : c ,
readerDone : make ( chan struct { } ) ,
nextStreamID : 1 ,
2022-02-11 14:53:56 -08:00
maxFrameSize : 16 << 10 , // spec default
initialWindowSize : 65535 , // spec default
maxConcurrentStreams : http2initialMaxConcurrentStreams , // "infinite", per spec. Use a smaller value until we have received server settings.
peerMaxHeaderListSize : 0xffffffffffffffff , // "infinite", per spec. Use 2^64-1 instead.
2018-01-09 01:23:08 +00:00
streams : make ( map [ uint32 ] * http2clientStream ) ,
singleUse : singleUse ,
wantSettingsAck : true ,
pings : make ( map [ [ 8 ] byte ] chan struct { } ) ,
2022-02-11 14:53:56 -08:00
reqHeaderMu : make ( chan struct { } , 1 ) ,
2017-01-14 00:05:42 +00:00
}
if d := t . idleConnTimeout ( ) ; d != 0 {
cc . idleTimeout = d
cc . idleTimer = time . AfterFunc ( d , cc . onIdleTimeout )
2016-02-03 21:58:02 +00:00
}
2016-09-10 13:14:00 +00:00
if http2VerboseLogs {
t . vlogf ( "http2: Transport creating client conn %p to %v" , cc , c . RemoteAddr ( ) )
}
2016-02-03 21:58:02 +00:00
cc . cond = sync . NewCond ( & cc . mu )
cc . flow . add ( int32 ( http2initialWindowSize ) )
2017-09-14 17:11:35 +00:00
// TODO: adjust this writer size to account for frame size +
// MTU + crypto/tls record padding.
2022-02-11 14:53:56 -08:00
cc . bw = bufio . NewWriter ( http2stickyErrWriter {
conn : c ,
timeout : t . WriteByteTimeout ,
err : & cc . werr ,
} )
2016-02-03 21:58:02 +00:00
cc . br = bufio . NewReader ( c )
cc . fr = http2NewFramer ( cc . bw , cc . br )
2022-02-11 14:53:56 -08:00
if t . CountError != nil {
cc . fr . countError = t . CountError
}
2016-07-22 18:15:38 +00:00
cc . fr . ReadMetaHeaders = hpack . NewDecoder ( http2initialHeaderTableSize , nil )
cc . fr . MaxHeaderListSize = t . maxHeaderListSize ( )
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
// henc in response to SETTINGS frames?
2016-02-03 21:58:02 +00:00
cc . henc = hpack . NewEncoder ( & cc . hbuf )
2018-09-24 21:46:21 +00:00
if t . AllowHTTP {
cc . nextStreamID = 3
}
2016-02-18 05:56:46 +00:00
if cs , ok := c . ( http2connectionStater ) ; ok {
2016-02-03 21:58:02 +00:00
state := cs . ConnectionState ( )
cc . tlsState = & state
}
initialSettings := [ ] http2Setting {
2016-07-22 18:15:38 +00:00
{ ID : http2SettingEnablePush , Val : 0 } ,
{ ID : http2SettingInitialWindowSize , Val : http2transportDefaultStreamFlow } ,
2016-02-03 21:58:02 +00:00
}
if max := t . maxHeaderListSize ( ) ; max != 0 {
initialSettings = append ( initialSettings , http2Setting { ID : http2SettingMaxHeaderListSize , Val : max } )
}
2016-09-10 13:14:00 +00:00
cc . bw . Write ( http2clientPreface )
2016-02-03 21:58:02 +00:00
cc . fr . WriteSettings ( initialSettings ... )
cc . fr . WriteWindowUpdate ( 0 , http2transportDefaultConnFlow )
cc . inflow . add ( http2transportDefaultConnFlow + http2initialWindowSize )
cc . bw . Flush ( )
if cc . werr != nil {
2020-11-07 07:25:23 -08:00
cc . Close ( )
2016-02-03 21:58:02 +00:00
return nil , cc . werr
}
go cc . readLoop ( )
return cc , nil
}
2020-12-23 09:57:37 -08:00
func ( cc * http2ClientConn ) healthCheck ( ) {
pingTimeout := cc . t . pingTimeout ( )
// We don't need to periodically ping in the health check, because the readLoop of ClientConn will
// trigger the healthCheck again if there is no frame received.
ctx , cancel := context . WithTimeout ( context . Background ( ) , pingTimeout )
defer cancel ( )
err := cc . Ping ( ctx )
if err != nil {
cc . closeForLostPing ( )
cc . t . connPool ( ) . MarkDead ( cc )
return
}
}
2022-02-11 14:53:56 -08:00
// SetDoNotReuse marks cc as not reusable for future HTTP requests.
func ( cc * http2ClientConn ) SetDoNotReuse ( ) {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
cc . doNotReuse = true
}
2016-02-03 21:58:02 +00:00
func ( cc * http2ClientConn ) setGoAway ( f * http2GoAwayFrame ) {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
2016-07-22 18:15:38 +00:00
old := cc . goAway
2016-02-03 21:58:02 +00:00
cc . goAway = f
2016-07-22 18:15:38 +00:00
2017-09-14 17:11:35 +00:00
// Merge the previous and current GoAway error frames.
2016-07-22 18:15:38 +00:00
if cc . goAwayDebug == "" {
cc . goAwayDebug = string ( f . DebugData ( ) )
}
if old != nil && old . ErrCode != http2ErrCodeNo {
cc . goAway . ErrCode = old . ErrCode
}
2017-01-14 00:05:42 +00:00
last := f . LastStreamID
for streamID , cs := range cc . streams {
if streamID > last {
2022-02-11 14:53:56 -08:00
cs . abortStreamLocked ( http2errClientConnGotGoAway )
2017-01-14 00:05:42 +00:00
}
}
2016-02-03 21:58:02 +00:00
}
2018-01-09 01:23:08 +00:00
// CanTakeNewRequest reports whether the connection can take a new request,
// meaning it has not been closed or received or sent a GOAWAY.
2022-02-11 14:53:56 -08:00
//
// If the caller is going to immediately make a new request on this
// connection, use ReserveNewRequest instead.
2016-02-03 21:58:02 +00:00
func ( cc * http2ClientConn ) CanTakeNewRequest ( ) bool {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
return cc . canTakeNewRequestLocked ( )
}
2022-02-11 14:53:56 -08:00
// ReserveNewRequest is like CanTakeNewRequest but also reserves a
// concurrent stream in cc. The reservation is decremented on the
// next call to RoundTrip.
func ( cc * http2ClientConn ) ReserveNewRequest ( ) bool {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
if st := cc . idleStateLocked ( ) ; ! st . canTakeNewRequest {
return false
}
cc . streamsReserved ++
return true
}
// ClientConnState describes the state of a ClientConn.
type http2ClientConnState struct {
// Closed is whether the connection is closed.
Closed bool
// Closing is whether the connection is in the process of
// closing. It may be closing due to shutdown, being a
// single-use connection, being marked as DoNotReuse, or
// having received a GOAWAY frame.
Closing bool
// StreamsActive is how many streams are active.
StreamsActive int
// StreamsReserved is how many streams have been reserved via
// ClientConn.ReserveNewRequest.
StreamsReserved int
// StreamsPending is how many requests have been sent in excess
// of the peer's advertised MaxConcurrentStreams setting and
// are waiting for other streams to complete.
StreamsPending int
// MaxConcurrentStreams is how many concurrent streams the
// peer advertised as acceptable. Zero means no SETTINGS
// frame has been received yet.
MaxConcurrentStreams uint32
// LastIdle, if non-zero, is when the connection last
// transitioned to idle state.
LastIdle time . Time
}
// State returns a snapshot of cc's state.
func ( cc * http2ClientConn ) State ( ) http2ClientConnState {
cc . wmu . Lock ( )
maxConcurrent := cc . maxConcurrentStreams
if ! cc . seenSettings {
maxConcurrent = 0
}
cc . wmu . Unlock ( )
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
return http2ClientConnState {
Closed : cc . closed ,
Closing : cc . closing || cc . singleUse || cc . doNotReuse || cc . goAway != nil ,
StreamsActive : len ( cc . streams ) ,
StreamsReserved : cc . streamsReserved ,
StreamsPending : cc . pendingRequests ,
LastIdle : cc . lastIdle ,
MaxConcurrentStreams : maxConcurrent ,
}
}
2018-09-24 21:46:21 +00:00
// clientConnIdleState describes the suitability of a client
// connection to initiate a new RoundTrip request.
type http2clientConnIdleState struct {
canTakeNewRequest bool
}
func ( cc * http2ClientConn ) idleState ( ) http2clientConnIdleState {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
return cc . idleStateLocked ( )
}
func ( cc * http2ClientConn ) idleStateLocked ( ) ( st http2clientConnIdleState ) {
2016-09-10 13:14:00 +00:00
if cc . singleUse && cc . nextStreamID > 1 {
2018-09-24 21:46:21 +00:00
return
2016-09-10 13:14:00 +00:00
}
2019-01-18 19:04:36 +00:00
var maxConcurrentOkay bool
if cc . t . StrictMaxConcurrentStreams {
// We'll tell the caller we can take a new request to
// prevent the caller from dialing a new TCP
// connection, but then we'll block later before
// writing it.
maxConcurrentOkay = true
} else {
2022-02-11 14:53:56 -08:00
maxConcurrentOkay = int64 ( len ( cc . streams ) + cc . streamsReserved + 1 ) <= int64 ( cc . maxConcurrentStreams )
2019-01-18 19:04:36 +00:00
}
st . canTakeNewRequest = cc . goAway == nil && ! cc . closed && ! cc . closing && maxConcurrentOkay &&
2022-02-11 14:53:56 -08:00
! cc . doNotReuse &&
2020-01-02 15:05:27 -08:00
int64 ( cc . nextStreamID ) + 2 * int64 ( cc . pendingRequests ) < math . MaxInt32 &&
! cc . tooIdleLocked ( )
2018-09-24 21:46:21 +00:00
return
}
func ( cc * http2ClientConn ) canTakeNewRequestLocked ( ) bool {
st := cc . idleStateLocked ( )
return st . canTakeNewRequest
2016-02-03 21:58:02 +00:00
}
2020-01-02 15:05:27 -08:00
// tooIdleLocked reports whether this connection has been been sitting idle
// for too much wall time.
func ( cc * http2ClientConn ) tooIdleLocked ( ) bool {
// The Round(0) strips the monontonic clock reading so the
// times are compared based on their wall time. We don't want
// to reuse a connection that's been sitting idle during
// VM/laptop suspend if monotonic time was also frozen.
return cc . idleTimeout != 0 && ! cc . lastIdle . IsZero ( ) && time . Since ( cc . lastIdle . Round ( 0 ) ) > cc . idleTimeout
}
2017-09-14 17:11:35 +00:00
// onIdleTimeout is called from a time.AfterFunc goroutine. It will
2017-01-14 00:05:42 +00:00
// only be called when we're idle, but because we're coming from a new
// goroutine, there could be a new request coming in at the same time,
// so this simply calls the synchronized closeIfIdle to shut down this
// connection. The timer could just call closeIfIdle, but this is more
// clear.
func ( cc * http2ClientConn ) onIdleTimeout ( ) {
cc . closeIfIdle ( )
}
2016-02-03 21:58:02 +00:00
func ( cc * http2ClientConn ) closeIfIdle ( ) {
cc . mu . Lock ( )
2022-02-11 14:53:56 -08:00
if len ( cc . streams ) > 0 || cc . streamsReserved > 0 {
2016-02-03 21:58:02 +00:00
cc . mu . Unlock ( )
return
}
cc . closed = true
2016-09-10 13:14:00 +00:00
nextID := cc . nextStreamID
2017-09-14 17:11:35 +00:00
// TODO: do clients send GOAWAY too? maybe? Just Close:
2016-02-03 21:58:02 +00:00
cc . mu . Unlock ( )
2016-09-10 13:14:00 +00:00
if http2VerboseLogs {
cc . vlogf ( "http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)" , cc , cc . singleUse , nextID - 2 )
}
2016-02-03 21:58:02 +00:00
cc . tconn . Close ( )
}
2022-02-11 14:53:56 -08:00
func ( cc * http2ClientConn ) isDoNotReuseAndIdle ( ) bool {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
return cc . doNotReuse && len ( cc . streams ) == 0
}
2018-09-24 21:46:21 +00:00
var http2shutdownEnterWaitStateHook = func ( ) { }
2022-02-11 14:53:56 -08:00
// Shutdown gracefully closes the client connection, waiting for running streams to complete.
2019-01-18 19:04:36 +00:00
func ( cc * http2ClientConn ) Shutdown ( ctx context . Context ) error {
2018-09-24 21:46:21 +00:00
if err := cc . sendGoAway ( ) ; err != nil {
return err
}
// Wait for all in-flight streams to complete or connection to close
done := make ( chan error , 1 )
cancelled := false // guarded by cc.mu
go func ( ) {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
for {
if len ( cc . streams ) == 0 || cc . closed {
cc . closed = true
done <- cc . tconn . Close ( )
break
}
if cancelled {
break
}
cc . cond . Wait ( )
}
} ( )
http2shutdownEnterWaitStateHook ( )
select {
case err := <- done :
return err
case <- ctx . Done ( ) :
cc . mu . Lock ( )
// Free the goroutine above
cancelled = true
cc . cond . Broadcast ( )
cc . mu . Unlock ( )
return ctx . Err ( )
}
}
func ( cc * http2ClientConn ) sendGoAway ( ) error {
cc . mu . Lock ( )
2022-02-11 14:53:56 -08:00
closing := cc . closing
cc . closing = true
maxStreamID := cc . nextStreamID
cc . mu . Unlock ( )
if closing {
2018-09-24 21:46:21 +00:00
// GOAWAY sent already
return nil
}
2022-02-11 14:53:56 -08:00
cc . wmu . Lock ( )
defer cc . wmu . Unlock ( )
2018-09-24 21:46:21 +00:00
// Send a graceful shutdown frame to server
if err := cc . fr . WriteGoAway ( maxStreamID , http2ErrCodeNo , nil ) ; err != nil {
return err
}
if err := cc . bw . Flush ( ) ; err != nil {
return err
}
// Prevent new requests
return nil
}
2020-12-23 09:57:37 -08:00
// closes the client connection immediately. In-flight requests are interrupted.
// err is sent to streams.
func ( cc * http2ClientConn ) closeForError ( err error ) error {
2018-09-24 21:46:21 +00:00
cc . mu . Lock ( )
2022-02-11 14:53:56 -08:00
cc . closed = true
for _ , cs := range cc . streams {
cs . abortStreamLocked ( err )
}
2018-09-24 21:46:21 +00:00
defer cc . cond . Broadcast ( )
defer cc . mu . Unlock ( )
return cc . tconn . Close ( )
}
2020-12-23 09:57:37 -08:00
// Close closes the client connection immediately.
//
// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead.
func ( cc * http2ClientConn ) Close ( ) error {
err := errors . New ( "http2: client connection force closed via ClientConn.Close" )
return cc . closeForError ( err )
}
// closes the client connection immediately. In-flight requests are interrupted.
func ( cc * http2ClientConn ) closeForLostPing ( ) error {
err := errors . New ( "http2: client connection lost" )
2022-02-11 14:53:56 -08:00
if f := cc . t . CountError ; f != nil {
f ( "conn_close_lost_ping" )
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
return cc . closeForError ( err )
2016-02-03 21:58:02 +00:00
}
// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
// exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests.
var http2errRequestCanceled = errors . New ( "net/http: request canceled" )
func http2commaSeparatedTrailers ( req * Request ) ( string , error ) {
keys := make ( [ ] string , 0 , len ( req . Trailer ) )
for k := range req . Trailer {
k = CanonicalHeaderKey ( k )
switch k {
case "Transfer-Encoding" , "Trailer" , "Content-Length" :
2020-07-27 22:27:54 -07:00
return "" , fmt . Errorf ( "invalid Trailer key %q" , k )
2016-02-03 21:58:02 +00:00
}
keys = append ( keys , k )
}
if len ( keys ) > 0 {
sort . Strings ( keys )
return strings . Join ( keys , "," ) , nil
}
return "" , nil
}
func ( cc * http2ClientConn ) responseHeaderTimeout ( ) time . Duration {
if cc . t . t1 != nil {
return cc . t . t1 . ResponseHeaderTimeout
}
2017-09-14 17:11:35 +00:00
// No way to do this (yet?) with just an http2.Transport. Probably
// no need. Request.Cancel this is the new way. We only need to support
// this for compatibility with the old http.Transport fields when
// we're doing transparent http2.
2016-02-03 21:58:02 +00:00
return 0
}
2016-02-18 05:56:46 +00:00
// checkConnHeaders checks whether req has any invalid connection-level headers.
// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields.
// Certain headers are special-cased as okay but not transmitted later.
func http2checkConnHeaders ( req * Request ) error {
if v := req . Header . Get ( "Upgrade" ) ; v != "" {
2017-01-14 00:05:42 +00:00
return fmt . Errorf ( "http2: invalid Upgrade request header: %q" , req . Header [ "Upgrade" ] )
2016-02-18 05:56:46 +00:00
}
2017-01-14 00:05:42 +00:00
if vv := req . Header [ "Transfer-Encoding" ] ; len ( vv ) > 0 && ( len ( vv ) > 1 || vv [ 0 ] != "" && vv [ 0 ] != "chunked" ) {
return fmt . Errorf ( "http2: invalid Transfer-Encoding request header: %q" , vv )
2016-02-18 05:56:46 +00:00
}
2021-07-30 14:28:58 -07:00
if vv := req . Header [ "Connection" ] ; len ( vv ) > 0 && ( len ( vv ) > 1 || vv [ 0 ] != "" && ! http2asciiEqualFold ( vv [ 0 ] , "close" ) && ! http2asciiEqualFold ( vv [ 0 ] , "keep-alive" ) ) {
2017-01-14 00:05:42 +00:00
return fmt . Errorf ( "http2: invalid Connection request header: %q" , vv )
2016-02-18 05:56:46 +00:00
}
return nil
}
2017-01-14 00:05:42 +00:00
// actualContentLength returns a sanitized version of
// req.ContentLength, where 0 actually means zero (not unknown) and -1
// means unknown.
func http2actualContentLength ( req * Request ) int64 {
2019-01-18 19:04:36 +00:00
if req . Body == nil || req . Body == NoBody {
2017-01-14 00:05:42 +00:00
return 0
2016-07-22 18:15:38 +00:00
}
if req . ContentLength != 0 {
2017-01-14 00:05:42 +00:00
return req . ContentLength
2016-07-22 18:15:38 +00:00
}
2017-01-14 00:05:42 +00:00
return - 1
2016-07-22 18:15:38 +00:00
}
2022-02-11 14:53:56 -08:00
func ( cc * http2ClientConn ) decrStreamReservations ( ) {
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
cc . decrStreamReservationsLocked ( )
}
func ( cc * http2ClientConn ) decrStreamReservationsLocked ( ) {
if cc . streamsReserved > 0 {
cc . streamsReserved --
}
}
2016-02-03 21:58:02 +00:00
func ( cc * http2ClientConn ) RoundTrip ( req * Request ) ( * Response , error ) {
2022-02-11 14:53:56 -08:00
ctx := req . Context ( )
cs := & http2clientStream {
cc : cc ,
ctx : ctx ,
reqCancel : req . Cancel ,
isHead : req . Method == "HEAD" ,
reqBody : req . Body ,
reqBodyContentLength : http2actualContentLength ( req ) ,
trace : httptrace . ContextClientTrace ( ctx ) ,
peerClosed : make ( chan struct { } ) ,
abort : make ( chan struct { } ) ,
respHeaderRecv : make ( chan struct { } ) ,
donec : make ( chan struct { } ) ,
}
go cs . doRequest ( req )
waitDone := func ( ) error {
select {
case <- cs . donec :
return nil
case <- ctx . Done ( ) :
return ctx . Err ( )
case <- cs . reqCancel :
return http2errRequestCanceled
}
}
handleResponseHeaders := func ( ) ( * Response , error ) {
res := cs . res
if res . StatusCode > 299 {
// On error or status code 3xx, 4xx, 5xx, etc abort any
// ongoing write, assuming that the server doesn't care
// about our request body. If the server replied with 1xx or
// 2xx, however, then assume the server DOES potentially
// want our body (e.g. full-duplex streaming:
// golang.org/issue/13444). If it turns out the server
// doesn't, they'll RST_STREAM us soon enough. This is a
// heuristic to avoid adding knobs to Transport. Hopefully
// we can keep it.
cs . abortRequestBodyWrite ( )
}
res . Request = req
res . TLS = cc . tlsState
if res . Body == http2noBody && http2actualContentLength ( req ) == 0 {
// If there isn't a request or response body still being
// written, then wait for the stream to be closed before
// RoundTrip returns.
if err := waitDone ( ) ; err != nil {
return nil , err
}
}
return res , nil
}
for {
select {
case <- cs . respHeaderRecv :
return handleResponseHeaders ( )
case <- cs . abort :
select {
case <- cs . respHeaderRecv :
// If both cs.respHeaderRecv and cs.abort are signaling,
// pick respHeaderRecv. The server probably wrote the
// response and immediately reset the stream.
// golang.org/issue/49645
return handleResponseHeaders ( )
default :
waitDone ( )
return nil , cs . abortErr
}
case <- ctx . Done ( ) :
err := ctx . Err ( )
cs . abortStream ( err )
return nil , err
case <- cs . reqCancel :
cs . abortStream ( http2errRequestCanceled )
return nil , http2errRequestCanceled
}
}
}
// doRequest runs for the duration of the request lifetime.
//
// It sends the request and performs post-request cleanup (closing Request.Body, etc.).
func ( cs * http2clientStream ) doRequest ( req * Request ) {
err := cs . writeRequest ( req )
cs . cleanupWriteRequest ( err )
2018-01-09 01:23:08 +00:00
}
2022-02-11 14:53:56 -08:00
// writeRequest sends a request.
//
// It returns nil after the request is written, the response read,
// and the request stream is half-closed by the peer.
//
// It returns non-nil if the request ends otherwise.
// If the returned error is StreamError, the error Code may be used in resetting the stream.
func ( cs * http2clientStream ) writeRequest ( req * Request ) ( err error ) {
cc := cs . cc
ctx := cs . ctx
2016-02-18 05:56:46 +00:00
if err := http2checkConnHeaders ( req ) ; err != nil {
2022-02-11 14:53:56 -08:00
return err
2017-01-14 00:05:42 +00:00
}
2016-02-18 05:56:46 +00:00
2022-02-11 14:53:56 -08:00
// Acquire the new-request lock by writing to reqHeaderMu.
// This lock guards the critical section covering allocating a new stream ID
// (requires mu) and creating the stream (requires wmu).
if cc . reqHeaderMu == nil {
panic ( "RoundTrip on uninitialized ClientConn" ) // for tests
}
select {
case cc . reqHeaderMu <- struct { } { } :
case <- cs . reqCancel :
return http2errRequestCanceled
case <- ctx . Done ( ) :
return ctx . Err ( )
2016-02-03 21:58:02 +00:00
}
cc . mu . Lock ( )
2022-02-11 14:53:56 -08:00
if cc . idleTimer != nil {
cc . idleTimer . Stop ( )
}
cc . decrStreamReservationsLocked ( )
if err := cc . awaitOpenSlotForStreamLocked ( cs ) ; err != nil {
2016-02-03 21:58:02 +00:00
cc . mu . Unlock ( )
2022-02-11 14:53:56 -08:00
<- cc . reqHeaderMu
return err
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
cc . addStreamLocked ( cs ) // assigns stream ID
if http2isConnectionCloseRequest ( req ) {
cc . doNotReuse = true
}
cc . mu . Unlock ( )
2017-01-14 00:05:42 +00:00
2016-07-22 18:15:38 +00:00
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
2016-02-03 21:58:02 +00:00
if ! cc . t . disableCompression ( ) &&
req . Header . Get ( "Accept-Encoding" ) == "" &&
req . Header . Get ( "Range" ) == "" &&
2022-02-11 14:53:56 -08:00
! cs . isHead {
2017-09-14 17:11:35 +00:00
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
2019-09-12 23:22:53 +00:00
// See: https://zlib.net/zlib_faq.html#faq39
2017-09-14 17:11:35 +00:00
//
// Note that we don't request this for HEAD requests,
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// https://golang.org/issue/5522
//
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
2022-02-11 14:53:56 -08:00
cs . requestedGzip = true
2016-07-22 18:15:38 +00:00
}
2022-02-11 14:53:56 -08:00
continueTimeout := cc . t . expectContinueTimeout ( )
if continueTimeout != 0 {
if ! httpguts . HeaderValuesContainsToken ( req . Header [ "Expect" ] , "100-continue" ) {
continueTimeout = 0
} else {
cs . on100 = make ( chan struct { } , 1 )
}
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
// Past this point (where we send request headers), it is possible for
// RoundTrip to return successfully. Since the RoundTrip contract permits
// the caller to "mutate or reuse" the Request after closing the Response's Body,
// we must take care when referencing the Request from here on.
err = cs . encodeAndWriteHeaders ( req )
<- cc . reqHeaderMu
if err != nil {
return err
}
2016-07-22 18:15:38 +00:00
2022-02-11 14:53:56 -08:00
hasBody := cs . reqBodyContentLength != 0
if ! hasBody {
cs . sentEndStream = true
} else {
if continueTimeout != 0 {
http2traceWait100Continue ( cs . trace )
timer := time . NewTimer ( continueTimeout )
select {
case <- timer . C :
err = nil
case <- cs . on100 :
err = nil
case <- cs . abort :
err = cs . abortErr
case <- ctx . Done ( ) :
err = ctx . Err ( )
case <- cs . reqCancel :
err = http2errRequestCanceled
}
timer . Stop ( )
if err != nil {
http2traceWroteRequest ( cs . trace , err )
return err
}
2020-11-07 07:25:23 -08:00
}
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
if err = cs . writeRequestBody ( req ) ; err != nil {
if err != http2errStopReqBodyWrite {
http2traceWroteRequest ( cs . trace , err )
return err
}
} else {
cs . sentEndStream = true
2016-02-03 21:58:02 +00:00
}
}
2022-02-11 14:53:56 -08:00
http2traceWroteRequest ( cs . trace , err )
2016-02-03 21:58:02 +00:00
var respHeaderTimer <- chan time . Time
2022-02-11 14:53:56 -08:00
var respHeaderRecv chan struct { }
if d := cc . responseHeaderTimeout ( ) ; d != 0 {
timer := time . NewTimer ( d )
defer timer . Stop ( )
respHeaderTimer = timer . C
respHeaderRecv = cs . respHeaderRecv
}
// Wait until the peer half-closes its end of the stream,
// or until the request is aborted (via context, error, or otherwise),
// whichever comes first.
for {
select {
case <- cs . peerClosed :
return nil
case <- respHeaderTimer :
return http2errTimeout
case <- respHeaderRecv :
respHeaderRecv = nil
respHeaderTimer = nil // keep waiting for END_STREAM
case <- cs . abort :
return cs . abortErr
case <- ctx . Done ( ) :
return ctx . Err ( )
case <- cs . reqCancel :
return http2errRequestCanceled
2016-02-03 21:58:02 +00:00
}
}
2022-02-11 14:53:56 -08:00
}
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
func ( cs * http2clientStream ) encodeAndWriteHeaders ( req * Request ) error {
cc := cs . cc
ctx := cs . ctx
2016-07-22 18:15:38 +00:00
2022-02-11 14:53:56 -08:00
cc . wmu . Lock ( )
defer cc . wmu . Unlock ( )
// If the request was canceled while waiting for cc.mu, just quit.
select {
case <- cs . abort :
return cs . abortErr
case <- ctx . Done ( ) :
return ctx . Err ( )
case <- cs . reqCancel :
return http2errRequestCanceled
default :
2016-07-22 18:15:38 +00:00
}
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
// Encode headers.
//
// we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
// sent by writeRequestBody below, along with any Trailers,
// again in form HEADERS{1}, CONTINUATION{0,})
trailers , err := http2commaSeparatedTrailers ( req )
if err != nil {
return err
}
hasTrailers := trailers != ""
contentLen := http2actualContentLength ( req )
hasBody := contentLen != 0
hdrs , err := cc . encodeHeaders ( req , cs . requestedGzip , trailers , contentLen )
if err != nil {
return err
}
// Write the request.
endStream := ! hasBody && ! hasTrailers
cs . sentHeaders = true
err = cc . writeHeaders ( cs . ID , endStream , int ( cc . maxFrameSize ) , hdrs )
http2traceWroteHeaders ( cs . trace )
return err
}
// cleanupWriteRequest performs post-request tasks.
//
// If err (the result of writeRequest) is non-nil and the stream is not closed,
// cleanupWriteRequest will send a reset to the peer.
func ( cs * http2clientStream ) cleanupWriteRequest ( err error ) {
cc := cs . cc
if cs . ID == 0 {
// We were canceled before creating the stream, so return our reservation.
cc . decrStreamReservations ( )
}
// TODO: write h12Compare test showing whether
// Request.Body is closed by the Transport,
// and in multiple cases: server replies <=299 and >299
// while still writing request body
cc . mu . Lock ( )
bodyClosed := cs . reqBodyClosed
cs . reqBodyClosed = true
cc . mu . Unlock ( )
if ! bodyClosed && cs . reqBody != nil {
cs . reqBody . Close ( )
}
if err != nil && cs . sentEndStream {
// If the connection is closed immediately after the response is read,
// we may be aborted before finishing up here. If the stream was closed
// cleanly on both sides, there is no error.
2016-02-03 21:58:02 +00:00
select {
2022-02-11 14:53:56 -08:00
case <- cs . peerClosed :
err = nil
default :
}
}
if err != nil {
cs . abortStream ( err ) // possibly redundant, but harmless
if cs . sentHeaders {
if se , ok := err . ( http2StreamError ) ; ok {
if se . Cause != http2errFromPeer {
cc . writeStreamReset ( cs . ID , se . Code , err )
}
2016-02-03 21:58:02 +00:00
} else {
2022-02-11 14:53:56 -08:00
cc . writeStreamReset ( cs . ID , http2ErrCodeCancel , err )
2016-02-03 21:58:02 +00:00
}
}
2022-02-11 14:53:56 -08:00
cs . bufPipe . CloseWithError ( err ) // no-op if already closed
} else {
if cs . sentHeaders && ! cs . sentEndStream {
cc . writeStreamReset ( cs . ID , http2ErrCodeNo , nil )
}
cs . bufPipe . CloseWithError ( http2errRequestCanceled )
}
if cs . ID != 0 {
cc . forgetStreamID ( cs . ID )
}
cc . wmu . Lock ( )
werr := cc . werr
cc . wmu . Unlock ( )
if werr != nil {
cc . Close ( )
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
close ( cs . donec )
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
// awaitOpenSlotForStream waits until len(streams) < maxConcurrentStreams.
2018-01-09 01:23:08 +00:00
// Must hold cc.mu.
2022-02-11 14:53:56 -08:00
func ( cc * http2ClientConn ) awaitOpenSlotForStreamLocked ( cs * http2clientStream ) error {
2018-01-09 01:23:08 +00:00
for {
cc . lastActive = time . Now ( )
if cc . closed || ! cc . canTakeNewRequestLocked ( ) {
return http2errClientConnUnusable
}
2020-01-02 15:05:27 -08:00
cc . lastIdle = time . Time { }
2022-02-11 14:53:56 -08:00
if int64 ( len ( cc . streams ) ) < int64 ( cc . maxConcurrentStreams ) {
2018-01-09 01:23:08 +00:00
return nil
}
cc . pendingRequests ++
cc . cond . Wait ( )
cc . pendingRequests --
2022-02-11 14:53:56 -08:00
select {
case <- cs . abort :
return cs . abortErr
default :
2018-01-09 01:23:08 +00:00
}
}
}
2016-02-03 21:58:02 +00:00
// requires cc.wmu be held
2018-01-09 01:23:08 +00:00
func ( cc * http2ClientConn ) writeHeaders ( streamID uint32 , endStream bool , maxFrameSize int , hdrs [ ] byte ) error {
2017-09-14 17:11:35 +00:00
first := true // first frame written (HEADERS is first, then CONTINUATION)
2016-02-03 21:58:02 +00:00
for len ( hdrs ) > 0 && cc . werr == nil {
chunk := hdrs
2018-01-09 01:23:08 +00:00
if len ( chunk ) > maxFrameSize {
chunk = chunk [ : maxFrameSize ]
2016-02-03 21:58:02 +00:00
}
hdrs = hdrs [ len ( chunk ) : ]
endHeaders := len ( hdrs ) == 0
if first {
cc . fr . WriteHeaders ( http2HeadersFrameParam {
StreamID : streamID ,
BlockFragment : chunk ,
EndStream : endStream ,
EndHeaders : endHeaders ,
} )
first = false
} else {
cc . fr . WriteContinuation ( streamID , endHeaders , chunk )
}
}
cc . bw . Flush ( )
return cc . werr
}
// internal error values; they don't escape to callers
var (
// abort request body write; don't send cancel
http2errStopReqBodyWrite = errors . New ( "http2: aborting request body write" )
// abort request body write, but send stream reset of cancel.
http2errStopReqBodyWriteAndCancel = errors . New ( "http2: canceling request" )
2020-01-02 15:05:27 -08:00
http2errReqBodyTooLong = errors . New ( "http2: request body larger than specified content length" )
2016-02-03 21:58:02 +00:00
)
2022-02-11 14:53:56 -08:00
// frameScratchBufferLen returns the length of a buffer to use for
// outgoing request bodies to read/write to/from.
//
// It returns max(1, min(peer's advertised max frame size,
// Request.ContentLength+1, 512KB)).
func ( cs * http2clientStream ) frameScratchBufferLen ( maxFrameSize int ) int {
const max = 512 << 10
n := int64 ( maxFrameSize )
if n > max {
n = max
}
if cl := cs . reqBodyContentLength ; cl != - 1 && cl + 1 < n {
// Add an extra byte past the declared content-length to
// give the caller's Request.Body io.Reader a chance to
// give us more bytes than they declared, so we can catch it
// early.
n = cl + 1
}
if n < 1 {
return 1
}
return int ( n ) // doesn't truncate; max is 512K
}
var http2bufPool sync . Pool // of *[]byte
func ( cs * http2clientStream ) writeRequestBody ( req * Request ) ( err error ) {
2016-02-03 21:58:02 +00:00
cc := cs . cc
2022-02-11 14:53:56 -08:00
body := cs . reqBody
2017-09-14 17:11:35 +00:00
sentEnd := false // whether we sent the final DATA frame w/ END_STREAM
2016-02-03 21:58:02 +00:00
hasTrailers := req . Trailer != nil
2022-02-11 14:53:56 -08:00
remainLen := cs . reqBodyContentLength
2020-01-02 15:05:27 -08:00
hasContentLen := remainLen != - 1
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
cc . mu . Lock ( )
maxFrameSize := int ( cc . maxFrameSize )
cc . mu . Unlock ( )
// Scratch buffer for reading into & writing from.
scratchLen := cs . frameScratchBufferLen ( maxFrameSize )
var buf [ ] byte
if bp , ok := http2bufPool . Get ( ) . ( * [ ] byte ) ; ok && len ( * bp ) >= scratchLen {
defer http2bufPool . Put ( bp )
buf = * bp
} else {
buf = make ( [ ] byte , scratchLen )
defer http2bufPool . Put ( & buf )
}
2016-02-03 21:58:02 +00:00
var sawEOF bool
for ! sawEOF {
2022-02-11 14:53:56 -08:00
n , err := body . Read ( buf [ : len ( buf ) ] )
2020-01-02 15:05:27 -08:00
if hasContentLen {
remainLen -= int64 ( n )
if remainLen == 0 && err == nil {
// The request body's Content-Length was predeclared and
// we just finished reading it all, but the underlying io.Reader
// returned the final chunk with a nil error (which is one of
// the two valid things a Reader can do at EOF). Because we'd prefer
// to send the END_STREAM bit early, double-check that we're actually
// at EOF. Subsequent reads should return (0, EOF) at this point.
// If either value is different, we return an error in one of two ways below.
2022-02-11 14:53:56 -08:00
var scratch [ 1 ] byte
2020-01-02 15:05:27 -08:00
var n1 int
2022-02-11 14:53:56 -08:00
n1 , err = body . Read ( scratch [ : ] )
2020-01-02 15:05:27 -08:00
remainLen -= int64 ( n1 )
}
if remainLen < 0 {
err = http2errReqBodyTooLong
return err
}
}
2022-02-11 14:53:56 -08:00
if err != nil {
cc . mu . Lock ( )
bodyClosed := cs . reqBodyClosed
cc . mu . Unlock ( )
switch {
case bodyClosed :
return http2errStopReqBodyWrite
case err == io . EOF :
sawEOF = true
err = nil
default :
return err
}
2016-02-03 21:58:02 +00:00
}
remain := buf [ : n ]
for len ( remain ) > 0 && err == nil {
var allowed int32
allowed , err = cs . awaitFlowControl ( len ( remain ) )
2022-02-11 14:53:56 -08:00
if err != nil {
2016-02-03 21:58:02 +00:00
return err
}
cc . wmu . Lock ( )
data := remain [ : allowed ]
remain = remain [ allowed : ]
sentEnd = sawEOF && len ( remain ) == 0 && ! hasTrailers
err = cc . fr . WriteData ( cs . ID , sentEnd , data )
if err == nil {
2017-09-14 17:11:35 +00:00
// TODO(bradfitz): this flush is for latency, not bandwidth.
// Most requests won't need this. Make this opt-in or
// opt-out? Use some heuristic on the body type? Nagel-like
// timers? Based on 'n'? Only last chunk of this for loop,
// unless flow control tokens are low? For now, always.
// If we change this, see comment below.
2016-02-03 21:58:02 +00:00
err = cc . bw . Flush ( )
}
cc . wmu . Unlock ( )
}
if err != nil {
return err
}
}
2016-09-10 13:14:00 +00:00
if sentEnd {
2017-09-14 17:11:35 +00:00
// Already sent END_STREAM (which implies we have no
// trailers) and flushed, because currently all
// WriteData frames above get a flush. So we're done.
2016-09-10 13:14:00 +00:00
return nil
}
2022-02-11 14:53:56 -08:00
// Since the RoundTrip contract permits the caller to "mutate or reuse"
// a request after the Response's Body is closed, verify that this hasn't
// happened before accessing the trailers.
2018-01-09 01:23:08 +00:00
cc . mu . Lock ( )
2022-02-11 14:53:56 -08:00
trailer := req . Trailer
err = cs . abortErr
2018-01-09 01:23:08 +00:00
cc . mu . Unlock ( )
2022-02-11 14:53:56 -08:00
if err != nil {
return err
}
2018-01-09 01:23:08 +00:00
2016-02-03 21:58:02 +00:00
cc . wmu . Lock ( )
2016-09-10 13:14:00 +00:00
defer cc . wmu . Unlock ( )
2022-02-11 14:53:56 -08:00
var trls [ ] byte
if len ( trailer ) > 0 {
trls , err = cc . encodeTrailers ( trailer )
if err != nil {
return err
}
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Two ways to send END_STREAM: either with trailers, or
// with an empty DATA frame.
2016-09-10 13:14:00 +00:00
if len ( trls ) > 0 {
2018-01-09 01:23:08 +00:00
err = cc . writeHeaders ( cs . ID , true , maxFrameSize , trls )
2016-09-10 13:14:00 +00:00
} else {
err = cc . fr . WriteData ( cs . ID , true , nil )
2016-02-03 21:58:02 +00:00
}
if ferr := cc . bw . Flush ( ) ; ferr != nil && err == nil {
err = ferr
}
return err
}
// awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow
// control tokens from the server.
// It returns either the non-zero number of tokens taken or an error
// if the stream is dead.
func ( cs * http2clientStream ) awaitFlowControl ( maxBytes int ) ( taken int32 , err error ) {
cc := cs . cc
2022-02-11 14:53:56 -08:00
ctx := cs . ctx
2016-02-03 21:58:02 +00:00
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
for {
if cc . closed {
return 0 , http2errClientConnClosed
}
2022-02-11 14:53:56 -08:00
if cs . reqBodyClosed {
return 0 , http2errStopReqBodyWrite
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
select {
case <- cs . abort :
return 0 , cs . abortErr
case <- ctx . Done ( ) :
return 0 , ctx . Err ( )
case <- cs . reqCancel :
return 0 , http2errRequestCanceled
default :
2016-02-03 21:58:02 +00:00
}
if a := cs . flow . available ( ) ; a > 0 {
take := a
if int ( take ) > maxBytes {
2017-09-14 17:11:35 +00:00
take = int32 ( maxBytes ) // can't truncate int; take is int32
2016-02-03 21:58:02 +00:00
}
if take > int32 ( cc . maxFrameSize ) {
take = int32 ( cc . maxFrameSize )
}
cs . flow . take ( take )
return take , nil
}
cc . cond . Wait ( )
}
}
2022-02-11 14:53:56 -08:00
var http2errNilRequestURL = errors . New ( "http2: Request.URI is nil" )
// requires cc.wmu be held.
2016-07-22 18:15:38 +00:00
func ( cc * http2ClientConn ) encodeHeaders ( req * Request , addGzipHeader bool , trailers string , contentLength int64 ) ( [ ] byte , error ) {
2016-02-03 21:58:02 +00:00
cc . hbuf . Reset ( )
2022-02-11 14:53:56 -08:00
if req . URL == nil {
return nil , http2errNilRequestURL
}
2016-02-03 21:58:02 +00:00
host := req . Host
if host == "" {
host = req . URL . Host
}
2018-09-24 21:46:21 +00:00
host , err := httpguts . PunycodeHostPort ( host )
2017-01-14 00:05:42 +00:00
if err != nil {
return nil , err
}
var path string
if req . Method != "CONNECT" {
path = req . URL . RequestURI ( )
if ! http2validPseudoPath ( path ) {
orig := path
path = strings . TrimPrefix ( path , req . URL . Scheme + "://" + host )
if ! http2validPseudoPath ( path ) {
if req . URL . Opaque != "" {
return nil , fmt . Errorf ( "invalid request :path %q from URL.Opaque = %q" , orig , req . URL . Opaque )
} else {
return nil , fmt . Errorf ( "invalid request :path %q" , orig )
}
}
}
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Check for any invalid headers and return an error before we
// potentially pollute our hpack state. (We want to be able to
// continue to reuse the hpack encoder for future requests)
2016-07-22 18:15:38 +00:00
for k , vv := range req . Header {
2018-09-24 21:46:21 +00:00
if ! httpguts . ValidHeaderFieldName ( k ) {
2016-07-22 18:15:38 +00:00
return nil , fmt . Errorf ( "invalid HTTP header name %q" , k )
}
for _ , v := range vv {
2018-09-24 21:46:21 +00:00
if ! httpguts . ValidHeaderFieldValue ( v ) {
2016-07-22 18:15:38 +00:00
return nil , fmt . Errorf ( "invalid HTTP header value %q for header %q" , v , k )
}
}
}
2018-01-09 01:23:08 +00:00
enumerateHeaders := func ( f func ( name , value string ) ) {
// 8.1.2.3 Request Pseudo-Header Fields
// The :path pseudo-header field includes the path and query parts of the
// target URI (the path-absolute production and optionally a '?' character
// followed by the query production (see Sections 3.3 and 3.4 of
// [RFC3986]).
f ( ":authority" , host )
2019-09-06 18:12:46 +00:00
m := req . Method
if m == "" {
m = MethodGet
}
f ( ":method" , m )
2018-01-09 01:23:08 +00:00
if req . Method != "CONNECT" {
f ( ":path" , path )
f ( ":scheme" , req . URL . Scheme )
}
if trailers != "" {
f ( "trailer" , trailers )
}
var didUA bool
for k , vv := range req . Header {
2021-07-30 14:28:58 -07:00
if http2asciiEqualFold ( k , "host" ) || http2asciiEqualFold ( k , "content-length" ) {
2018-01-09 01:23:08 +00:00
// Host is :authority, already sent.
// Content-Length is automatic, set below.
2016-02-03 21:58:02 +00:00
continue
2021-07-30 14:28:58 -07:00
} else if http2asciiEqualFold ( k , "connection" ) ||
http2asciiEqualFold ( k , "proxy-connection" ) ||
http2asciiEqualFold ( k , "transfer-encoding" ) ||
http2asciiEqualFold ( k , "upgrade" ) ||
http2asciiEqualFold ( k , "keep-alive" ) {
2018-01-09 01:23:08 +00:00
// Per 8.1.2.2 Connection-Specific Header
// Fields, don't send connection-specific
// fields. We have already checked if any
// are error-worthy so just ignore the rest.
2016-02-03 21:58:02 +00:00
continue
2021-07-30 14:28:58 -07:00
} else if http2asciiEqualFold ( k , "user-agent" ) {
2018-01-09 01:23:08 +00:00
// Match Go's http1 behavior: at most one
// User-Agent. If set to nil or empty string,
// then omit it. Otherwise if not mentioned,
// include the default (below).
didUA = true
if len ( vv ) < 1 {
continue
}
vv = vv [ : 1 ]
if vv [ 0 ] == "" {
continue
}
2021-07-30 14:28:58 -07:00
} else if http2asciiEqualFold ( k , "cookie" ) {
2020-01-02 15:05:27 -08:00
// Per 8.1.2.5 To allow for better compression efficiency, the
// Cookie header field MAY be split into separate header fields,
// each with one or more cookie-pairs.
for _ , v := range vv {
for {
p := strings . IndexByte ( v , ';' )
if p < 0 {
break
}
f ( "cookie" , v [ : p ] )
p ++
// strip space after semicolon if any.
for p + 1 <= len ( v ) && v [ p ] == ' ' {
p ++
}
v = v [ p : ]
}
if len ( v ) > 0 {
f ( "cookie" , v )
}
}
continue
2018-01-09 01:23:08 +00:00
}
for _ , v := range vv {
f ( k , v )
2016-02-03 21:58:02 +00:00
}
}
2018-01-09 01:23:08 +00:00
if http2shouldSendReqContentLength ( req . Method , contentLength ) {
f ( "content-length" , strconv . FormatInt ( contentLength , 10 ) )
}
if addGzipHeader {
f ( "accept-encoding" , "gzip" )
}
if ! didUA {
f ( "user-agent" , http2defaultUserAgent )
2016-02-03 21:58:02 +00:00
}
}
2018-01-09 01:23:08 +00:00
// Do a first pass over the headers counting bytes to ensure
// we don't exceed cc.peerMaxHeaderListSize. This is done as a
// separate pass before encoding the headers to prevent
// modifying the hpack state.
hlSize := uint64 ( 0 )
enumerateHeaders ( func ( name , value string ) {
hf := hpack . HeaderField { Name : name , Value : value }
hlSize += uint64 ( hf . Size ( ) )
} )
if hlSize > cc . peerMaxHeaderListSize {
return nil , http2errRequestHeaderListSize
2016-02-03 21:58:02 +00:00
}
2018-01-09 01:23:08 +00:00
2019-01-18 19:04:36 +00:00
trace := httptrace . ContextClientTrace ( req . Context ( ) )
2018-09-24 21:46:21 +00:00
traceHeaders := http2traceHasWroteHeaderField ( trace )
2018-01-09 01:23:08 +00:00
// Header list size is ok. Write the headers.
enumerateHeaders ( func ( name , value string ) {
2021-07-30 14:28:58 -07:00
name , ascii := http2asciiToLower ( name )
if ! ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
return
}
2018-09-24 21:46:21 +00:00
cc . writeHeader ( name , value )
if traceHeaders {
http2traceWroteHeaderField ( trace , name , value )
}
2018-01-09 01:23:08 +00:00
} )
2016-07-22 18:15:38 +00:00
return cc . hbuf . Bytes ( ) , nil
2016-02-03 21:58:02 +00:00
}
// shouldSendReqContentLength reports whether the http2.Transport should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func http2shouldSendReqContentLength ( method string , contentLength int64 ) bool {
if contentLength > 0 {
return true
}
if contentLength < 0 {
return false
}
2017-09-14 17:11:35 +00:00
// For zero bodies, whether we send a content-length depends on the method.
// It also kinda doesn't matter for http2 either way, with END_STREAM.
2016-02-03 21:58:02 +00:00
switch method {
case "POST" , "PUT" , "PATCH" :
return true
default :
return false
}
}
2022-02-11 14:53:56 -08:00
// requires cc.wmu be held.
func ( cc * http2ClientConn ) encodeTrailers ( trailer Header ) ( [ ] byte , error ) {
2016-02-03 21:58:02 +00:00
cc . hbuf . Reset ( )
2018-01-09 01:23:08 +00:00
hlSize := uint64 ( 0 )
2022-02-11 14:53:56 -08:00
for k , vv := range trailer {
2018-01-09 01:23:08 +00:00
for _ , v := range vv {
hf := hpack . HeaderField { Name : k , Value : v }
hlSize += uint64 ( hf . Size ( ) )
}
}
if hlSize > cc . peerMaxHeaderListSize {
return nil , http2errRequestHeaderListSize
}
2022-02-11 14:53:56 -08:00
for k , vv := range trailer {
2021-07-30 14:28:58 -07:00
lowKey , ascii := http2asciiToLower ( k )
if ! ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
continue
}
2018-01-09 01:23:08 +00:00
// Transfer-Encoding, etc.. have already been filtered at the
2017-09-14 17:11:35 +00:00
// start of RoundTrip
2016-02-03 21:58:02 +00:00
for _ , v := range vv {
cc . writeHeader ( lowKey , v )
}
}
2018-01-09 01:23:08 +00:00
return cc . hbuf . Bytes ( ) , nil
2016-02-03 21:58:02 +00:00
}
func ( cc * http2ClientConn ) writeHeader ( name , value string ) {
if http2VerboseLogs {
log . Printf ( "http2: Transport encoding header %q = %q" , name , value )
}
cc . henc . WriteField ( hpack . HeaderField { Name : name , Value : value } )
}
type http2resAndError struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
res * Response
err error
}
// requires cc.mu be held.
2022-02-11 14:53:56 -08:00
func ( cc * http2ClientConn ) addStreamLocked ( cs * http2clientStream ) {
2016-02-03 21:58:02 +00:00
cs . flow . add ( int32 ( cc . initialWindowSize ) )
cs . flow . setConnFlow ( & cc . flow )
cs . inflow . add ( http2transportDefaultStreamFlow )
cs . inflow . setConnFlow ( & cc . inflow )
2022-02-11 14:53:56 -08:00
cs . ID = cc . nextStreamID
2016-02-03 21:58:02 +00:00
cc . nextStreamID += 2
cc . streams [ cs . ID ] = cs
2022-02-11 14:53:56 -08:00
if cs . ID == 0 {
panic ( "assigned stream ID 0" )
}
2016-02-03 21:58:02 +00:00
}
func ( cc * http2ClientConn ) forgetStreamID ( id uint32 ) {
cc . mu . Lock ( )
2022-02-11 14:53:56 -08:00
slen := len ( cc . streams )
delete ( cc . streams , id )
if len ( cc . streams ) != slen - 1 {
panic ( "forgetting unknown stream id" )
}
cc . lastActive = time . Now ( )
if len ( cc . streams ) == 0 && cc . idleTimer != nil {
cc . idleTimer . Reset ( cc . idleTimeout )
cc . lastIdle = time . Now ( )
}
// Wake up writeRequestBody via clientStream.awaitFlowControl and
// wake up RoundTrip if there is a pending request.
cc . cond . Broadcast ( )
closeOnIdle := cc . singleUse || cc . doNotReuse || cc . t . disableKeepAlives ( )
if closeOnIdle && cc . streamsReserved == 0 && len ( cc . streams ) == 0 {
if http2VerboseLogs {
cc . vlogf ( "http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)" , cc , cc . singleUse , cc . nextStreamID - 2 )
}
cc . closed = true
defer cc . tconn . Close ( )
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
cc . mu . Unlock ( )
2016-02-03 21:58:02 +00:00
}
// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
type http2clientConnReadLoop struct {
2022-02-11 14:53:56 -08:00
_ http2incomparable
cc * http2ClientConn
2016-02-03 21:58:02 +00:00
}
// readLoop runs in its own goroutine and reads and dispatches frames.
func ( cc * http2ClientConn ) readLoop ( ) {
2018-01-09 01:23:08 +00:00
rl := & http2clientConnReadLoop { cc : cc }
2016-02-03 21:58:02 +00:00
defer rl . cleanup ( )
cc . readerErr = rl . run ( )
if ce , ok := cc . readerErr . ( http2ConnectionError ) ; ok {
cc . wmu . Lock ( )
cc . fr . WriteGoAway ( 0 , http2ErrCode ( ce ) , nil )
cc . wmu . Unlock ( )
}
}
2016-07-22 18:15:38 +00:00
// GoAwayError is returned by the Transport when the server closes the
// TCP connection after sending a GOAWAY frame.
type http2GoAwayError struct {
LastStreamID uint32
ErrCode http2ErrCode
DebugData string
}
func ( e http2GoAwayError ) Error ( ) string {
return fmt . Sprintf ( "http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q" ,
e . LastStreamID , e . ErrCode , e . DebugData )
}
2016-09-10 13:14:00 +00:00
func http2isEOFOrNetReadError ( err error ) bool {
if err == io . EOF {
return true
}
ne , ok := err . ( * net . OpError )
return ok && ne . Op == "read"
}
2016-02-03 21:58:02 +00:00
func ( rl * http2clientConnReadLoop ) cleanup ( ) {
cc := rl . cc
defer cc . tconn . Close ( )
defer cc . t . connPool ( ) . MarkDead ( cc )
defer close ( cc . readerDone )
2017-01-14 00:05:42 +00:00
if cc . idleTimer != nil {
cc . idleTimer . Stop ( )
}
2017-09-14 17:11:35 +00:00
// Close any response bodies if the server closes prematurely.
// TODO: also do this if we've written the headers but not
// gotten a response yet.
2016-02-03 21:58:02 +00:00
err := cc . readerErr
2016-07-22 18:15:38 +00:00
cc . mu . Lock ( )
2016-09-10 13:14:00 +00:00
if cc . goAway != nil && http2isEOFOrNetReadError ( err ) {
err = http2GoAwayError {
LastStreamID : cc . goAway . LastStreamID ,
ErrCode : cc . goAway . ErrCode ,
DebugData : cc . goAwayDebug ,
2016-07-22 18:15:38 +00:00
}
2016-09-10 13:14:00 +00:00
} else if err == io . EOF {
err = io . ErrUnexpectedEOF
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
cc . closed = true
2016-02-03 21:58:02 +00:00
for _ , cs := range cc . streams {
select {
2022-02-11 14:53:56 -08:00
case <- cs . peerClosed :
// The server closed the stream before closing the conn,
// so no need to interrupt it.
2016-02-03 21:58:02 +00:00
default :
2022-02-11 14:53:56 -08:00
cs . abortStreamLocked ( err )
2016-02-03 21:58:02 +00:00
}
}
cc . cond . Broadcast ( )
cc . mu . Unlock ( )
}
2022-02-11 14:53:56 -08:00
// countReadFrameError calls Transport.CountError with a string
// representing err.
func ( cc * http2ClientConn ) countReadFrameError ( err error ) {
f := cc . t . CountError
if f == nil || err == nil {
return
}
if ce , ok := err . ( http2ConnectionError ) ; ok {
errCode := http2ErrCode ( ce )
f ( fmt . Sprintf ( "read_frame_conn_error_%s" , errCode . stringToken ( ) ) )
return
}
if errors . Is ( err , io . EOF ) {
f ( "read_frame_eof" )
return
}
if errors . Is ( err , io . ErrUnexpectedEOF ) {
f ( "read_frame_unexpected_eof" )
return
}
if errors . Is ( err , http2ErrFrameTooLarge ) {
f ( "read_frame_too_large" )
return
}
f ( "read_frame_other" )
}
2016-02-03 21:58:02 +00:00
func ( rl * http2clientConnReadLoop ) run ( ) error {
cc := rl . cc
2016-09-10 13:14:00 +00:00
gotSettings := false
2020-12-23 09:57:37 -08:00
readIdleTimeout := cc . t . ReadIdleTimeout
var t * time . Timer
if readIdleTimeout != 0 {
t = time . AfterFunc ( readIdleTimeout , cc . healthCheck )
defer t . Stop ( )
}
2016-02-03 21:58:02 +00:00
for {
f , err := cc . fr . ReadFrame ( )
2020-12-23 09:57:37 -08:00
if t != nil {
t . Reset ( readIdleTimeout )
}
2016-02-03 21:58:02 +00:00
if err != nil {
2016-09-10 13:14:00 +00:00
cc . vlogf ( "http2: Transport readFrame error on conn %p: (%T) %v" , cc , err , err )
2016-02-03 21:58:02 +00:00
}
if se , ok := err . ( http2StreamError ) ; ok {
2022-02-11 14:53:56 -08:00
if cs := rl . streamByID ( se . StreamID ) ; cs != nil {
2016-09-10 13:14:00 +00:00
if se . Cause == nil {
se . Cause = cc . fr . errDetail
}
rl . endStreamError ( cs , se )
2016-07-22 18:15:38 +00:00
}
continue
2016-02-03 21:58:02 +00:00
} else if err != nil {
2022-02-11 14:53:56 -08:00
cc . countReadFrameError ( err )
2016-02-03 21:58:02 +00:00
return err
}
if http2VerboseLogs {
cc . vlogf ( "http2: Transport received %s" , http2summarizeFrame ( f ) )
}
2016-09-10 13:14:00 +00:00
if ! gotSettings {
if _ , ok := f . ( * http2SettingsFrame ) ; ! ok {
cc . logf ( "protocol error: received %T before a SETTINGS frame" , f )
return http2ConnectionError ( http2ErrCodeProtocol )
}
gotSettings = true
}
2016-02-03 21:58:02 +00:00
switch f := f . ( type ) {
2016-07-22 18:15:38 +00:00
case * http2MetaHeadersFrame :
2016-02-03 21:58:02 +00:00
err = rl . processHeaders ( f )
case * http2DataFrame :
err = rl . processData ( f )
case * http2GoAwayFrame :
err = rl . processGoAway ( f )
case * http2RSTStreamFrame :
err = rl . processResetStream ( f )
case * http2SettingsFrame :
err = rl . processSettings ( f )
case * http2PushPromiseFrame :
err = rl . processPushPromise ( f )
case * http2WindowUpdateFrame :
err = rl . processWindowUpdate ( f )
case * http2PingFrame :
err = rl . processPing ( f )
default :
cc . logf ( "Transport: unhandled response frame type %T" , f )
}
if err != nil {
2016-09-10 13:14:00 +00:00
if http2VerboseLogs {
cc . vlogf ( "http2: Transport conn %p received error from processing frame %v: %v" , cc , http2summarizeFrame ( f ) , err )
}
2016-02-03 21:58:02 +00:00
return err
}
}
}
2016-07-22 18:15:38 +00:00
func ( rl * http2clientConnReadLoop ) processHeaders ( f * http2MetaHeadersFrame ) error {
2022-02-11 14:53:56 -08:00
cs := rl . streamByID ( f . StreamID )
2016-02-03 21:58:02 +00:00
if cs == nil {
2017-09-14 17:11:35 +00:00
// We'd get here if we canceled a request while the
// server had its response still in flight. So if this
// was just something we canceled, ignore it.
2016-02-03 21:58:02 +00:00
return nil
}
2022-02-11 14:53:56 -08:00
if cs . readClosed {
rl . endStreamError ( cs , http2StreamError {
StreamID : f . StreamID ,
Code : http2ErrCodeProtocol ,
Cause : errors . New ( "protocol error: headers after END_STREAM" ) ,
} )
return nil
2018-01-09 01:23:08 +00:00
}
2016-07-22 18:15:38 +00:00
if ! cs . firstByte {
if cs . trace != nil {
2017-09-14 17:11:35 +00:00
// TODO(bradfitz): move first response byte earlier,
// when we first read the 9 byte header, not waiting
// until all the HEADERS+CONTINUATION frames have been
// merged. This works for now.
2016-07-22 18:15:38 +00:00
http2traceFirstResponseByte ( cs . trace )
}
cs . firstByte = true
2016-02-03 21:58:02 +00:00
}
if ! cs . pastHeaders {
cs . pastHeaders = true
} else {
2016-07-22 18:15:38 +00:00
return rl . processTrailers ( cs , f )
}
2016-02-03 21:58:02 +00:00
2016-07-22 18:15:38 +00:00
res , err := rl . handleResponse ( cs , f )
if err != nil {
if _ , ok := err . ( http2ConnectionError ) ; ok {
return err
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// Any other error type is a stream error.
2022-02-11 14:53:56 -08:00
rl . endStreamError ( cs , http2StreamError {
StreamID : f . StreamID ,
Code : http2ErrCodeProtocol ,
Cause : err ,
} )
2017-09-14 17:11:35 +00:00
return nil // return nil from process* funcs to keep conn alive
2016-02-03 21:58:02 +00:00
}
2016-07-22 18:15:38 +00:00
if res == nil {
2017-09-14 17:11:35 +00:00
// (nil, nil) special case. See handleResponse docs.
2016-02-03 21:58:02 +00:00
return nil
}
2016-07-22 18:15:38 +00:00
cs . resTrailer = & res . Trailer
2022-02-11 14:53:56 -08:00
cs . res = res
close ( cs . respHeaderRecv )
if f . StreamEnded ( ) {
rl . endStream ( cs )
}
2016-07-22 18:15:38 +00:00
return nil
}
2016-02-03 21:58:02 +00:00
2016-07-22 18:15:38 +00:00
// may return error types nil, or ConnectionError. Any other error value
// is a StreamError of type ErrCodeProtocol. The returned error in that case
// is the detail.
//
// As a special case, handleResponse may return (nil, nil) to skip the
2018-09-24 21:46:21 +00:00
// frame (currently only used for 1xx responses).
2016-07-22 18:15:38 +00:00
func ( rl * http2clientConnReadLoop ) handleResponse ( cs * http2clientStream , f * http2MetaHeadersFrame ) ( * Response , error ) {
if f . Truncated {
return nil , http2errResponseHeaderListSize
}
2016-02-03 21:58:02 +00:00
2016-07-22 18:15:38 +00:00
status := f . PseudoValue ( "status" )
if status == "" {
2018-01-09 01:23:08 +00:00
return nil , errors . New ( "malformed response from server: missing status pseudo header" )
2016-07-22 18:15:38 +00:00
}
statusCode , err := strconv . Atoi ( status )
if err != nil {
2018-01-09 01:23:08 +00:00
return nil , errors . New ( "malformed response from server: malformed non-numeric status pseudo header" )
2016-07-22 18:15:38 +00:00
}
2016-02-03 21:58:02 +00:00
2020-07-27 22:27:54 -07:00
regularFields := f . RegularFields ( )
strs := make ( [ ] string , len ( regularFields ) )
header := make ( Header , len ( regularFields ) )
2016-07-22 18:15:38 +00:00
res := & Response {
Proto : "HTTP/2.0" ,
ProtoMajor : 2 ,
Header : header ,
StatusCode : statusCode ,
Status : status + " " + StatusText ( statusCode ) ,
}
2020-07-27 22:27:54 -07:00
for _ , hf := range regularFields {
2016-07-22 18:15:38 +00:00
key := CanonicalHeaderKey ( hf . Name )
if key == "Trailer" {
t := res . Trailer
if t == nil {
t = make ( Header )
res . Trailer = t
}
http2foreachHeaderElement ( hf . Value , func ( v string ) {
t [ CanonicalHeaderKey ( v ) ] = nil
} )
} else {
2020-07-27 22:27:54 -07:00
vv := header [ key ]
if vv == nil && len ( strs ) > 0 {
// More than likely this will be a single-element key.
// Most headers aren't multi-valued.
// Set the capacity on strs[0] to 1, so any future append
// won't extend the slice into the other strings.
vv , strs = strs [ : 1 : 1 ] , strs [ 1 : ]
vv [ 0 ] = hf . Value
header [ key ] = vv
} else {
header [ key ] = append ( vv , hf . Value )
}
2016-07-22 18:15:38 +00:00
}
2016-02-03 21:58:02 +00:00
}
2018-09-24 21:46:21 +00:00
if statusCode >= 100 && statusCode <= 199 {
2022-02-11 14:53:56 -08:00
if f . StreamEnded ( ) {
return nil , errors . New ( "1xx informational response with END_STREAM flag" )
}
2018-09-24 21:46:21 +00:00
cs . num1xx ++
const max1xxResponses = 5 // arbitrary bound on number of informational responses, same as net/http
if cs . num1xx > max1xxResponses {
return nil , errors . New ( "http2: too many 1xx informational responses" )
}
if fn := cs . get1xxTraceFunc ( ) ; fn != nil {
if err := fn ( statusCode , textproto . MIMEHeader ( header ) ) ; err != nil {
return nil , err
}
}
if statusCode == 100 {
http2traceGot100Continue ( cs . trace )
2022-02-11 14:53:56 -08:00
select {
case cs . on100 <- struct { } { } :
default :
2018-09-24 21:46:21 +00:00
}
}
cs . pastHeaders = false // do it all again
return nil , nil
}
2022-02-11 14:53:56 -08:00
res . ContentLength = - 1
if clens := res . Header [ "Content-Length" ] ; len ( clens ) == 1 {
if cl , err := strconv . ParseUint ( clens [ 0 ] , 10 , 63 ) ; err == nil {
res . ContentLength = int64 ( cl )
} else {
2017-09-14 17:11:35 +00:00
// TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore.
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
} else if len ( clens ) > 1 {
// TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore.
} else if f . StreamEnded ( ) && ! cs . isHead {
res . ContentLength = 0
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
if cs . isHead {
2016-02-03 21:58:02 +00:00
res . Body = http2noBody
2016-07-22 18:15:38 +00:00
return res , nil
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
if f . StreamEnded ( ) {
if res . ContentLength > 0 {
res . Body = http2missingBody { }
} else {
res . Body = http2noBody
}
return res , nil
}
cs . bufPipe . setBuffer ( & http2dataBuffer { expected : res . ContentLength } )
2016-07-22 18:15:38 +00:00
cs . bytesRemain = res . ContentLength
res . Body = http2transportResponseBody { cs }
2022-02-11 14:53:56 -08:00
if cs . requestedGzip && http2asciiEqualFold ( res . Header . Get ( "Content-Encoding" ) , "gzip" ) {
2016-07-22 18:15:38 +00:00
res . Header . Del ( "Content-Encoding" )
res . Header . Del ( "Content-Length" )
res . ContentLength = - 1
res . Body = & http2gzipReader { body : res . Body }
2019-01-18 19:04:36 +00:00
res . Uncompressed = true
2016-07-22 18:15:38 +00:00
}
return res , nil
}
func ( rl * http2clientConnReadLoop ) processTrailers ( cs * http2clientStream , f * http2MetaHeadersFrame ) error {
if cs . pastTrailers {
2017-09-14 17:11:35 +00:00
// Too many HEADERS frames for this stream.
2016-07-22 18:15:38 +00:00
return http2ConnectionError ( http2ErrCodeProtocol )
}
cs . pastTrailers = true
if ! f . StreamEnded ( ) {
2017-09-14 17:11:35 +00:00
// We expect that any headers for trailers also
// has END_STREAM.
2016-07-22 18:15:38 +00:00
return http2ConnectionError ( http2ErrCodeProtocol )
}
if len ( f . PseudoFields ( ) ) > 0 {
2017-09-14 17:11:35 +00:00
// No pseudo header fields are defined for trailers.
// TODO: ConnectionError might be overly harsh? Check.
2016-07-22 18:15:38 +00:00
return http2ConnectionError ( http2ErrCodeProtocol )
}
trailer := make ( Header )
for _ , hf := range f . RegularFields ( ) {
key := CanonicalHeaderKey ( hf . Name )
trailer [ key ] = append ( trailer [ key ] , hf . Value )
}
cs . trailer = trailer
rl . endStream ( cs )
2016-02-03 21:58:02 +00:00
return nil
}
// transportResponseBody is the concrete type of Transport.RoundTrip's
2022-02-11 14:53:56 -08:00
// Response.Body. It is an io.ReadCloser.
2016-02-03 21:58:02 +00:00
type http2transportResponseBody struct {
cs * http2clientStream
}
func ( b http2transportResponseBody ) Read ( p [ ] byte ) ( n int , err error ) {
cs := b . cs
cc := cs . cc
if cs . readErr != nil {
return 0 , cs . readErr
}
n , err = b . cs . bufPipe . Read ( p )
if cs . bytesRemain != - 1 {
if int64 ( n ) > cs . bytesRemain {
n = int ( cs . bytesRemain )
if err == nil {
err = errors . New ( "net/http: server replied with more than declared Content-Length; truncated" )
2022-02-11 14:53:56 -08:00
cs . abortStream ( err )
2016-02-03 21:58:02 +00:00
}
cs . readErr = err
return int ( cs . bytesRemain ) , err
}
cs . bytesRemain -= int64 ( n )
if err == io . EOF && cs . bytesRemain > 0 {
err = io . ErrUnexpectedEOF
cs . readErr = err
return n , err
}
}
if n == 0 {
2017-09-14 17:11:35 +00:00
// No flow control tokens to send back.
2016-02-03 21:58:02 +00:00
return
}
cc . mu . Lock ( )
var connAdd , streamAdd int32
2017-09-14 17:11:35 +00:00
// Check the conn-level first, before the stream-level.
2016-02-03 21:58:02 +00:00
if v := cc . inflow . available ( ) ; v < http2transportDefaultConnFlow / 2 {
connAdd = http2transportDefaultConnFlow - v
cc . inflow . add ( connAdd )
}
2017-09-14 17:11:35 +00:00
if err == nil { // No need to refresh if the stream is over or failed.
// Consider any buffered body data (read from the conn but not
// consumed by the client) when computing flow control for this
// stream.
2016-07-22 18:15:38 +00:00
v := int ( cs . inflow . available ( ) ) + cs . bufPipe . Len ( )
if v < http2transportDefaultStreamFlow - http2transportDefaultStreamMinRefresh {
streamAdd = int32 ( http2transportDefaultStreamFlow - v )
2016-02-03 21:58:02 +00:00
cs . inflow . add ( streamAdd )
}
}
2022-02-11 14:53:56 -08:00
cc . mu . Unlock ( )
2016-02-03 21:58:02 +00:00
if connAdd != 0 || streamAdd != 0 {
cc . wmu . Lock ( )
defer cc . wmu . Unlock ( )
if connAdd != 0 {
cc . fr . WriteWindowUpdate ( 0 , http2mustUint31 ( connAdd ) )
}
if streamAdd != 0 {
cc . fr . WriteWindowUpdate ( cs . ID , http2mustUint31 ( streamAdd ) )
}
cc . bw . Flush ( )
}
return
}
var http2errClosedResponseBody = errors . New ( "http2: response body closed" )
func ( b http2transportResponseBody ) Close ( ) error {
cs := b . cs
2016-09-10 13:14:00 +00:00
cc := cs . cc
2016-02-03 21:58:02 +00:00
2016-09-10 13:14:00 +00:00
unread := cs . bufPipe . Len ( )
2022-02-11 14:53:56 -08:00
if unread > 0 {
2016-09-10 13:14:00 +00:00
cc . mu . Lock ( )
2017-09-14 17:11:35 +00:00
// Return connection-level flow control.
2016-09-10 13:14:00 +00:00
if unread > 0 {
cc . inflow . add ( int32 ( unread ) )
2022-02-11 14:53:56 -08:00
}
cc . mu . Unlock ( )
// TODO(dneil): Acquiring this mutex can block indefinitely.
// Move flow control return to a goroutine?
cc . wmu . Lock ( )
// Return connection-level flow control.
if unread > 0 {
2016-09-10 13:14:00 +00:00
cc . fr . WriteWindowUpdate ( 0 , uint32 ( unread ) )
}
cc . bw . Flush ( )
cc . wmu . Unlock ( )
2016-02-03 21:58:02 +00:00
}
2016-09-10 13:14:00 +00:00
2016-02-03 21:58:02 +00:00
cs . bufPipe . BreakWithError ( http2errClosedResponseBody )
2022-02-11 14:53:56 -08:00
cs . abortStream ( http2errClosedResponseBody )
select {
case <- cs . donec :
case <- cs . ctx . Done ( ) :
// See golang/go#49366: The net/http package can cancel the
// request context after the response body is fully read.
// Don't treat this as an error.
return nil
case <- cs . reqCancel :
return http2errRequestCanceled
}
2016-02-03 21:58:02 +00:00
return nil
}
func ( rl * http2clientConnReadLoop ) processData ( f * http2DataFrame ) error {
cc := rl . cc
2022-02-11 14:53:56 -08:00
cs := rl . streamByID ( f . StreamID )
2016-09-10 13:14:00 +00:00
data := f . Data ( )
2016-02-03 21:58:02 +00:00
if cs == nil {
cc . mu . Lock ( )
neverSent := cc . nextStreamID
cc . mu . Unlock ( )
if f . StreamID >= neverSent {
2017-09-14 17:11:35 +00:00
// We never asked for this.
2016-02-03 21:58:02 +00:00
cc . logf ( "http2: Transport received unsolicited DATA frame; closing connection" )
return http2ConnectionError ( http2ErrCodeProtocol )
}
2017-09-14 17:11:35 +00:00
// We probably did ask for this, but canceled. Just ignore it.
// TODO: be stricter here? only silently ignore things which
// we canceled, but not things which were closed normally
// by the peer? Tough without accumulating too much state.
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// But at least return their flow control:
2016-09-10 13:14:00 +00:00
if f . Length > 0 {
cc . mu . Lock ( )
cc . inflow . add ( int32 ( f . Length ) )
cc . mu . Unlock ( )
cc . wmu . Lock ( )
cc . fr . WriteWindowUpdate ( 0 , uint32 ( f . Length ) )
cc . bw . Flush ( )
cc . wmu . Unlock ( )
}
2016-02-03 21:58:02 +00:00
return nil
}
2022-02-11 14:53:56 -08:00
if cs . readClosed {
cc . logf ( "protocol error: received DATA after END_STREAM" )
rl . endStreamError ( cs , http2StreamError {
StreamID : f . StreamID ,
Code : http2ErrCodeProtocol ,
} )
return nil
}
2018-01-09 01:23:08 +00:00
if ! cs . firstByte {
cc . logf ( "protocol error: received DATA before a HEADERS frame" )
rl . endStreamError ( cs , http2StreamError {
StreamID : f . StreamID ,
Code : http2ErrCodeProtocol ,
} )
return nil
}
2016-09-10 13:14:00 +00:00
if f . Length > 0 {
2022-02-11 14:53:56 -08:00
if cs . isHead && len ( data ) > 0 {
2018-01-09 01:23:08 +00:00
cc . logf ( "protocol error: received DATA on a HEAD request" )
rl . endStreamError ( cs , http2StreamError {
StreamID : f . StreamID ,
Code : http2ErrCodeProtocol ,
} )
return nil
}
2017-09-14 17:11:35 +00:00
// Check connection-level flow control.
2016-02-03 21:58:02 +00:00
cc . mu . Lock ( )
2016-09-10 13:14:00 +00:00
if cs . inflow . available ( ) >= int32 ( f . Length ) {
cs . inflow . take ( int32 ( f . Length ) )
2016-02-03 21:58:02 +00:00
} else {
cc . mu . Unlock ( )
return http2ConnectionError ( http2ErrCodeFlowControl )
}
2017-09-14 17:11:35 +00:00
// Return any padded flow control now, since we won't
// refund it later on body reads.
var refund int
if pad := int ( f . Length ) - len ( data ) ; pad > 0 {
refund += pad
}
2022-02-11 14:53:56 -08:00
didReset := false
var err error
if len ( data ) > 0 {
if _ , err = cs . bufPipe . Write ( data ) ; err != nil {
// Return len(data) now if the stream is already closed,
// since data will never be read.
didReset = true
refund += len ( data )
}
2017-09-14 17:11:35 +00:00
}
2022-02-11 14:53:56 -08:00
2017-09-14 17:11:35 +00:00
if refund > 0 {
cc . inflow . add ( int32 ( refund ) )
2022-02-11 14:53:56 -08:00
if ! didReset {
cs . inflow . add ( int32 ( refund ) )
}
}
cc . mu . Unlock ( )
if refund > 0 {
2016-09-10 13:14:00 +00:00
cc . wmu . Lock ( )
2017-09-14 17:11:35 +00:00
cc . fr . WriteWindowUpdate ( 0 , uint32 ( refund ) )
if ! didReset {
cc . fr . WriteWindowUpdate ( cs . ID , uint32 ( refund ) )
}
2016-09-10 13:14:00 +00:00
cc . bw . Flush ( )
cc . wmu . Unlock ( )
}
2016-02-03 21:58:02 +00:00
2022-02-11 14:53:56 -08:00
if err != nil {
rl . endStreamError ( cs , err )
return nil
2016-02-03 21:58:02 +00:00
}
}
if f . StreamEnded ( ) {
rl . endStream ( cs )
}
return nil
}
func ( rl * http2clientConnReadLoop ) endStream ( cs * http2clientStream ) {
2017-09-14 17:11:35 +00:00
// TODO: check that any declared content-length matches, like
// server.go's (*stream).endStream method.
2022-02-11 14:53:56 -08:00
if ! cs . readClosed {
cs . readClosed = true
// Close cs.bufPipe and cs.peerClosed with cc.mu held to avoid a
// race condition: The caller can read io.EOF from Response.Body
// and close the body before we close cs.peerClosed, causing
// cleanupWriteRequest to send a RST_STREAM.
rl . cc . mu . Lock ( )
defer rl . cc . mu . Unlock ( )
cs . bufPipe . closeWithErrorAndCode ( io . EOF , cs . copyTrailers )
close ( cs . peerClosed )
}
2016-07-22 18:15:38 +00:00
}
func ( rl * http2clientConnReadLoop ) endStreamError ( cs * http2clientStream , err error ) {
2022-02-11 14:53:56 -08:00
cs . readAborted = true
cs . abortStream ( err )
}
2016-09-10 13:14:00 +00:00
2022-02-11 14:53:56 -08:00
func ( rl * http2clientConnReadLoop ) streamByID ( id uint32 ) * http2clientStream {
rl . cc . mu . Lock ( )
defer rl . cc . mu . Unlock ( )
cs := rl . cc . streams [ id ]
if cs != nil && ! cs . readAborted {
return cs
2016-09-10 13:14:00 +00:00
}
2022-02-11 14:53:56 -08:00
return nil
2016-02-03 21:58:02 +00:00
}
func ( cs * http2clientStream ) copyTrailers ( ) {
for k , vv := range cs . trailer {
t := cs . resTrailer
if * t == nil {
* t = make ( Header )
}
( * t ) [ k ] = vv
}
}
func ( rl * http2clientConnReadLoop ) processGoAway ( f * http2GoAwayFrame ) error {
cc := rl . cc
cc . t . connPool ( ) . MarkDead ( cc )
if f . ErrCode != 0 {
2017-09-14 17:11:35 +00:00
// TODO: deal with GOAWAY more. particularly the error code
2016-02-03 21:58:02 +00:00
cc . vlogf ( "transport got GOAWAY with error code = %v" , f . ErrCode )
2022-02-11 14:53:56 -08:00
if fn := cc . t . CountError ; fn != nil {
fn ( "recv_goaway_" + f . ErrCode . stringToken ( ) )
}
2016-02-03 21:58:02 +00:00
}
cc . setGoAway ( f )
return nil
}
func ( rl * http2clientConnReadLoop ) processSettings ( f * http2SettingsFrame ) error {
2022-02-11 14:53:56 -08:00
cc := rl . cc
// Locking both mu and wmu here allows frame encoding to read settings with only wmu held.
// Acquiring wmu when f.IsAck() is unnecessary, but convenient and mostly harmless.
cc . wmu . Lock ( )
defer cc . wmu . Unlock ( )
if err := rl . processSettingsNoWrite ( f ) ; err != nil {
return err
}
if ! f . IsAck ( ) {
cc . fr . WriteSettingsAck ( )
cc . bw . Flush ( )
}
return nil
}
func ( rl * http2clientConnReadLoop ) processSettingsNoWrite ( f * http2SettingsFrame ) error {
2016-02-03 21:58:02 +00:00
cc := rl . cc
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
2016-09-10 13:14:00 +00:00
if f . IsAck ( ) {
if cc . wantSettingsAck {
cc . wantSettingsAck = false
return nil
}
return http2ConnectionError ( http2ErrCodeProtocol )
}
2022-02-11 14:53:56 -08:00
var seenMaxConcurrentStreams bool
2016-09-10 13:14:00 +00:00
err := f . ForeachSetting ( func ( s http2Setting ) error {
2016-02-03 21:58:02 +00:00
switch s . ID {
case http2SettingMaxFrameSize :
cc . maxFrameSize = s . Val
case http2SettingMaxConcurrentStreams :
cc . maxConcurrentStreams = s . Val
2022-02-11 14:53:56 -08:00
seenMaxConcurrentStreams = true
2018-01-09 01:23:08 +00:00
case http2SettingMaxHeaderListSize :
cc . peerMaxHeaderListSize = uint64 ( s . Val )
2016-02-03 21:58:02 +00:00
case http2SettingInitialWindowSize :
2017-09-14 17:11:35 +00:00
// Values above the maximum flow-control
// window size of 2^31-1 MUST be treated as a
// connection error (Section 5.4.1) of type
// FLOW_CONTROL_ERROR.
2016-09-10 13:14:00 +00:00
if s . Val > math . MaxInt32 {
return http2ConnectionError ( http2ErrCodeFlowControl )
}
2017-09-14 17:11:35 +00:00
// Adjust flow control of currently-open
// frames by the difference of the old initial
// window size and this one.
2016-09-10 13:14:00 +00:00
delta := int32 ( s . Val ) - int32 ( cc . initialWindowSize )
for _ , cs := range cc . streams {
cs . flow . add ( delta )
}
cc . cond . Broadcast ( )
2016-02-03 21:58:02 +00:00
cc . initialWindowSize = s . Val
default :
2017-09-14 17:11:35 +00:00
// TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably.
2016-02-03 21:58:02 +00:00
cc . vlogf ( "Unhandled Setting: %v" , s )
}
return nil
} )
2016-09-10 13:14:00 +00:00
if err != nil {
return err
}
2022-02-11 14:53:56 -08:00
if ! cc . seenSettings {
if ! seenMaxConcurrentStreams {
// This was the servers initial SETTINGS frame and it
// didn't contain a MAX_CONCURRENT_STREAMS field so
// increase the number of concurrent streams this
// connection can establish to our default.
cc . maxConcurrentStreams = http2defaultMaxConcurrentStreams
}
cc . seenSettings = true
}
2016-09-10 13:14:00 +00:00
2022-02-11 14:53:56 -08:00
return nil
2016-02-03 21:58:02 +00:00
}
func ( rl * http2clientConnReadLoop ) processWindowUpdate ( f * http2WindowUpdateFrame ) error {
cc := rl . cc
2022-02-11 14:53:56 -08:00
cs := rl . streamByID ( f . StreamID )
2016-02-03 21:58:02 +00:00
if f . StreamID != 0 && cs == nil {
return nil
}
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
fl := & cc . flow
if cs != nil {
fl = & cs . flow
}
if ! fl . add ( int32 ( f . Increment ) ) {
return http2ConnectionError ( http2ErrCodeFlowControl )
}
cc . cond . Broadcast ( )
return nil
}
func ( rl * http2clientConnReadLoop ) processResetStream ( f * http2RSTStreamFrame ) error {
2022-02-11 14:53:56 -08:00
cs := rl . streamByID ( f . StreamID )
2016-02-03 21:58:02 +00:00
if cs == nil {
2022-02-11 14:53:56 -08:00
// TODO: return error if server tries to RST_STREAM an idle stream
2016-02-03 21:58:02 +00:00
return nil
}
2022-02-11 14:53:56 -08:00
serr := http2streamError ( cs . ID , f . ErrCode )
serr . Cause = http2errFromPeer
if f . ErrCode == http2ErrCodeProtocol {
rl . cc . SetDoNotReuse ( )
}
if fn := cs . cc . t . CountError ; fn != nil {
fn ( "recv_rststream_" + f . ErrCode . stringToken ( ) )
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
cs . abortStream ( serr )
cs . bufPipe . CloseWithError ( serr )
2016-02-03 21:58:02 +00:00
return nil
}
2017-01-14 00:05:42 +00:00
// Ping sends a PING frame to the server and waits for the ack.
2019-01-18 19:04:36 +00:00
func ( cc * http2ClientConn ) Ping ( ctx context . Context ) error {
2017-01-14 00:05:42 +00:00
c := make ( chan struct { } )
// Generate a random payload
var p [ 8 ] byte
for {
if _ , err := rand . Read ( p [ : ] ) ; err != nil {
return err
}
cc . mu . Lock ( )
2017-09-14 17:11:35 +00:00
// check for dup before insert
2017-01-14 00:05:42 +00:00
if _ , found := cc . pings [ p ] ; ! found {
cc . pings [ p ] = c
cc . mu . Unlock ( )
break
}
cc . mu . Unlock ( )
}
2022-02-11 14:53:56 -08:00
errc := make ( chan error , 1 )
go func ( ) {
cc . wmu . Lock ( )
defer cc . wmu . Unlock ( )
if err := cc . fr . WritePing ( false , p ) ; err != nil {
errc <- err
return
}
if err := cc . bw . Flush ( ) ; err != nil {
errc <- err
return
}
} ( )
2017-01-14 00:05:42 +00:00
select {
case <- c :
return nil
2022-02-11 14:53:56 -08:00
case err := <- errc :
return err
2017-01-14 00:05:42 +00:00
case <- ctx . Done ( ) :
return ctx . Err ( )
case <- cc . readerDone :
2017-09-14 17:11:35 +00:00
// connection closed
2017-01-14 00:05:42 +00:00
return cc . readerErr
}
}
2016-02-03 21:58:02 +00:00
func ( rl * http2clientConnReadLoop ) processPing ( f * http2PingFrame ) error {
if f . IsAck ( ) {
2017-01-14 00:05:42 +00:00
cc := rl . cc
cc . mu . Lock ( )
defer cc . mu . Unlock ( )
2017-09-14 17:11:35 +00:00
// If ack, notify listener if any
2017-01-14 00:05:42 +00:00
if c , ok := cc . pings [ f . Data ] ; ok {
close ( c )
delete ( cc . pings , f . Data )
}
2016-02-03 21:58:02 +00:00
return nil
}
cc := rl . cc
cc . wmu . Lock ( )
defer cc . wmu . Unlock ( )
if err := cc . fr . WritePing ( true , f . Data ) ; err != nil {
return err
}
return cc . bw . Flush ( )
}
func ( rl * http2clientConnReadLoop ) processPushPromise ( f * http2PushPromiseFrame ) error {
2017-09-14 17:11:35 +00:00
// We told the peer we don't want them.
// Spec says:
// "PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH
// setting of the peer endpoint is set to 0. An endpoint that
// has set this setting and has received acknowledgement MUST
// treat the receipt of a PUSH_PROMISE frame as a connection
// error (Section 5.4.1) of type PROTOCOL_ERROR."
2016-02-03 21:58:02 +00:00
return http2ConnectionError ( http2ErrCodeProtocol )
}
func ( cc * http2ClientConn ) writeStreamReset ( streamID uint32 , code http2ErrCode , err error ) {
2017-09-14 17:11:35 +00:00
// TODO: map err to more interesting error codes, once the
// HTTP community comes up with some. But currently for
// RST_STREAM there's no equivalent to GOAWAY frame's debug
// data, and the error codes are all pretty vague ("cancel").
2016-02-03 21:58:02 +00:00
cc . wmu . Lock ( )
cc . fr . WriteRSTStream ( streamID , code )
cc . bw . Flush ( )
cc . wmu . Unlock ( )
}
var (
http2errResponseHeaderListSize = errors . New ( "http2: response header list larger than advertised limit" )
2018-01-09 01:23:08 +00:00
http2errRequestHeaderListSize = errors . New ( "http2: request header list larger than peer's advertised limit" )
2016-02-03 21:58:02 +00:00
)
func ( cc * http2ClientConn ) logf ( format string , args ... interface { } ) {
cc . t . logf ( format , args ... )
}
func ( cc * http2ClientConn ) vlogf ( format string , args ... interface { } ) {
cc . t . vlogf ( format , args ... )
}
func ( t * http2Transport ) vlogf ( format string , args ... interface { } ) {
if http2VerboseLogs {
t . logf ( format , args ... )
}
}
func ( t * http2Transport ) logf ( format string , args ... interface { } ) {
log . Printf ( format , args ... )
}
var http2noBody io . ReadCloser = ioutil . NopCloser ( bytes . NewReader ( nil ) )
2022-02-11 14:53:56 -08:00
type http2missingBody struct { }
func ( http2missingBody ) Close ( ) error { return nil }
func ( http2missingBody ) Read ( [ ] byte ) ( int , error ) { return 0 , io . ErrUnexpectedEOF }
2016-02-03 21:58:02 +00:00
func http2strSliceContains ( ss [ ] string , s string ) bool {
for _ , v := range ss {
if v == s {
return true
}
}
return false
}
type http2erringRoundTripper struct { err error }
2020-12-23 09:57:37 -08:00
func ( rt http2erringRoundTripper ) RoundTripErr ( ) error { return rt . err }
2016-02-03 21:58:02 +00:00
func ( rt http2erringRoundTripper ) RoundTrip ( * Request ) ( * Response , error ) { return nil , rt . err }
// gzipReader wraps a response body so it can lazily
// call gzip.NewReader on the first call to Read
type http2gzipReader struct {
2020-07-27 22:27:54 -07:00
_ http2incomparable
2016-02-03 21:58:02 +00:00
body io . ReadCloser // underlying Response.Body
2016-02-18 05:56:46 +00:00
zr * gzip . Reader // lazily-initialized gzip reader
zerr error // sticky error
2016-02-03 21:58:02 +00:00
}
func ( gz * http2gzipReader ) Read ( p [ ] byte ) ( n int , err error ) {
2016-02-18 05:56:46 +00:00
if gz . zerr != nil {
return 0 , gz . zerr
}
2016-02-03 21:58:02 +00:00
if gz . zr == nil {
gz . zr , err = gzip . NewReader ( gz . body )
if err != nil {
2016-02-18 05:56:46 +00:00
gz . zerr = err
2016-02-03 21:58:02 +00:00
return 0 , err
}
}
return gz . zr . Read ( p )
}
func ( gz * http2gzipReader ) Close ( ) error {
return gz . body . Close ( )
}
type http2errorReader struct { err error }
func ( r http2errorReader ) Read ( p [ ] byte ) ( int , error ) { return 0 , r . err }
2016-09-10 13:14:00 +00:00
// isConnectionCloseRequest reports whether req should use its own
// connection for a single request and then close the connection.
func http2isConnectionCloseRequest ( req * Request ) bool {
2018-09-24 21:46:21 +00:00
return req . Close || httpguts . HeaderValuesContainsToken ( req . Header [ "Connection" ] , "close" )
2016-09-10 13:14:00 +00:00
}
2019-01-18 19:04:36 +00:00
// registerHTTPSProtocol calls Transport.RegisterProtocol but
// converting panics into errors.
func http2registerHTTPSProtocol ( t * Transport , rt http2noDialH2RoundTripper ) ( err error ) {
defer func ( ) {
if e := recover ( ) ; e != nil {
err = fmt . Errorf ( "%v" , e )
}
} ( )
t . RegisterProtocol ( "https" , rt )
return nil
}
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
// if there's already has a cached connection to the host.
// (The field is exported so it can be accessed via reflect from net/http; tested
// by TestNoDialH2RoundTripperType)
type http2noDialH2RoundTripper struct { * http2Transport }
func ( rt http2noDialH2RoundTripper ) RoundTrip ( req * Request ) ( * Response , error ) {
res , err := rt . http2Transport . RoundTrip ( req )
if http2isNoCachedConnError ( err ) {
return nil , ErrSkipAltProtocol
}
return res , err
}
func ( t * http2Transport ) idleConnTimeout ( ) time . Duration {
if t . t1 != nil {
return t . t1 . IdleConnTimeout
}
return 0
}
func http2traceGetConn ( req * Request , hostPort string ) {
trace := httptrace . ContextClientTrace ( req . Context ( ) )
if trace == nil || trace . GetConn == nil {
return
}
trace . GetConn ( hostPort )
}
2019-09-06 18:12:46 +00:00
func http2traceGotConn ( req * Request , cc * http2ClientConn , reused bool ) {
2019-01-18 19:04:36 +00:00
trace := httptrace . ContextClientTrace ( req . Context ( ) )
if trace == nil || trace . GotConn == nil {
return
}
ci := httptrace . GotConnInfo { Conn : cc . tconn }
2019-09-06 18:12:46 +00:00
ci . Reused = reused
2019-01-18 19:04:36 +00:00
cc . mu . Lock ( )
2019-09-06 18:12:46 +00:00
ci . WasIdle = len ( cc . streams ) == 0 && reused
2019-01-18 19:04:36 +00:00
if ci . WasIdle && ! cc . lastActive . IsZero ( ) {
ci . IdleTime = time . Now ( ) . Sub ( cc . lastActive )
}
cc . mu . Unlock ( )
trace . GotConn ( ci )
}
func http2traceWroteHeaders ( trace * httptrace . ClientTrace ) {
if trace != nil && trace . WroteHeaders != nil {
trace . WroteHeaders ( )
}
}
func http2traceGot100Continue ( trace * httptrace . ClientTrace ) {
if trace != nil && trace . Got100Continue != nil {
trace . Got100Continue ( )
}
}
func http2traceWait100Continue ( trace * httptrace . ClientTrace ) {
if trace != nil && trace . Wait100Continue != nil {
trace . Wait100Continue ( )
}
}
func http2traceWroteRequest ( trace * httptrace . ClientTrace , err error ) {
if trace != nil && trace . WroteRequest != nil {
trace . WroteRequest ( httptrace . WroteRequestInfo { Err : err } )
}
}
func http2traceFirstResponseByte ( trace * httptrace . ClientTrace ) {
if trace != nil && trace . GotFirstResponseByte != nil {
trace . GotFirstResponseByte ( )
}
}
2016-02-03 21:58:02 +00:00
// writeFramer is implemented by any type that is used to write frames.
type http2writeFramer interface {
writeFrame ( http2writeContext ) error
2017-01-14 00:05:42 +00:00
// staysWithinBuffer reports whether this writer promises that
// it will only write less than or equal to size bytes, and it
// won't Flush the write context.
staysWithinBuffer ( size int ) bool
2016-02-03 21:58:02 +00:00
}
// writeContext is the interface needed by the various frame writer
// types below. All the writeFrame methods below are scheduled via the
// frame writing scheduler (see writeScheduler in writesched.go).
//
// This interface is implemented by *serverConn.
//
// TODO: decide whether to a) use this in the client code (which didn't
// end up using this yet, because it has a simpler design, not
// currently implementing priorities), or b) delete this and
// make the server code a bit more concrete.
type http2writeContext interface {
Framer ( ) * http2Framer
Flush ( ) error
CloseConn ( ) error
// HeaderEncoder returns an HPACK encoder that writes to the
// returned buffer.
HeaderEncoder ( ) ( * hpack . Encoder , * bytes . Buffer )
}
2017-01-14 00:05:42 +00:00
// writeEndsStream reports whether w writes a frame that will transition
// the stream to a half-closed local state. This returns false for RST_STREAM,
// which closes the entire stream (not just the local half).
func http2writeEndsStream ( w http2writeFramer ) bool {
2016-02-03 21:58:02 +00:00
switch v := w . ( type ) {
case * http2writeData :
return v . endStream
case * http2writeResHeaders :
return v . endStream
case nil :
2017-09-14 17:11:35 +00:00
// This can only happen if the caller reuses w after it's
// been intentionally nil'ed out to prevent use. Keep this
// here to catch future refactoring breaking it.
2017-01-14 00:05:42 +00:00
panic ( "writeEndsStream called on nil writeFramer" )
2016-02-03 21:58:02 +00:00
}
return false
}
type http2flushFrameWriter struct { }
func ( http2flushFrameWriter ) writeFrame ( ctx http2writeContext ) error {
return ctx . Flush ( )
}
2017-01-14 00:05:42 +00:00
func ( http2flushFrameWriter ) staysWithinBuffer ( max int ) bool { return false }
2016-02-03 21:58:02 +00:00
type http2writeSettings [ ] http2Setting
2017-01-14 00:05:42 +00:00
func ( s http2writeSettings ) staysWithinBuffer ( max int ) bool {
const settingSize = 6 // uint16 + uint32
return http2frameHeaderLen + settingSize * len ( s ) <= max
}
2016-02-03 21:58:02 +00:00
func ( s http2writeSettings ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WriteSettings ( [ ] http2Setting ( s ) ... )
}
type http2writeGoAway struct {
maxStreamID uint32
code http2ErrCode
}
func ( p * http2writeGoAway ) writeFrame ( ctx http2writeContext ) error {
err := ctx . Framer ( ) . WriteGoAway ( p . maxStreamID , p . code , nil )
2018-01-09 01:23:08 +00:00
ctx . Flush ( ) // ignore error: we're hanging up on them anyway
2016-02-03 21:58:02 +00:00
return err
}
2017-09-14 17:11:35 +00:00
func ( * http2writeGoAway ) staysWithinBuffer ( max int ) bool { return false } // flushes
2017-01-14 00:05:42 +00:00
2016-02-03 21:58:02 +00:00
type http2writeData struct {
streamID uint32
p [ ] byte
endStream bool
}
func ( w * http2writeData ) String ( ) string {
return fmt . Sprintf ( "writeData(stream=%d, p=%d, endStream=%v)" , w . streamID , len ( w . p ) , w . endStream )
}
func ( w * http2writeData ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WriteData ( w . streamID , w . endStream , w . p )
}
2017-01-14 00:05:42 +00:00
func ( w * http2writeData ) staysWithinBuffer ( max int ) bool {
return http2frameHeaderLen + len ( w . p ) <= max
}
2016-02-03 21:58:02 +00:00
// handlerPanicRST is the message sent from handler goroutines when
// the handler panics.
type http2handlerPanicRST struct {
StreamID uint32
}
func ( hp http2handlerPanicRST ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WriteRSTStream ( hp . StreamID , http2ErrCodeInternal )
}
2017-01-14 00:05:42 +00:00
func ( hp http2handlerPanicRST ) staysWithinBuffer ( max int ) bool { return http2frameHeaderLen + 4 <= max }
2016-02-03 21:58:02 +00:00
func ( se http2StreamError ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WriteRSTStream ( se . StreamID , se . Code )
}
2017-01-14 00:05:42 +00:00
func ( se http2StreamError ) staysWithinBuffer ( max int ) bool { return http2frameHeaderLen + 4 <= max }
2016-02-03 21:58:02 +00:00
type http2writePingAck struct { pf * http2PingFrame }
func ( w http2writePingAck ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WritePing ( true , w . pf . Data )
}
2017-01-14 00:05:42 +00:00
func ( w http2writePingAck ) staysWithinBuffer ( max int ) bool {
return http2frameHeaderLen + len ( w . pf . Data ) <= max
}
2016-02-03 21:58:02 +00:00
type http2writeSettingsAck struct { }
func ( http2writeSettingsAck ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WriteSettingsAck ( )
}
2017-01-14 00:05:42 +00:00
func ( http2writeSettingsAck ) staysWithinBuffer ( max int ) bool { return http2frameHeaderLen <= max }
// splitHeaderBlock splits headerBlock into fragments so that each fragment fits
// in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
// for the first/last fragment, respectively.
func http2splitHeaderBlock ( ctx http2writeContext , headerBlock [ ] byte , fn func ( ctx http2writeContext , frag [ ] byte , firstFrag , lastFrag bool ) error ) error {
// For now we're lazy and just pick the minimum MAX_FRAME_SIZE
// that all peers must support (16KB). Later we could care
// more and send larger frames if the peer advertised it, but
// there's little point. Most headers are small anyway (so we
// generally won't have CONTINUATION frames), and extra frames
// only waste 9 bytes anyway.
const maxFrameSize = 16384
first := true
for len ( headerBlock ) > 0 {
frag := headerBlock
if len ( frag ) > maxFrameSize {
frag = frag [ : maxFrameSize ]
}
headerBlock = headerBlock [ len ( frag ) : ]
if err := fn ( ctx , frag , first , len ( headerBlock ) == 0 ) ; err != nil {
return err
}
first = false
}
return nil
}
2016-02-03 21:58:02 +00:00
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
// for HTTP response headers or trailers from a server handler.
type http2writeResHeaders struct {
streamID uint32
httpResCode int // 0 means no ":status" line
h Header // may be nil
trailers [ ] string // if non-nil, which keys of h to write. nil means all.
endStream bool
date string
contentType string
contentLength string
}
func http2encKV ( enc * hpack . Encoder , k , v string ) {
if http2VerboseLogs {
log . Printf ( "http2: server encoding header %q = %q" , k , v )
}
enc . WriteField ( hpack . HeaderField { Name : k , Value : v } )
}
2017-01-14 00:05:42 +00:00
func ( w * http2writeResHeaders ) staysWithinBuffer ( max int ) bool {
2017-09-14 17:11:35 +00:00
// TODO: this is a common one. It'd be nice to return true
// here and get into the fast path if we could be clever and
// calculate the size fast enough, or at least a conservative
2019-01-18 19:04:36 +00:00
// upper bound that usually fires. (Maybe if w.h and
2017-09-14 17:11:35 +00:00
// w.trailers are nil, so we don't need to enumerate it.)
// Otherwise I'm afraid that just calculating the length to
// answer this question would be slower than the ~2µs benefit.
2017-01-14 00:05:42 +00:00
return false
}
2016-02-03 21:58:02 +00:00
func ( w * http2writeResHeaders ) writeFrame ( ctx http2writeContext ) error {
enc , buf := ctx . HeaderEncoder ( )
buf . Reset ( )
if w . httpResCode != 0 {
http2encKV ( enc , ":status" , http2httpCodeString ( w . httpResCode ) )
}
http2encodeHeaders ( enc , w . h , w . trailers )
if w . contentType != "" {
http2encKV ( enc , "content-type" , w . contentType )
}
if w . contentLength != "" {
http2encKV ( enc , "content-length" , w . contentLength )
}
if w . date != "" {
http2encKV ( enc , "date" , w . date )
}
headerBlock := buf . Bytes ( )
if len ( headerBlock ) == 0 && w . trailers == nil {
panic ( "unexpected empty hpack" )
}
2017-01-14 00:05:42 +00:00
return http2splitHeaderBlock ( ctx , headerBlock , w . writeHeaderBlock )
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
func ( w * http2writeResHeaders ) writeHeaderBlock ( ctx http2writeContext , frag [ ] byte , firstFrag , lastFrag bool ) error {
if firstFrag {
return ctx . Framer ( ) . WriteHeaders ( http2HeadersFrameParam {
StreamID : w . streamID ,
BlockFragment : frag ,
EndStream : w . endStream ,
EndHeaders : lastFrag ,
} )
} else {
return ctx . Framer ( ) . WriteContinuation ( w . streamID , lastFrag , frag )
}
}
// writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
type http2writePushPromise struct {
streamID uint32 // pusher stream
method string // for :method
url * url . URL // for :scheme, :authority, :path
h Header
// Creates an ID for a pushed stream. This runs on serveG just before
// the frame is written. The returned ID is copied to promisedID.
allocatePromisedID func ( ) ( uint32 , error )
promisedID uint32
}
func ( w * http2writePushPromise ) staysWithinBuffer ( max int ) bool {
2017-09-14 17:11:35 +00:00
// TODO: see writeResHeaders.staysWithinBuffer
2017-01-14 00:05:42 +00:00
return false
}
func ( w * http2writePushPromise ) writeFrame ( ctx http2writeContext ) error {
enc , buf := ctx . HeaderEncoder ( )
buf . Reset ( )
http2encKV ( enc , ":method" , w . method )
http2encKV ( enc , ":scheme" , w . url . Scheme )
http2encKV ( enc , ":authority" , w . url . Host )
http2encKV ( enc , ":path" , w . url . RequestURI ( ) )
http2encodeHeaders ( enc , w . h , nil )
headerBlock := buf . Bytes ( )
if len ( headerBlock ) == 0 {
panic ( "unexpected empty hpack" )
}
return http2splitHeaderBlock ( ctx , headerBlock , w . writeHeaderBlock )
}
func ( w * http2writePushPromise ) writeHeaderBlock ( ctx http2writeContext , frag [ ] byte , firstFrag , lastFrag bool ) error {
if firstFrag {
return ctx . Framer ( ) . WritePushPromise ( http2PushPromiseParam {
StreamID : w . streamID ,
PromiseID : w . promisedID ,
BlockFragment : frag ,
EndHeaders : lastFrag ,
} )
} else {
return ctx . Framer ( ) . WriteContinuation ( w . streamID , lastFrag , frag )
2016-02-03 21:58:02 +00:00
}
}
type http2write100ContinueHeadersFrame struct {
streamID uint32
}
func ( w http2write100ContinueHeadersFrame ) writeFrame ( ctx http2writeContext ) error {
enc , buf := ctx . HeaderEncoder ( )
buf . Reset ( )
http2encKV ( enc , ":status" , "100" )
return ctx . Framer ( ) . WriteHeaders ( http2HeadersFrameParam {
StreamID : w . streamID ,
BlockFragment : buf . Bytes ( ) ,
EndStream : false ,
EndHeaders : true ,
} )
}
2017-01-14 00:05:42 +00:00
func ( w http2write100ContinueHeadersFrame ) staysWithinBuffer ( max int ) bool {
2017-09-14 17:11:35 +00:00
// Sloppy but conservative:
2017-01-14 00:05:42 +00:00
return 9 + 2 * ( len ( ":status" ) + len ( "100" ) ) <= max
}
2016-02-03 21:58:02 +00:00
type http2writeWindowUpdate struct {
streamID uint32 // or 0 for conn-level
n uint32
}
2017-01-14 00:05:42 +00:00
func ( wu http2writeWindowUpdate ) staysWithinBuffer ( max int ) bool { return http2frameHeaderLen + 4 <= max }
2016-02-03 21:58:02 +00:00
func ( wu http2writeWindowUpdate ) writeFrame ( ctx http2writeContext ) error {
return ctx . Framer ( ) . WriteWindowUpdate ( wu . streamID , wu . n )
}
2017-01-14 00:05:42 +00:00
// encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
2019-01-18 19:04:36 +00:00
// is encoded only if k is in keys.
2016-02-03 21:58:02 +00:00
func http2encodeHeaders ( enc * hpack . Encoder , h Header , keys [ ] string ) {
if keys == nil {
2016-07-22 18:15:38 +00:00
sorter := http2sorterPool . Get ( ) . ( * http2sorter )
2017-09-14 17:11:35 +00:00
// Using defer here, since the returned keys from the
// sorter.Keys method is only valid until the sorter
// is returned:
2016-07-22 18:15:38 +00:00
defer http2sorterPool . Put ( sorter )
keys = sorter . Keys ( h )
2016-02-03 21:58:02 +00:00
}
for _ , k := range keys {
vv := h [ k ]
2021-07-30 14:28:58 -07:00
k , ascii := http2lowerHeader ( k )
if ! ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
continue
}
2016-07-22 18:15:38 +00:00
if ! http2validWireHeaderFieldName ( k ) {
2017-09-14 17:11:35 +00:00
// Skip it as backup paranoia. Per
// golang.org/issue/14048, these should
// already be rejected at a higher level.
2016-02-18 05:56:46 +00:00
continue
}
2016-02-03 21:58:02 +00:00
isTE := k == "transfer-encoding"
for _ , v := range vv {
2018-09-24 21:46:21 +00:00
if ! httpguts . ValidHeaderFieldValue ( v ) {
2017-09-14 17:11:35 +00:00
// TODO: return an error? golang.org/issue/14048
// For now just omit it.
2016-02-18 05:56:46 +00:00
continue
}
2017-09-14 17:11:35 +00:00
// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
2016-02-03 21:58:02 +00:00
if isTE && v != "trailers" {
continue
}
http2encKV ( enc , k , v )
}
}
}
2017-01-14 00:05:42 +00:00
// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
// Methods are never called concurrently.
type http2WriteScheduler interface {
// OpenStream opens a new stream in the write scheduler.
// It is illegal to call this with streamID=0 or with a streamID that is
// already open -- the call may panic.
OpenStream ( streamID uint32 , options http2OpenStreamOptions )
// CloseStream closes a stream in the write scheduler. Any frames queued on
// this stream should be discarded. It is illegal to call this on a stream
// that is not open -- the call may panic.
CloseStream ( streamID uint32 )
// AdjustStream adjusts the priority of the given stream. This may be called
// on a stream that has not yet been opened or has been closed. Note that
// RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
// https://tools.ietf.org/html/rfc7540#section-5.1
AdjustStream ( streamID uint32 , priority http2PriorityParam )
// Push queues a frame in the scheduler. In most cases, this will not be
// called with wr.StreamID()!=0 unless that stream is currently open. The one
// exception is RST_STREAM frames, which may be sent on idle or closed streams.
Push ( wr http2FrameWriteRequest )
// Pop dequeues the next frame to write. Returns false if no frames can
// be written. Frames with a given wr.StreamID() are Pop'd in the same
2022-02-11 14:53:56 -08:00
// order they are Push'd, except RST_STREAM frames. No frames should be
// discarded except by CloseStream.
2017-01-14 00:05:42 +00:00
Pop ( ) ( wr http2FrameWriteRequest , ok bool )
}
// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
type http2OpenStreamOptions struct {
// PusherID is zero if the stream was initiated by the client. Otherwise,
// PusherID names the stream that pushed the newly opened stream.
PusherID uint32
}
// FrameWriteRequest is a request to write a frame.
type http2FrameWriteRequest struct {
2016-02-03 21:58:02 +00:00
// write is the interface value that does the writing, once the
2017-01-14 00:05:42 +00:00
// WriteScheduler has selected this frame to write. The write
// functions are all defined in write.go.
2016-02-03 21:58:02 +00:00
write http2writeFramer
2017-01-14 00:05:42 +00:00
// stream is the stream on which this frame will be written.
// nil for non-stream frames like PING and SETTINGS.
2022-02-11 14:53:56 -08:00
// nil for RST_STREAM streams, which use the StreamError.StreamID field instead.
2017-01-14 00:05:42 +00:00
stream * http2stream
2016-02-03 21:58:02 +00:00
// done, if non-nil, must be a buffered channel with space for
// 1 message and is sent the return value from write (or an
// earlier error) when the frame has been written.
done chan error
}
2017-01-14 00:05:42 +00:00
// StreamID returns the id of the stream this frame will be written to.
// 0 is used for non-stream frames such as PING and SETTINGS.
func ( wr http2FrameWriteRequest ) StreamID ( ) uint32 {
if wr . stream == nil {
if se , ok := wr . write . ( http2StreamError ) ; ok {
2017-09-14 17:11:35 +00:00
// (*serverConn).resetStream doesn't set
// stream because it doesn't necessarily have
// one. So special case this type of write
// message.
2017-01-14 00:05:42 +00:00
return se . StreamID
}
return 0
}
return wr . stream . id
}
2019-09-12 23:22:53 +00:00
// isControl reports whether wr is a control frame for MaxQueuedControlFrames
// purposes. That includes non-stream frames and RST_STREAM frames.
func ( wr http2FrameWriteRequest ) isControl ( ) bool {
return wr . stream == nil
}
2017-01-14 00:05:42 +00:00
// DataSize returns the number of flow control bytes that must be consumed
// to write this entire frame. This is 0 for non-DATA frames.
func ( wr http2FrameWriteRequest ) DataSize ( ) int {
if wd , ok := wr . write . ( * http2writeData ) ; ok {
return len ( wd . p )
}
return 0
}
// Consume consumes min(n, available) bytes from this frame, where available
// is the number of flow control bytes available on the stream. Consume returns
// 0, 1, or 2 frames, where the integer return value gives the number of frames
// returned.
//
// If flow control prevents consuming any bytes, this returns (_, _, 0). If
// the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
// returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
// 'rest' contains the remaining bytes. The consumed bytes are deducted from the
// underlying stream's flow control budget.
func ( wr http2FrameWriteRequest ) Consume ( n int32 ) ( http2FrameWriteRequest , http2FrameWriteRequest , int ) {
var empty http2FrameWriteRequest
2017-09-14 17:11:35 +00:00
// Non-DATA frames are always consumed whole.
2017-01-14 00:05:42 +00:00
wd , ok := wr . write . ( * http2writeData )
if ! ok || len ( wd . p ) == 0 {
return wr , empty , 1
}
2017-09-14 17:11:35 +00:00
// Might need to split after applying limits.
2017-01-14 00:05:42 +00:00
allowed := wr . stream . flow . available ( )
if n < allowed {
allowed = n
}
if wr . stream . sc . maxFrameSize < allowed {
allowed = wr . stream . sc . maxFrameSize
}
if allowed <= 0 {
return empty , empty , 0
}
if len ( wd . p ) > int ( allowed ) {
wr . stream . flow . take ( allowed )
consumed := http2FrameWriteRequest {
stream : wr . stream ,
write : & http2writeData {
streamID : wd . streamID ,
p : wd . p [ : allowed ] ,
2017-09-14 17:11:35 +00:00
// Even if the original had endStream set, there
// are bytes remaining because len(wd.p) > allowed,
// so we know endStream is false.
2017-01-14 00:05:42 +00:00
endStream : false ,
} ,
2017-09-14 17:11:35 +00:00
// Our caller is blocking on the final DATA frame, not
// this intermediate frame, so no need to wait.
2017-01-14 00:05:42 +00:00
done : nil ,
}
rest := http2FrameWriteRequest {
stream : wr . stream ,
write : & http2writeData {
streamID : wd . streamID ,
p : wd . p [ allowed : ] ,
endStream : wd . endStream ,
} ,
done : wr . done ,
}
return consumed , rest , 2
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
2017-09-14 17:11:35 +00:00
// The frame is consumed whole.
// NB: This cast cannot overflow because allowed is <= math.MaxInt32.
2017-01-14 00:05:42 +00:00
wr . stream . flow . take ( int32 ( len ( wd . p ) ) )
return wr , empty , 1
}
// String is for debugging only.
func ( wr http2FrameWriteRequest ) String ( ) string {
2016-02-03 21:58:02 +00:00
var des string
2017-01-14 00:05:42 +00:00
if s , ok := wr . write . ( fmt . Stringer ) ; ok {
2016-02-03 21:58:02 +00:00
des = s . String ( )
} else {
2017-01-14 00:05:42 +00:00
des = fmt . Sprintf ( "%T" , wr . write )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
return fmt . Sprintf ( "[FrameWriteRequest stream=%d, ch=%v, writer=%v]" , wr . StreamID ( ) , wr . done != nil , des )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
// replyToWriter sends err to wr.done and panics if the send must block
// This does nothing if wr.done is nil.
func ( wr * http2FrameWriteRequest ) replyToWriter ( err error ) {
if wr . done == nil {
return
}
select {
case wr . done <- err :
default :
panic ( fmt . Sprintf ( "unbuffered done channel passed in for type %T" , wr . write ) )
}
2017-09-14 17:11:35 +00:00
wr . write = nil // prevent use (assume it's tainted after wr.done send)
2017-01-14 00:05:42 +00:00
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
// writeQueue is used by implementations of WriteScheduler.
type http2writeQueue struct {
s [ ] http2FrameWriteRequest
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
func ( q * http2writeQueue ) empty ( ) bool { return len ( q . s ) == 0 }
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
func ( q * http2writeQueue ) push ( wr http2FrameWriteRequest ) {
q . s = append ( q . s , wr )
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
func ( q * http2writeQueue ) shift ( ) http2FrameWriteRequest {
if len ( q . s ) == 0 {
panic ( "invalid use of queue" )
}
wr := q . s [ 0 ]
2017-09-14 17:11:35 +00:00
// TODO: less copy-happy queue.
2017-01-14 00:05:42 +00:00
copy ( q . s , q . s [ 1 : ] )
q . s [ len ( q . s ) - 1 ] = http2FrameWriteRequest { }
q . s = q . s [ : len ( q . s ) - 1 ]
return wr
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
// consume consumes up to n bytes from q.s[0]. If the frame is
// entirely consumed, it is removed from the queue. If the frame
// is partially consumed, the frame is kept with the consumed
// bytes removed. Returns true iff any bytes were consumed.
func ( q * http2writeQueue ) consume ( n int32 ) ( http2FrameWriteRequest , bool ) {
if len ( q . s ) == 0 {
return http2FrameWriteRequest { } , false
}
consumed , rest , numresult := q . s [ 0 ] . Consume ( n )
switch numresult {
case 0 :
return http2FrameWriteRequest { } , false
case 1 :
q . shift ( )
case 2 :
q . s [ 0 ] = rest
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
return consumed , true
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
type http2writeQueuePool [ ] * http2writeQueue
2017-09-14 17:11:35 +00:00
// put inserts an unused writeQueue into the pool.
2017-01-14 00:05:42 +00:00
// put inserts an unused writeQueue into the pool.
func ( p * http2writeQueuePool ) put ( q * http2writeQueue ) {
for i := range q . s {
q . s [ i ] = http2FrameWriteRequest { }
}
q . s = q . s [ : 0 ]
* p = append ( * p , q )
}
// get returns an empty writeQueue.
func ( p * http2writeQueuePool ) get ( ) * http2writeQueue {
ln := len ( * p )
2016-02-03 21:58:02 +00:00
if ln == 0 {
return new ( http2writeQueue )
}
2017-01-14 00:05:42 +00:00
x := ln - 1
q := ( * p ) [ x ]
( * p ) [ x ] = nil
* p = ( * p ) [ : x ]
2016-02-03 21:58:02 +00:00
return q
}
2017-01-14 00:05:42 +00:00
// RFC 7540, Section 5.3.5: the default weight is 16.
const http2priorityDefaultWeight = 15 // 16 = 15 + 1
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
type http2PriorityWriteSchedulerConfig struct {
// MaxClosedNodesInTree controls the maximum number of closed streams to
// retain in the priority tree. Setting this to zero saves a small amount
// of memory at the cost of performance.
//
// See RFC 7540, Section 5.3.4:
// "It is possible for a stream to become closed while prioritization
// information ... is in transit. ... This potentially creates suboptimal
// prioritization, since the stream could be given a priority that is
// different from what is intended. To avoid these problems, an endpoint
// SHOULD retain stream prioritization state for a period after streams
// become closed. The longer state is retained, the lower the chance that
// streams are assigned incorrect or default priority values."
MaxClosedNodesInTree int
// MaxIdleNodesInTree controls the maximum number of idle streams to
// retain in the priority tree. Setting this to zero saves a small amount
// of memory at the cost of performance.
//
// See RFC 7540, Section 5.3.4:
// Similarly, streams that are in the "idle" state can be assigned
// priority or become a parent of other streams. This allows for the
// creation of a grouping node in the dependency tree, which enables
// more flexible expressions of priority. Idle streams begin with a
// default priority (Section 5.3.5).
MaxIdleNodesInTree int
// ThrottleOutOfOrderWrites enables write throttling to help ensure that
// data is delivered in priority order. This works around a race where
// stream B depends on stream A and both streams are about to call Write
// to queue DATA frames. If B wins the race, a naive scheduler would eagerly
// write as much data from B as possible, but this is suboptimal because A
// is a higher-priority stream. With throttling enabled, we write a small
// amount of data from B to minimize the amount of bandwidth that B can
// steal from A.
ThrottleOutOfOrderWrites bool
}
// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
2017-09-14 17:11:35 +00:00
// frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3.
2017-01-14 00:05:42 +00:00
// If cfg is nil, default options are used.
func http2NewPriorityWriteScheduler ( cfg * http2PriorityWriteSchedulerConfig ) http2WriteScheduler {
if cfg == nil {
2017-09-14 17:11:35 +00:00
// For justification of these defaults, see:
// https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY
2017-01-14 00:05:42 +00:00
cfg = & http2PriorityWriteSchedulerConfig {
MaxClosedNodesInTree : 10 ,
MaxIdleNodesInTree : 10 ,
ThrottleOutOfOrderWrites : false ,
}
}
ws := & http2priorityWriteScheduler {
nodes : make ( map [ uint32 ] * http2priorityNode ) ,
maxClosedNodesInTree : cfg . MaxClosedNodesInTree ,
maxIdleNodesInTree : cfg . MaxIdleNodesInTree ,
enableWriteThrottle : cfg . ThrottleOutOfOrderWrites ,
}
ws . nodes [ 0 ] = & ws . root
if cfg . ThrottleOutOfOrderWrites {
ws . writeThrottleLimit = 1024
2016-02-03 21:58:02 +00:00
} else {
2017-01-14 00:05:42 +00:00
ws . writeThrottleLimit = math . MaxInt32
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
return ws
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
type http2priorityNodeState int
const (
http2priorityNodeOpen http2priorityNodeState = iota
http2priorityNodeClosed
http2priorityNodeIdle
)
// priorityNode is a node in an HTTP/2 priority tree.
// Each node is associated with a single stream ID.
// See RFC 7540, Section 5.3.
type http2priorityNode struct {
q http2writeQueue // queue of pending frames to write
id uint32 // id of the stream, or 0 for the root of the tree
weight uint8 // the actual weight is weight+1, so the value is in [1,256]
state http2priorityNodeState // open | closed | idle
bytes int64 // number of bytes written by this node, or 0 if closed
subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
// These links form the priority tree.
parent * http2priorityNode
kids * http2priorityNode // start of the kids list
prev , next * http2priorityNode // doubly-linked list of siblings
}
func ( n * http2priorityNode ) setParent ( parent * http2priorityNode ) {
if n == parent {
panic ( "setParent to self" )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if n . parent == parent {
return
}
2017-09-14 17:11:35 +00:00
// Unlink from current parent.
2017-01-14 00:05:42 +00:00
if parent := n . parent ; parent != nil {
if n . prev == nil {
parent . kids = n . next
} else {
n . prev . next = n . next
}
if n . next != nil {
n . next . prev = n . prev
}
}
2017-09-14 17:11:35 +00:00
// Link to new parent.
// If parent=nil, remove n from the tree.
// Always insert at the head of parent.kids (this is assumed by walkReadyInOrder).
2017-01-14 00:05:42 +00:00
n . parent = parent
if parent == nil {
n . next = nil
n . prev = nil
} else {
n . next = parent . kids
n . prev = nil
if n . next != nil {
n . next . prev = n
}
parent . kids = n
2016-02-03 21:58:02 +00:00
}
}
2017-01-14 00:05:42 +00:00
func ( n * http2priorityNode ) addBytes ( b int64 ) {
n . bytes += b
for ; n != nil ; n = n . parent {
n . subtreeBytes += b
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
// walkReadyInOrder iterates over the tree in priority order, calling f for each node
2020-01-02 15:05:27 -08:00
// with a non-empty write queue. When f returns true, this function returns true and the
2017-01-14 00:05:42 +00:00
// walk halts. tmp is used as scratch space for sorting.
//
// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
// if any ancestor p of n is still open (ignoring the root node).
func ( n * http2priorityNode ) walkReadyInOrder ( openParent bool , tmp * [ ] * http2priorityNode , f func ( * http2priorityNode , bool ) bool ) bool {
if ! n . q . empty ( ) && f ( n , openParent ) {
return true
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if n . kids == nil {
return false
}
2017-09-14 17:11:35 +00:00
// Don't consider the root "open" when updating openParent since
// we can't send data frames on the root stream (only control frames).
2017-01-14 00:05:42 +00:00
if n . id != 0 {
openParent = openParent || ( n . state == http2priorityNodeOpen )
2016-02-03 21:58:02 +00:00
}
2017-09-14 17:11:35 +00:00
// Common case: only one kid or all kids have the same weight.
// Some clients don't use weights; other clients (like web browsers)
// use mostly-linear priority trees.
2017-01-14 00:05:42 +00:00
w := n . kids . weight
needSort := false
for k := n . kids . next ; k != nil ; k = k . next {
if k . weight != w {
needSort = true
break
2016-02-03 21:58:02 +00:00
}
}
2017-01-14 00:05:42 +00:00
if ! needSort {
for k := n . kids ; k != nil ; k = k . next {
if k . walkReadyInOrder ( openParent , tmp , f ) {
return true
}
}
return false
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Uncommon case: sort the child nodes. We remove the kids from the parent,
// then re-insert after sorting so we can reuse tmp for future sort calls.
2017-01-14 00:05:42 +00:00
* tmp = ( * tmp ) [ : 0 ]
for n . kids != nil {
* tmp = append ( * tmp , n . kids )
n . kids . setParent ( nil )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
sort . Sort ( http2sortPriorityNodeSiblings ( * tmp ) )
for i := len ( * tmp ) - 1 ; i >= 0 ; i -- {
2017-09-14 17:11:35 +00:00
( * tmp ) [ i ] . setParent ( n ) // setParent inserts at the head of n.kids
2017-01-14 00:05:42 +00:00
}
for k := n . kids ; k != nil ; k = k . next {
if k . walkReadyInOrder ( openParent , tmp , f ) {
return true
2016-02-03 21:58:02 +00:00
}
}
2017-01-14 00:05:42 +00:00
return false
}
type http2sortPriorityNodeSiblings [ ] * http2priorityNode
func ( z http2sortPriorityNodeSiblings ) Len ( ) int { return len ( z ) }
func ( z http2sortPriorityNodeSiblings ) Swap ( i , k int ) { z [ i ] , z [ k ] = z [ k ] , z [ i ] }
func ( z http2sortPriorityNodeSiblings ) Less ( i , k int ) bool {
2017-09-14 17:11:35 +00:00
// Prefer the subtree that has sent fewer bytes relative to its weight.
// See sections 5.3.2 and 5.3.4.
2017-01-14 00:05:42 +00:00
wi , bi := float64 ( z [ i ] . weight + 1 ) , float64 ( z [ i ] . subtreeBytes )
wk , bk := float64 ( z [ k ] . weight + 1 ) , float64 ( z [ k ] . subtreeBytes )
if bi == 0 && bk == 0 {
return wi >= wk
}
if bk == 0 {
return false
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
return bi / bk <= wi / wk
}
type http2priorityWriteScheduler struct {
// root is the root of the priority tree, where root.id = 0.
// The root queues control frames that are not associated with any stream.
root http2priorityNode
// nodes maps stream ids to priority tree nodes.
nodes map [ uint32 ] * http2priorityNode
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
// maxID is the maximum stream id in nodes.
maxID uint32
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
// lists of nodes that have been closed or are idle, but are kept in
// the tree for improved prioritization. When the lengths exceed either
// maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded.
closedNodes , idleNodes [ ] * http2priorityNode
// From the config.
maxClosedNodesInTree int
maxIdleNodesInTree int
writeThrottleLimit int32
enableWriteThrottle bool
// tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations.
tmp [ ] * http2priorityNode
// pool of empty queues for reuse.
queuePool http2writeQueuePool
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
func ( ws * http2priorityWriteScheduler ) OpenStream ( streamID uint32 , options http2OpenStreamOptions ) {
2017-09-14 17:11:35 +00:00
// The stream may be currently idle but cannot be opened or closed.
2017-01-14 00:05:42 +00:00
if curr := ws . nodes [ streamID ] ; curr != nil {
if curr . state != http2priorityNodeIdle {
panic ( fmt . Sprintf ( "stream %d already opened" , streamID ) )
}
curr . state = http2priorityNodeOpen
return
}
2017-09-14 17:11:35 +00:00
// RFC 7540, Section 5.3.5:
// "All streams are initially assigned a non-exclusive dependency on stream 0x0.
// Pushed streams initially depend on their associated stream. In both cases,
// streams are assigned a default weight of 16."
2017-01-14 00:05:42 +00:00
parent := ws . nodes [ options . PusherID ]
if parent == nil {
parent = & ws . root
}
n := & http2priorityNode {
q : * ws . queuePool . get ( ) ,
id : streamID ,
weight : http2priorityDefaultWeight ,
state : http2priorityNodeOpen ,
}
n . setParent ( parent )
ws . nodes [ streamID ] = n
if streamID > ws . maxID {
ws . maxID = streamID
2016-02-03 21:58:02 +00:00
}
}
2017-01-14 00:05:42 +00:00
func ( ws * http2priorityWriteScheduler ) CloseStream ( streamID uint32 ) {
if streamID == 0 {
panic ( "violation of WriteScheduler interface: cannot close stream 0" )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if ws . nodes [ streamID ] == nil {
panic ( fmt . Sprintf ( "violation of WriteScheduler interface: unknown stream %d" , streamID ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
if ws . nodes [ streamID ] . state != http2priorityNodeOpen {
panic ( fmt . Sprintf ( "violation of WriteScheduler interface: stream %d already closed" , streamID ) )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
n := ws . nodes [ streamID ]
n . state = http2priorityNodeClosed
n . addBytes ( - n . bytes )
q := n . q
ws . queuePool . put ( & q )
n . q . s = nil
if ws . maxClosedNodesInTree > 0 {
ws . addClosedOrIdleNode ( & ws . closedNodes , ws . maxClosedNodesInTree , n )
} else {
ws . removeNode ( n )
2016-02-03 21:58:02 +00:00
}
}
2017-01-14 00:05:42 +00:00
func ( ws * http2priorityWriteScheduler ) AdjustStream ( streamID uint32 , priority http2PriorityParam ) {
if streamID == 0 {
panic ( "adjustPriority on root" )
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// If streamID does not exist, there are two cases:
// - A closed stream that has been removed (this will have ID <= maxID)
// - An idle stream that is being used for "grouping" (this will have ID > maxID)
2017-01-14 00:05:42 +00:00
n := ws . nodes [ streamID ]
if n == nil {
if streamID <= ws . maxID || ws . maxIdleNodesInTree == 0 {
return
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
ws . maxID = streamID
n = & http2priorityNode {
q : * ws . queuePool . get ( ) ,
id : streamID ,
weight : http2priorityDefaultWeight ,
state : http2priorityNodeIdle ,
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
n . setParent ( & ws . root )
ws . nodes [ streamID ] = n
ws . addClosedOrIdleNode ( & ws . idleNodes , ws . maxIdleNodesInTree , n )
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Section 5.3.1: A dependency on a stream that is not currently in the tree
// results in that stream being given a default priority (Section 5.3.5).
2017-01-14 00:05:42 +00:00
parent := ws . nodes [ priority . StreamDep ]
if parent == nil {
n . setParent ( & ws . root )
n . weight = http2priorityDefaultWeight
return
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Ignore if the client tries to make a node its own parent.
2017-01-14 00:05:42 +00:00
if n == parent {
return
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Section 5.3.3:
// "If a stream is made dependent on one of its own dependencies, the
// formerly dependent stream is first moved to be dependent on the
// reprioritized stream's previous parent. The moved dependency retains
// its weight."
//
// That is: if parent depends on n, move parent to depend on n.parent.
2017-01-14 00:05:42 +00:00
for x := parent . parent ; x != nil ; x = x . parent {
if x == n {
parent . setParent ( n . parent )
break
}
}
2016-02-03 21:58:02 +00:00
2017-09-14 17:11:35 +00:00
// Section 5.3.3: The exclusive flag causes the stream to become the sole
// dependency of its parent stream, causing other dependencies to become
// dependent on the exclusive stream.
2017-01-14 00:05:42 +00:00
if priority . Exclusive {
k := parent . kids
for k != nil {
next := k . next
if k != n {
k . setParent ( n )
}
k = next
2016-02-03 21:58:02 +00:00
}
}
2017-01-14 00:05:42 +00:00
n . setParent ( parent )
n . weight = priority . Weight
}
func ( ws * http2priorityWriteScheduler ) Push ( wr http2FrameWriteRequest ) {
var n * http2priorityNode
if id := wr . StreamID ( ) ; id == 0 {
n = & ws . root
} else {
n = ws . nodes [ id ]
if n == nil {
2017-09-14 17:11:35 +00:00
// id is an idle or closed stream. wr should not be a HEADERS or
// DATA frame. However, wr can be a RST_STREAM. In this case, we
// push wr onto the root, rather than creating a new priorityNode,
// since RST_STREAM is tiny and the stream's priority is unknown
// anyway. See issue #17919.
2017-01-14 00:05:42 +00:00
if wr . DataSize ( ) > 0 {
panic ( "add DATA on non-open stream" )
}
n = & ws . root
}
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
n . q . push ( wr )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
func ( ws * http2priorityWriteScheduler ) Pop ( ) ( wr http2FrameWriteRequest , ok bool ) {
ws . root . walkReadyInOrder ( false , & ws . tmp , func ( n * http2priorityNode , openParent bool ) bool {
limit := int32 ( math . MaxInt32 )
if openParent {
limit = ws . writeThrottleLimit
}
wr , ok = n . q . consume ( limit )
if ! ok {
return false
}
n . addBytes ( int64 ( wr . DataSize ( ) ) )
2017-09-14 17:11:35 +00:00
// If B depends on A and B continuously has data available but A
// does not, gradually increase the throttling limit to allow B to
// steal more and more bandwidth from A.
2017-01-14 00:05:42 +00:00
if openParent {
ws . writeThrottleLimit += 1024
if ws . writeThrottleLimit < 0 {
ws . writeThrottleLimit = math . MaxInt32
}
} else if ws . enableWriteThrottle {
ws . writeThrottleLimit = 1024
}
return true
} )
return wr , ok
}
func ( ws * http2priorityWriteScheduler ) addClosedOrIdleNode ( list * [ ] * http2priorityNode , maxSize int , n * http2priorityNode ) {
if maxSize == 0 {
2016-02-03 21:58:02 +00:00
return
}
2017-01-14 00:05:42 +00:00
if len ( * list ) == maxSize {
2017-09-14 17:11:35 +00:00
// Remove the oldest node, then shift left.
2017-01-14 00:05:42 +00:00
ws . removeNode ( ( * list ) [ 0 ] )
x := ( * list ) [ 1 : ]
copy ( * list , x )
* list = ( * list ) [ : len ( x ) ]
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
* list = append ( * list , n )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
func ( ws * http2priorityWriteScheduler ) removeNode ( n * http2priorityNode ) {
for k := n . kids ; k != nil ; k = k . next {
k . setParent ( n . parent )
}
n . setParent ( nil )
delete ( ws . nodes , n . id )
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
// priorities. Control frames like SETTINGS and PING are written before DATA
// frames, but if no control frames are queued and multiple streams have queued
// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
func http2NewRandomWriteScheduler ( ) http2WriteScheduler {
return & http2randomWriteScheduler { sq : make ( map [ uint32 ] * http2writeQueue ) }
}
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
type http2randomWriteScheduler struct {
// zero are frames not associated with a specific stream.
zero http2writeQueue
2016-02-03 21:58:02 +00:00
2017-01-14 00:05:42 +00:00
// sq contains the stream-specific queues, keyed by stream ID.
2020-01-02 15:05:27 -08:00
// When a stream is idle, closed, or emptied, it's deleted
// from the map.
2017-01-14 00:05:42 +00:00
sq map [ uint32 ] * http2writeQueue
// pool of empty queues for reuse.
queuePool http2writeQueuePool
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
func ( ws * http2randomWriteScheduler ) OpenStream ( streamID uint32 , options http2OpenStreamOptions ) {
2017-09-14 17:11:35 +00:00
// no-op: idle streams are not tracked
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
func ( ws * http2randomWriteScheduler ) CloseStream ( streamID uint32 ) {
q , ok := ws . sq [ streamID ]
if ! ok {
return
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
delete ( ws . sq , streamID )
ws . queuePool . put ( q )
}
func ( ws * http2randomWriteScheduler ) AdjustStream ( streamID uint32 , priority http2PriorityParam ) {
2017-09-14 17:11:35 +00:00
// no-op: priorities are ignored
2016-02-03 21:58:02 +00:00
}
2017-01-14 00:05:42 +00:00
func ( ws * http2randomWriteScheduler ) Push ( wr http2FrameWriteRequest ) {
2022-02-11 14:53:56 -08:00
if wr . isControl ( ) {
2017-01-14 00:05:42 +00:00
ws . zero . push ( wr )
return
2016-02-03 21:58:02 +00:00
}
2022-02-11 14:53:56 -08:00
id := wr . StreamID ( )
2017-01-14 00:05:42 +00:00
q , ok := ws . sq [ id ]
if ! ok {
q = ws . queuePool . get ( )
ws . sq [ id ] = q
}
q . push ( wr )
}
func ( ws * http2randomWriteScheduler ) Pop ( ) ( http2FrameWriteRequest , bool ) {
2022-02-11 14:53:56 -08:00
// Control and RST_STREAM frames first.
2017-01-14 00:05:42 +00:00
if ! ws . zero . empty ( ) {
return ws . zero . shift ( ) , true
}
2017-09-14 17:11:35 +00:00
// Iterate over all non-idle streams until finding one that can be consumed.
2020-01-02 15:05:27 -08:00
for streamID , q := range ws . sq {
2017-01-14 00:05:42 +00:00
if wr , ok := q . consume ( math . MaxInt32 ) ; ok {
2020-01-02 15:05:27 -08:00
if q . empty ( ) {
delete ( ws . sq , streamID )
ws . queuePool . put ( q )
}
2017-01-14 00:05:42 +00:00
return wr , true
}
}
return http2FrameWriteRequest { } , false
2016-02-03 21:58:02 +00:00
}