| // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. |
| //go:generate bundle -o h2_bundle.go -prefix http2 -underscore golang.org/x/net/http2 |
| |
| // 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" |
| "context" |
| "crypto/rand" |
| "crypto/tls" |
| "encoding/binary" |
| "errors" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "log" |
| "math" |
| "net" |
| "net/http/httptrace" |
| "net/textproto" |
| "net/url" |
| "os" |
| "reflect" |
| "runtime" |
| "sort" |
| "strconv" |
| "strings" |
| "sync" |
| "time" |
| |
| "golang_org/x/net/http2/hpack" |
| "golang_org/x/net/idna" |
| "golang_org/x/net/lex/httplex" |
| ) |
| |
| // A list of the possible cipher suite ids. Taken from |
| // http://www.iana.org/assignments/tls-parameters/tls-parameters.txt |
| |
| 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 |
| } |
| } |
| |
| // ClientConnPool manages a pool of HTTP/2 client connections. |
| type http2ClientConnPool interface { |
| GetClientConn(req *Request, addr string) (*http2ClientConn, error) |
| MarkDead(*http2ClientConn) |
| } |
| |
| // 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{} |
| ) |
| |
| // 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 |
| addConnCalls map[string]*http2addConnCall // in-flight addConnIfNeede calls |
| } |
| |
| func (p *http2clientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) { |
| return p.getClientConn(req, addr, http2dialOnMiss) |
| } |
| |
| const ( |
| http2dialOnMiss = true |
| http2noDialOnMiss = false |
| ) |
| |
| func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) { |
| if http2isConnectionCloseRequest(req) && dialOnMiss { |
| // It gets its own connection. |
| const singleUse = true |
| cc, err := p.t.dialClientConn(addr, singleUse) |
| if err != nil { |
| return nil, err |
| } |
| return cc, nil |
| } |
| p.mu.Lock() |
| for _, cc := range p.conns[addr] { |
| if cc.CanTakeNewRequest() { |
| p.mu.Unlock() |
| return cc, nil |
| } |
| } |
| if !dialOnMiss { |
| p.mu.Unlock() |
| return nil, http2ErrNoCachedConn |
| } |
| call := p.getStartDialLocked(addr) |
| p.mu.Unlock() |
| <-call.done |
| return call.res, call.err |
| } |
| |
| // dialCall is an in-flight Transport dial call to a host. |
| type http2dialCall struct { |
| p *http2clientConnPool |
| 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. |
| func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall { |
| if call, ok := p.dialing[addr]; ok { |
| // A dial is already in-flight. Don't start another. |
| return call |
| } |
| call := &http2dialCall{p: p, done: make(chan struct{})} |
| if p.dialing == nil { |
| p.dialing = make(map[string]*http2dialCall) |
| } |
| p.dialing[addr] = call |
| go call.dial(addr) |
| return call |
| } |
| |
| // run in its own goroutine. |
| func (c *http2dialCall) dial(addr string) { |
| const singleUse = false // shared conn |
| c.res, c.err = c.p.t.dialClientConn(addr, singleUse) |
| 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 { |
| 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 { |
| p.addConnLocked(key, cc) |
| } |
| delete(p.addConnCalls, key) |
| p.mu.Unlock() |
| close(c.done) |
| } |
| |
| func (p *http2clientConnPool) addConn(key string, cc *http2ClientConn) { |
| p.mu.Lock() |
| p.addConnLocked(key, cc) |
| p.mu.Unlock() |
| } |
| |
| // 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() |
| // 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. |
| 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) |
| } |
| } |
| // If we filtered it out, zero out the last item to prevent |
| // the GC from seeing it. |
| if len(in) != len(out) { |
| in[len(in)-1] = nil |
| } |
| return out |
| } |
| |
| // noDialClientConnPool is an implementation of http2.ClientConnPool |
| // which never dials. We let the HTTP/1.1 client dial and use its TLS |
| // connection instead. |
| type http2noDialClientConnPool struct{ *http2clientConnPool } |
| |
| func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) { |
| return p.getClientConn(req, addr, http2noDialOnMiss) |
| } |
| |
| func http2configureTransport(t1 *Transport) (*http2Transport, error) { |
| 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 |
| } |
| |
| // registerHTTPSProtocol calls Transport.RegisterProtocol but |
| // converting panics into errors. |
| func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (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. |
| type http2noDialH2RoundTripper struct{ t *http2Transport } |
| |
| func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) { |
| res, err := rt.t.RoundTrip(req) |
| if err == http2ErrNoCachedConn { |
| return nil, ErrSkipAltProtocol |
| } |
| return res, err |
| } |
| |
| // 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 |
| } |
| |
| // 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)) |
| } |
| |
| // 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 |
| Cause error // optional additional detail |
| } |
| |
| func http2streamError(id uint32, code http2ErrCode) http2StreamError { |
| return http2StreamError{StreamID: id, Code: code} |
| } |
| |
| func (e http2StreamError) Error() string { |
| if e.Cause != nil { |
| return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause) |
| } |
| 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" } |
| |
| // connError represents an HTTP/2 ConnectionError error code, along |
| // with a string (for debugging) explaining why. |
| // |
| // Errors of this type are only returned by the frame parser functions |
| // and converted into ConnectionError(Code), after stashing away |
| // the Reason into the Framer's errDetail field, accessible via |
| // the (*Framer).ErrorDetail method. |
| type http2connError struct { |
| Code http2ErrCode // the ConnectionError error code |
| Reason string // additional reason |
| } |
| |
| func (e http2connError) Error() string { |
| return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason) |
| } |
| |
| 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") |
| ) |
| |
| // flow is the flow control window's size. |
| type http2flow struct { |
| // 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 { |
| remain := (1<<31 - 1) - f.n |
| if n > remain { |
| return false |
| } |
| f.n += n |
| return true |
| } |
| |
| 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). |
| type http2frameParser func(fc *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) |
| |
| 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 |
| errDetail error |
| |
| // 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. |
| // It is not compatible with ReadMetaHeaders. |
| AllowIllegalReads bool |
| |
| // 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 |
| |
| // 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. |
| |
| logReads, logWrites bool |
| |
| debugFramer *http2Framer // only use for logging written writes |
| debugFramerBuf *bytes.Buffer |
| debugReadLoggerf func(string, ...interface{}) |
| debugWriteLoggerf func(string, ...interface{}) |
| |
| frameCache *http2frameCache // nil if frames aren't reused (default) |
| } |
| |
| func (fr *http2Framer) maxHeaderListSize() uint32 { |
| if fr.MaxHeaderListSize == 0 { |
| return 16 << 20 // sane default, per docs |
| } |
| return fr.MaxHeaderListSize |
| } |
| |
| func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamID uint32) { |
| // Write the FrameHeader. |
| f.wbuf = append(f.wbuf[:0], |
| 0, // 3 bytes of length, filled in in endWrite |
| 0, |
| 0, |
| byte(ftype), |
| byte(flags), |
| byte(streamID>>24), |
| byte(streamID>>16), |
| byte(streamID>>8), |
| byte(streamID)) |
| } |
| |
| func (f *http2Framer) endWrite() error { |
| // Now that we know the final size, fill in the FrameHeader in |
| // the space previously reserved for it. Abuse append. |
| length := len(f.wbuf) - http2frameHeaderLen |
| if length >= (1 << 24) { |
| return http2ErrFrameTooLarge |
| } |
| _ = append(f.wbuf[:0], |
| byte(length>>16), |
| byte(length>>8), |
| byte(length)) |
| if f.logWrites { |
| 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) |
| 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: |
| f.debugFramer.AllowIllegalReads = true |
| } |
| f.debugFramerBuf.Write(f.wbuf) |
| fr, err := f.debugFramer.ReadFrame() |
| if err != nil { |
| f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f) |
| return |
| } |
| f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, http2summarizeFrame(fr)) |
| } |
| |
| 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 |
| ) |
| |
| // 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 |
| } |
| |
| // 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{ |
| w: w, |
| r: r, |
| logReads: http2logFrameReads, |
| logWrites: http2logFrameWrites, |
| debugReadLoggerf: log.Printf, |
| debugWriteLoggerf: log.Printf, |
| } |
| 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 |
| } |
| |
| // 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 |
| } |
| |
| // 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 |
| // ConnectionError, StreamError, or anything else from the underlying |
| // reader. |
| func (fr *http2Framer) ReadFrame() (http2Frame, error) { |
| fr.errDetail = nil |
| 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 |
| } |
| f, err := http2typeFrameParser(fh.Type)(fr.frameCache, fh, payload) |
| 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 { |
| fr.debugReadLoggerf("http2: Framer %p: read %v", fr, http2summarizeFrame(f)) |
| } |
| if fh.Type == http2FrameHeaders && fr.ReadMetaHeaders != nil { |
| return fr.readMetaFrame(f.(*http2HeadersFrame)) |
| } |
| 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 { |
| fr.errDetail = errors.New(reason) |
| 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 |
| } |
| |
| func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) { |
| if fh.StreamID == 0 { |
| // 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. |
| return nil, http2connError{http2ErrCodeProtocol, "DATA frame with stream ID 0"} |
| } |
| f := fc.getDataFrame() |
| f.http2FrameHeader = fh |
| |
| var padSize byte |
| if fh.Flags.Has(http2FlagDataPadded) { |
| var err error |
| payload, padSize, err = http2readByte(payload) |
| if err != nil { |
| return nil, err |
| } |
| } |
| if int(padSize) > len(payload) { |
| // 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 |
| return nil, http2connError{http2ErrCodeProtocol, "pad size larger than data payload"} |
| } |
| f.data = payload[:len(payload)-int(padSize)] |
| return f, nil |
| } |
| |
| var ( |
| http2errStreamID = errors.New("invalid stream ID") |
| http2errDepStreamID = errors.New("invalid dependent stream ID") |
| http2errPadLength = errors.New("pad length too large") |
| http2errPadBytes = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled") |
| ) |
| |
| func http2validStreamIDOrZero(streamID uint32) bool { |
| return streamID&(1<<31) == 0 |
| } |
| |
| 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. |
| // It is the caller's responsibility not to violate the maximum frame size |
| // and to not call other Write methods concurrently. |
| func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) error { |
| return f.WriteDataPadded(streamID, endStream, data, nil) |
| } |
| |
| // WriteData writes a DATA frame with optional padding. |
| // |
| // If pad is nil, the padding bit is not sent. |
| // The length of pad must not exceed 255 bytes. |
| // The bytes of pad must all be zero, unless f.AllowIllegalWrites is set. |
| // |
| // 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 { |
| if !http2validStreamID(streamID) && !f.AllowIllegalWrites { |
| return http2errStreamID |
| } |
| 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 |
| } |
| } |
| } |
| } |
| var flags http2Flags |
| if endStream { |
| flags |= http2FlagDataEndStream |
| } |
| if pad != nil { |
| flags |= http2FlagDataPadded |
| } |
| f.startWrite(http2FrameData, flags, streamID) |
| if pad != nil { |
| f.wbuf = append(f.wbuf, byte(len(pad))) |
| } |
| f.wbuf = append(f.wbuf, data...) |
| f.wbuf = append(f.wbuf, pad...) |
| 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 |
| } |
| |
| func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) { |
| if fh.Flags.Has(http2FlagSettingsAck) && fh.Length > 0 { |
| // 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. |
| return nil, http2ConnectionError(http2ErrCodeFrameSize) |
| } |
| if fh.StreamID != 0 { |
| // 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. |
| return nil, http2ConnectionError(http2ErrCodeProtocol) |
| } |
| if len(p)%6 != 0 { |
| // Expecting even number of 6 byte settings. |
| return nil, http2ConnectionError(http2ErrCodeFrameSize) |
| } |
| f := &http2SettingsFrame{http2FrameHeader: fh, p: p} |
| if v, ok := f.Value(http2SettingInitialWindowSize); ok && v > (1<<31)-1 { |
| // 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. |
| return nil, http2ConnectionError(http2ErrCodeFlowControl) |
| } |
| return f, nil |
| } |
| |
| func (f *http2SettingsFrame) IsAck() bool { |
| return f.http2FrameHeader.Flags.Has(http2FlagSettingsAck) |
| } |
| |
| func (f *http2SettingsFrame) Value(s http2SettingID) (v uint32, ok bool) { |
| f.checkValid() |
| buf := f.p |
| for len(buf) > 0 { |
| settingID := http2SettingID(binary.BigEndian.Uint16(buf[:2])) |
| if settingID == s { |
| return binary.BigEndian.Uint32(buf[2:6]), true |
| } |
| buf = buf[6:] |
| } |
| return 0, false |
| } |
| |
| // ForeachSetting runs fn for each setting. |
| // It stops and returns the first error. |
| func (f *http2SettingsFrame) ForeachSetting(fn func(http2Setting) error) error { |
| f.checkValid() |
| buf := f.p |
| for len(buf) > 0 { |
| if err := fn(http2Setting{ |
| http2SettingID(binary.BigEndian.Uint16(buf[:2])), |
| binary.BigEndian.Uint32(buf[2:6]), |
| }); err != nil { |
| return err |
| } |
| buf = buf[6:] |
| } |
| 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() |
| } |
| |
| // WriteSettingsAck writes an empty SETTINGS frame with the ACK bit 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) 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) } |
| |
| func http2parsePingFrame(_ *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) { |
| if len(payload) != 8 { |
| return nil, http2ConnectionError(http2ErrCodeFrameSize) |
| } |
| if fh.StreamID != 0 { |
| 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 |
| } |
| |
| func http2parseGoAwayFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) { |
| if fh.StreamID != 0 { |
| return nil, http2ConnectionError(http2ErrCodeProtocol) |
| } |
| if len(p) < 8 { |
| 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 |
| } |
| |
| func http2parseUnknownFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) { |
| 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 |
| } |
| |
| func http2parseWindowUpdateFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) { |
| if len(p) != 4 { |
| return nil, http2ConnectionError(http2ErrCodeFrameSize) |
| } |
| inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit |
| if inc == 0 { |
| // 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). |
| if fh.StreamID == 0 { |
| return nil, http2ConnectionError(http2ErrCodeProtocol) |
| } |
| return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol) |
| } |
| 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 { |
| // "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets." |
| 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) |
| } |
| |
| func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (_ http2Frame, err error) { |
| hf := &http2HeadersFrame{ |
| http2FrameHeader: fh, |
| } |
| if fh.StreamID == 0 { |
| // 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. |
| 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 { |
| return |
| } |
| } |
| if fh.Flags.Has(http2FlagHeadersPriority) { |
| var v uint32 |
| p, v, err = http2readUint32(p) |
| if err != nil { |
| return nil, err |
| } |
| hf.Priority.StreamDep = v & 0x7fffffff |
| hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set |
| p, hf.Priority.Weight, err = http2readByte(p) |
| if err != nil { |
| return nil, err |
| } |
| } |
| if len(p)-int(padLength) <= 0 { |
| return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol) |
| } |
| 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 |
| if !http2validStreamIDOrZero(v) && !f.AllowIllegalWrites { |
| return http2errDepStreamID |
| } |
| 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 |
| // set together with StreamDep, or neither should be set. Per |
| // 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{} |
| } |
| |
| func http2parsePriorityFrame(_ *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) { |
| if fh.StreamID == 0 { |
| return nil, http2connError{http2ErrCodeProtocol, "PRIORITY frame with stream ID 0"} |
| } |
| if len(payload) != 5 { |
| return nil, http2connError{http2ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))} |
| } |
| v := binary.BigEndian.Uint32(payload[:4]) |
| streamID := v & 0x7fffffff // mask off high bit |
| return &http2PriorityFrame{ |
| http2FrameHeader: fh, |
| http2PriorityParam: http2PriorityParam{ |
| Weight: payload[4], |
| StreamDep: streamID, |
| Exclusive: streamID != v, // was high bit set? |
| }, |
| }, 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 |
| } |
| if !http2validStreamIDOrZero(p.StreamDep) { |
| return http2errDepStreamID |
| } |
| 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 |
| } |
| |
| func http2parseRSTStreamFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) { |
| if len(p) != 4 { |
| return nil, http2ConnectionError(http2ErrCodeFrameSize) |
| } |
| if fh.StreamID == 0 { |
| 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 |
| } |
| |
| func http2parseContinuationFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) { |
| if fh.StreamID == 0 { |
| 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) |
| } |
| |
| func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, p []byte) (_ http2Frame, err error) { |
| pp := &http2PushPromiseFrame{ |
| http2FrameHeader: fh, |
| } |
| if pp.StreamID == 0 { |
| // 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. |
| 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 { |
| return |
| } |
| } |
| |
| p, pp.PromiseID, err = http2readUint32(p) |
| if err != nil { |
| return |
| } |
| pp.PromiseID = pp.PromiseID & (1<<31 - 1) |
| |
| if int(padLength) > len(p) { |
| // like the DATA frame, error out if padding is longer than the body. |
| 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 |
| } |
| |
| 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) |
| } |
| // Check for duplicates. |
| // This would be a bad algorithm, but N is 4. |
| // And this doesn't allocate. |
| 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) |
| } |
| // They had a crazy big number for MaxHeaderBytes anyway, |
| // so give them unlimited header lengths: |
| return 0 |
| } |
| |
| // readMetaFrame returns 0 or more CONTINUATION frames from fr and |
| // merge them into into the provided hf and returns a MetaHeadersFrame |
| // 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) { |
| if http2VerboseLogs && fr.logReads { |
| fr.debugReadLoggerf("http2: decoded hpack field %+v", hf) |
| } |
| if !httplex.ValidHeaderFieldValue(hf.Value) { |
| 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) |
| }) |
| // Lose reference to MetaHeadersFrame: |
| 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 { |
| hc = f.(*http2ContinuationFrame) // guaranteed by checkFrameOrder |
| } |
| } |
| |
| mh.http2HeadersFrame.headerFragBuf = nil |
| mh.http2HeadersFrame.invalidate() |
| |
| if err := hdec.Close(); err != nil { |
| return nil, http2ConnectionError(http2ErrCodeCompression) |
| } |
| if invalid != nil { |
| fr.errDetail = invalid |
| if http2VerboseLogs { |
| log.Printf("http2: invalid header: %v", invalid) |
| } |
| return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, invalid} |
| } |
| if err := mh.checkPseudos(); err != nil { |
| fr.errDetail = err |
| if http2VerboseLogs { |
| log.Printf("http2: invalid pseudo headers: %v", err) |
| } |
| return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, err} |
| } |
| return mh, nil |
| } |
| |
| 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 { |
| buf.Truncate(buf.Len() - 1) // remove trailing comma |
| } |
| 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() |
| } |
| |
| func http2transportExpectContinueTimeout(t1 *Transport) time.Duration { |
| return t1.ExpectContinueTimeout |
| } |
| |
| type http2contextContext interface { |
| context.Context |
| } |
| |
| func http2serverConnBaseContext(c net.Conn, opts *http2ServeConnOpts) (ctx http2contextContext, cancel func()) { |
| ctx, cancel = context.WithCancel(context.Background()) |
| ctx = context.WithValue(ctx, LocalAddrContextKey, c.LocalAddr()) |
| if hs := opts.baseConfig(); hs != nil { |
| ctx = context.WithValue(ctx, ServerContextKey, hs) |
| } |
| return |
| } |
| |
| func http2contextWithCancel(ctx http2contextContext) (_ http2contextContext, cancel func()) { |
| return context.WithCancel(ctx) |
| } |
| |
| func http2requestWithContext(req *Request, ctx http2contextContext) *Request { |
| return req.WithContext(ctx) |
| } |
| |
| type http2clientTrace httptrace.ClientTrace |
| |
| func http2reqContext(r *Request) context.Context { return r.Context() } |
| |
| func (t *http2Transport) idleConnTimeout() time.Duration { |
| if t.t1 != nil { |
| return t.t1.IdleConnTimeout |
| } |
| return 0 |
| } |
| |
| func http2setResponseUncompressed(res *Response) { res.Uncompressed = true } |
| |
| func http2traceGotConn(req *Request, cc *http2ClientConn) { |
| trace := httptrace.ContextClientTrace(req.Context()) |
| if trace == nil || trace.GotConn == nil { |
| return |
| } |
| ci := httptrace.GotConnInfo{Conn: cc.tconn} |
| cc.mu.Lock() |
| ci.Reused = cc.nextStreamID > 1 |
| ci.WasIdle = len(cc.streams) == 0 && ci.Reused |
| if ci.WasIdle && !cc.lastActive.IsZero() { |
| ci.IdleTime = time.Now().Sub(cc.lastActive) |
| } |
| cc.mu.Unlock() |
| |
| trace.GotConn(ci) |
| } |
| |
| func http2traceWroteHeaders(trace *http2clientTrace) { |
| if trace != nil && trace.WroteHeaders != nil { |
| trace.WroteHeaders() |
| } |
| } |
| |
| func http2traceGot100Continue(trace *http2clientTrace) { |
| if trace != nil && trace.Got100Continue != nil { |
| trace.Got100Continue() |
| } |
| } |
| |
| func http2traceWait100Continue(trace *http2clientTrace) { |
| if trace != nil && trace.Wait100Continue != nil { |
| trace.Wait100Continue() |
| } |
| } |
| |
| func http2traceWroteRequest(trace *http2clientTrace, err error) { |
| if trace != nil && trace.WroteRequest != nil { |
| trace.WroteRequest(httptrace.WroteRequestInfo{Err: err}) |
| } |
| } |
| |
| func http2traceFirstResponseByte(trace *http2clientTrace) { |
| if trace != nil && trace.GotFirstResponseByte != nil { |
| trace.GotFirstResponseByte() |
| } |
| } |
| |
| func http2requestTrace(req *Request) *http2clientTrace { |
| trace := httptrace.ContextClientTrace(req.Context()) |
| return (*http2clientTrace)(trace) |
| } |
| |
| // Ping sends a PING frame to the server and waits for the ack. |
| func (cc *http2ClientConn) Ping(ctx context.Context) error { |
| return cc.ping(ctx) |
| } |
| |
| func http2cloneTLSConfig(c *tls.Config) *tls.Config { |
| c2 := c.Clone() |
| c2.GetClientCertificate = c.GetClientCertificate // golang.org/issue/19264 |
| return c2 |
| } |
| |
| var _ Pusher = (*http2responseWriter)(nil) |
| |
| // Push implements http.Pusher. |
| func (w *http2responseWriter) Push(target string, opts *PushOptions) error { |
| internalOpts := http2pushOptions{} |
| if opts != nil { |
| internalOpts.Method = opts.Method |
| internalOpts.Header = opts.Header |
| } |
| return w.push(target, internalOpts) |
| } |
| |
| func http2configureServer18(h1 *Server, h2 *http2Server) error { |
| if h2.IdleTimeout == 0 { |
| if h1.IdleTimeout != 0 { |
| h2.IdleTimeout = h1.IdleTimeout |
| } else { |
| h2.IdleTimeout = h1.ReadTimeout |
| } |
| } |
| return nil |
| } |
| |
| func http2shouldLogPanic(panicValue interface{}) bool { |
| return panicValue != nil && panicValue != ErrAbortHandler |
| } |
| |
| func http2reqGetBody(req *Request) func() (io.ReadCloser, error) { |
| return req.GetBody |
| } |
| |
| func http2reqBodyIsNoBody(body io.ReadCloser) bool { |
| return body == NoBody |
| } |
| |
| func http2go18httpNoBody() io.ReadCloser { return NoBody } // for tests only |
| |
| func http2configureServer19(s *Server, conf *http2Server) error { |
| s.RegisterOnShutdown(conf.state.startGracefulShutdown) |
| return nil |
| } |
| |
| 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)] |
| // Parse the 4707 out of "goroutine 4707 [" |
| 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: |
| // valid base; nothing to do |
| |
| case base == 0: |
| // Look for octal, hex prefix. |
| 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 { |
| // n*base overflows |
| n = 1<<64 - 1 |
| err = strconv.ErrRange |
| goto Error |
| } |
| n *= uint64(base) |
| |
| n1 := n + uint64(v) |
| if n1 < n || n1 > maxVal { |
| // n+v overflows |
| 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 ( |
| http2commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case |
| http2commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case |
| ) |
| |
| func init() { |
| for _, v := range []string{ |
| "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", |
| } { |
| chk := CanonicalHeaderKey(v) |
| http2commonLowerHeader[chk] = v |
| http2commonCanonHeader[v] = chk |
| } |
| } |
| |
| func http2lowerHeader(v string) string { |
| if s, ok := http2commonLowerHeader[v]; ok { |
| return s |
| } |
| return strings.ToLower(v) |
| } |
| |
| var ( |
| http2VerboseLogs bool |
| http2logFrameWrites bool |
| http2logFrameReads bool |
| http2inTests bool |
| ) |
| |
| 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 |
| |
| // 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. |
| 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 { |
| // Limits and error codes from 6.5.2 Defined SETTINGS Parameters |
| 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)) |
| } |
| |
| var ( |
| http2errInvalidHeaderFieldName = errors.New("http2: invalid header field name") |
| http2errInvalidHeaderFieldValue = errors.New("http2: invalid header field value") |
| ) |
| |
| // validWireHeaderFieldName reports whether v is a valid header field |
| // name (key). See httplex.ValidHeaderName for the base rules. |
| // |
| // 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. " |
| func http2validWireHeaderFieldName(v string) bool { |
| if len(v) == 0 { |
| return false |
| } |
| for _, r := range v { |
| if !httplex.IsTokenRune(r) { |
| return false |
| } |
| if 'A' <= r && r <= 'Z' { |
| return false |
| } |
| } |
| return true |
| } |
| |
| var http2httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n) |
| |
| func init() { |
| for i := 100; i <= 999; i++ { |
| if v := StatusText(i); v != "" { |
| http2httpCodeStringCommon[i] = strconv.Itoa(i) |
| } |
| } |
| } |
| |
| func http2httpCodeString(code int) string { |
| if s, ok := http2httpCodeStringCommon[code]; ok { |
| return s |
| } |
| 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 { |
| w io.Writer // immutable |
| bw *bufio.Writer // non-nil when data is buffered |
| } |
| |
| func http2newBufferedWriter(w io.Writer) *http2bufferedWriter { |
| return &http2bufferedWriter{w: w} |
| } |
| |
| // 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 |
| |
| var http2bufWriterPool = sync.Pool{ |
| New: func() interface{} { |
| return bufio.NewWriterSize(nil, http2bufWriterPoolBufferSize) |
| }, |
| } |
| |
| func (w *http2bufferedWriter) Available() int { |
| if w.bw == nil { |
| return http2bufWriterPoolBufferSize |
| } |
| return w.bw.Available() |
| } |
| |
| 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 |
| // permits a body. See RFC 2616, section 4.4. |
| 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 { |
| 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} |
| |
| type http2connectionStater interface { |
| ConnectionState() tls.ConnectionState |
| } |
| |
| 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) { |
| // Our sorter works on s.v, which sorter owns, so |
| // stash it away while we sort the user's buffer. |
| save := s.v |
| s.v = ss |
| sort.Sort(s) |
| s.v = save |
| } |
| |
| // validPseudoPath reports whether v is a valid :path pseudo-header |
| // value. It must be either: |
| // |
| // *) a non-empty string starting with '/' |
| // *) 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 |
| // |
| // 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. |
| func http2validPseudoPath(v string) bool { |
| return (len(v) > 0 && v[0] == '/') || v == "*" |
| } |
| |
| // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like |
| // 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 |
| c sync.Cond // c.L lazily initialized to &p.mu |
| b http2pipeBuffer // nil when done reading |
| 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 |
| } |
| |
| type http2pipeBuffer interface { |
| Len() int |
| io.Writer |
| io.Reader |
| } |
| |
| func (p *http2pipe) Len() int { |
| p.mu.Lock() |
| defer p.mu.Unlock() |
| if p.b == nil { |
| return 0 |
| } |
| return p.b.Len() |
| } |
| |
| // 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 |
| } |
| if p.b != nil && p.b.Len() > 0 { |
| return p.b.Read(d) |
| } |
| if p.err != nil { |
| if p.readFn != nil { |
| p.readFn() // e.g. copy trailers |
| p.readFn = nil // not sticky like p.err |
| } |
| p.b = nil |
| 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 |
| } |
| if p.breakErr != nil { |
| return len(d), nil // discard when there is no reader |
| } |
| 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 { |
| // Already been done. |
| return |
| } |
| p.readFn = fn |
| if dst == &p.breakErr { |
| p.b = nil |
| } |
| *dst = err |
| p.closeDoneLocked() |
| } |
| |
| // requires p.mu be held. |
| func (p *http2pipe) closeDoneLocked() { |
| if p.donec == nil { |
| return |
| } |
| // Close if unclosed. This isn't racy since we always |
| // hold p.mu while closing. |
| 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 { |
| // Already hit an error. |
| p.closeDoneLocked() |
| } |
| } |
| return p.donec |
| } |
| |
| const ( |
| 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? |
| ) |
| |
| 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 |
| |
| // 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 |
| |
| // 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 |
| |
| // NewWriteScheduler constructs a write scheduler for a connection. |
| // If nil, a default scheduler is chosen. |
| NewWriteScheduler func() http2WriteScheduler |
| |
| // 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 |
| } |
| |
| 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 |
| } |
| |
| 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() |
| } |
| |
| // 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 { |
| if s == nil { |
| panic("nil *http.Server") |
| } |
| if conf == nil { |
| conf = new(http2Server) |
| } |
| conf.state = &http2serverInternalState{activeConns: make(map[*http2serverConn]struct{})} |
| if err := http2configureServer18(s, conf); err != nil { |
| return err |
| } |
| if err := http2configureServer19(s, conf); err != nil { |
| return err |
| } |
| |
| if s.TLSConfig == nil { |
| s.TLSConfig = new(tls.Config) |
| } else if s.TLSConfig.CipherSuites != nil { |
| // If they already provided a CipherSuite list, return |
| // an error if it has a bad order or is missing |
| // ECDHE_RSA_WITH_AES_128_GCM_SHA256. |
| const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
| haveRequired := false |
| sawBad := false |
| for i, cs := range s.TLSConfig.CipherSuites { |
| if cs == requiredCipher { |
| haveRequired = true |
| } |
| if http2isBadCipher(cs) { |
| sawBad = true |
| } else if sawBad { |
| return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs) |
| } |
| } |
| if !haveRequired { |
| return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256") |
| } |
| } |
| |
| // 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. |
| |
| s.TLSConfig.PreferServerCipherSuites = true |
| |
| haveNPN := false |
| for _, p := range s.TLSConfig.NextProtos { |
| if p == http2NextProtoTLS { |
| haveNPN = true |
| break |
| } |
| } |
| if !haveNPN { |
| s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, http2NextProtoTLS) |
| } |
| |
| 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() |
| } |
| conf.ServeConn(c, &http2ServeConnOpts{ |
| Handler: h, |
| BaseConfig: hs, |
| }) |
| } |
| s.TLSNextProto[http2NextProtoTLS] = protoHandler |
| return nil |
| } |
| |
| // ServeConnOpts are options for the Server.ServeConn method. |
| type http2ServeConnOpts struct { |
| // 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 |
| } |
| |
| 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) { |
| baseCtx, cancel := http2serverConnBaseContext(c, opts) |
| defer cancel() |
| |
| sc := &http2serverConn{ |
| 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. |
| if sc.hs.WriteTimeout != 0 { |
| sc.conn.SetWriteDeadline(time.Time{}) |
| } |
| |
| if s.NewWriteScheduler != nil { |
| sc.writeSched = s.NewWriteScheduler() |
| } else { |
| sc.writeSched = http2NewRandomWriteScheduler() |
| } |
| |
| // 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. |
| sc.flow.add(http2initialWindowSize) |
| sc.inflow.add(http2initialWindowSize) |
| sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) |
| |
| fr := http2NewFramer(sc.bw, c) |
| fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil) |
| fr.MaxHeaderListSize = sc.maxHeaderListSize() |
| fr.SetMaxReadFrameSize(s.maxReadFrameSize()) |
| sc.framer = fr |
| |
| if tc, ok := c.(http2connectionStater); ok { |
| sc.tlsState = new(tls.ConnectionState) |
| *sc.tlsState = tc.ConnectionState() |
| // 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. |
| if sc.tlsState.Version < tls.VersionTLS12 { |
| sc.rejectConn(http2ErrCodeInadequateSecurity, "TLS version too low") |
| return |
| } |
| |
| if sc.tlsState.ServerName == "" { |
| // 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 |
| // a new request, and verify the the ServerName matches the :authority? |
| // But that precludes proxy situations, perhaps. |
| // |
| // So for now, do nothing here again. |
| } |
| |
| if !s.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) { |
| // "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. |
| 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() |
| } |
| |
| func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) { |
| sc.vlogf("http2: server rejecting conn: %v, %s", err, debug) |
| // ignoring errors. hanging up anyway. |
| 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 |
| baseCtx http2contextContext |
| framer *http2Framer |
| 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 |
| serveMsgCh chan interface{} // misc messages & code to send to / run on the serve loop |
| 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 |
| remoteAddrStr string |
| writeSched http2WriteScheduler |
| |
| // Everything following is owned by the serve loop; use serveG.check(): |
| 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? |
| 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 |
| |
| // Owned by the writeFrameAsync goroutine: |
| headerWriteBuf bytes.Buffer |
| hpackEncoder *hpack.Encoder |
| |
| // Used by startGracefulShutdown. |
| shutdownOnce sync.Once |
| } |
| |
| 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) |
| } |
| |
| func (sc *http2serverConn) curOpenStreams() uint32 { |
| sc.serveG.check() |
| return sc.curClientStreams + sc.curPushedStreams |
| } |
| |
| // 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: |
| sc *http2serverConn |
| id uint32 |
| body *http2pipe // non-nil if expecting DATA frames |
| cw http2closeWaiter // closed wait stream transitions to closed state |
| ctx http2contextContext |
| cancelCtx func() |
| |
| // owned by serverConn's serve loop: |
| 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 |
| parent *http2stream // or nil |
| numTrailerValues int64 |
| weight uint8 |
| state http2streamState |
| 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 |
| |
| 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() |
| // http://tools.ietf.org/html/rfc7540#section-5.1 |
| if st, ok := sc.streams[streamID]; ok { |
| return st.state, st |
| } |
| // "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." |
| if streamID%2 == 1 { |
| if streamID <= sc.maxClientStreamID { |
| return http2stateClosed, nil |
| } |
| } else { |
| if streamID <= sc.maxPushPromiseID { |
| return http2stateClosed, nil |
| } |
| } |
| |