|  | // 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" | 
|  | mathrand "math/rand" | 
|  | "net" | 
|  | "net/http/httptrace" | 
|  | "net/textproto" | 
|  | "net/url" | 
|  | "os" | 
|  | "reflect" | 
|  | "runtime" | 
|  | "sort" | 
|  | "strconv" | 
|  | "strings" | 
|  | "sync" | 
|  | "time" | 
|  |  | 
|  | "golang_org/x/net/http/httpguts" | 
|  | "golang_org/x/net/http2/hpack" | 
|  | "golang_org/x/net/idna" | 
|  | ) | 
|  |  | 
|  | // A list of the possible cipher suite ids. Taken from | 
|  | // https://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 | 
|  | ) | 
|  |  | 
|  | // shouldTraceGetConn reports whether getClientConn should call any | 
|  | // ClientTrace.GetConn hook associated with the http.Request. | 
|  | // | 
|  | // This complexity is needed to avoid double calls of the GetConn hook | 
|  | // during the back-and-forth between net/http and x/net/http2 (when the | 
|  | // net/http.Transport is upgraded to also speak http2), as well as support | 
|  | // the case where x/net/http2 is being used directly. | 
|  | func (p *http2clientConnPool) shouldTraceGetConn(st http2clientConnIdleState) bool { | 
|  | // If our Transport wasn't made via ConfigureTransport, always | 
|  | // trace the GetConn hook if provided, because that means the | 
|  | // http2 package is being used directly and it's the one | 
|  | // dialing, as opposed to net/http. | 
|  | if _, ok := p.t.ConnPool.(http2noDialClientConnPool); !ok { | 
|  | return true | 
|  | } | 
|  | // Otherwise, only use the GetConn hook if this connection has | 
|  | // been used previously for other requests. For fresh | 
|  | // connections, the net/http package does the dialing. | 
|  | return !st.freshConn | 
|  | } | 
|  |  | 
|  | func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) { | 
|  | if http2isConnectionCloseRequest(req) && dialOnMiss { | 
|  | // It gets its own connection. | 
|  | http2traceGetConn(req, addr) | 
|  | 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 st := cc.idleState(); st.canTakeNewRequest { | 
|  | if p.shouldTraceGetConn(st) { | 
|  | http2traceGetConn(req, addr) | 
|  | } | 
|  | p.mu.Unlock() | 
|  | return cc, nil | 
|  | } | 
|  | } | 
|  | if !dialOnMiss { | 
|  | p.mu.Unlock() | 
|  | return nil, http2ErrNoCachedConn | 
|  | } | 
|  | http2traceGetConn(req, addr) | 
|  | 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 http2noDialH2RoundTripper) (err error) { | 
|  | defer func() { | 
|  | if e := recover(); e != nil { | 
|  | err = fmt.Errorf("%v", e) | 
|  | } | 
|  | }() | 
|  | t.RegisterProtocol("https", rt) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // noDialH2RoundTripper is a RoundTripper which only tries to complete the request | 
|  | // if there's already has a cached connection to the host. | 
|  | // (The field is exported so it can be accessed via reflect from net/http; tested | 
|  | // by TestNoDialH2RoundTripperType) | 
|  | type http2noDialH2RoundTripper struct{ *http2Transport } | 
|  |  | 
|  | func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) { | 
|  | res, err := rt.http2Transport.RoundTrip(req) | 
|  | if http2isNoCachedConnError(err) { | 
|  | return nil, ErrSkipAltProtocol | 
|  | } | 
|  | return res, err | 
|  | } | 
|  |  | 
|  | // 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 { | 
|  | sum := f.n + n | 
|  | if (sum > n) == (f.n > 0) { | 
|  | f.n = sum | 
|  | return true | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | 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(id http2SettingID) (v uint32, ok bool) { | 
|  | f.checkValid() | 
|  | for i := 0; i < f.NumSettings(); i++ { | 
|  | if s := f.Setting(i); s.ID == id { | 
|  | return s.Val, true | 
|  | } | 
|  | } | 
|  | return 0, false | 
|  | } | 
|  |  | 
|  | // Setting returns the setting from the frame at the given 0-based index. | 
|  | // The index must be >= 0 and less than f.NumSettings(). | 
|  | func (f *http2SettingsFrame) Setting(i int) http2Setting { | 
|  | buf := f.p | 
|  | return http2Setting{ | 
|  | ID:  http2SettingID(binary.BigEndian.Uint16(buf[i*6 : i*6+2])), | 
|  | Val: binary.BigEndian.Uint32(buf[i*6+2 : i*6+6]), | 
|  | } | 
|  | } | 
|  |  | 
|  | func (f *http2SettingsFrame) NumSettings() int { return len(f.p) / 6 } | 
|  |  | 
|  | // HasDuplicates reports whether f contains any duplicate setting IDs. | 
|  | func (f *http2SettingsFrame) HasDuplicates() bool { | 
|  | num := f.NumSettings() | 
|  | if num == 0 { | 
|  | return false | 
|  | } | 
|  | // If it's small enough (the common case), just do the n^2 | 
|  | // thing and avoid a map allocation. | 
|  | if num < 10 { | 
|  | for i := 0; i < num; i++ { | 
|  | idi := f.Setting(i).ID | 
|  | for j := i + 1; j < num; j++ { | 
|  | idj := f.Setting(j).ID | 
|  | if idi == idj { | 
|  | return true | 
|  | } | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  | seen := map[http2SettingID]bool{} | 
|  | for i := 0; i < num; i++ { | 
|  | id := f.Setting(i).ID | 
|  | if seen[id] { | 
|  | return true | 
|  | } | 
|  | seen[id] = true | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // ForeachSetting runs fn for each setting. | 
|  | // It stops and returns the first error. | 
|  | func (f *http2SettingsFrame) ForeachSetting(fn func(http2Setting) error) error { | 
|  | f.checkValid() | 
|  | for i := 0; i < f.NumSettings(); i++ { | 
|  | if err := fn(f.Setting(i)); err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // WriteSettings writes a SETTINGS frame with zero or more settings | 
|  | // specified and the ACK bit not set. | 
|  | // | 
|  | // It will perform exactly one Write to the underlying Writer. | 
|  | // It is the caller's responsibility to not call other Write methods concurrently. | 
|  | func (f *http2Framer) WriteSettings(settings ...http2Setting) error { | 
|  | f.startWrite(http2FrameSettings, 0, 0) | 
|  | for _, s := range settings { | 
|  | f.writeUint16(uint16(s.ID)) | 
|  | f.writeUint32(s.Val) | 
|  | } | 
|  | return f.endWrite() | 
|  | } | 
|  |  | 
|  | // 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 !httpguts.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 http2traceHasWroteHeaderField(trace *http2clientTrace) bool { | 
|  | return trace != nil && trace.WroteHeaderField != nil | 
|  | } | 
|  |  | 
|  | func http2traceWroteHeaderField(trace *http2clientTrace, k, v string) { | 
|  | if trace != nil && trace.WroteHeaderField != nil { | 
|  | trace.WroteHeaderField(k, []string{v}) | 
|  | } | 
|  | } | 
|  |  | 
|  | func http2traceGot1xxResponseFunc(trace *http2clientTrace) func(int, textproto.MIMEHeader) error { | 
|  | if trace != nil { | 
|  | return trace.Got1xxResponse | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func http2transportExpectContinueTimeout(t1 *Transport) time.Duration { | 
|  | return t1.ExpectContinueTimeout | 
|  | } | 
|  |  | 
|  | type http2contextContext interface { | 
|  | context.Context | 
|  | } | 
|  |  | 
|  | var http2errCanceled = context.Canceled | 
|  |  | 
|  | 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 http2traceGetConn(req *Request, hostPort string) { | 
|  | trace := httptrace.ContextClientTrace(req.Context()) | 
|  | if trace == nil || trace.GetConn == nil { | 
|  | return | 
|  | } | 
|  | trace.GetConn(hostPort) | 
|  | } | 
|  |  | 
|  | 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) | 
|  | } | 
|  |  | 
|  | // Shutdown gracefully closes the client connection, waiting for running streams to complete. | 
|  | func (cc *http2ClientConn) Shutdown(ctx context.Context) error { | 
|  | return cc.shutdown(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 httpguts.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 !httpguts.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 7230, section 3.3. | 
|  | 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 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. | 
|  | haveRequired := false | 
|  | sawBad := false | 
|  | for i, cs := range s.TLSConfig.CipherSuites { | 
|  | switch cs { | 
|  | case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | 
|  | // Alternative MTI cipher to not discourage ECDSA-only servers. | 
|  | // See http://golang.org/cl/30721 for further information. | 
|  | tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: | 
|  | 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 an HTTP/2-required AES_128_GCM_SHA256 cipher.") | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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 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 | 
|  | } | 
|  | } | 
|  | return http2stateIdle, nil | 
|  | } | 
|  |  | 
|  | // setConnState calls the net/http ConnState hook for this connection, if configured. | 
|  | // Note that the net/http package does StateNew and StateClosed for us. | 
|  | // There is currently no plan for StateHijacked or hijacking HTTP/2 connections. | 
|  | func (sc *http2serverConn) setConnState(state ConnState) { | 
|  | if sc.hs.ConnState != nil { | 
|  | sc.hs.ConnState(sc.conn, state) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) vlogf(format string, args ...interface{}) { | 
|  | if http2VerboseLogs { | 
|  | sc.logf(format, args...) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) logf(format string, args ...interface{}) { | 
|  | if lg := sc.hs.ErrorLog; lg != nil { | 
|  | lg.Printf(format, args...) | 
|  | } else { | 
|  | log.Printf(format, args...) | 
|  | } | 
|  | } | 
|  |  | 
|  | // errno returns v's underlying uintptr, else 0. | 
|  | // | 
|  | // TODO: remove this helper function once http2 can use build | 
|  | // tags. See comment in isClosedConnError. | 
|  | func http2errno(v error) uintptr { | 
|  | if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr { | 
|  | return uintptr(rv.Uint()) | 
|  | } | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | // isClosedConnError reports whether err is an error from use of a closed | 
|  | // network connection. | 
|  | func http2isClosedConnError(err error) bool { | 
|  | if err == nil { | 
|  | return false | 
|  | } | 
|  |  | 
|  | // TODO: remove this string search and be more like the Windows | 
|  | // case below. That might involve modifying the standard library | 
|  | // to return better error types. | 
|  | str := err.Error() | 
|  | if strings.Contains(str, "use of closed network connection") { | 
|  | return true | 
|  | } | 
|  |  | 
|  | // TODO(bradfitz): x/tools/cmd/bundle doesn't really support | 
|  | // build tags, so I can't make an http2_windows.go file with | 
|  | // Windows-specific stuff. Fix that and move this, once we | 
|  | // have a way to bundle this into std's net/http somehow. | 
|  | if runtime.GOOS == "windows" { | 
|  | if oe, ok := err.(*net.OpError); ok && oe.Op == "read" { | 
|  | if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" { | 
|  | const WSAECONNABORTED = 10053 | 
|  | const WSAECONNRESET = 10054 | 
|  | if n := http2errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED { | 
|  | return true | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) condlogf(err error, format string, args ...interface{}) { | 
|  | if err == nil { | 
|  | return | 
|  | } | 
|  | if err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) || err == http2errPrefaceTimeout { | 
|  | // Boring, expected errors. | 
|  | sc.vlogf(format, args...) | 
|  | } else { | 
|  | sc.logf(format, args...) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) canonicalHeader(v string) string { | 
|  | sc.serveG.check() | 
|  | cv, ok := http2commonCanonHeader[v] | 
|  | if ok { | 
|  | return cv | 
|  | } | 
|  | cv, ok = sc.canonHeader[v] | 
|  | if ok { | 
|  | return cv | 
|  | } | 
|  | if sc.canonHeader == nil { | 
|  | sc.canonHeader = make(map[string]string) | 
|  | } | 
|  | cv = CanonicalHeaderKey(v) | 
|  | sc.canonHeader[v] = cv | 
|  | return cv | 
|  | } | 
|  |  | 
|  | type http2readFrameResult struct { | 
|  | f   http2Frame // valid until readMore is called | 
|  | err error | 
|  |  | 
|  | // readMore should be called once the consumer no longer needs or | 
|  | // retains f. After readMore, f is invalid and more frames can be | 
|  | // read. | 
|  | readMore func() | 
|  | } | 
|  |  | 
|  | // readFrames is the loop that reads incoming frames. | 
|  | // It takes care to only read one frame at a time, blocking until the | 
|  | // consumer is done with the frame. | 
|  | // It's run on its own goroutine. | 
|  | func (sc *http2serverConn) readFrames() { | 
|  | gate := make(http2gate) | 
|  | gateDone := gate.Done | 
|  | for { | 
|  | f, err := sc.framer.ReadFrame() | 
|  | select { | 
|  | case sc.readFrameCh <- http2readFrameResult{f, err, gateDone}: | 
|  | case <-sc.doneServing: | 
|  | return | 
|  | } | 
|  | select { | 
|  | case <-gate: | 
|  | case <-sc.doneServing: | 
|  | return | 
|  | } | 
|  | if http2terminalReadFrameError(err) { | 
|  | return | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // frameWriteResult is the message passed from writeFrameAsync to the serve goroutine. | 
|  | type http2frameWriteResult struct { | 
|  | wr  http2FrameWriteRequest // what was written (or attempted) | 
|  | err error                  // result of the writeFrame call | 
|  | } | 
|  |  | 
|  | // writeFrameAsync runs in its own goroutine and writes a single frame | 
|  | // and then reports when it's done. | 
|  | // At most one goroutine can be running writeFrameAsync at a time per | 
|  | // serverConn. | 
|  | func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest) { | 
|  | err := wr.write.writeFrame(sc) | 
|  | sc.wroteFrameCh <- http2frameWriteResult{wr, err} | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) closeAllStreamsOnConnClose() { | 
|  | sc.serveG.check() | 
|  | for _, st := range sc.streams { | 
|  | sc.closeStream(st, http2errClientDisconnected) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) stopShutdownTimer() { | 
|  | sc.serveG.check() | 
|  | if t := sc.shutdownTimer; t != nil { | 
|  | t.Stop() | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) notePanic() { | 
|  | // Note: this is for serverConn.serve panicking, not http.Handler code. | 
|  | if http2testHookOnPanicMu != nil { | 
|  | http2testHookOnPanicMu.Lock() | 
|  | defer http2testHookOnPanicMu.Unlock() | 
|  | } | 
|  | if http2testHookOnPanic != nil { | 
|  | if e := recover(); e != nil { | 
|  | if http2testHookOnPanic(sc, e) { | 
|  | panic(e) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) serve() { | 
|  | sc.serveG.check() | 
|  | defer sc.notePanic() | 
|  | defer sc.conn.Close() | 
|  | defer sc.closeAllStreamsOnConnClose() | 
|  | defer sc.stopShutdownTimer() | 
|  | defer close(sc.doneServing) // unblocks handlers trying to send | 
|  |  | 
|  | if http2VerboseLogs { | 
|  | sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs) | 
|  | } | 
|  |  | 
|  | sc.writeFrame(http2FrameWriteRequest{ | 
|  | write: http2writeSettings{ | 
|  | {http2SettingMaxFrameSize, sc.srv.maxReadFrameSize()}, | 
|  | {http2SettingMaxConcurrentStreams, sc.advMaxStreams}, | 
|  | {http2SettingMaxHeaderListSize, sc.maxHeaderListSize()}, | 
|  | {http2SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())}, | 
|  | }, | 
|  | }) | 
|  | sc.unackedSettings++ | 
|  |  | 
|  | // Each connection starts with intialWindowSize inflow tokens. | 
|  | // If a higher value is configured, we add more tokens. | 
|  | if diff := sc.srv.initialConnRecvWindowSize() - http2initialWindowSize; diff > 0 { | 
|  | sc.sendWindowUpdate(nil, int(diff)) | 
|  | } | 
|  |  | 
|  | if err := sc.readPreface(); err != nil { | 
|  | sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err) | 
|  | return | 
|  | } | 
|  | // Now that we've got the preface, get us out of the | 
|  | // "StateNew" state. We can't go directly to idle, though. | 
|  | // Active means we read some data and anticipate a request. We'll | 
|  | // do another Active when we get a HEADERS frame. | 
|  | sc.setConnState(StateActive) | 
|  | sc.setConnState(StateIdle) | 
|  |  | 
|  | if sc.srv.IdleTimeout != 0 { | 
|  | sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer) | 
|  | defer sc.idleTimer.Stop() | 
|  | } | 
|  |  | 
|  | go sc.readFrames() // closed by defer sc.conn.Close above | 
|  |  | 
|  | settingsTimer := time.AfterFunc(http2firstSettingsTimeout, sc.onSettingsTimer) | 
|  | defer settingsTimer.Stop() | 
|  |  | 
|  | loopNum := 0 | 
|  | for { | 
|  | loopNum++ | 
|  | select { | 
|  | case wr := <-sc.wantWriteFrameCh: | 
|  | if se, ok := wr.write.(http2StreamError); ok { | 
|  | sc.resetStream(se) | 
|  | break | 
|  | } | 
|  | sc.writeFrame(wr) | 
|  | case res := <-sc.wroteFrameCh: | 
|  | sc.wroteFrame(res) | 
|  | case res := <-sc.readFrameCh: | 
|  | if !sc.processFrameFromReader(res) { | 
|  | return | 
|  | } | 
|  | res.readMore() | 
|  | if settingsTimer != nil { | 
|  | settingsTimer.Stop() | 
|  | settingsTimer = nil | 
|  | } | 
|  | case m := <-sc.bodyReadCh: | 
|  | sc.noteBodyRead(m.st, m.n) | 
|  | case msg := <-sc.serveMsgCh: | 
|  | switch v := msg.(type) { | 
|  | case func(int): | 
|  | v(loopNum) // for testing | 
|  | case *http2serverMessage: | 
|  | switch v { | 
|  | case http2settingsTimerMsg: | 
|  | sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr()) | 
|  | return | 
|  | case http2idleTimerMsg: | 
|  | sc.vlogf("connection is idle") | 
|  | sc.goAway(http2ErrCodeNo) | 
|  | case http2shutdownTimerMsg: | 
|  | sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr()) | 
|  | return | 
|  | case http2gracefulShutdownMsg: | 
|  | sc.startGracefulShutdownInternal() | 
|  | default: | 
|  | panic("unknown timer") | 
|  | } | 
|  | case *http2startPushRequest: | 
|  | sc.startPush(v) | 
|  | default: | 
|  | panic(fmt.Sprintf("unexpected type %T", v)) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Start the shutdown timer after sending a GOAWAY. When sending GOAWAY | 
|  | // with no error code (graceful shutdown), don't start the timer until | 
|  | // all open streams have been completed. | 
|  | sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame | 
|  | gracefulShutdownComplete := sc.goAwayCode == http2ErrCodeNo && sc.curOpenStreams() == 0 | 
|  | if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != http2ErrCodeNo || gracefulShutdownComplete) { | 
|  | sc.shutDownIn(http2goAwayTimeout) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, privateCh chan struct{}) { | 
|  | select { | 
|  | case <-sc.doneServing: | 
|  | case <-sharedCh: | 
|  | close(privateCh) | 
|  | } | 
|  | } | 
|  |  | 
|  | type http2serverMessage int | 
|  |  | 
|  | // Message values sent to serveMsgCh. | 
|  | var ( | 
|  | http2settingsTimerMsg    = new(http2serverMessage) | 
|  | http2idleTimerMsg        = new(http2serverMessage) | 
|  | http2shutdownTimerMsg    = new(http2serverMessage) | 
|  | http2gracefulShutdownMsg = new(http2serverMessage) | 
|  | ) | 
|  |  | 
|  | func (sc *http2serverConn) onSettingsTimer() { sc.sendServeMsg(http2settingsTimerMsg) } | 
|  |  | 
|  | func (sc *http2serverConn) onIdleTimer() { sc.sendServeMsg(http2idleTimerMsg) } | 
|  |  | 
|  | func (sc *http2serverConn) onShutdownTimer() { sc.sendServeMsg(http2shutdownTimerMsg) } | 
|  |  | 
|  | func (sc *http2serverConn) sendServeMsg(msg interface{}) { | 
|  | sc.serveG.checkNotOn() // NOT | 
|  | select { | 
|  | case sc.serveMsgCh <- msg: | 
|  | case <-sc.doneServing: | 
|  | } | 
|  | } | 
|  |  | 
|  | var http2errPrefaceTimeout = errors.New("timeout waiting for client preface") | 
|  |  | 
|  | // readPreface reads the ClientPreface greeting from the peer or | 
|  | // returns errPrefaceTimeout on timeout, or an error if the greeting | 
|  | // is invalid. | 
|  | func (sc *http2serverConn) readPreface() error { | 
|  | errc := make(chan error, 1) | 
|  | go func() { | 
|  | // Read the client preface | 
|  | buf := make([]byte, len(http2ClientPreface)) | 
|  | if _, err := io.ReadFull(sc.conn, buf); err != nil { | 
|  | errc <- err | 
|  | } else if !bytes.Equal(buf, http2clientPreface) { | 
|  | errc <- fmt.Errorf("bogus greeting %q", buf) | 
|  | } else { | 
|  | errc <- nil | 
|  | } | 
|  | }() | 
|  | timer := time.NewTimer(http2prefaceTimeout) // TODO: configurable on *Server? | 
|  | defer timer.Stop() | 
|  | select { | 
|  | case <-timer.C: | 
|  | return http2errPrefaceTimeout | 
|  | case err := <-errc: | 
|  | if err == nil { | 
|  | if http2VerboseLogs { | 
|  | sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr()) | 
|  | } | 
|  | } | 
|  | return err | 
|  | } | 
|  | } | 
|  |  | 
|  | var http2errChanPool = sync.Pool{ | 
|  | New: func() interface{} { return make(chan error, 1) }, | 
|  | } | 
|  |  | 
|  | var http2writeDataPool = sync.Pool{ | 
|  | New: func() interface{} { return new(http2writeData) }, | 
|  | } | 
|  |  | 
|  | // writeDataFromHandler writes DATA response frames from a handler on | 
|  | // the given stream. | 
|  | func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte, endStream bool) error { | 
|  | ch := http2errChanPool.Get().(chan error) | 
|  | writeArg := http2writeDataPool.Get().(*http2writeData) | 
|  | *writeArg = http2writeData{stream.id, data, endStream} | 
|  | err := sc.writeFrameFromHandler(http2FrameWriteRequest{ | 
|  | write:  writeArg, | 
|  | stream: stream, | 
|  | done:   ch, | 
|  | }) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | var frameWriteDone bool // the frame write is done (successfully or not) | 
|  | select { | 
|  | case err = <-ch: | 
|  | frameWriteDone = true | 
|  | case <-sc.doneServing: | 
|  | return http2errClientDisconnected | 
|  | case <-stream.cw: | 
|  | // If both ch and stream.cw were ready (as might | 
|  | // happen on the final Write after an http.Handler | 
|  | // ends), prefer the write result. Otherwise this | 
|  | // might just be us successfully closing the stream. | 
|  | // The writeFrameAsync and serve goroutines guarantee | 
|  | // that the ch send will happen before the stream.cw | 
|  | // close. | 
|  | select { | 
|  | case err = <-ch: | 
|  | frameWriteDone = true | 
|  | default: | 
|  | return http2errStreamClosed | 
|  | } | 
|  | } | 
|  | http2errChanPool.Put(ch) | 
|  | if frameWriteDone { | 
|  | http2writeDataPool.Put(writeArg) | 
|  | } | 
|  | return err | 
|  | } | 
|  |  | 
|  | // writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts | 
|  | // if the connection has gone away. | 
|  | // | 
|  | // This must not be run from the serve goroutine itself, else it might | 
|  | // deadlock writing to sc.wantWriteFrameCh (which is only mildly | 
|  | // buffered and is read by serve itself). If you're on the serve | 
|  | // goroutine, call writeFrame instead. | 
|  | func (sc *http2serverConn) writeFrameFromHandler(wr http2FrameWriteRequest) error { | 
|  | sc.serveG.checkNotOn() // NOT | 
|  | select { | 
|  | case sc.wantWriteFrameCh <- wr: | 
|  | return nil | 
|  | case <-sc.doneServing: | 
|  | // Serve loop is gone. | 
|  | // Client has closed their connection to the server. | 
|  | return http2errClientDisconnected | 
|  | } | 
|  | } | 
|  |  | 
|  | // writeFrame schedules a frame to write and sends it if there's nothing | 
|  | // already being written. | 
|  | // | 
|  | // There is no pushback here (the serve goroutine never blocks). It's | 
|  | // the http.Handlers that block, waiting for their previous frames to | 
|  | // make it onto the wire | 
|  | // | 
|  | // If you're not on the serve goroutine, use writeFrameFromHandler instead. | 
|  | func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) { | 
|  | sc.serveG.check() | 
|  |  | 
|  | // If true, wr will not be written and wr.done will not be signaled. | 
|  | var ignoreWrite bool | 
|  |  | 
|  | // We are not allowed to write frames on closed streams. RFC 7540 Section | 
|  | // 5.1.1 says: "An endpoint MUST NOT send frames other than PRIORITY on | 
|  | // a closed stream." Our server never sends PRIORITY, so that exception | 
|  | // does not apply. | 
|  | // | 
|  | // The serverConn might close an open stream while the stream's handler | 
|  | // is still running. For example, the server might close a stream when it | 
|  | // receives bad data from the client. If this happens, the handler might | 
|  | // attempt to write a frame after the stream has been closed (since the | 
|  | // handler hasn't yet been notified of the close). In this case, we simply | 
|  | // ignore the frame. The handler will notice that the stream is closed when | 
|  | // it waits for the frame to be written. | 
|  | // | 
|  | // As an exception to this rule, we allow sending RST_STREAM after close. | 
|  | // This allows us to immediately reject new streams without tracking any | 
|  | // state for those streams (except for the queued RST_STREAM frame). This | 
|  | // may result in duplicate RST_STREAMs in some cases, but the client should | 
|  | // ignore those. | 
|  | if wr.StreamID() != 0 { | 
|  | _, isReset := wr.write.(http2StreamError) | 
|  | if state, _ := sc.state(wr.StreamID()); state == http2stateClosed && !isReset { | 
|  | ignoreWrite = true | 
|  | } | 
|  | } | 
|  |  | 
|  | // Don't send a 100-continue response if we've already sent headers. | 
|  | // See golang.org/issue/14030. | 
|  | switch wr.write.(type) { | 
|  | case *http2writeResHeaders: | 
|  | wr.stream.wroteHeaders = true | 
|  | case http2write100ContinueHeadersFrame: | 
|  | if wr.stream.wroteHeaders { | 
|  | // We do not need to notify wr.done because this frame is | 
|  | // never written with wr.done != nil. | 
|  | if wr.done != nil { | 
|  | panic("wr.done != nil for write100ContinueHeadersFrame") | 
|  | } | 
|  | ignoreWrite = true | 
|  | } | 
|  | } | 
|  |  | 
|  | if !ignoreWrite { | 
|  | sc.writeSched.Push(wr) | 
|  | } | 
|  | sc.scheduleFrameWrite() | 
|  | } | 
|  |  | 
|  | // startFrameWrite starts a goroutine to write wr (in a separate | 
|  | // goroutine since that might block on the network), and updates the | 
|  | // serve goroutine's state about the world, updated from info in wr. | 
|  | func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) { | 
|  | sc.serveG.check() | 
|  | if sc.writingFrame { | 
|  | panic("internal error: can only be writing one frame at a time") | 
|  | } | 
|  |  | 
|  | st := wr.stream | 
|  | if st != nil { | 
|  | switch st.state { | 
|  | case http2stateHalfClosedLocal: | 
|  | switch wr.write.(type) { | 
|  | case http2StreamError, http2handlerPanicRST, http2writeWindowUpdate: | 
|  | // RFC 7540 Section 5.1 allows sending RST_STREAM, PRIORITY, and WINDOW_UPDATE | 
|  | // in this state. (We never send PRIORITY from the server, so that is not checked.) | 
|  | default: | 
|  | panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr)) | 
|  | } | 
|  | case http2stateClosed: | 
|  | panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr)) | 
|  | } | 
|  | } | 
|  | if wpp, ok := wr.write.(*http2writePushPromise); ok { | 
|  | var err error | 
|  | wpp.promisedID, err = wpp.allocatePromisedID() | 
|  | if err != nil { | 
|  | sc.writingFrameAsync = false | 
|  | wr.replyToWriter(err) | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | sc.writingFrame = true | 
|  | sc.needsFrameFlush = true | 
|  | if wr.write.staysWithinBuffer(sc.bw.Available()) { | 
|  | sc.writingFrameAsync = false | 
|  | err := wr.write.writeFrame(sc) | 
|  | sc.wroteFrame(http2frameWriteResult{wr, err}) | 
|  | } else { | 
|  | sc.writingFrameAsync = true | 
|  | go sc.writeFrameAsync(wr) | 
|  | } | 
|  | } | 
|  |  | 
|  | // errHandlerPanicked is the error given to any callers blocked in a read from | 
|  | // Request.Body when the main goroutine panics. Since most handlers read in the | 
|  | // the main ServeHTTP goroutine, this will show up rarely. | 
|  | var http2errHandlerPanicked = errors.New("http2: handler panicked") | 
|  |  | 
|  | // wroteFrame is called on the serve goroutine with the result of | 
|  | // whatever happened on writeFrameAsync. | 
|  | func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) { | 
|  | sc.serveG.check() | 
|  | if !sc.writingFrame { | 
|  | panic("internal error: expected to be already writing a frame") | 
|  | } | 
|  | sc.writingFrame = false | 
|  | sc.writingFrameAsync = false | 
|  |  | 
|  | wr := res.wr | 
|  |  | 
|  | if http2writeEndsStream(wr.write) { | 
|  | st := wr.stream | 
|  | if st == nil { | 
|  | panic("internal error: expecting non-nil stream") | 
|  | } | 
|  | switch st.state { | 
|  | case http2stateOpen: | 
|  | // Here we would go to stateHalfClosedLocal in | 
|  | // theory, but since our handler is done and | 
|  | // the net/http package provides no mechanism | 
|  | // for closing a ResponseWriter while still | 
|  | // reading data (see possible TODO at top of | 
|  | // this file), we go into closed state here | 
|  | // anyway, after telling the peer we're | 
|  | // hanging up on them. We'll transition to | 
|  | // stateClosed after the RST_STREAM frame is | 
|  | // written. | 
|  | st.state = http2stateHalfClosedLocal | 
|  | // Section 8.1: a server MAY request that the client abort | 
|  | // transmission of a request without error by sending a | 
|  | // RST_STREAM with an error code of NO_ERROR after sending | 
|  | // a complete response. | 
|  | sc.resetStream(http2streamError(st.id, http2ErrCodeNo)) | 
|  | case http2stateHalfClosedRemote: | 
|  | sc.closeStream(st, http2errHandlerComplete) | 
|  | } | 
|  | } else { | 
|  | switch v := wr.write.(type) { | 
|  | case http2StreamError: | 
|  | // st may be unknown if the RST_STREAM was generated to reject bad input. | 
|  | if st, ok := sc.streams[v.StreamID]; ok { | 
|  | sc.closeStream(st, v) | 
|  | } | 
|  | case http2handlerPanicRST: | 
|  | sc.closeStream(wr.stream, http2errHandlerPanicked) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Reply (if requested) to unblock the ServeHTTP goroutine. | 
|  | wr.replyToWriter(res.err) | 
|  |  | 
|  | sc.scheduleFrameWrite() | 
|  | } | 
|  |  | 
|  | // scheduleFrameWrite tickles the frame writing scheduler. | 
|  | // | 
|  | // If a frame is already being written, nothing happens. This will be called again | 
|  | // when the frame is done being written. | 
|  | // | 
|  | // If a frame isn't being written we need to send one, the best frame | 
|  | // to send is selected, preferring first things that aren't | 
|  | // stream-specific (e.g. ACKing settings), and then finding the | 
|  | // highest priority stream. | 
|  | // | 
|  | // If a frame isn't being written and there's nothing else to send, we | 
|  | // flush the write buffer. | 
|  | func (sc *http2serverConn) scheduleFrameWrite() { | 
|  | sc.serveG.check() | 
|  | if sc.writingFrame || sc.inFrameScheduleLoop { | 
|  | return | 
|  | } | 
|  | sc.inFrameScheduleLoop = true | 
|  | for !sc.writingFrameAsync { | 
|  | if sc.needToSendGoAway { | 
|  | sc.needToSendGoAway = false | 
|  | sc.startFrameWrite(http2FrameWriteRequest{ | 
|  | write: &http2writeGoAway{ | 
|  | maxStreamID: sc.maxClientStreamID, | 
|  | code:        sc.goAwayCode, | 
|  | }, | 
|  | }) | 
|  | continue | 
|  | } | 
|  | if sc.needToSendSettingsAck { | 
|  | sc.needToSendSettingsAck = false | 
|  | sc.startFrameWrite(http2FrameWriteRequest{write: http2writeSettingsAck{}}) | 
|  | continue | 
|  | } | 
|  | if !sc.inGoAway || sc.goAwayCode == http2ErrCodeNo { | 
|  | if wr, ok := sc.writeSched.Pop(); ok { | 
|  | sc.startFrameWrite(wr) | 
|  | continue | 
|  | } | 
|  | } | 
|  | if sc.needsFrameFlush { | 
|  | sc.startFrameWrite(http2FrameWriteRequest{write: http2flushFrameWriter{}}) | 
|  | sc.needsFrameFlush = false // after startFrameWrite, since it sets this true | 
|  | continue | 
|  | } | 
|  | break | 
|  | } | 
|  | sc.inFrameScheduleLoop = false | 
|  | } | 
|  |  | 
|  | // startGracefulShutdown gracefully shuts down a connection. This | 
|  | // sends GOAWAY with ErrCodeNo to tell the client we're gracefully | 
|  | // shutting down. The connection isn't closed until all current | 
|  | // streams are done. | 
|  | // | 
|  | // startGracefulShutdown returns immediately; it does not wait until | 
|  | // the connection has shut down. | 
|  | func (sc *http2serverConn) startGracefulShutdown() { | 
|  | sc.serveG.checkNotOn() // NOT | 
|  | sc.shutdownOnce.Do(func() { sc.sendServeMsg(http2gracefulShutdownMsg) }) | 
|  | } | 
|  |  | 
|  | // After sending GOAWAY, the connection will close after goAwayTimeout. | 
|  | // If we close the connection immediately after sending GOAWAY, there may | 
|  | // be unsent data in our kernel receive buffer, which will cause the kernel | 
|  | // to send a TCP RST on close() instead of a FIN. This RST will abort the | 
|  | // connection immediately, whether or not the client had received the GOAWAY. | 
|  | // | 
|  | // Ideally we should delay for at least 1 RTT + epsilon so the client has | 
|  | // a chance to read the GOAWAY and stop sending messages. Measuring RTT | 
|  | // is hard, so we approximate with 1 second. See golang.org/issue/18701. | 
|  | // | 
|  | // This is a var so it can be shorter in tests, where all requests uses the | 
|  | // loopback interface making the expected RTT very small. | 
|  | // | 
|  | // TODO: configurable? | 
|  | var http2goAwayTimeout = 1 * time.Second | 
|  |  | 
|  | func (sc *http2serverConn) startGracefulShutdownInternal() { | 
|  | sc.goAway(http2ErrCodeNo) | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) goAway(code http2ErrCode) { | 
|  | sc.serveG.check() | 
|  | if sc.inGoAway { | 
|  | return | 
|  | } | 
|  | sc.inGoAway = true | 
|  | sc.needToSendGoAway = true | 
|  | sc.goAwayCode = code | 
|  | sc.scheduleFrameWrite() | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) shutDownIn(d time.Duration) { | 
|  | sc.serveG.check() | 
|  | sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer) | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) resetStream(se http2StreamError) { | 
|  | sc.serveG.check() | 
|  | sc.writeFrame(http2FrameWriteRequest{write: se}) | 
|  | if st, ok := sc.streams[se.StreamID]; ok { | 
|  | st.resetQueued = true | 
|  | } | 
|  | } | 
|  |  | 
|  | // processFrameFromReader processes the serve loop's read from readFrameCh from the | 
|  | // frame-reading goroutine. | 
|  | // processFrameFromReader returns whether the connection should be kept open. | 
|  | func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool { | 
|  | sc.serveG.check() | 
|  | err := res.err | 
|  | if err != nil { | 
|  | if err == http2ErrFrameTooLarge { | 
|  | sc.goAway(http2ErrCodeFrameSize) | 
|  | return true // goAway will close the loop | 
|  | } | 
|  | clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) | 
|  | if clientGone { | 
|  | // TODO: could we also get into this state if | 
|  | // the peer does a half close | 
|  | // (e.g. CloseWrite) because they're done | 
|  | // sending frames but they're still wanting | 
|  | // our open replies?  Investigate. | 
|  | // TODO: add CloseWrite to crypto/tls.Conn first | 
|  | // so we have a way to test this? I suppose | 
|  | // just for testing we could have a non-TLS mode. | 
|  | return false | 
|  | } | 
|  | } else { | 
|  | f := res.f | 
|  | if http2VerboseLogs { | 
|  | sc.vlogf("http2: server read frame %v", http2summarizeFrame(f)) | 
|  | } | 
|  | err = sc.processFrame(f) | 
|  | if err == nil { | 
|  | return true | 
|  | } | 
|  | } | 
|  |  | 
|  | switch ev := err.(type) { | 
|  | case http2StreamError: | 
|  | sc.resetStream(ev) | 
|  | return true | 
|  | case http2goAwayFlowError: | 
|  | sc.goAway(http2ErrCodeFlowControl) | 
|  | return true | 
|  | case http2ConnectionError: | 
|  | sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev) | 
|  | sc.goAway(http2ErrCode(ev)) | 
|  | return true // goAway will handle shutdown | 
|  | default: | 
|  | if res.err != nil { | 
|  | sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err) | 
|  | } else { | 
|  | sc.logf("http2: server closing client connection: %v", err) | 
|  | } | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processFrame(f http2Frame) error { | 
|  | sc.serveG.check() | 
|  |  | 
|  | // First frame received must be SETTINGS. | 
|  | if !sc.sawFirstSettings { | 
|  | if _, ok := f.(*http2SettingsFrame); !ok { | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | sc.sawFirstSettings = true | 
|  | } | 
|  |  | 
|  | switch f := f.(type) { | 
|  | case *http2SettingsFrame: | 
|  | return sc.processSettings(f) | 
|  | case *http2MetaHeadersFrame: | 
|  | return sc.processHeaders(f) | 
|  | case *http2WindowUpdateFrame: | 
|  | return sc.processWindowUpdate(f) | 
|  | case *http2PingFrame: | 
|  | return sc.processPing(f) | 
|  | case *http2DataFrame: | 
|  | return sc.processData(f) | 
|  | case *http2RSTStreamFrame: | 
|  | return sc.processResetStream(f) | 
|  | case *http2PriorityFrame: | 
|  | return sc.processPriority(f) | 
|  | case *http2GoAwayFrame: | 
|  | return sc.processGoAway(f) | 
|  | case *http2PushPromiseFrame: | 
|  | // A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE | 
|  | // frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | default: | 
|  | sc.vlogf("http2: server ignoring frame: %v", f.Header()) | 
|  | return nil | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processPing(f *http2PingFrame) error { | 
|  | sc.serveG.check() | 
|  | if f.IsAck() { | 
|  | // 6.7 PING: " An endpoint MUST NOT respond to PING frames | 
|  | // containing this flag." | 
|  | return nil | 
|  | } | 
|  | if f.StreamID != 0 { | 
|  | // "PING frames are not associated with any individual | 
|  | // stream. If a PING frame is received with a stream | 
|  | // identifier field value other than 0x0, the recipient MUST | 
|  | // respond with a connection error (Section 5.4.1) of type | 
|  | // PROTOCOL_ERROR." | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo { | 
|  | return nil | 
|  | } | 
|  | sc.writeFrame(http2FrameWriteRequest{write: http2writePingAck{f}}) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error { | 
|  | sc.serveG.check() | 
|  | switch { | 
|  | case f.StreamID != 0: // stream-level flow control | 
|  | state, st := sc.state(f.StreamID) | 
|  | if state == http2stateIdle { | 
|  | // Section 5.1: "Receiving any frame other than HEADERS | 
|  | // or PRIORITY on a stream in this state MUST be | 
|  | // treated as a connection error (Section 5.4.1) of | 
|  | // type PROTOCOL_ERROR." | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | if st == nil { | 
|  | // "WINDOW_UPDATE can be sent by a peer that has sent a | 
|  | // frame bearing the END_STREAM flag. This means that a | 
|  | // receiver could receive a WINDOW_UPDATE frame on a "half | 
|  | // closed (remote)" or "closed" stream. A receiver MUST | 
|  | // NOT treat this as an error, see Section 5.1." | 
|  | return nil | 
|  | } | 
|  | if !st.flow.add(int32(f.Increment)) { | 
|  | return http2streamError(f.StreamID, http2ErrCodeFlowControl) | 
|  | } | 
|  | default: // connection-level flow control | 
|  | if !sc.flow.add(int32(f.Increment)) { | 
|  | return http2goAwayFlowError{} | 
|  | } | 
|  | } | 
|  | sc.scheduleFrameWrite() | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error { | 
|  | sc.serveG.check() | 
|  |  | 
|  | state, st := sc.state(f.StreamID) | 
|  | if state == http2stateIdle { | 
|  | // 6.4 "RST_STREAM frames MUST NOT be sent for a | 
|  | // stream in the "idle" state. If a RST_STREAM frame | 
|  | // identifying an idle stream is received, the | 
|  | // recipient MUST treat this as a connection error | 
|  | // (Section 5.4.1) of type PROTOCOL_ERROR. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | if st != nil { | 
|  | st.cancelCtx() | 
|  | sc.closeStream(st, http2streamError(f.StreamID, f.ErrCode)) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) closeStream(st *http2stream, err error) { | 
|  | sc.serveG.check() | 
|  | if st.state == http2stateIdle || st.state == http2stateClosed { | 
|  | panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state)) | 
|  | } | 
|  | st.state = http2stateClosed | 
|  | if st.writeDeadline != nil { | 
|  | st.writeDeadline.Stop() | 
|  | } | 
|  | if st.isPushed() { | 
|  | sc.curPushedStreams-- | 
|  | } else { | 
|  | sc.curClientStreams-- | 
|  | } | 
|  | delete(sc.streams, st.id) | 
|  | if len(sc.streams) == 0 { | 
|  | sc.setConnState(StateIdle) | 
|  | if sc.srv.IdleTimeout != 0 { | 
|  | sc.idleTimer.Reset(sc.srv.IdleTimeout) | 
|  | } | 
|  | if http2h1ServerKeepAlivesDisabled(sc.hs) { | 
|  | sc.startGracefulShutdownInternal() | 
|  | } | 
|  | } | 
|  | if p := st.body; p != nil { | 
|  | // Return any buffered unread bytes worth of conn-level flow control. | 
|  | // See golang.org/issue/16481 | 
|  | sc.sendWindowUpdate(nil, p.Len()) | 
|  |  | 
|  | p.CloseWithError(err) | 
|  | } | 
|  | st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc | 
|  | sc.writeSched.CloseStream(st.id) | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error { | 
|  | sc.serveG.check() | 
|  | if f.IsAck() { | 
|  | sc.unackedSettings-- | 
|  | if sc.unackedSettings < 0 { | 
|  | // Why is the peer ACKing settings we never sent? | 
|  | // The spec doesn't mention this case, but | 
|  | // hang up on them anyway. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | return nil | 
|  | } | 
|  | if f.NumSettings() > 100 || f.HasDuplicates() { | 
|  | // This isn't actually in the spec, but hang up on | 
|  | // suspiciously large settings frames or those with | 
|  | // duplicate entries. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | if err := f.ForeachSetting(sc.processSetting); err != nil { | 
|  | return err | 
|  | } | 
|  | sc.needToSendSettingsAck = true | 
|  | sc.scheduleFrameWrite() | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processSetting(s http2Setting) error { | 
|  | sc.serveG.check() | 
|  | if err := s.Valid(); err != nil { | 
|  | return err | 
|  | } | 
|  | if http2VerboseLogs { | 
|  | sc.vlogf("http2: server processing setting %v", s) | 
|  | } | 
|  | switch s.ID { | 
|  | case http2SettingHeaderTableSize: | 
|  | sc.headerTableSize = s.Val | 
|  | sc.hpackEncoder.SetMaxDynamicTableSize(s.Val) | 
|  | case http2SettingEnablePush: | 
|  | sc.pushEnabled = s.Val != 0 | 
|  | case http2SettingMaxConcurrentStreams: | 
|  | sc.clientMaxStreams = s.Val | 
|  | case http2SettingInitialWindowSize: | 
|  | return sc.processSettingInitialWindowSize(s.Val) | 
|  | case http2SettingMaxFrameSize: | 
|  | sc.maxFrameSize = int32(s.Val) // the maximum valid s.Val is < 2^31 | 
|  | case http2SettingMaxHeaderListSize: | 
|  | sc.peerMaxHeaderListSize = s.Val | 
|  | default: | 
|  | // Unknown setting: "An endpoint that receives a SETTINGS | 
|  | // frame with any unknown or unsupported identifier MUST | 
|  | // ignore that setting." | 
|  | if http2VerboseLogs { | 
|  | sc.vlogf("http2: server ignoring unknown setting %v", s) | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error { | 
|  | sc.serveG.check() | 
|  | // Note: val already validated to be within range by | 
|  | // processSetting's Valid call. | 
|  |  | 
|  | // "A SETTINGS frame can alter the initial flow control window | 
|  | // size for all current streams. When the value of | 
|  | // SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST | 
|  | // adjust the size of all stream flow control windows that it | 
|  | // maintains by the difference between the new value and the | 
|  | // old value." | 
|  | old := sc.initialStreamSendWindowSize | 
|  | sc.initialStreamSendWindowSize = int32(val) | 
|  | growth := int32(val) - old // may be negative | 
|  | for _, st := range sc.streams { | 
|  | if !st.flow.add(growth) { | 
|  | // 6.9.2 Initial Flow Control Window Size | 
|  | // "An endpoint MUST treat a change to | 
|  | // SETTINGS_INITIAL_WINDOW_SIZE that causes any flow | 
|  | // control window to exceed the maximum size as a | 
|  | // connection error (Section 5.4.1) of type | 
|  | // FLOW_CONTROL_ERROR." | 
|  | return http2ConnectionError(http2ErrCodeFlowControl) | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processData(f *http2DataFrame) error { | 
|  | sc.serveG.check() | 
|  | if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo { | 
|  | return nil | 
|  | } | 
|  | data := f.Data() | 
|  |  | 
|  | // "If a DATA frame is received whose stream is not in "open" | 
|  | // or "half closed (local)" state, the recipient MUST respond | 
|  | // with a stream error (Section 5.4.2) of type STREAM_CLOSED." | 
|  | id := f.Header().StreamID | 
|  | state, st := sc.state(id) | 
|  | if id == 0 || state == http2stateIdle { | 
|  | // Section 5.1: "Receiving any frame other than HEADERS | 
|  | // or PRIORITY on a stream in this state MUST be | 
|  | // treated as a connection error (Section 5.4.1) of | 
|  | // type PROTOCOL_ERROR." | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | // RFC 7540, sec 6.1: If a DATA frame is received whose stream is not in | 
|  | // "open" or "half-closed (local)" state, the recipient MUST respond with a | 
|  | // stream error (Section 5.4.2) of type STREAM_CLOSED. | 
|  | if state == http2stateClosed { | 
|  | return http2streamError(id, http2ErrCodeStreamClosed) | 
|  | } | 
|  | if st == nil || state != http2stateOpen || st.gotTrailerHeader || st.resetQueued { | 
|  | // This includes sending a RST_STREAM if the stream is | 
|  | // in stateHalfClosedLocal (which currently means that | 
|  | // the http.Handler returned, so it's done reading & | 
|  | // done writing). Try to stop the client from sending | 
|  | // more DATA. | 
|  |  | 
|  | // But still enforce their connection-level flow control, | 
|  | // and return any flow control bytes since we're not going | 
|  | // to consume them. | 
|  | if sc.inflow.available() < int32(f.Length) { | 
|  | return http2streamError(id, http2ErrCodeFlowControl) | 
|  | } | 
|  | // Deduct the flow control from inflow, since we're | 
|  | // going to immediately add it back in | 
|  | // sendWindowUpdate, which also schedules sending the | 
|  | // frames. | 
|  | sc.inflow.take(int32(f.Length)) | 
|  | sc.sendWindowUpdate(nil, int(f.Length)) // conn-level | 
|  |  | 
|  | if st != nil && st.resetQueued { | 
|  | // Already have a stream error in flight. Don't send another. | 
|  | return nil | 
|  | } | 
|  | return http2streamError(id, http2ErrCodeStreamClosed) | 
|  | } | 
|  | if st.body == nil { | 
|  | panic("internal error: should have a body in this state") | 
|  | } | 
|  |  | 
|  | // Sender sending more than they'd declared? | 
|  | if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes { | 
|  | st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes)) | 
|  | // RFC 7540, sec 8.1.2.6: A request or response is also malformed if the | 
|  | // value of a content-length header field does not equal the sum of the | 
|  | // DATA frame payload lengths that form the body. | 
|  | return http2streamError(id, http2ErrCodeProtocol) | 
|  | } | 
|  | if f.Length > 0 { | 
|  | // Check whether the client has flow control quota. | 
|  | if st.inflow.available() < int32(f.Length) { | 
|  | return http2streamError(id, http2ErrCodeFlowControl) | 
|  | } | 
|  | st.inflow.take(int32(f.Length)) | 
|  |  | 
|  | if len(data) > 0 { | 
|  | wrote, err := st.body.Write(data) | 
|  | if err != nil { | 
|  | return http2streamError(id, http2ErrCodeStreamClosed) | 
|  | } | 
|  | if wrote != len(data) { | 
|  | panic("internal error: bad Writer") | 
|  | } | 
|  | st.bodyBytes += int64(len(data)) | 
|  | } | 
|  |  | 
|  | // Return any padded flow control now, since we won't | 
|  | // refund it later on body reads. | 
|  | if pad := int32(f.Length) - int32(len(data)); pad > 0 { | 
|  | sc.sendWindowUpdate32(nil, pad) | 
|  | sc.sendWindowUpdate32(st, pad) | 
|  | } | 
|  | } | 
|  | if f.StreamEnded() { | 
|  | st.endStream() | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error { | 
|  | sc.serveG.check() | 
|  | if f.ErrCode != http2ErrCodeNo { | 
|  | sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f) | 
|  | } else { | 
|  | sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f) | 
|  | } | 
|  | sc.startGracefulShutdownInternal() | 
|  | // http://tools.ietf.org/html/rfc7540#section-6.8 | 
|  | // We should not create any new streams, which means we should disable push. | 
|  | sc.pushEnabled = false | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // isPushed reports whether the stream is server-initiated. | 
|  | func (st *http2stream) isPushed() bool { | 
|  | return st.id%2 == 0 | 
|  | } | 
|  |  | 
|  | // endStream closes a Request.Body's pipe. It is called when a DATA | 
|  | // frame says a request body is over (or after trailers). | 
|  | func (st *http2stream) endStream() { | 
|  | sc := st.sc | 
|  | sc.serveG.check() | 
|  |  | 
|  | if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes { | 
|  | st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes", | 
|  | st.declBodyBytes, st.bodyBytes)) | 
|  | } else { | 
|  | st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest) | 
|  | st.body.CloseWithError(io.EOF) | 
|  | } | 
|  | st.state = http2stateHalfClosedRemote | 
|  | } | 
|  |  | 
|  | // copyTrailersToHandlerRequest is run in the Handler's goroutine in | 
|  | // its Request.Body.Read just before it gets io.EOF. | 
|  | func (st *http2stream) copyTrailersToHandlerRequest() { | 
|  | for k, vv := range st.trailer { | 
|  | if _, ok := st.reqTrailer[k]; ok { | 
|  | // Only copy it over it was pre-declared. | 
|  | st.reqTrailer[k] = vv | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // onWriteTimeout is run on its own goroutine (from time.AfterFunc) | 
|  | // when the stream's WriteTimeout has fired. | 
|  | func (st *http2stream) onWriteTimeout() { | 
|  | st.sc.writeFrameFromHandler(http2FrameWriteRequest{write: http2streamError(st.id, http2ErrCodeInternal)}) | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error { | 
|  | sc.serveG.check() | 
|  | id := f.StreamID | 
|  | if sc.inGoAway { | 
|  | // Ignore. | 
|  | return nil | 
|  | } | 
|  | // http://tools.ietf.org/html/rfc7540#section-5.1.1 | 
|  | // Streams initiated by a client MUST use odd-numbered stream | 
|  | // identifiers. [...] An endpoint that receives an unexpected | 
|  | // stream identifier MUST respond with a connection error | 
|  | // (Section 5.4.1) of type PROTOCOL_ERROR. | 
|  | if id%2 != 1 { | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | // A HEADERS frame can be used to create a new stream or | 
|  | // send a trailer for an open one. If we already have a stream | 
|  | // open, let it process its own HEADERS frame (trailers at this | 
|  | // point, if it's valid). | 
|  | if st := sc.streams[f.StreamID]; st != nil { | 
|  | if st.resetQueued { | 
|  | // We're sending RST_STREAM to close the stream, so don't bother | 
|  | // processing this frame. | 
|  | return nil | 
|  | } | 
|  | // RFC 7540, sec 5.1: If an endpoint receives additional frames, other than | 
|  | // WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream that is in | 
|  | // this state, it MUST respond with a stream error (Section 5.4.2) of | 
|  | // type STREAM_CLOSED. | 
|  | if st.state == http2stateHalfClosedRemote { | 
|  | return http2streamError(id, http2ErrCodeStreamClosed) | 
|  | } | 
|  | return st.processTrailerHeaders(f) | 
|  | } | 
|  |  | 
|  | // [...] The identifier of a newly established stream MUST be | 
|  | // numerically greater than all streams that the initiating | 
|  | // endpoint has opened or reserved. [...]  An endpoint that | 
|  | // receives an unexpected stream identifier MUST respond with | 
|  | // a connection error (Section 5.4.1) of type PROTOCOL_ERROR. | 
|  | if id <= sc.maxClientStreamID { | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | sc.maxClientStreamID = id | 
|  |  | 
|  | if sc.idleTimer != nil { | 
|  | sc.idleTimer.Stop() | 
|  | } | 
|  |  | 
|  | // http://tools.ietf.org/html/rfc7540#section-5.1.2 | 
|  | // [...] Endpoints MUST NOT exceed the limit set by their peer. An | 
|  | // endpoint that receives a HEADERS frame that causes their | 
|  | // advertised concurrent stream limit to be exceeded MUST treat | 
|  | // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR | 
|  | // or REFUSED_STREAM. | 
|  | if sc.curClientStreams+1 > sc.advMaxStreams { | 
|  | if sc.unackedSettings == 0 { | 
|  | // They should know better. | 
|  | return http2streamError(id, http2ErrCodeProtocol) | 
|  | } | 
|  | // Assume it's a network race, where they just haven't | 
|  | // received our last SETTINGS update. But actually | 
|  | // this can't happen yet, because we don't yet provide | 
|  | // a way for users to adjust server parameters at | 
|  | // runtime. | 
|  | return http2streamError(id, http2ErrCodeRefusedStream) | 
|  | } | 
|  |  | 
|  | initialState := http2stateOpen | 
|  | if f.StreamEnded() { | 
|  | initialState = http2stateHalfClosedRemote | 
|  | } | 
|  | st := sc.newStream(id, 0, initialState) | 
|  |  | 
|  | if f.HasPriority() { | 
|  | if err := http2checkPriority(f.StreamID, f.Priority); err != nil { | 
|  | return err | 
|  | } | 
|  | sc.writeSched.AdjustStream(st.id, f.Priority) | 
|  | } | 
|  |  | 
|  | rw, req, err := sc.newWriterAndRequest(st, f) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | st.reqTrailer = req.Trailer | 
|  | if st.reqTrailer != nil { | 
|  | st.trailer = make(Header) | 
|  | } | 
|  | st.body = req.Body.(*http2requestBody).pipe // may be nil | 
|  | st.declBodyBytes = req.ContentLength | 
|  |  | 
|  | handler := sc.handler.ServeHTTP | 
|  | if f.Truncated { | 
|  | // Their header list was too long. Send a 431 error. | 
|  | handler = http2handleHeaderListTooLong | 
|  | } else if err := http2checkValidHTTP2RequestHeaders(req.Header); err != nil { | 
|  | handler = http2new400Handler(err) | 
|  | } | 
|  |  | 
|  | // The net/http package sets the read deadline from the | 
|  | // http.Server.ReadTimeout during the TLS handshake, but then | 
|  | // passes the connection off to us with the deadline already | 
|  | // set. Disarm it here after the request headers are read, | 
|  | // similar to how the http1 server works. Here it's | 
|  | // technically more like the http1 Server's ReadHeaderTimeout | 
|  | // (in Go 1.8), though. That's a more sane option anyway. | 
|  | if sc.hs.ReadTimeout != 0 { | 
|  | sc.conn.SetReadDeadline(time.Time{}) | 
|  | } | 
|  |  | 
|  | go sc.runHandler(rw, req, handler) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error { | 
|  | sc := st.sc | 
|  | sc.serveG.check() | 
|  | if st.gotTrailerHeader { | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | st.gotTrailerHeader = true | 
|  | if !f.StreamEnded() { | 
|  | return http2streamError(st.id, http2ErrCodeProtocol) | 
|  | } | 
|  |  | 
|  | if len(f.PseudoFields()) > 0 { | 
|  | return http2streamError(st.id, http2ErrCodeProtocol) | 
|  | } | 
|  | if st.trailer != nil { | 
|  | for _, hf := range f.RegularFields() { | 
|  | key := sc.canonicalHeader(hf.Name) | 
|  | if !httpguts.ValidTrailerHeader(key) { | 
|  | // TODO: send more details to the peer somehow. But http2 has | 
|  | // no way to send debug data at a stream level. Discuss with | 
|  | // HTTP folk. | 
|  | return http2streamError(st.id, http2ErrCodeProtocol) | 
|  | } | 
|  | st.trailer[key] = append(st.trailer[key], hf.Value) | 
|  | } | 
|  | } | 
|  | st.endStream() | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func http2checkPriority(streamID uint32, p http2PriorityParam) error { | 
|  | if streamID == p.StreamDep { | 
|  | // Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat | 
|  | // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR." | 
|  | // Section 5.3.3 says that a stream can depend on one of its dependencies, | 
|  | // so it's only self-dependencies that are forbidden. | 
|  | return http2streamError(streamID, http2ErrCodeProtocol) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error { | 
|  | if sc.inGoAway { | 
|  | return nil | 
|  | } | 
|  | if err := http2checkPriority(f.StreamID, f.http2PriorityParam); err != nil { | 
|  | return err | 
|  | } | 
|  | sc.writeSched.AdjustStream(f.StreamID, f.http2PriorityParam) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState) *http2stream { | 
|  | sc.serveG.check() | 
|  | if id == 0 { | 
|  | panic("internal error: cannot create stream with id 0") | 
|  | } | 
|  |  | 
|  | ctx, cancelCtx := http2contextWithCancel(sc.baseCtx) | 
|  | st := &http2stream{ | 
|  | sc:        sc, | 
|  | id:        id, | 
|  | state:     state, | 
|  | ctx:       ctx, | 
|  | cancelCtx: cancelCtx, | 
|  | } | 
|  | st.cw.Init() | 
|  | st.flow.conn = &sc.flow // link to conn-level counter | 
|  | st.flow.add(sc.initialStreamSendWindowSize) | 
|  | st.inflow.conn = &sc.inflow // link to conn-level counter | 
|  | st.inflow.add(sc.srv.initialStreamRecvWindowSize()) | 
|  | if sc.hs.WriteTimeout != 0 { | 
|  | st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) | 
|  | } | 
|  |  | 
|  | sc.streams[id] = st | 
|  | sc.writeSched.OpenStream(st.id, http2OpenStreamOptions{PusherID: pusherID}) | 
|  | if st.isPushed() { | 
|  | sc.curPushedStreams++ | 
|  | } else { | 
|  | sc.curClientStreams++ | 
|  | } | 
|  | if sc.curOpenStreams() == 1 { | 
|  | sc.setConnState(StateActive) | 
|  | } | 
|  |  | 
|  | return st | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHeadersFrame) (*http2responseWriter, *Request, error) { | 
|  | sc.serveG.check() | 
|  |  | 
|  | rp := http2requestParam{ | 
|  | method:    f.PseudoValue("method"), | 
|  | scheme:    f.PseudoValue("scheme"), | 
|  | authority: f.PseudoValue("authority"), | 
|  | path:      f.PseudoValue("path"), | 
|  | } | 
|  |  | 
|  | isConnect := rp.method == "CONNECT" | 
|  | if isConnect { | 
|  | if rp.path != "" || rp.scheme != "" || rp.authority == "" { | 
|  | return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) | 
|  | } | 
|  | } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") { | 
|  | // See 8.1.2.6 Malformed Requests and Responses: | 
|  | // | 
|  | // Malformed requests or responses that are detected | 
|  | // MUST be treated as a stream error (Section 5.4.2) | 
|  | // of type PROTOCOL_ERROR." | 
|  | // | 
|  | // 8.1.2.3 Request Pseudo-Header Fields | 
|  | // "All HTTP/2 requests MUST include exactly one valid | 
|  | // value for the :method, :scheme, and :path | 
|  | // pseudo-header fields" | 
|  | return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) | 
|  | } | 
|  |  | 
|  | bodyOpen := !f.StreamEnded() | 
|  | if rp.method == "HEAD" && bodyOpen { | 
|  | // HEAD requests can't have bodies | 
|  | return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) | 
|  | } | 
|  |  | 
|  | rp.header = make(Header) | 
|  | for _, hf := range f.RegularFields() { | 
|  | rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value) | 
|  | } | 
|  | if rp.authority == "" { | 
|  | rp.authority = rp.header.Get("Host") | 
|  | } | 
|  |  | 
|  | rw, req, err := sc.newWriterAndRequestNoBody(st, rp) | 
|  | if err != nil { | 
|  | return nil, nil, err | 
|  | } | 
|  | if bodyOpen { | 
|  | if vv, ok := rp.header["Content-Length"]; ok { | 
|  | req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64) | 
|  | } else { | 
|  | req.ContentLength = -1 | 
|  | } | 
|  | req.Body.(*http2requestBody).pipe = &http2pipe{ | 
|  | b: &http2dataBuffer{expected: req.ContentLength}, | 
|  | } | 
|  | } | 
|  | return rw, req, nil | 
|  | } | 
|  |  | 
|  | type http2requestParam struct { | 
|  | method                  string | 
|  | scheme, authority, path string | 
|  | header                  Header | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2requestParam) (*http2responseWriter, *Request, error) { | 
|  | sc.serveG.check() | 
|  |  | 
|  | var tlsState *tls.ConnectionState // nil if not scheme https | 
|  | if rp.scheme == "https" { | 
|  | tlsState = sc.tlsState | 
|  | } | 
|  |  | 
|  | needsContinue := rp.header.Get("Expect") == "100-continue" | 
|  | if needsContinue { | 
|  | rp.header.Del("Expect") | 
|  | } | 
|  | // Merge Cookie headers into one "; "-delimited value. | 
|  | if cookies := rp.header["Cookie"]; len(cookies) > 1 { | 
|  | rp.header.Set("Cookie", strings.Join(cookies, "; ")) | 
|  | } | 
|  |  | 
|  | // Setup Trailers | 
|  | var trailer Header | 
|  | for _, v := range rp.header["Trailer"] { | 
|  | for _, key := range strings.Split(v, ",") { | 
|  | key = CanonicalHeaderKey(strings.TrimSpace(key)) | 
|  | switch key { | 
|  | case "Transfer-Encoding", "Trailer", "Content-Length": | 
|  | // Bogus. (copy of http1 rules) | 
|  | // Ignore. | 
|  | default: | 
|  | if trailer == nil { | 
|  | trailer = make(Header) | 
|  | } | 
|  | trailer[key] = nil | 
|  | } | 
|  | } | 
|  | } | 
|  | delete(rp.header, "Trailer") | 
|  |  | 
|  | var url_ *url.URL | 
|  | var requestURI string | 
|  | if rp.method == "CONNECT" { | 
|  | url_ = &url.URL{Host: rp.authority} | 
|  | requestURI = rp.authority // mimic HTTP/1 server behavior | 
|  | } else { | 
|  | var err error | 
|  | url_, err = url.ParseRequestURI(rp.path) | 
|  | if err != nil { | 
|  | return nil, nil, http2streamError(st.id, http2ErrCodeProtocol) | 
|  | } | 
|  | requestURI = rp.path | 
|  | } | 
|  |  | 
|  | body := &http2requestBody{ | 
|  | conn:          sc, | 
|  | stream:        st, | 
|  | needsContinue: needsContinue, | 
|  | } | 
|  | req := &Request{ | 
|  | Method:     rp.method, | 
|  | URL:        url_, | 
|  | RemoteAddr: sc.remoteAddrStr, | 
|  | Header:     rp.header, | 
|  | RequestURI: requestURI, | 
|  | Proto:      "HTTP/2.0", | 
|  | ProtoMajor: 2, | 
|  | ProtoMinor: 0, | 
|  | TLS:        tlsState, | 
|  | Host:       rp.authority, | 
|  | Body:       body, | 
|  | Trailer:    trailer, | 
|  | } | 
|  | req = http2requestWithContext(req, st.ctx) | 
|  |  | 
|  | rws := http2responseWriterStatePool.Get().(*http2responseWriterState) | 
|  | bwSave := rws.bw | 
|  | *rws = http2responseWriterState{} // zero all the fields | 
|  | rws.conn = sc | 
|  | rws.bw = bwSave | 
|  | rws.bw.Reset(http2chunkWriter{rws}) | 
|  | rws.stream = st | 
|  | rws.req = req | 
|  | rws.body = body | 
|  |  | 
|  | rw := &http2responseWriter{rws: rws} | 
|  | return rw, req, nil | 
|  | } | 
|  |  | 
|  | // Run on its own goroutine. | 
|  | func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) { | 
|  | didPanic := true | 
|  | defer func() { | 
|  | rw.rws.stream.cancelCtx() | 
|  | if didPanic { | 
|  | e := recover() | 
|  | sc.writeFrameFromHandler(http2FrameWriteRequest{ | 
|  | write:  http2handlerPanicRST{rw.rws.stream.id}, | 
|  | stream: rw.rws.stream, | 
|  | }) | 
|  | // Same as net/http: | 
|  | if http2shouldLogPanic(e) { | 
|  | const size = 64 << 10 | 
|  | buf := make([]byte, size) | 
|  | buf = buf[:runtime.Stack(buf, false)] | 
|  | sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf) | 
|  | } | 
|  | return | 
|  | } | 
|  | rw.handlerDone() | 
|  | }() | 
|  | handler(rw, req) | 
|  | didPanic = false | 
|  | } | 
|  |  | 
|  | func http2handleHeaderListTooLong(w ResponseWriter, r *Request) { | 
|  | // 10.5.1 Limits on Header Block Size: | 
|  | // .. "A server that receives a larger header block than it is | 
|  | // willing to handle can send an HTTP 431 (Request Header Fields Too | 
|  | // Large) status code" | 
|  | const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+ | 
|  | w.WriteHeader(statusRequestHeaderFieldsTooLarge) | 
|  | io.WriteString(w, "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>") | 
|  | } | 
|  |  | 
|  | // called from handler goroutines. | 
|  | // h may be nil. | 
|  | func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeResHeaders) error { | 
|  | sc.serveG.checkNotOn() // NOT on | 
|  | var errc chan error | 
|  | if headerData.h != nil { | 
|  | // If there's a header map (which we don't own), so we have to block on | 
|  | // waiting for this frame to be written, so an http.Flush mid-handler | 
|  | // writes out the correct value of keys, before a handler later potentially | 
|  | // mutates it. | 
|  | errc = http2errChanPool.Get().(chan error) | 
|  | } | 
|  | if err := sc.writeFrameFromHandler(http2FrameWriteRequest{ | 
|  | write:  headerData, | 
|  | stream: st, | 
|  | done:   errc, | 
|  | }); err != nil { | 
|  | return err | 
|  | } | 
|  | if errc != nil { | 
|  | select { | 
|  | case err := <-errc: | 
|  | http2errChanPool.Put(errc) | 
|  | return err | 
|  | case <-sc.doneServing: | 
|  | return http2errClientDisconnected | 
|  | case <-st.cw: | 
|  | return http2errStreamClosed | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // called from handler goroutines. | 
|  | func (sc *http2serverConn) write100ContinueHeaders(st *http2stream) { | 
|  | sc.writeFrameFromHandler(http2FrameWriteRequest{ | 
|  | write:  http2write100ContinueHeadersFrame{st.id}, | 
|  | stream: st, | 
|  | }) | 
|  | } | 
|  |  | 
|  | // A bodyReadMsg tells the server loop that the http.Handler read n | 
|  | // bytes of the DATA from the client on the given stream. | 
|  | type http2bodyReadMsg struct { | 
|  | st *http2stream | 
|  | n  int | 
|  | } | 
|  |  | 
|  | // called from handler goroutines. | 
|  | // Notes that the handler for the given stream ID read n bytes of its body | 
|  | // and schedules flow control tokens to be sent. | 
|  | func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int, err error) { | 
|  | sc.serveG.checkNotOn() // NOT on | 
|  | if n > 0 { | 
|  | select { | 
|  | case sc.bodyReadCh <- http2bodyReadMsg{st, n}: | 
|  | case <-sc.doneServing: | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) noteBodyRead(st *http2stream, n int) { | 
|  | sc.serveG.check() | 
|  | sc.sendWindowUpdate(nil, n) // conn-level | 
|  | if st.state != http2stateHalfClosedRemote && st.state != http2stateClosed { | 
|  | // Don't send this WINDOW_UPDATE if the stream is closed | 
|  | // remotely. | 
|  | sc.sendWindowUpdate(st, n) | 
|  | } | 
|  | } | 
|  |  | 
|  | // st may be nil for conn-level | 
|  | func (sc *http2serverConn) sendWindowUpdate(st *http2stream, n int) { | 
|  | sc.serveG.check() | 
|  | // "The legal range for the increment to the flow control | 
|  | // window is 1 to 2^31-1 (2,147,483,647) octets." | 
|  | // A Go Read call on 64-bit machines could in theory read | 
|  | // a larger Read than this. Very unlikely, but we handle it here | 
|  | // rather than elsewhere for now. | 
|  | const maxUint31 = 1<<31 - 1 | 
|  | for n >= maxUint31 { | 
|  | sc.sendWindowUpdate32(st, maxUint31) | 
|  | n -= maxUint31 | 
|  | } | 
|  | sc.sendWindowUpdate32(st, int32(n)) | 
|  | } | 
|  |  | 
|  | // st may be nil for conn-level | 
|  | func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) { | 
|  | sc.serveG.check() | 
|  | if n == 0 { | 
|  | return | 
|  | } | 
|  | if n < 0 { | 
|  | panic("negative update") | 
|  | } | 
|  | var streamID uint32 | 
|  | if st != nil { | 
|  | streamID = st.id | 
|  | } | 
|  | sc.writeFrame(http2FrameWriteRequest{ | 
|  | write:  http2writeWindowUpdate{streamID: streamID, n: uint32(n)}, | 
|  | stream: st, | 
|  | }) | 
|  | var ok bool | 
|  | if st == nil { | 
|  | ok = sc.inflow.add(n) | 
|  | } else { | 
|  | ok = st.inflow.add(n) | 
|  | } | 
|  | if !ok { | 
|  | panic("internal error; sent too many window updates without decrements?") | 
|  | } | 
|  | } | 
|  |  | 
|  | // requestBody is the Handler's Request.Body type. | 
|  | // Read and Close may be called concurrently. | 
|  | type http2requestBody struct { | 
|  | stream        *http2stream | 
|  | conn          *http2serverConn | 
|  | closed        bool       // for use by Close only | 
|  | sawEOF        bool       // for use by Read only | 
|  | pipe          *http2pipe // non-nil if we have a HTTP entity message body | 
|  | needsContinue bool       // need to send a 100-continue | 
|  | } | 
|  |  | 
|  | func (b *http2requestBody) Close() error { | 
|  | if b.pipe != nil && !b.closed { | 
|  | b.pipe.BreakWithError(http2errClosedBody) | 
|  | } | 
|  | b.closed = true | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (b *http2requestBody) Read(p []byte) (n int, err error) { | 
|  | if b.needsContinue { | 
|  | b.needsContinue = false | 
|  | b.conn.write100ContinueHeaders(b.stream) | 
|  | } | 
|  | if b.pipe == nil || b.sawEOF { | 
|  | return 0, io.EOF | 
|  | } | 
|  | n, err = b.pipe.Read(p) | 
|  | if err == io.EOF { | 
|  | b.sawEOF = true | 
|  | } | 
|  | if b.conn == nil && http2inTests { | 
|  | return | 
|  | } | 
|  | b.conn.noteBodyReadFromHandler(b.stream, n, err) | 
|  | return | 
|  | } | 
|  |  | 
|  | // responseWriter is the http.ResponseWriter implementation. It's | 
|  | // intentionally small (1 pointer wide) to minimize garbage. The | 
|  | // responseWriterState pointer inside is zeroed at the end of a | 
|  | // request (in handlerDone) and calls on the responseWriter thereafter | 
|  | // simply crash (caller's mistake), but the much larger responseWriterState | 
|  | // and buffers are reused between multiple requests. | 
|  | type http2responseWriter struct { | 
|  | rws *http2responseWriterState | 
|  | } | 
|  |  | 
|  | // Optional http.ResponseWriter interfaces implemented. | 
|  | var ( | 
|  | _ CloseNotifier     = (*http2responseWriter)(nil) | 
|  | _ Flusher           = (*http2responseWriter)(nil) | 
|  | _ http2stringWriter = (*http2responseWriter)(nil) | 
|  | ) | 
|  |  | 
|  | type http2responseWriterState struct { | 
|  | // immutable within a request: | 
|  | stream *http2stream | 
|  | req    *Request | 
|  | body   *http2requestBody // to close at end of request, if DATA frames didn't | 
|  | conn   *http2serverConn | 
|  |  | 
|  | // TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc | 
|  | bw *bufio.Writer // writing to a chunkWriter{this *responseWriterState} | 
|  |  | 
|  | // mutated by http.Handler goroutine: | 
|  | handlerHeader Header   // nil until called | 
|  | snapHeader    Header   // snapshot of handlerHeader at WriteHeader time | 
|  | trailers      []string // set in writeChunk | 
|  | status        int      // status code passed to WriteHeader | 
|  | wroteHeader   bool     // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. | 
|  | sentHeader    bool     // have we sent the header frame? | 
|  | handlerDone   bool     // handler has finished | 
|  | dirty         bool     // a Write failed; don't reuse this responseWriterState | 
|  |  | 
|  | sentContentLen int64 // non-zero if handler set a Content-Length header | 
|  | wroteBytes     int64 | 
|  |  | 
|  | closeNotifierMu sync.Mutex // guards closeNotifierCh | 
|  | closeNotifierCh chan bool  // nil until first used | 
|  | } | 
|  |  | 
|  | type http2chunkWriter struct{ rws *http2responseWriterState } | 
|  |  | 
|  | func (cw http2chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) } | 
|  |  | 
|  | func (rws *http2responseWriterState) hasTrailers() bool { return len(rws.trailers) != 0 } | 
|  |  | 
|  | // declareTrailer is called for each Trailer header when the | 
|  | // response header is written. It notes that a header will need to be | 
|  | // written in the trailers at the end of the response. | 
|  | func (rws *http2responseWriterState) declareTrailer(k string) { | 
|  | k = CanonicalHeaderKey(k) | 
|  | if !httpguts.ValidTrailerHeader(k) { | 
|  | // Forbidden by RFC 7230, section 4.1.2. | 
|  | rws.conn.logf("ignoring invalid trailer %q", k) | 
|  | return | 
|  | } | 
|  | if !http2strSliceContains(rws.trailers, k) { | 
|  | rws.trailers = append(rws.trailers, k) | 
|  | } | 
|  | } | 
|  |  | 
|  | // writeChunk writes chunks from the bufio.Writer. But because | 
|  | // bufio.Writer may bypass its chunking, sometimes p may be | 
|  | // arbitrarily large. | 
|  | // | 
|  | // writeChunk is also responsible (on the first chunk) for sending the | 
|  | // HEADER response. | 
|  | func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) { | 
|  | if !rws.wroteHeader { | 
|  | rws.writeHeader(200) | 
|  | } | 
|  |  | 
|  | isHeadResp := rws.req.Method == "HEAD" | 
|  | if !rws.sentHeader { | 
|  | rws.sentHeader = true | 
|  | var ctype, clen string | 
|  | if clen = rws.snapHeader.Get("Content-Length"); clen != "" { | 
|  | rws.snapHeader.Del("Content-Length") | 
|  | clen64, err := strconv.ParseInt(clen, 10, 64) | 
|  | if err == nil && clen64 >= 0 { | 
|  | rws.sentContentLen = clen64 | 
|  | } else { | 
|  | clen = "" | 
|  | } | 
|  | } | 
|  | if clen == "" && rws.handlerDone && http2bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) { | 
|  | clen = strconv.Itoa(len(p)) | 
|  | } | 
|  | _, hasContentType := rws.snapHeader["Content-Type"] | 
|  | if !hasContentType && http2bodyAllowedForStatus(rws.status) && len(p) > 0 { | 
|  | ctype = DetectContentType(p) | 
|  | } | 
|  | var date string | 
|  | if _, ok := rws.snapHeader["Date"]; !ok { | 
|  | // TODO(bradfitz): be faster here, like net/http? measure. | 
|  | date = time.Now().UTC().Format(TimeFormat) | 
|  | } | 
|  |  | 
|  | for _, v := range rws.snapHeader["Trailer"] { | 
|  | http2foreachHeaderElement(v, rws.declareTrailer) | 
|  | } | 
|  |  | 
|  | // "Connection" headers aren't allowed in HTTP/2 (RFC 7540, 8.1.2.2), | 
|  | // but respect "Connection" == "close" to mean sending a GOAWAY and tearing | 
|  | // down the TCP connection when idle, like we do for HTTP/1. | 
|  | // TODO: remove more Connection-specific header fields here, in addition | 
|  | // to "Connection". | 
|  | if _, ok := rws.snapHeader["Connection"]; ok { | 
|  | v := rws.snapHeader.Get("Connection") | 
|  | delete(rws.snapHeader, "Connection") | 
|  | if v == "close" { | 
|  | rws.conn.startGracefulShutdown() | 
|  | } | 
|  | } | 
|  |  | 
|  | endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp | 
|  | err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{ | 
|  | streamID:      rws.stream.id, | 
|  | httpResCode:   rws.status, | 
|  | h:             rws.snapHeader, | 
|  | endStream:     endStream, | 
|  | contentType:   ctype, | 
|  | contentLength: clen, | 
|  | date:          date, | 
|  | }) | 
|  | if err != nil { | 
|  | rws.dirty = true | 
|  | return 0, err | 
|  | } | 
|  | if endStream { | 
|  | return 0, nil | 
|  | } | 
|  | } | 
|  | if isHeadResp { | 
|  | return len(p), nil | 
|  | } | 
|  | if len(p) == 0 && !rws.handlerDone { | 
|  | return 0, nil | 
|  | } | 
|  |  | 
|  | if rws.handlerDone { | 
|  | rws.promoteUndeclaredTrailers() | 
|  | } | 
|  |  | 
|  | endStream := rws.handlerDone && !rws.hasTrailers() | 
|  | if len(p) > 0 || endStream { | 
|  | // only send a 0 byte DATA frame if we're ending the stream. | 
|  | if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { | 
|  | rws.dirty = true | 
|  | return 0, err | 
|  | } | 
|  | } | 
|  |  | 
|  | if rws.handlerDone && rws.hasTrailers() { | 
|  | err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{ | 
|  | streamID:  rws.stream.id, | 
|  | h:         rws.handlerHeader, | 
|  | trailers:  rws.trailers, | 
|  | endStream: true, | 
|  | }) | 
|  | if err != nil { | 
|  | rws.dirty = true | 
|  | } | 
|  | return len(p), err | 
|  | } | 
|  | return len(p), nil | 
|  | } | 
|  |  | 
|  | // TrailerPrefix is a magic prefix for ResponseWriter.Header map keys | 
|  | // that, if present, signals that the map entry is actually for | 
|  | // the response trailers, and not the response headers. The prefix | 
|  | // is stripped after the ServeHTTP call finishes and the values are | 
|  | // sent in the trailers. | 
|  | // | 
|  | // This mechanism is intended only for trailers that are not known | 
|  | // prior to the headers being written. If the set of trailers is fixed | 
|  | // or known before the header is written, the normal Go trailers mechanism | 
|  | // is preferred: | 
|  | //    https://golang.org/pkg/net/http/#ResponseWriter | 
|  | //    https://golang.org/pkg/net/http/#example_ResponseWriter_trailers | 
|  | const http2TrailerPrefix = "Trailer:" | 
|  |  | 
|  | // promoteUndeclaredTrailers permits http.Handlers to set trailers | 
|  | // after the header has already been flushed. Because the Go | 
|  | // ResponseWriter interface has no way to set Trailers (only the | 
|  | // Header), and because we didn't want to expand the ResponseWriter | 
|  | // interface, and because nobody used trailers, and because RFC 7230 | 
|  | // says you SHOULD (but not must) predeclare any trailers in the | 
|  | // header, the official ResponseWriter rules said trailers in Go must | 
|  | // be predeclared, and then we reuse the same ResponseWriter.Header() | 
|  | // map to mean both Headers and Trailers. When it's time to write the | 
|  | // Trailers, we pick out the fields of Headers that were declared as | 
|  | // trailers. That worked for a while, until we found the first major | 
|  | // user of Trailers in the wild: gRPC (using them only over http2), | 
|  | // and gRPC libraries permit setting trailers mid-stream without | 
|  | // predeclarnig them. So: change of plans. We still permit the old | 
|  | // way, but we also permit this hack: if a Header() key begins with | 
|  | // "Trailer:", the suffix of that key is a Trailer. Because ':' is an | 
|  | // invalid token byte anyway, there is no ambiguity. (And it's already | 
|  | // filtered out) It's mildly hacky, but not terrible. | 
|  | // | 
|  | // This method runs after the Handler is done and promotes any Header | 
|  | // fields to be trailers. | 
|  | func (rws *http2responseWriterState) promoteUndeclaredTrailers() { | 
|  | for k, vv := range rws.handlerHeader { | 
|  | if !strings.HasPrefix(k, http2TrailerPrefix) { | 
|  | continue | 
|  | } | 
|  | trailerKey := strings.TrimPrefix(k, http2TrailerPrefix) | 
|  | rws.declareTrailer(trailerKey) | 
|  | rws.handlerHeader[CanonicalHeaderKey(trailerKey)] = vv | 
|  | } | 
|  |  | 
|  | if len(rws.trailers) > 1 { | 
|  | sorter := http2sorterPool.Get().(*http2sorter) | 
|  | sorter.SortStrings(rws.trailers) | 
|  | http2sorterPool.Put(sorter) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) Flush() { | 
|  | rws := w.rws | 
|  | if rws == nil { | 
|  | panic("Header called after Handler finished") | 
|  | } | 
|  | if rws.bw.Buffered() > 0 { | 
|  | if err := rws.bw.Flush(); err != nil { | 
|  | // Ignore the error. The frame writer already knows. | 
|  | return | 
|  | } | 
|  | } else { | 
|  | // The bufio.Writer won't call chunkWriter.Write | 
|  | // (writeChunk with zero bytes, so we have to do it | 
|  | // ourselves to force the HTTP response header and/or | 
|  | // final DATA frame (with END_STREAM) to be sent. | 
|  | rws.writeChunk(nil) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) CloseNotify() <-chan bool { | 
|  | rws := w.rws | 
|  | if rws == nil { | 
|  | panic("CloseNotify called after Handler finished") | 
|  | } | 
|  | rws.closeNotifierMu.Lock() | 
|  | ch := rws.closeNotifierCh | 
|  | if ch == nil { | 
|  | ch = make(chan bool, 1) | 
|  | rws.closeNotifierCh = ch | 
|  | cw := rws.stream.cw | 
|  | go func() { | 
|  | cw.Wait() // wait for close | 
|  | ch <- true | 
|  | }() | 
|  | } | 
|  | rws.closeNotifierMu.Unlock() | 
|  | return ch | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) Header() Header { | 
|  | rws := w.rws | 
|  | if rws == nil { | 
|  | panic("Header called after Handler finished") | 
|  | } | 
|  | if rws.handlerHeader == nil { | 
|  | rws.handlerHeader = make(Header) | 
|  | } | 
|  | return rws.handlerHeader | 
|  | } | 
|  |  | 
|  | // checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode. | 
|  | func http2checkWriteHeaderCode(code int) { | 
|  | // Issue 22880: require valid WriteHeader status codes. | 
|  | // For now we only enforce that it's three digits. | 
|  | // In the future we might block things over 599 (600 and above aren't defined | 
|  | // at http://httpwg.org/specs/rfc7231.html#status.codes) | 
|  | // and we might block under 200 (once we have more mature 1xx support). | 
|  | // But for now any three digits. | 
|  | // | 
|  | // We used to send "HTTP/1.1 000 0" on the wire in responses but there's | 
|  | // no equivalent bogus thing we can realistically send in HTTP/2, | 
|  | // so we'll consistently panic instead and help people find their bugs | 
|  | // early. (We can't return an error from WriteHeader even if we wanted to.) | 
|  | if code < 100 || code > 999 { | 
|  | panic(fmt.Sprintf("invalid WriteHeader code %v", code)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) WriteHeader(code int) { | 
|  | rws := w.rws | 
|  | if rws == nil { | 
|  | panic("WriteHeader called after Handler finished") | 
|  | } | 
|  | rws.writeHeader(code) | 
|  | } | 
|  |  | 
|  | func (rws *http2responseWriterState) writeHeader(code int) { | 
|  | if !rws.wroteHeader { | 
|  | http2checkWriteHeaderCode(code) | 
|  | rws.wroteHeader = true | 
|  | rws.status = code | 
|  | if len(rws.handlerHeader) > 0 { | 
|  | rws.snapHeader = http2cloneHeader(rws.handlerHeader) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func http2cloneHeader(h Header) Header { | 
|  | h2 := make(Header, len(h)) | 
|  | for k, vv := range h { | 
|  | vv2 := make([]string, len(vv)) | 
|  | copy(vv2, vv) | 
|  | h2[k] = vv2 | 
|  | } | 
|  | return h2 | 
|  | } | 
|  |  | 
|  | // The Life Of A Write is like this: | 
|  | // | 
|  | // * Handler calls w.Write or w.WriteString -> | 
|  | // * -> rws.bw (*bufio.Writer) -> | 
|  | // * (Handler might call Flush) | 
|  | // * -> chunkWriter{rws} | 
|  | // * -> responseWriterState.writeChunk(p []byte) | 
|  | // * -> responseWriterState.writeChunk (most of the magic; see comment there) | 
|  | func (w *http2responseWriter) Write(p []byte) (n int, err error) { | 
|  | return w.write(len(p), p, "") | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) WriteString(s string) (n int, err error) { | 
|  | return w.write(len(s), nil, s) | 
|  | } | 
|  |  | 
|  | // either dataB or dataS is non-zero. | 
|  | func (w *http2responseWriter) write(lenData int, dataB []byte, dataS string) (n int, err error) { | 
|  | rws := w.rws | 
|  | if rws == nil { | 
|  | panic("Write called after Handler finished") | 
|  | } | 
|  | if !rws.wroteHeader { | 
|  | w.WriteHeader(200) | 
|  | } | 
|  | if !http2bodyAllowedForStatus(rws.status) { | 
|  | return 0, ErrBodyNotAllowed | 
|  | } | 
|  | rws.wroteBytes += int64(len(dataB)) + int64(len(dataS)) // only one can be set | 
|  | if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen { | 
|  | // TODO: send a RST_STREAM | 
|  | return 0, errors.New("http2: handler wrote more than declared Content-Length") | 
|  | } | 
|  |  | 
|  | if dataB != nil { | 
|  | return rws.bw.Write(dataB) | 
|  | } else { | 
|  | return rws.bw.WriteString(dataS) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) handlerDone() { | 
|  | rws := w.rws | 
|  | dirty := rws.dirty | 
|  | rws.handlerDone = true | 
|  | w.Flush() | 
|  | w.rws = nil | 
|  | if !dirty { | 
|  | // Only recycle the pool if all prior Write calls to | 
|  | // the serverConn goroutine completed successfully. If | 
|  | // they returned earlier due to resets from the peer | 
|  | // there might still be write goroutines outstanding | 
|  | // from the serverConn referencing the rws memory. See | 
|  | // issue 20704. | 
|  | http2responseWriterStatePool.Put(rws) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Push errors. | 
|  | var ( | 
|  | http2ErrRecursivePush    = errors.New("http2: recursive push not allowed") | 
|  | http2ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS") | 
|  | ) | 
|  |  | 
|  | // pushOptions is the internal version of http.PushOptions, which we | 
|  | // cannot include here because it's only defined in Go 1.8 and later. | 
|  | type http2pushOptions struct { | 
|  | Method string | 
|  | Header Header | 
|  | } | 
|  |  | 
|  | func (w *http2responseWriter) push(target string, opts http2pushOptions) error { | 
|  | st := w.rws.stream | 
|  | sc := st.sc | 
|  | sc.serveG.checkNotOn() | 
|  |  | 
|  | // No recursive pushes: "PUSH_PROMISE frames MUST only be sent on a peer-initiated stream." | 
|  | // http://tools.ietf.org/html/rfc7540#section-6.6 | 
|  | if st.isPushed() { | 
|  | return http2ErrRecursivePush | 
|  | } | 
|  |  | 
|  | // Default options. | 
|  | if opts.Method == "" { | 
|  | opts.Method = "GET" | 
|  | } | 
|  | if opts.Header == nil { | 
|  | opts.Header = Header{} | 
|  | } | 
|  | wantScheme := "http" | 
|  | if w.rws.req.TLS != nil { | 
|  | wantScheme = "https" | 
|  | } | 
|  |  | 
|  | // Validate the request. | 
|  | u, err := url.Parse(target) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | if u.Scheme == "" { | 
|  | if !strings.HasPrefix(target, "/") { | 
|  | return fmt.Errorf("target must be an absolute URL or an absolute path: %q", target) | 
|  | } | 
|  | u.Scheme = wantScheme | 
|  | u.Host = w.rws.req.Host | 
|  | } else { | 
|  | if u.Scheme != wantScheme { | 
|  | return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", u.Scheme, wantScheme) | 
|  | } | 
|  | if u.Host == "" { | 
|  | return errors.New("URL must have a host") | 
|  | } | 
|  | } | 
|  | for k := range opts.Header { | 
|  | if strings.HasPrefix(k, ":") { | 
|  | return fmt.Errorf("promised request headers cannot include pseudo header %q", k) | 
|  | } | 
|  | // These headers are meaningful only if the request has a body, | 
|  | // but PUSH_PROMISE requests cannot have a body. | 
|  | // http://tools.ietf.org/html/rfc7540#section-8.2 | 
|  | // Also disallow Host, since the promised URL must be absolute. | 
|  | switch strings.ToLower(k) { | 
|  | case "content-length", "content-encoding", "trailer", "te", "expect", "host": | 
|  | return fmt.Errorf("promised request headers cannot include %q", k) | 
|  | } | 
|  | } | 
|  | if err := http2checkValidHTTP2RequestHeaders(opts.Header); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // The RFC effectively limits promised requests to GET and HEAD: | 
|  | // "Promised requests MUST be cacheable [GET, HEAD, or POST], and MUST be safe [GET or HEAD]" | 
|  | // http://tools.ietf.org/html/rfc7540#section-8.2 | 
|  | if opts.Method != "GET" && opts.Method != "HEAD" { | 
|  | return fmt.Errorf("method %q must be GET or HEAD", opts.Method) | 
|  | } | 
|  |  | 
|  | msg := &http2startPushRequest{ | 
|  | parent: st, | 
|  | method: opts.Method, | 
|  | url:    u, | 
|  | header: http2cloneHeader(opts.Header), | 
|  | done:   http2errChanPool.Get().(chan error), | 
|  | } | 
|  |  | 
|  | select { | 
|  | case <-sc.doneServing: | 
|  | return http2errClientDisconnected | 
|  | case <-st.cw: | 
|  | return http2errStreamClosed | 
|  | case sc.serveMsgCh <- msg: | 
|  | } | 
|  |  | 
|  | select { | 
|  | case <-sc.doneServing: | 
|  | return http2errClientDisconnected | 
|  | case <-st.cw: | 
|  | return http2errStreamClosed | 
|  | case err := <-msg.done: | 
|  | http2errChanPool.Put(msg.done) | 
|  | return err | 
|  | } | 
|  | } | 
|  |  | 
|  | type http2startPushRequest struct { | 
|  | parent *http2stream | 
|  | method string | 
|  | url    *url.URL | 
|  | header Header | 
|  | done   chan error | 
|  | } | 
|  |  | 
|  | func (sc *http2serverConn) startPush(msg *http2startPushRequest) { | 
|  | sc.serveG.check() | 
|  |  | 
|  | // http://tools.ietf.org/html/rfc7540#section-6.6. | 
|  | // PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that | 
|  | // is in either the "open" or "half-closed (remote)" state. | 
|  | if msg.parent.state != http2stateOpen && msg.parent.state != http2stateHalfClosedRemote { | 
|  | // responseWriter.Push checks that the stream is peer-initiaed. | 
|  | msg.done <- http2errStreamClosed | 
|  | return | 
|  | } | 
|  |  | 
|  | // http://tools.ietf.org/html/rfc7540#section-6.6. | 
|  | if !sc.pushEnabled { | 
|  | msg.done <- ErrNotSupported | 
|  | return | 
|  | } | 
|  |  | 
|  | // PUSH_PROMISE frames must be sent in increasing order by stream ID, so | 
|  | // we allocate an ID for the promised stream lazily, when the PUSH_PROMISE | 
|  | // is written. Once the ID is allocated, we start the request handler. | 
|  | allocatePromisedID := func() (uint32, error) { | 
|  | sc.serveG.check() | 
|  |  | 
|  | // Check this again, just in case. Technically, we might have received | 
|  | // an updated SETTINGS by the time we got around to writing this frame. | 
|  | if !sc.pushEnabled { | 
|  | return 0, ErrNotSupported | 
|  | } | 
|  | // http://tools.ietf.org/html/rfc7540#section-6.5.2. | 
|  | if sc.curPushedStreams+1 > sc.clientMaxStreams { | 
|  | return 0, http2ErrPushLimitReached | 
|  | } | 
|  |  | 
|  | // http://tools.ietf.org/html/rfc7540#section-5.1.1. | 
|  | // Streams initiated by the server MUST use even-numbered identifiers. | 
|  | // A server that is unable to establish a new stream identifier can send a GOAWAY | 
|  | // frame so that the client is forced to open a new connection for new streams. | 
|  | if sc.maxPushPromiseID+2 >= 1<<31 { | 
|  | sc.startGracefulShutdownInternal() | 
|  | return 0, http2ErrPushLimitReached | 
|  | } | 
|  | sc.maxPushPromiseID += 2 | 
|  | promisedID := sc.maxPushPromiseID | 
|  |  | 
|  | // http://tools.ietf.org/html/rfc7540#section-8.2. | 
|  | // Strictly speaking, the new stream should start in "reserved (local)", then | 
|  | // transition to "half closed (remote)" after sending the initial HEADERS, but | 
|  | // we start in "half closed (remote)" for simplicity. | 
|  | // See further comments at the definition of stateHalfClosedRemote. | 
|  | promised := sc.newStream(promisedID, msg.parent.id, http2stateHalfClosedRemote) | 
|  | rw, req, err := sc.newWriterAndRequestNoBody(promised, http2requestParam{ | 
|  | method:    msg.method, | 
|  | scheme:    msg.url.Scheme, | 
|  | authority: msg.url.Host, | 
|  | path:      msg.url.RequestURI(), | 
|  | header:    http2cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE | 
|  | }) | 
|  | if err != nil { | 
|  | // Should not happen, since we've already validated msg.url. | 
|  | panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err)) | 
|  | } | 
|  |  | 
|  | go sc.runHandler(rw, req, sc.handler.ServeHTTP) | 
|  | return promisedID, nil | 
|  | } | 
|  |  | 
|  | sc.writeFrame(http2FrameWriteRequest{ | 
|  | write: &http2writePushPromise{ | 
|  | streamID:           msg.parent.id, | 
|  | method:             msg.method, | 
|  | url:                msg.url, | 
|  | h:                  msg.header, | 
|  | allocatePromisedID: allocatePromisedID, | 
|  | }, | 
|  | stream: msg.parent, | 
|  | done:   msg.done, | 
|  | }) | 
|  | } | 
|  |  | 
|  | // foreachHeaderElement splits v according to the "#rule" construction | 
|  | // in RFC 7230 section 7 and calls fn for each non-empty element. | 
|  | func http2foreachHeaderElement(v string, fn func(string)) { | 
|  | v = textproto.TrimString(v) | 
|  | if v == "" { | 
|  | return | 
|  | } | 
|  | if !strings.Contains(v, ",") { | 
|  | fn(v) | 
|  | return | 
|  | } | 
|  | for _, f := range strings.Split(v, ",") { | 
|  | if f = textproto.TrimString(f); f != "" { | 
|  | fn(f) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2 | 
|  | var http2connHeaders = []string{ | 
|  | "Connection", | 
|  | "Keep-Alive", | 
|  | "Proxy-Connection", | 
|  | "Transfer-Encoding", | 
|  | "Upgrade", | 
|  | } | 
|  |  | 
|  | // checkValidHTTP2RequestHeaders checks whether h is a valid HTTP/2 request, | 
|  | // per RFC 7540 Section 8.1.2.2. | 
|  | // The returned error is reported to users. | 
|  | func http2checkValidHTTP2RequestHeaders(h Header) error { | 
|  | for _, k := range http2connHeaders { | 
|  | if _, ok := h[k]; ok { | 
|  | return fmt.Errorf("request header %q is not valid in HTTP/2", k) | 
|  | } | 
|  | } | 
|  | te := h["Te"] | 
|  | if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) { | 
|  | return errors.New(`request header "TE" may only be "trailers" in HTTP/2`) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func http2new400Handler(err error) HandlerFunc { | 
|  | return func(w ResponseWriter, r *Request) { | 
|  | Error(w, err.Error(), StatusBadRequest) | 
|  | } | 
|  | } | 
|  |  | 
|  | // h1ServerKeepAlivesDisabled reports whether hs has its keep-alives | 
|  | // disabled. See comments on h1ServerShutdownChan above for why | 
|  | // the code is written this way. | 
|  | func http2h1ServerKeepAlivesDisabled(hs *Server) bool { | 
|  | var x interface{} = hs | 
|  | type I interface { | 
|  | doKeepAlives() bool | 
|  | } | 
|  | if hs, ok := x.(I); ok { | 
|  | return !hs.doKeepAlives() | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | const ( | 
|  | // transportDefaultConnFlow is how many connection-level flow control | 
|  | // tokens we give the server at start-up, past the default 64k. | 
|  | http2transportDefaultConnFlow = 1 << 30 | 
|  |  | 
|  | // transportDefaultStreamFlow is how many stream-level flow | 
|  | // control tokens we announce to the peer, and how many bytes | 
|  | // we buffer per stream. | 
|  | http2transportDefaultStreamFlow = 4 << 20 | 
|  |  | 
|  | // transportDefaultStreamMinRefresh is the minimum number of bytes we'll send | 
|  | // a stream-level WINDOW_UPDATE for at a time. | 
|  | http2transportDefaultStreamMinRefresh = 4 << 10 | 
|  |  | 
|  | http2defaultUserAgent = "Go-http-client/2.0" | 
|  | ) | 
|  |  | 
|  | // Transport is an HTTP/2 Transport. | 
|  | // | 
|  | // A Transport internally caches connections to servers. It is safe | 
|  | // for concurrent use by multiple goroutines. | 
|  | type http2Transport struct { | 
|  | // DialTLS specifies an optional dial function for creating | 
|  | // TLS connections for requests. | 
|  | // | 
|  | // If DialTLS is nil, tls.Dial is used. | 
|  | // | 
|  | // If the returned net.Conn has a ConnectionState method like tls.Conn, | 
|  | // it will be used to set http.Response.TLS. | 
|  | DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error) | 
|  |  | 
|  | // TLSClientConfig specifies the TLS configuration to use with | 
|  | // tls.Client. If nil, the default configuration is used. | 
|  | TLSClientConfig *tls.Config | 
|  |  | 
|  | // ConnPool optionally specifies an alternate connection pool to use. | 
|  | // If nil, the default is used. | 
|  | ConnPool http2ClientConnPool | 
|  |  | 
|  | // DisableCompression, if true, prevents the Transport from | 
|  | // requesting compression with an "Accept-Encoding: gzip" | 
|  | // request header when the Request contains no existing | 
|  | // Accept-Encoding value. If the Transport requests gzip on | 
|  | // its own and gets a gzipped response, it's transparently | 
|  | // decoded in the Response.Body. However, if the user | 
|  | // explicitly requested gzip it is not automatically | 
|  | // uncompressed. | 
|  | DisableCompression bool | 
|  |  | 
|  | // AllowHTTP, if true, permits HTTP/2 requests using the insecure, | 
|  | // plain-text "http" scheme. Note that this does not enable h2c support. | 
|  | AllowHTTP bool | 
|  |  | 
|  | // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to | 
|  | // send in the initial settings frame. It is how many bytes | 
|  | // of response headers are allowed. Unlike the http2 spec, zero here | 
|  | // means to use a default limit (currently 10MB). If you actually | 
|  | // want to advertise an ulimited value to the peer, Transport | 
|  | // interprets the highest possible value here (0xffffffff or 1<<32-1) | 
|  | // to mean no limit. | 
|  | MaxHeaderListSize uint32 | 
|  |  | 
|  | // t1, if non-nil, is the standard library Transport using | 
|  | // this transport. Its settings are used (but not its | 
|  | // RoundTrip method, etc). | 
|  | t1 *Transport | 
|  |  | 
|  | connPoolOnce  sync.Once | 
|  | connPoolOrDef http2ClientConnPool // non-nil version of ConnPool | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) maxHeaderListSize() uint32 { | 
|  | if t.MaxHeaderListSize == 0 { | 
|  | return 10 << 20 | 
|  | } | 
|  | if t.MaxHeaderListSize == 0xffffffff { | 
|  | return 0 | 
|  | } | 
|  | return t.MaxHeaderListSize | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) disableCompression() bool { | 
|  | return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression) | 
|  | } | 
|  |  | 
|  | var http2errTransportVersion = errors.New("http2: ConfigureTransport is only supported starting at Go 1.6") | 
|  |  | 
|  | // ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2. | 
|  | // It requires Go 1.6 or later and returns an error if the net/http package is too old | 
|  | // or if t1 has already been HTTP/2-enabled. | 
|  | func http2ConfigureTransport(t1 *Transport) error { | 
|  | _, err := http2configureTransport(t1) // in configure_transport.go (go1.6) or not_go16.go | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) connPool() http2ClientConnPool { | 
|  | t.connPoolOnce.Do(t.initConnPool) | 
|  | return t.connPoolOrDef | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) initConnPool() { | 
|  | if t.ConnPool != nil { | 
|  | t.connPoolOrDef = t.ConnPool | 
|  | } else { | 
|  | t.connPoolOrDef = &http2clientConnPool{t: t} | 
|  | } | 
|  | } | 
|  |  | 
|  | // ClientConn is the state of a single HTTP/2 client connection to an | 
|  | // HTTP/2 server. | 
|  | type http2ClientConn struct { | 
|  | t         *http2Transport | 
|  | tconn     net.Conn             // usually *tls.Conn, except specialized impls | 
|  | tlsState  *tls.ConnectionState // nil only for specialized impls | 
|  | singleUse bool                 // whether being used for a single http.Request | 
|  |  | 
|  | // readLoop goroutine fields: | 
|  | readerDone chan struct{} // closed on error | 
|  | readerErr  error         // set before readerDone is closed | 
|  |  | 
|  | idleTimeout time.Duration // or 0 for never | 
|  | idleTimer   *time.Timer | 
|  |  | 
|  | mu              sync.Mutex // guards following | 
|  | cond            *sync.Cond // hold mu; broadcast on flow/closed changes | 
|  | flow            http2flow  // our conn-level flow control quota (cs.flow is per stream) | 
|  | inflow          http2flow  // peer's conn-level flow control | 
|  | closing         bool | 
|  | closed          bool | 
|  | wantSettingsAck bool                          // we sent a SETTINGS frame and haven't heard back | 
|  | goAway          *http2GoAwayFrame             // if non-nil, the GoAwayFrame we received | 
|  | goAwayDebug     string                        // goAway frame's debug data, retained as a string | 
|  | streams         map[uint32]*http2clientStream // client-initiated | 
|  | nextStreamID    uint32 | 
|  | pendingRequests int                       // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams | 
|  | pings           map[[8]byte]chan struct{} // in flight ping data to notification channel | 
|  | bw              *bufio.Writer | 
|  | br              *bufio.Reader | 
|  | fr              *http2Framer | 
|  | lastActive      time.Time | 
|  | // Settings from peer: (also guarded by mu) | 
|  | maxFrameSize          uint32 | 
|  | maxConcurrentStreams  uint32 | 
|  | peerMaxHeaderListSize uint64 | 
|  | initialWindowSize     uint32 | 
|  |  | 
|  | hbuf    bytes.Buffer // HPACK encoder writes into this | 
|  | henc    *hpack.Encoder | 
|  | freeBuf [][]byte | 
|  |  | 
|  | wmu  sync.Mutex // held while writing; acquire AFTER mu if holding both | 
|  | werr error      // first write error that has occurred | 
|  | } | 
|  |  | 
|  | // clientStream is the state for a single HTTP/2 stream. One of these | 
|  | // is created for each Transport.RoundTrip call. | 
|  | type http2clientStream struct { | 
|  | cc            *http2ClientConn | 
|  | req           *Request | 
|  | trace         *http2clientTrace // or nil | 
|  | ID            uint32 | 
|  | resc          chan http2resAndError | 
|  | bufPipe       http2pipe // buffered pipe with the flow-controlled response payload | 
|  | startedWrite  bool      // started request body write; guarded by cc.mu | 
|  | requestedGzip bool | 
|  | on100         func() // optional code to run if get a 100 continue response | 
|  |  | 
|  | flow        http2flow // guarded by cc.mu | 
|  | inflow      http2flow // guarded by cc.mu | 
|  | bytesRemain int64     // -1 means unknown; owned by transportResponseBody.Read | 
|  | readErr     error     // sticky read error; owned by transportResponseBody.Read | 
|  | stopReqBody error     // if non-nil, stop writing req body; guarded by cc.mu | 
|  | didReset    bool      // whether we sent a RST_STREAM to the server; guarded by cc.mu | 
|  |  | 
|  | peerReset chan struct{} // closed on peer reset | 
|  | resetErr  error         // populated before peerReset is closed | 
|  |  | 
|  | done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu | 
|  |  | 
|  | // owned by clientConnReadLoop: | 
|  | firstByte    bool  // got the first response byte | 
|  | pastHeaders  bool  // got first MetaHeadersFrame (actual headers) | 
|  | pastTrailers bool  // got optional second MetaHeadersFrame (trailers) | 
|  | num1xx       uint8 // number of 1xx responses seen | 
|  |  | 
|  | trailer    Header  // accumulated trailers | 
|  | resTrailer *Header // client's Response.Trailer | 
|  | } | 
|  |  | 
|  | // awaitRequestCancel waits for the user to cancel a request or for the done | 
|  | // channel to be signaled. A non-nil error is returned only if the request was | 
|  | // canceled. | 
|  | func http2awaitRequestCancel(req *Request, done <-chan struct{}) error { | 
|  | ctx := http2reqContext(req) | 
|  | if req.Cancel == nil && ctx.Done() == nil { | 
|  | return nil | 
|  | } | 
|  | select { | 
|  | case <-req.Cancel: | 
|  | return http2errRequestCanceled | 
|  | case <-ctx.Done(): | 
|  | return ctx.Err() | 
|  | case <-done: | 
|  | return nil | 
|  | } | 
|  | } | 
|  |  | 
|  | var http2got1xxFuncForTests func(int, textproto.MIMEHeader) error | 
|  |  | 
|  | // get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func, | 
|  | // if any. It returns nil if not set or if the Go version is too old. | 
|  | func (cs *http2clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) error { | 
|  | if fn := http2got1xxFuncForTests; fn != nil { | 
|  | return fn | 
|  | } | 
|  | return http2traceGot1xxResponseFunc(cs.trace) | 
|  | } | 
|  |  | 
|  | // awaitRequestCancel waits for the user to cancel a request, its context to | 
|  | // expire, or for the request to be done (any way it might be removed from the | 
|  | // cc.streams map: peer reset, successful completion, TCP connection breakage, | 
|  | // etc). If the request is canceled, then cs will be canceled and closed. | 
|  | func (cs *http2clientStream) awaitRequestCancel(req *Request) { | 
|  | if err := http2awaitRequestCancel(req, cs.done); err != nil { | 
|  | cs.cancelStream() | 
|  | cs.bufPipe.CloseWithError(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (cs *http2clientStream) cancelStream() { | 
|  | cc := cs.cc | 
|  | cc.mu.Lock() | 
|  | didReset := cs.didReset | 
|  | cs.didReset = true | 
|  | cc.mu.Unlock() | 
|  |  | 
|  | if !didReset { | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) | 
|  | cc.forgetStreamID(cs.ID) | 
|  | } | 
|  | } | 
|  |  | 
|  | // checkResetOrDone reports any error sent in a RST_STREAM frame by the | 
|  | // server, or errStreamClosed if the stream is complete. | 
|  | func (cs *http2clientStream) checkResetOrDone() error { | 
|  | select { | 
|  | case <-cs.peerReset: | 
|  | return cs.resetErr | 
|  | case <-cs.done: | 
|  | return http2errStreamClosed | 
|  | default: | 
|  | return nil | 
|  | } | 
|  | } | 
|  |  | 
|  | func (cs *http2clientStream) getStartedWrite() bool { | 
|  | cc := cs.cc | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | return cs.startedWrite | 
|  | } | 
|  |  | 
|  | func (cs *http2clientStream) abortRequestBodyWrite(err error) { | 
|  | if err == nil { | 
|  | panic("nil error") | 
|  | } | 
|  | cc := cs.cc | 
|  | cc.mu.Lock() | 
|  | cs.stopReqBody = err | 
|  | cc.cond.Broadcast() | 
|  | cc.mu.Unlock() | 
|  | } | 
|  |  | 
|  | type http2stickyErrWriter struct { | 
|  | w   io.Writer | 
|  | err *error | 
|  | } | 
|  |  | 
|  | func (sew http2stickyErrWriter) Write(p []byte) (n int, err error) { | 
|  | if *sew.err != nil { | 
|  | return 0, *sew.err | 
|  | } | 
|  | n, err = sew.w.Write(p) | 
|  | *sew.err = err | 
|  | return | 
|  | } | 
|  |  | 
|  | // noCachedConnError is the concrete type of ErrNoCachedConn, which | 
|  | // needs to be detected by net/http regardless of whether it's its | 
|  | // bundled version (in h2_bundle.go with a rewritten type name) or | 
|  | // from a user's x/net/http2. As such, as it has a unique method name | 
|  | // (IsHTTP2NoCachedConnError) that net/http sniffs for via func | 
|  | // isNoCachedConnError. | 
|  | type http2noCachedConnError struct{} | 
|  |  | 
|  | func (http2noCachedConnError) IsHTTP2NoCachedConnError() {} | 
|  |  | 
|  | func (http2noCachedConnError) Error() string { return "http2: no cached connection was available" } | 
|  |  | 
|  | // isNoCachedConnError reports whether err is of type noCachedConnError | 
|  | // or its equivalent renamed type in net/http2's h2_bundle.go. Both types | 
|  | // may coexist in the same running program. | 
|  | func http2isNoCachedConnError(err error) bool { | 
|  | _, ok := err.(interface{ IsHTTP2NoCachedConnError() }) | 
|  | return ok | 
|  | } | 
|  |  | 
|  | var http2ErrNoCachedConn error = http2noCachedConnError{} | 
|  |  | 
|  | // RoundTripOpt are options for the Transport.RoundTripOpt method. | 
|  | type http2RoundTripOpt struct { | 
|  | // OnlyCachedConn controls whether RoundTripOpt may | 
|  | // create a new TCP connection. If set true and | 
|  | // no cached connection is available, RoundTripOpt | 
|  | // will return ErrNoCachedConn. | 
|  | OnlyCachedConn bool | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) RoundTrip(req *Request) (*Response, error) { | 
|  | return t.RoundTripOpt(req, http2RoundTripOpt{}) | 
|  | } | 
|  |  | 
|  | // authorityAddr returns a given authority (a host/IP, or host:port / ip:port) | 
|  | // and returns a host:port. The port 443 is added if needed. | 
|  | func http2authorityAddr(scheme string, authority string) (addr string) { | 
|  | host, port, err := net.SplitHostPort(authority) | 
|  | if err != nil { // authority didn't have a port | 
|  | port = "443" | 
|  | if scheme == "http" { | 
|  | port = "80" | 
|  | } | 
|  | host = authority | 
|  | } | 
|  | if a, err := idna.ToASCII(host); err == nil { | 
|  | host = a | 
|  | } | 
|  | // IPv6 address literal, without a port: | 
|  | if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { | 
|  | return host + ":" + port | 
|  | } | 
|  | return net.JoinHostPort(host, port) | 
|  | } | 
|  |  | 
|  | // RoundTripOpt is like RoundTrip, but takes options. | 
|  | func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) { | 
|  | if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) { | 
|  | return nil, errors.New("http2: unsupported scheme") | 
|  | } | 
|  |  | 
|  | addr := http2authorityAddr(req.URL.Scheme, req.URL.Host) | 
|  | for retry := 0; ; retry++ { | 
|  | cc, err := t.connPool().GetClientConn(req, addr) | 
|  | if err != nil { | 
|  | t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err) | 
|  | return nil, err | 
|  | } | 
|  | http2traceGotConn(req, cc) | 
|  | res, gotErrAfterReqBodyWrite, err := cc.roundTrip(req) | 
|  | if err != nil && retry <= 6 { | 
|  | if req, err = http2shouldRetryRequest(req, err, gotErrAfterReqBodyWrite); err == nil { | 
|  | // After the first retry, do exponential backoff with 10% jitter. | 
|  | if retry == 0 { | 
|  | continue | 
|  | } | 
|  | backoff := float64(uint(1) << (uint(retry) - 1)) | 
|  | backoff += backoff * (0.1 * mathrand.Float64()) | 
|  | select { | 
|  | case <-time.After(time.Second * time.Duration(backoff)): | 
|  | continue | 
|  | case <-http2reqContext(req).Done(): | 
|  | return nil, http2reqContext(req).Err() | 
|  | } | 
|  | } | 
|  | } | 
|  | if err != nil { | 
|  | t.vlogf("RoundTrip failure: %v", err) | 
|  | return nil, err | 
|  | } | 
|  | return res, nil | 
|  | } | 
|  | } | 
|  |  | 
|  | // CloseIdleConnections closes any connections which were previously | 
|  | // connected from previous requests but are now sitting idle. | 
|  | // It does not interrupt any connections currently in use. | 
|  | func (t *http2Transport) CloseIdleConnections() { | 
|  | if cp, ok := t.connPool().(http2clientConnPoolIdleCloser); ok { | 
|  | cp.closeIdleConnections() | 
|  | } | 
|  | } | 
|  |  | 
|  | var ( | 
|  | http2errClientConnClosed    = errors.New("http2: client conn is closed") | 
|  | http2errClientConnUnusable  = errors.New("http2: client conn not usable") | 
|  | http2errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY") | 
|  | ) | 
|  |  | 
|  | // shouldRetryRequest is called by RoundTrip when a request fails to get | 
|  | // response headers. It is always called with a non-nil error. | 
|  | // It returns either a request to retry (either the same request, or a | 
|  | // modified clone), or an error if the request can't be replayed. | 
|  | func http2shouldRetryRequest(req *Request, err error, afterBodyWrite bool) (*Request, error) { | 
|  | if !http2canRetryError(err) { | 
|  | return nil, err | 
|  | } | 
|  | // If the Body is nil (or http.NoBody), it's safe to reuse | 
|  | // this request and its Body. | 
|  | if req.Body == nil || http2reqBodyIsNoBody(req.Body) { | 
|  | return req, nil | 
|  | } | 
|  |  | 
|  | // If the request body can be reset back to its original | 
|  | // state via the optional req.GetBody, do that. | 
|  | getBody := http2reqGetBody(req) // Go 1.8: getBody = req.GetBody | 
|  | if getBody != nil { | 
|  | // TODO: consider a req.Body.Close here? or audit that all caller paths do? | 
|  | body, err := getBody() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | newReq := *req | 
|  | newReq.Body = body | 
|  | return &newReq, nil | 
|  | } | 
|  |  | 
|  | // The Request.Body can't reset back to the beginning, but we | 
|  | // don't seem to have started to read from it yet, so reuse | 
|  | // the request directly. The "afterBodyWrite" means the | 
|  | // bodyWrite process has started, which becomes true before | 
|  | // the first Read. | 
|  | if !afterBodyWrite { | 
|  | return req, nil | 
|  | } | 
|  |  | 
|  | return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", err) | 
|  | } | 
|  |  | 
|  | func http2canRetryError(err error) bool { | 
|  | if err == http2errClientConnUnusable || err == http2errClientConnGotGoAway { | 
|  | return true | 
|  | } | 
|  | if se, ok := err.(http2StreamError); ok { | 
|  | return se.Code == http2ErrCodeRefusedStream | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2ClientConn, error) { | 
|  | host, _, err := net.SplitHostPort(addr) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host)) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | return t.newClientConn(tconn, singleUse) | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) newTLSConfig(host string) *tls.Config { | 
|  | cfg := new(tls.Config) | 
|  | if t.TLSClientConfig != nil { | 
|  | *cfg = *http2cloneTLSConfig(t.TLSClientConfig) | 
|  | } | 
|  | if !http2strSliceContains(cfg.NextProtos, http2NextProtoTLS) { | 
|  | cfg.NextProtos = append([]string{http2NextProtoTLS}, cfg.NextProtos...) | 
|  | } | 
|  | if cfg.ServerName == "" { | 
|  | cfg.ServerName = host | 
|  | } | 
|  | return cfg | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) { | 
|  | if t.DialTLS != nil { | 
|  | return t.DialTLS | 
|  | } | 
|  | return t.dialTLSDefault | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) { | 
|  | cn, err := tls.Dial(network, addr, cfg) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | if err := cn.Handshake(); err != nil { | 
|  | return nil, err | 
|  | } | 
|  | if !cfg.InsecureSkipVerify { | 
|  | if err := cn.VerifyHostname(cfg.ServerName); err != nil { | 
|  | return nil, err | 
|  | } | 
|  | } | 
|  | state := cn.ConnectionState() | 
|  | if p := state.NegotiatedProtocol; p != http2NextProtoTLS { | 
|  | return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, http2NextProtoTLS) | 
|  | } | 
|  | if !state.NegotiatedProtocolIsMutual { | 
|  | return nil, errors.New("http2: could not negotiate protocol mutually") | 
|  | } | 
|  | return cn, nil | 
|  | } | 
|  |  | 
|  | // disableKeepAlives reports whether connections should be closed as | 
|  | // soon as possible after handling the first request. | 
|  | func (t *http2Transport) disableKeepAlives() bool { | 
|  | return t.t1 != nil && t.t1.DisableKeepAlives | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) expectContinueTimeout() time.Duration { | 
|  | if t.t1 == nil { | 
|  | return 0 | 
|  | } | 
|  | return http2transportExpectContinueTimeout(t.t1) | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { | 
|  | return t.newClientConn(c, false) | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) { | 
|  | cc := &http2ClientConn{ | 
|  | t:                     t, | 
|  | tconn:                 c, | 
|  | readerDone:            make(chan struct{}), | 
|  | nextStreamID:          1, | 
|  | maxFrameSize:          16 << 10,           // spec default | 
|  | initialWindowSize:     65535,              // spec default | 
|  | maxConcurrentStreams:  1000,               // "infinite", per spec. 1000 seems good enough. | 
|  | peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead. | 
|  | streams:               make(map[uint32]*http2clientStream), | 
|  | singleUse:             singleUse, | 
|  | wantSettingsAck:       true, | 
|  | pings:                 make(map[[8]byte]chan struct{}), | 
|  | } | 
|  | if d := t.idleConnTimeout(); d != 0 { | 
|  | cc.idleTimeout = d | 
|  | cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout) | 
|  | } | 
|  | if http2VerboseLogs { | 
|  | t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr()) | 
|  | } | 
|  |  | 
|  | cc.cond = sync.NewCond(&cc.mu) | 
|  | cc.flow.add(int32(http2initialWindowSize)) | 
|  |  | 
|  | // TODO: adjust this writer size to account for frame size + | 
|  | // MTU + crypto/tls record padding. | 
|  | cc.bw = bufio.NewWriter(http2stickyErrWriter{c, &cc.werr}) | 
|  | cc.br = bufio.NewReader(c) | 
|  | cc.fr = http2NewFramer(cc.bw, cc.br) | 
|  | cc.fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil) | 
|  | cc.fr.MaxHeaderListSize = t.maxHeaderListSize() | 
|  |  | 
|  | // TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on | 
|  | // henc in response to SETTINGS frames? | 
|  | cc.henc = hpack.NewEncoder(&cc.hbuf) | 
|  |  | 
|  | if t.AllowHTTP { | 
|  | cc.nextStreamID = 3 | 
|  | } | 
|  |  | 
|  | if cs, ok := c.(http2connectionStater); ok { | 
|  | state := cs.ConnectionState() | 
|  | cc.tlsState = &state | 
|  | } | 
|  |  | 
|  | initialSettings := []http2Setting{ | 
|  | {ID: http2SettingEnablePush, Val: 0}, | 
|  | {ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow}, | 
|  | } | 
|  | if max := t.maxHeaderListSize(); max != 0 { | 
|  | initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max}) | 
|  | } | 
|  |  | 
|  | cc.bw.Write(http2clientPreface) | 
|  | cc.fr.WriteSettings(initialSettings...) | 
|  | cc.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow) | 
|  | cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize) | 
|  | cc.bw.Flush() | 
|  | if cc.werr != nil { | 
|  | return nil, cc.werr | 
|  | } | 
|  |  | 
|  | go cc.readLoop() | 
|  | return cc, nil | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  |  | 
|  | old := cc.goAway | 
|  | cc.goAway = f | 
|  |  | 
|  | // Merge the previous and current GoAway error frames. | 
|  | if cc.goAwayDebug == "" { | 
|  | cc.goAwayDebug = string(f.DebugData()) | 
|  | } | 
|  | if old != nil && old.ErrCode != http2ErrCodeNo { | 
|  | cc.goAway.ErrCode = old.ErrCode | 
|  | } | 
|  | last := f.LastStreamID | 
|  | for streamID, cs := range cc.streams { | 
|  | if streamID > last { | 
|  | select { | 
|  | case cs.resc <- http2resAndError{err: http2errClientConnGotGoAway}: | 
|  | default: | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // CanTakeNewRequest reports whether the connection can take a new request, | 
|  | // meaning it has not been closed or received or sent a GOAWAY. | 
|  | func (cc *http2ClientConn) CanTakeNewRequest() bool { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | return cc.canTakeNewRequestLocked() | 
|  | } | 
|  |  | 
|  | // clientConnIdleState describes the suitability of a client | 
|  | // connection to initiate a new RoundTrip request. | 
|  | type http2clientConnIdleState struct { | 
|  | canTakeNewRequest bool | 
|  | freshConn         bool // whether it's unused by any previous request | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) idleState() http2clientConnIdleState { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | return cc.idleStateLocked() | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) idleStateLocked() (st http2clientConnIdleState) { | 
|  | if cc.singleUse && cc.nextStreamID > 1 { | 
|  | return | 
|  | } | 
|  | st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && | 
|  | int64(cc.nextStreamID)+int64(cc.pendingRequests) < math.MaxInt32 | 
|  | st.freshConn = cc.nextStreamID == 1 && st.canTakeNewRequest | 
|  | return | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) canTakeNewRequestLocked() bool { | 
|  | st := cc.idleStateLocked() | 
|  | return st.canTakeNewRequest | 
|  | } | 
|  |  | 
|  | // onIdleTimeout is called from a time.AfterFunc goroutine. It will | 
|  | // only be called when we're idle, but because we're coming from a new | 
|  | // goroutine, there could be a new request coming in at the same time, | 
|  | // so this simply calls the synchronized closeIfIdle to shut down this | 
|  | // connection. The timer could just call closeIfIdle, but this is more | 
|  | // clear. | 
|  | func (cc *http2ClientConn) onIdleTimeout() { | 
|  | cc.closeIfIdle() | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) closeIfIdle() { | 
|  | cc.mu.Lock() | 
|  | if len(cc.streams) > 0 { | 
|  | cc.mu.Unlock() | 
|  | return | 
|  | } | 
|  | cc.closed = true | 
|  | nextID := cc.nextStreamID | 
|  | // TODO: do clients send GOAWAY too? maybe? Just Close: | 
|  | cc.mu.Unlock() | 
|  |  | 
|  | if http2VerboseLogs { | 
|  | cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2) | 
|  | } | 
|  | cc.tconn.Close() | 
|  | } | 
|  |  | 
|  | var http2shutdownEnterWaitStateHook = func() {} | 
|  |  | 
|  | // Shutdown gracefully close the client connection, waiting for running streams to complete. | 
|  | // Public implementation is in go17.go and not_go17.go | 
|  | func (cc *http2ClientConn) shutdown(ctx http2contextContext) error { | 
|  | if err := cc.sendGoAway(); err != nil { | 
|  | return err | 
|  | } | 
|  | // Wait for all in-flight streams to complete or connection to close | 
|  | done := make(chan error, 1) | 
|  | cancelled := false // guarded by cc.mu | 
|  | go func() { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | for { | 
|  | if len(cc.streams) == 0 || cc.closed { | 
|  | cc.closed = true | 
|  | done <- cc.tconn.Close() | 
|  | break | 
|  | } | 
|  | if cancelled { | 
|  | break | 
|  | } | 
|  | cc.cond.Wait() | 
|  | } | 
|  | }() | 
|  | http2shutdownEnterWaitStateHook() | 
|  | select { | 
|  | case err := <-done: | 
|  | return err | 
|  | case <-ctx.Done(): | 
|  | cc.mu.Lock() | 
|  | // Free the goroutine above | 
|  | cancelled = true | 
|  | cc.cond.Broadcast() | 
|  | cc.mu.Unlock() | 
|  | return ctx.Err() | 
|  | } | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) sendGoAway() error { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | cc.wmu.Lock() | 
|  | defer cc.wmu.Unlock() | 
|  | if cc.closing { | 
|  | // GOAWAY sent already | 
|  | return nil | 
|  | } | 
|  | // Send a graceful shutdown frame to server | 
|  | maxStreamID := cc.nextStreamID | 
|  | if err := cc.fr.WriteGoAway(maxStreamID, http2ErrCodeNo, nil); err != nil { | 
|  | return err | 
|  | } | 
|  | if err := cc.bw.Flush(); err != nil { | 
|  | return err | 
|  | } | 
|  | // Prevent new requests | 
|  | cc.closing = true | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Close closes the client connection immediately. | 
|  | // | 
|  | // In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead. | 
|  | func (cc *http2ClientConn) Close() error { | 
|  | cc.mu.Lock() | 
|  | defer cc.cond.Broadcast() | 
|  | defer cc.mu.Unlock() | 
|  | err := errors.New("http2: client connection force closed via ClientConn.Close") | 
|  | for id, cs := range cc.streams { | 
|  | select { | 
|  | case cs.resc <- http2resAndError{err: err}: | 
|  | default: | 
|  | } | 
|  | cs.bufPipe.CloseWithError(err) | 
|  | delete(cc.streams, id) | 
|  | } | 
|  | cc.closed = true | 
|  | return cc.tconn.Close() | 
|  | } | 
|  |  | 
|  | const http2maxAllocFrameSize = 512 << 10 | 
|  |  | 
|  | // frameBuffer returns a scratch buffer suitable for writing DATA frames. | 
|  | // They're capped at the min of the peer's max frame size or 512KB | 
|  | // (kinda arbitrarily), but definitely capped so we don't allocate 4GB | 
|  | // bufers. | 
|  | func (cc *http2ClientConn) frameScratchBuffer() []byte { | 
|  | cc.mu.Lock() | 
|  | size := cc.maxFrameSize | 
|  | if size > http2maxAllocFrameSize { | 
|  | size = http2maxAllocFrameSize | 
|  | } | 
|  | for i, buf := range cc.freeBuf { | 
|  | if len(buf) >= int(size) { | 
|  | cc.freeBuf[i] = nil | 
|  | cc.mu.Unlock() | 
|  | return buf[:size] | 
|  | } | 
|  | } | 
|  | cc.mu.Unlock() | 
|  | return make([]byte, size) | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) putFrameScratchBuffer(buf []byte) { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | const maxBufs = 4 // arbitrary; 4 concurrent requests per conn? investigate. | 
|  | if len(cc.freeBuf) < maxBufs { | 
|  | cc.freeBuf = append(cc.freeBuf, buf) | 
|  | return | 
|  | } | 
|  | for i, old := range cc.freeBuf { | 
|  | if old == nil { | 
|  | cc.freeBuf[i] = buf | 
|  | return | 
|  | } | 
|  | } | 
|  | // forget about it. | 
|  | } | 
|  |  | 
|  | // errRequestCanceled is a copy of net/http's errRequestCanceled because it's not | 
|  | // exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests. | 
|  | var http2errRequestCanceled = errors.New("net/http: request canceled") | 
|  |  | 
|  | func http2commaSeparatedTrailers(req *Request) (string, error) { | 
|  | keys := make([]string, 0, len(req.Trailer)) | 
|  | for k := range req.Trailer { | 
|  | k = CanonicalHeaderKey(k) | 
|  | switch k { | 
|  | case "Transfer-Encoding", "Trailer", "Content-Length": | 
|  | return "", &http2badStringError{"invalid Trailer key", k} | 
|  | } | 
|  | keys = append(keys, k) | 
|  | } | 
|  | if len(keys) > 0 { | 
|  | sort.Strings(keys) | 
|  | return strings.Join(keys, ","), nil | 
|  | } | 
|  | return "", nil | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) responseHeaderTimeout() time.Duration { | 
|  | if cc.t.t1 != nil { | 
|  | return cc.t.t1.ResponseHeaderTimeout | 
|  | } | 
|  | // No way to do this (yet?) with just an http2.Transport. Probably | 
|  | // no need. Request.Cancel this is the new way. We only need to support | 
|  | // this for compatibility with the old http.Transport fields when | 
|  | // we're doing transparent http2. | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | // checkConnHeaders checks whether req has any invalid connection-level headers. | 
|  | // per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields. | 
|  | // Certain headers are special-cased as okay but not transmitted later. | 
|  | func http2checkConnHeaders(req *Request) error { | 
|  | if v := req.Header.Get("Upgrade"); v != "" { | 
|  | return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"]) | 
|  | } | 
|  | if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") { | 
|  | return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv) | 
|  | } | 
|  | if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !strings.EqualFold(vv[0], "close") && !strings.EqualFold(vv[0], "keep-alive")) { | 
|  | return fmt.Errorf("http2: invalid Connection request header: %q", vv) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // actualContentLength returns a sanitized version of | 
|  | // req.ContentLength, where 0 actually means zero (not unknown) and -1 | 
|  | // means unknown. | 
|  | func http2actualContentLength(req *Request) int64 { | 
|  | if req.Body == nil || http2reqBodyIsNoBody(req.Body) { | 
|  | return 0 | 
|  | } | 
|  | if req.ContentLength != 0 { | 
|  | return req.ContentLength | 
|  | } | 
|  | return -1 | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { | 
|  | resp, _, err := cc.roundTrip(req) | 
|  | return resp, err | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterReqBodyWrite bool, err error) { | 
|  | if err := http2checkConnHeaders(req); err != nil { | 
|  | return nil, false, err | 
|  | } | 
|  | if cc.idleTimer != nil { | 
|  | cc.idleTimer.Stop() | 
|  | } | 
|  |  | 
|  | trailers, err := http2commaSeparatedTrailers(req) | 
|  | if err != nil { | 
|  | return nil, false, err | 
|  | } | 
|  | hasTrailers := trailers != "" | 
|  |  | 
|  | cc.mu.Lock() | 
|  | if err := cc.awaitOpenSlotForRequest(req); err != nil { | 
|  | cc.mu.Unlock() | 
|  | return nil, false, err | 
|  | } | 
|  |  | 
|  | body := req.Body | 
|  | contentLen := http2actualContentLength(req) | 
|  | hasBody := contentLen != 0 | 
|  |  | 
|  | // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? | 
|  | var requestedGzip bool | 
|  | if !cc.t.disableCompression() && | 
|  | req.Header.Get("Accept-Encoding") == "" && | 
|  | req.Header.Get("Range") == "" && | 
|  | req.Method != "HEAD" { | 
|  | // Request gzip only, not deflate. Deflate is ambiguous and | 
|  | // not as universally supported anyway. | 
|  | // See: http://www.gzip.org/zlib/zlib_faq.html#faq38 | 
|  | // | 
|  | // Note that we don't request this for HEAD requests, | 
|  | // due to a bug in nginx: | 
|  | //   http://trac.nginx.org/nginx/ticket/358 | 
|  | //   https://golang.org/issue/5522 | 
|  | // | 
|  | // We don't request gzip if the request is for a range, since | 
|  | // auto-decoding a portion of a gzipped document will just fail | 
|  | // anyway. See https://golang.org/issue/8923 | 
|  | requestedGzip = true | 
|  | } | 
|  |  | 
|  | // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is | 
|  | // sent by writeRequestBody below, along with any Trailers, | 
|  | // again in form HEADERS{1}, CONTINUATION{0,}) | 
|  | hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen) | 
|  | if err != nil { | 
|  | cc.mu.Unlock() | 
|  | return nil, false, err | 
|  | } | 
|  |  | 
|  | cs := cc.newStream() | 
|  | cs.req = req | 
|  | cs.trace = http2requestTrace(req) | 
|  | cs.requestedGzip = requestedGzip | 
|  | bodyWriter := cc.t.getBodyWriterState(cs, body) | 
|  | cs.on100 = bodyWriter.on100 | 
|  |  | 
|  | cc.wmu.Lock() | 
|  | endStream := !hasBody && !hasTrailers | 
|  | werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) | 
|  | cc.wmu.Unlock() | 
|  | http2traceWroteHeaders(cs.trace) | 
|  | cc.mu.Unlock() | 
|  |  | 
|  | if werr != nil { | 
|  | if hasBody { | 
|  | req.Body.Close() // per RoundTripper contract | 
|  | bodyWriter.cancel() | 
|  | } | 
|  | cc.forgetStreamID(cs.ID) | 
|  | // Don't bother sending a RST_STREAM (our write already failed; | 
|  | // no need to keep writing) | 
|  | http2traceWroteRequest(cs.trace, werr) | 
|  | return nil, false, werr | 
|  | } | 
|  |  | 
|  | var respHeaderTimer <-chan time.Time | 
|  | if hasBody { | 
|  | bodyWriter.scheduleBodyWrite() | 
|  | } else { | 
|  | http2traceWroteRequest(cs.trace, nil) | 
|  | if d := cc.responseHeaderTimeout(); d != 0 { | 
|  | timer := time.NewTimer(d) | 
|  | defer timer.Stop() | 
|  | respHeaderTimer = timer.C | 
|  | } | 
|  | } | 
|  |  | 
|  | readLoopResCh := cs.resc | 
|  | bodyWritten := false | 
|  | ctx := http2reqContext(req) | 
|  |  | 
|  | handleReadLoopResponse := func(re http2resAndError) (*Response, bool, error) { | 
|  | res := re.res | 
|  | if re.err != nil || res.StatusCode > 299 { | 
|  | // On error or status code 3xx, 4xx, 5xx, etc abort any | 
|  | // ongoing write, assuming that the server doesn't care | 
|  | // about our request body. If the server replied with 1xx or | 
|  | // 2xx, however, then assume the server DOES potentially | 
|  | // want our body (e.g. full-duplex streaming: | 
|  | // golang.org/issue/13444). If it turns out the server | 
|  | // doesn't, they'll RST_STREAM us soon enough. This is a | 
|  | // heuristic to avoid adding knobs to Transport. Hopefully | 
|  | // we can keep it. | 
|  | bodyWriter.cancel() | 
|  | cs.abortRequestBodyWrite(http2errStopReqBodyWrite) | 
|  | } | 
|  | if re.err != nil { | 
|  | cc.forgetStreamID(cs.ID) | 
|  | return nil, cs.getStartedWrite(), re.err | 
|  | } | 
|  | res.Request = req | 
|  | res.TLS = cc.tlsState | 
|  | return res, false, nil | 
|  | } | 
|  |  | 
|  | for { | 
|  | select { | 
|  | case re := <-readLoopResCh: | 
|  | return handleReadLoopResponse(re) | 
|  | case <-respHeaderTimer: | 
|  | if !hasBody || bodyWritten { | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) | 
|  | } else { | 
|  | bodyWriter.cancel() | 
|  | cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) | 
|  | } | 
|  | cc.forgetStreamID(cs.ID) | 
|  | return nil, cs.getStartedWrite(), http2errTimeout | 
|  | case <-ctx.Done(): | 
|  | if !hasBody || bodyWritten { | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) | 
|  | } else { | 
|  | bodyWriter.cancel() | 
|  | cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) | 
|  | } | 
|  | cc.forgetStreamID(cs.ID) | 
|  | return nil, cs.getStartedWrite(), ctx.Err() | 
|  | case <-req.Cancel: | 
|  | if !hasBody || bodyWritten { | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) | 
|  | } else { | 
|  | bodyWriter.cancel() | 
|  | cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) | 
|  | } | 
|  | cc.forgetStreamID(cs.ID) | 
|  | return nil, cs.getStartedWrite(), http2errRequestCanceled | 
|  | case <-cs.peerReset: | 
|  | // processResetStream already removed the | 
|  | // stream from the streams map; no need for | 
|  | // forgetStreamID. | 
|  | return nil, cs.getStartedWrite(), cs.resetErr | 
|  | case err := <-bodyWriter.resc: | 
|  | // Prefer the read loop's response, if available. Issue 16102. | 
|  | select { | 
|  | case re := <-readLoopResCh: | 
|  | return handleReadLoopResponse(re) | 
|  | default: | 
|  | } | 
|  | if err != nil { | 
|  | return nil, cs.getStartedWrite(), err | 
|  | } | 
|  | bodyWritten = true | 
|  | if d := cc.responseHeaderTimeout(); d != 0 { | 
|  | timer := time.NewTimer(d) | 
|  | defer timer.Stop() | 
|  | respHeaderTimer = timer.C | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // awaitOpenSlotForRequest waits until len(streams) < maxConcurrentStreams. | 
|  | // Must hold cc.mu. | 
|  | func (cc *http2ClientConn) awaitOpenSlotForRequest(req *Request) error { | 
|  | var waitingForConn chan struct{} | 
|  | var waitingForConnErr error // guarded by cc.mu | 
|  | for { | 
|  | cc.lastActive = time.Now() | 
|  | if cc.closed || !cc.canTakeNewRequestLocked() { | 
|  | if waitingForConn != nil { | 
|  | close(waitingForConn) | 
|  | } | 
|  | return http2errClientConnUnusable | 
|  | } | 
|  | if int64(len(cc.streams))+1 <= int64(cc.maxConcurrentStreams) { | 
|  | if waitingForConn != nil { | 
|  | close(waitingForConn) | 
|  | } | 
|  | return nil | 
|  | } | 
|  | // Unfortunately, we cannot wait on a condition variable and channel at | 
|  | // the same time, so instead, we spin up a goroutine to check if the | 
|  | // request is canceled while we wait for a slot to open in the connection. | 
|  | if waitingForConn == nil { | 
|  | waitingForConn = make(chan struct{}) | 
|  | go func() { | 
|  | if err := http2awaitRequestCancel(req, waitingForConn); err != nil { | 
|  | cc.mu.Lock() | 
|  | waitingForConnErr = err | 
|  | cc.cond.Broadcast() | 
|  | cc.mu.Unlock() | 
|  | } | 
|  | }() | 
|  | } | 
|  | cc.pendingRequests++ | 
|  | cc.cond.Wait() | 
|  | cc.pendingRequests-- | 
|  | if waitingForConnErr != nil { | 
|  | return waitingForConnErr | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // requires cc.wmu be held | 
|  | func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error { | 
|  | first := true // first frame written (HEADERS is first, then CONTINUATION) | 
|  | for len(hdrs) > 0 && cc.werr == nil { | 
|  | chunk := hdrs | 
|  | if len(chunk) > maxFrameSize { | 
|  | chunk = chunk[:maxFrameSize] | 
|  | } | 
|  | hdrs = hdrs[len(chunk):] | 
|  | endHeaders := len(hdrs) == 0 | 
|  | if first { | 
|  | cc.fr.WriteHeaders(http2HeadersFrameParam{ | 
|  | StreamID:      streamID, | 
|  | BlockFragment: chunk, | 
|  | EndStream:     endStream, | 
|  | EndHeaders:    endHeaders, | 
|  | }) | 
|  | first = false | 
|  | } else { | 
|  | cc.fr.WriteContinuation(streamID, endHeaders, chunk) | 
|  | } | 
|  | } | 
|  | // TODO(bradfitz): this Flush could potentially block (as | 
|  | // could the WriteHeaders call(s) above), which means they | 
|  | // wouldn't respond to Request.Cancel being readable. That's | 
|  | // rare, but this should probably be in a goroutine. | 
|  | cc.bw.Flush() | 
|  | return cc.werr | 
|  | } | 
|  |  | 
|  | // internal error values; they don't escape to callers | 
|  | var ( | 
|  | // abort request body write; don't send cancel | 
|  | http2errStopReqBodyWrite = errors.New("http2: aborting request body write") | 
|  |  | 
|  | // abort request body write, but send stream reset of cancel. | 
|  | http2errStopReqBodyWriteAndCancel = errors.New("http2: canceling request") | 
|  | ) | 
|  |  | 
|  | func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) { | 
|  | cc := cs.cc | 
|  | sentEnd := false // whether we sent the final DATA frame w/ END_STREAM | 
|  | buf := cc.frameScratchBuffer() | 
|  | defer cc.putFrameScratchBuffer(buf) | 
|  |  | 
|  | defer func() { | 
|  | http2traceWroteRequest(cs.trace, err) | 
|  | // TODO: write h12Compare test showing whether | 
|  | // Request.Body is closed by the Transport, | 
|  | // and in multiple cases: server replies <=299 and >299 | 
|  | // while still writing request body | 
|  | cerr := bodyCloser.Close() | 
|  | if err == nil { | 
|  | err = cerr | 
|  | } | 
|  | }() | 
|  |  | 
|  | req := cs.req | 
|  | hasTrailers := req.Trailer != nil | 
|  |  | 
|  | var sawEOF bool | 
|  | for !sawEOF { | 
|  | n, err := body.Read(buf) | 
|  | if err == io.EOF { | 
|  | sawEOF = true | 
|  | err = nil | 
|  | } else if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | remain := buf[:n] | 
|  | for len(remain) > 0 && err == nil { | 
|  | var allowed int32 | 
|  | allowed, err = cs.awaitFlowControl(len(remain)) | 
|  | switch { | 
|  | case err == http2errStopReqBodyWrite: | 
|  | return err | 
|  | case err == http2errStopReqBodyWriteAndCancel: | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) | 
|  | return err | 
|  | case err != nil: | 
|  | return err | 
|  | } | 
|  | cc.wmu.Lock() | 
|  | data := remain[:allowed] | 
|  | remain = remain[allowed:] | 
|  | sentEnd = sawEOF && len(remain) == 0 && !hasTrailers | 
|  | err = cc.fr.WriteData(cs.ID, sentEnd, data) | 
|  | if err == nil { | 
|  | // TODO(bradfitz): this flush is for latency, not bandwidth. | 
|  | // Most requests won't need this. Make this opt-in or | 
|  | // opt-out?  Use some heuristic on the body type? Nagel-like | 
|  | // timers?  Based on 'n'? Only last chunk of this for loop, | 
|  | // unless flow control tokens are low? For now, always. | 
|  | // If we change this, see comment below. | 
|  | err = cc.bw.Flush() | 
|  | } | 
|  | cc.wmu.Unlock() | 
|  | } | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  |  | 
|  | if sentEnd { | 
|  | // Already sent END_STREAM (which implies we have no | 
|  | // trailers) and flushed, because currently all | 
|  | // WriteData frames above get a flush. So we're done. | 
|  | return nil | 
|  | } | 
|  |  | 
|  | var trls []byte | 
|  | if hasTrailers { | 
|  | cc.mu.Lock() | 
|  | trls, err = cc.encodeTrailers(req) | 
|  | cc.mu.Unlock() | 
|  | if err != nil { | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeInternal, err) | 
|  | cc.forgetStreamID(cs.ID) | 
|  | return err | 
|  | } | 
|  | } | 
|  |  | 
|  | cc.mu.Lock() | 
|  | maxFrameSize := int(cc.maxFrameSize) | 
|  | cc.mu.Unlock() | 
|  |  | 
|  | cc.wmu.Lock() | 
|  | defer cc.wmu.Unlock() | 
|  |  | 
|  | // Two ways to send END_STREAM: either with trailers, or | 
|  | // with an empty DATA frame. | 
|  | if len(trls) > 0 { | 
|  | err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls) | 
|  | } else { | 
|  | err = cc.fr.WriteData(cs.ID, true, nil) | 
|  | } | 
|  | if ferr := cc.bw.Flush(); ferr != nil && err == nil { | 
|  | err = ferr | 
|  | } | 
|  | return err | 
|  | } | 
|  |  | 
|  | // awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow | 
|  | // control tokens from the server. | 
|  | // It returns either the non-zero number of tokens taken or an error | 
|  | // if the stream is dead. | 
|  | func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) { | 
|  | cc := cs.cc | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | for { | 
|  | if cc.closed { | 
|  | return 0, http2errClientConnClosed | 
|  | } | 
|  | if cs.stopReqBody != nil { | 
|  | return 0, cs.stopReqBody | 
|  | } | 
|  | if err := cs.checkResetOrDone(); err != nil { | 
|  | return 0, err | 
|  | } | 
|  | if a := cs.flow.available(); a > 0 { | 
|  | take := a | 
|  | if int(take) > maxBytes { | 
|  |  | 
|  | take = int32(maxBytes) // can't truncate int; take is int32 | 
|  | } | 
|  | if take > int32(cc.maxFrameSize) { | 
|  | take = int32(cc.maxFrameSize) | 
|  | } | 
|  | cs.flow.take(take) | 
|  | return take, nil | 
|  | } | 
|  | cc.cond.Wait() | 
|  | } | 
|  | } | 
|  |  | 
|  | type http2badStringError struct { | 
|  | what string | 
|  | str  string | 
|  | } | 
|  |  | 
|  | func (e *http2badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) } | 
|  |  | 
|  | // requires cc.mu be held. | 
|  | func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { | 
|  | cc.hbuf.Reset() | 
|  |  | 
|  | host := req.Host | 
|  | if host == "" { | 
|  | host = req.URL.Host | 
|  | } | 
|  | host, err := httpguts.PunycodeHostPort(host) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | var path string | 
|  | if req.Method != "CONNECT" { | 
|  | path = req.URL.RequestURI() | 
|  | if !http2validPseudoPath(path) { | 
|  | orig := path | 
|  | path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host) | 
|  | if !http2validPseudoPath(path) { | 
|  | if req.URL.Opaque != "" { | 
|  | return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque) | 
|  | } else { | 
|  | return nil, fmt.Errorf("invalid request :path %q", orig) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Check for any invalid headers and return an error before we | 
|  | // potentially pollute our hpack state. (We want to be able to | 
|  | // continue to reuse the hpack encoder for future requests) | 
|  | for k, vv := range req.Header { | 
|  | if !httpguts.ValidHeaderFieldName(k) { | 
|  | return nil, fmt.Errorf("invalid HTTP header name %q", k) | 
|  | } | 
|  | for _, v := range vv { | 
|  | if !httpguts.ValidHeaderFieldValue(v) { | 
|  | return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | enumerateHeaders := func(f func(name, value string)) { | 
|  | // 8.1.2.3 Request Pseudo-Header Fields | 
|  | // The :path pseudo-header field includes the path and query parts of the | 
|  | // target URI (the path-absolute production and optionally a '?' character | 
|  | // followed by the query production (see Sections 3.3 and 3.4 of | 
|  | // [RFC3986]). | 
|  | f(":authority", host) | 
|  | f(":method", req.Method) | 
|  | if req.Method != "CONNECT" { | 
|  | f(":path", path) | 
|  | f(":scheme", req.URL.Scheme) | 
|  | } | 
|  | if trailers != "" { | 
|  | f("trailer", trailers) | 
|  | } | 
|  |  | 
|  | var didUA bool | 
|  | for k, vv := range req.Header { | 
|  | if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") { | 
|  | // Host is :authority, already sent. | 
|  | // Content-Length is automatic, set below. | 
|  | continue | 
|  | } else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") || | 
|  | strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") || | 
|  | strings.EqualFold(k, "keep-alive") { | 
|  | // Per 8.1.2.2 Connection-Specific Header | 
|  | // Fields, don't send connection-specific | 
|  | // fields. We have already checked if any | 
|  | // are error-worthy so just ignore the rest. | 
|  | continue | 
|  | } else if strings.EqualFold(k, "user-agent") { | 
|  | // Match Go's http1 behavior: at most one | 
|  | // User-Agent. If set to nil or empty string, | 
|  | // then omit it. Otherwise if not mentioned, | 
|  | // include the default (below). | 
|  | didUA = true | 
|  | if len(vv) < 1 { | 
|  | continue | 
|  | } | 
|  | vv = vv[:1] | 
|  | if vv[0] == "" { | 
|  | continue | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | for _, v := range vv { | 
|  | f(k, v) | 
|  | } | 
|  | } | 
|  | if http2shouldSendReqContentLength(req.Method, contentLength) { | 
|  | f("content-length", strconv.FormatInt(contentLength, 10)) | 
|  | } | 
|  | if addGzipHeader { | 
|  | f("accept-encoding", "gzip") | 
|  | } | 
|  | if !didUA { | 
|  | f("user-agent", http2defaultUserAgent) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Do a first pass over the headers counting bytes to ensure | 
|  | // we don't exceed cc.peerMaxHeaderListSize. This is done as a | 
|  | // separate pass before encoding the headers to prevent | 
|  | // modifying the hpack state. | 
|  | hlSize := uint64(0) | 
|  | enumerateHeaders(func(name, value string) { | 
|  | hf := hpack.HeaderField{Name: name, Value: value} | 
|  | hlSize += uint64(hf.Size()) | 
|  | }) | 
|  |  | 
|  | if hlSize > cc.peerMaxHeaderListSize { | 
|  | return nil, http2errRequestHeaderListSize | 
|  | } | 
|  |  | 
|  | trace := http2requestTrace(req) | 
|  | traceHeaders := http2traceHasWroteHeaderField(trace) | 
|  |  | 
|  | // Header list size is ok. Write the headers. | 
|  | enumerateHeaders(func(name, value string) { | 
|  | name = strings.ToLower(name) | 
|  | cc.writeHeader(name, value) | 
|  | if traceHeaders { | 
|  | http2traceWroteHeaderField(trace, name, value) | 
|  | } | 
|  | }) | 
|  |  | 
|  | return cc.hbuf.Bytes(), nil | 
|  | } | 
|  |  | 
|  | // shouldSendReqContentLength reports whether the http2.Transport should send | 
|  | // a "content-length" request header. This logic is basically a copy of the net/http | 
|  | // transferWriter.shouldSendContentLength. | 
|  | // The contentLength is the corrected contentLength (so 0 means actually 0, not unknown). | 
|  | // -1 means unknown. | 
|  | func http2shouldSendReqContentLength(method string, contentLength int64) bool { | 
|  | if contentLength > 0 { | 
|  | return true | 
|  | } | 
|  | if contentLength < 0 { | 
|  | return false | 
|  | } | 
|  | // For zero bodies, whether we send a content-length depends on the method. | 
|  | // It also kinda doesn't matter for http2 either way, with END_STREAM. | 
|  | switch method { | 
|  | case "POST", "PUT", "PATCH": | 
|  | return true | 
|  | default: | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | // requires cc.mu be held. | 
|  | func (cc *http2ClientConn) encodeTrailers(req *Request) ([]byte, error) { | 
|  | cc.hbuf.Reset() | 
|  |  | 
|  | hlSize := uint64(0) | 
|  | for k, vv := range req.Trailer { | 
|  | for _, v := range vv { | 
|  | hf := hpack.HeaderField{Name: k, Value: v} | 
|  | hlSize += uint64(hf.Size()) | 
|  | } | 
|  | } | 
|  | if hlSize > cc.peerMaxHeaderListSize { | 
|  | return nil, http2errRequestHeaderListSize | 
|  | } | 
|  |  | 
|  | for k, vv := range req.Trailer { | 
|  | // Transfer-Encoding, etc.. have already been filtered at the | 
|  | // start of RoundTrip | 
|  | lowKey := strings.ToLower(k) | 
|  | for _, v := range vv { | 
|  | cc.writeHeader(lowKey, v) | 
|  | } | 
|  | } | 
|  | return cc.hbuf.Bytes(), nil | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) writeHeader(name, value string) { | 
|  | if http2VerboseLogs { | 
|  | log.Printf("http2: Transport encoding header %q = %q", name, value) | 
|  | } | 
|  | cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value}) | 
|  | } | 
|  |  | 
|  | type http2resAndError struct { | 
|  | res *Response | 
|  | err error | 
|  | } | 
|  |  | 
|  | // requires cc.mu be held. | 
|  | func (cc *http2ClientConn) newStream() *http2clientStream { | 
|  | cs := &http2clientStream{ | 
|  | cc:        cc, | 
|  | ID:        cc.nextStreamID, | 
|  | resc:      make(chan http2resAndError, 1), | 
|  | peerReset: make(chan struct{}), | 
|  | done:      make(chan struct{}), | 
|  | } | 
|  | cs.flow.add(int32(cc.initialWindowSize)) | 
|  | cs.flow.setConnFlow(&cc.flow) | 
|  | cs.inflow.add(http2transportDefaultStreamFlow) | 
|  | cs.inflow.setConnFlow(&cc.inflow) | 
|  | cc.nextStreamID += 2 | 
|  | cc.streams[cs.ID] = cs | 
|  | return cs | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) forgetStreamID(id uint32) { | 
|  | cc.streamByID(id, true) | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStream { | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | cs := cc.streams[id] | 
|  | if andRemove && cs != nil && !cc.closed { | 
|  | cc.lastActive = time.Now() | 
|  | delete(cc.streams, id) | 
|  | if len(cc.streams) == 0 && cc.idleTimer != nil { | 
|  | cc.idleTimer.Reset(cc.idleTimeout) | 
|  | } | 
|  | close(cs.done) | 
|  | // Wake up checkResetOrDone via clientStream.awaitFlowControl and | 
|  | // wake up RoundTrip if there is a pending request. | 
|  | cc.cond.Broadcast() | 
|  | } | 
|  | return cs | 
|  | } | 
|  |  | 
|  | // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop. | 
|  | type http2clientConnReadLoop struct { | 
|  | cc            *http2ClientConn | 
|  | closeWhenIdle bool | 
|  | } | 
|  |  | 
|  | // readLoop runs in its own goroutine and reads and dispatches frames. | 
|  | func (cc *http2ClientConn) readLoop() { | 
|  | rl := &http2clientConnReadLoop{cc: cc} | 
|  | defer rl.cleanup() | 
|  | cc.readerErr = rl.run() | 
|  | if ce, ok := cc.readerErr.(http2ConnectionError); ok { | 
|  | cc.wmu.Lock() | 
|  | cc.fr.WriteGoAway(0, http2ErrCode(ce), nil) | 
|  | cc.wmu.Unlock() | 
|  | } | 
|  | } | 
|  |  | 
|  | // GoAwayError is returned by the Transport when the server closes the | 
|  | // TCP connection after sending a GOAWAY frame. | 
|  | type http2GoAwayError struct { | 
|  | LastStreamID uint32 | 
|  | ErrCode      http2ErrCode | 
|  | DebugData    string | 
|  | } | 
|  |  | 
|  | func (e http2GoAwayError) Error() string { | 
|  | return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q", | 
|  | e.LastStreamID, e.ErrCode, e.DebugData) | 
|  | } | 
|  |  | 
|  | func http2isEOFOrNetReadError(err error) bool { | 
|  | if err == io.EOF { | 
|  | return true | 
|  | } | 
|  | ne, ok := err.(*net.OpError) | 
|  | return ok && ne.Op == "read" | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) cleanup() { | 
|  | cc := rl.cc | 
|  | defer cc.tconn.Close() | 
|  | defer cc.t.connPool().MarkDead(cc) | 
|  | defer close(cc.readerDone) | 
|  |  | 
|  | if cc.idleTimer != nil { | 
|  | cc.idleTimer.Stop() | 
|  | } | 
|  |  | 
|  | // Close any response bodies if the server closes prematurely. | 
|  | // TODO: also do this if we've written the headers but not | 
|  | // gotten a response yet. | 
|  | err := cc.readerErr | 
|  | cc.mu.Lock() | 
|  | if cc.goAway != nil && http2isEOFOrNetReadError(err) { | 
|  | err = http2GoAwayError{ | 
|  | LastStreamID: cc.goAway.LastStreamID, | 
|  | ErrCode:      cc.goAway.ErrCode, | 
|  | DebugData:    cc.goAwayDebug, | 
|  | } | 
|  | } else if err == io.EOF { | 
|  | err = io.ErrUnexpectedEOF | 
|  | } | 
|  | for _, cs := range cc.streams { | 
|  | cs.bufPipe.CloseWithError(err) // no-op if already closed | 
|  | select { | 
|  | case cs.resc <- http2resAndError{err: err}: | 
|  | default: | 
|  | } | 
|  | close(cs.done) | 
|  | } | 
|  | cc.closed = true | 
|  | cc.cond.Broadcast() | 
|  | cc.mu.Unlock() | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) run() error { | 
|  | cc := rl.cc | 
|  | rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse | 
|  | gotReply := false // ever saw a HEADERS reply | 
|  | gotSettings := false | 
|  | for { | 
|  | f, err := cc.fr.ReadFrame() | 
|  | if err != nil { | 
|  | cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err) | 
|  | } | 
|  | if se, ok := err.(http2StreamError); ok { | 
|  | if cs := cc.streamByID(se.StreamID, false); cs != nil { | 
|  | cs.cc.writeStreamReset(cs.ID, se.Code, err) | 
|  | cs.cc.forgetStreamID(cs.ID) | 
|  | if se.Cause == nil { | 
|  | se.Cause = cc.fr.errDetail | 
|  | } | 
|  | rl.endStreamError(cs, se) | 
|  | } | 
|  | continue | 
|  | } else if err != nil { | 
|  | return err | 
|  | } | 
|  | if http2VerboseLogs { | 
|  | cc.vlogf("http2: Transport received %s", http2summarizeFrame(f)) | 
|  | } | 
|  | if !gotSettings { | 
|  | if _, ok := f.(*http2SettingsFrame); !ok { | 
|  | cc.logf("protocol error: received %T before a SETTINGS frame", f) | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | gotSettings = true | 
|  | } | 
|  | maybeIdle := false // whether frame might transition us to idle | 
|  |  | 
|  | switch f := f.(type) { | 
|  | case *http2MetaHeadersFrame: | 
|  | err = rl.processHeaders(f) | 
|  | maybeIdle = true | 
|  | gotReply = true | 
|  | case *http2DataFrame: | 
|  | err = rl.processData(f) | 
|  | maybeIdle = true | 
|  | case *http2GoAwayFrame: | 
|  | err = rl.processGoAway(f) | 
|  | maybeIdle = true | 
|  | case *http2RSTStreamFrame: | 
|  | err = rl.processResetStream(f) | 
|  | maybeIdle = true | 
|  | case *http2SettingsFrame: | 
|  | err = rl.processSettings(f) | 
|  | case *http2PushPromiseFrame: | 
|  | err = rl.processPushPromise(f) | 
|  | case *http2WindowUpdateFrame: | 
|  | err = rl.processWindowUpdate(f) | 
|  | case *http2PingFrame: | 
|  | err = rl.processPing(f) | 
|  | default: | 
|  | cc.logf("Transport: unhandled response frame type %T", f) | 
|  | } | 
|  | if err != nil { | 
|  | if http2VerboseLogs { | 
|  | cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, http2summarizeFrame(f), err) | 
|  | } | 
|  | return err | 
|  | } | 
|  | if rl.closeWhenIdle && gotReply && maybeIdle { | 
|  | cc.closeIfIdle() | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) error { | 
|  | cc := rl.cc | 
|  | cs := cc.streamByID(f.StreamID, false) | 
|  | if cs == nil { | 
|  | // We'd get here if we canceled a request while the | 
|  | // server had its response still in flight. So if this | 
|  | // was just something we canceled, ignore it. | 
|  | return nil | 
|  | } | 
|  | if f.StreamEnded() { | 
|  | // Issue 20521: If the stream has ended, streamByID() causes | 
|  | // clientStream.done to be closed, which causes the request's bodyWriter | 
|  | // to be closed with an errStreamClosed, which may be received by | 
|  | // clientConn.RoundTrip before the result of processing these headers. | 
|  | // Deferring stream closure allows the header processing to occur first. | 
|  | // clientConn.RoundTrip may still receive the bodyWriter error first, but | 
|  | // the fix for issue 16102 prioritises any response. | 
|  | // | 
|  | // Issue 22413: If there is no request body, we should close the | 
|  | // stream before writing to cs.resc so that the stream is closed | 
|  | // immediately once RoundTrip returns. | 
|  | if cs.req.Body != nil { | 
|  | defer cc.forgetStreamID(f.StreamID) | 
|  | } else { | 
|  | cc.forgetStreamID(f.StreamID) | 
|  | } | 
|  | } | 
|  | if !cs.firstByte { | 
|  | if cs.trace != nil { | 
|  | // TODO(bradfitz): move first response byte earlier, | 
|  | // when we first read the 9 byte header, not waiting | 
|  | // until all the HEADERS+CONTINUATION frames have been | 
|  | // merged. This works for now. | 
|  | http2traceFirstResponseByte(cs.trace) | 
|  | } | 
|  | cs.firstByte = true | 
|  | } | 
|  | if !cs.pastHeaders { | 
|  | cs.pastHeaders = true | 
|  | } else { | 
|  | return rl.processTrailers(cs, f) | 
|  | } | 
|  |  | 
|  | res, err := rl.handleResponse(cs, f) | 
|  | if err != nil { | 
|  | if _, ok := err.(http2ConnectionError); ok { | 
|  | return err | 
|  | } | 
|  | // Any other error type is a stream error. | 
|  | cs.cc.writeStreamReset(f.StreamID, http2ErrCodeProtocol, err) | 
|  | cc.forgetStreamID(cs.ID) | 
|  | cs.resc <- http2resAndError{err: err} | 
|  | return nil // return nil from process* funcs to keep conn alive | 
|  | } | 
|  | if res == nil { | 
|  | // (nil, nil) special case. See handleResponse docs. | 
|  | return nil | 
|  | } | 
|  | cs.resTrailer = &res.Trailer | 
|  | cs.resc <- http2resAndError{res: res} | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // may return error types nil, or ConnectionError. Any other error value | 
|  | // is a StreamError of type ErrCodeProtocol. The returned error in that case | 
|  | // is the detail. | 
|  | // | 
|  | // As a special case, handleResponse may return (nil, nil) to skip the | 
|  | // frame (currently only used for 1xx responses). | 
|  | func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http2MetaHeadersFrame) (*Response, error) { | 
|  | if f.Truncated { | 
|  | return nil, http2errResponseHeaderListSize | 
|  | } | 
|  |  | 
|  | status := f.PseudoValue("status") | 
|  | if status == "" { | 
|  | return nil, errors.New("malformed response from server: missing status pseudo header") | 
|  | } | 
|  | statusCode, err := strconv.Atoi(status) | 
|  | if err != nil { | 
|  | return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header") | 
|  | } | 
|  |  | 
|  | header := make(Header) | 
|  | res := &Response{ | 
|  | Proto:      "HTTP/2.0", | 
|  | ProtoMajor: 2, | 
|  | Header:     header, | 
|  | StatusCode: statusCode, | 
|  | Status:     status + " " + StatusText(statusCode), | 
|  | } | 
|  | for _, hf := range f.RegularFields() { | 
|  | key := CanonicalHeaderKey(hf.Name) | 
|  | if key == "Trailer" { | 
|  | t := res.Trailer | 
|  | if t == nil { | 
|  | t = make(Header) | 
|  | res.Trailer = t | 
|  | } | 
|  | http2foreachHeaderElement(hf.Value, func(v string) { | 
|  | t[CanonicalHeaderKey(v)] = nil | 
|  | }) | 
|  | } else { | 
|  | header[key] = append(header[key], hf.Value) | 
|  | } | 
|  | } | 
|  |  | 
|  | if statusCode >= 100 && statusCode <= 199 { | 
|  | cs.num1xx++ | 
|  | const max1xxResponses = 5 // arbitrary bound on number of informational responses, same as net/http | 
|  | if cs.num1xx > max1xxResponses { | 
|  | return nil, errors.New("http2: too many 1xx informational responses") | 
|  | } | 
|  | if fn := cs.get1xxTraceFunc(); fn != nil { | 
|  | if err := fn(statusCode, textproto.MIMEHeader(header)); err != nil { | 
|  | return nil, err | 
|  | } | 
|  | } | 
|  | if statusCode == 100 { | 
|  | http2traceGot100Continue(cs.trace) | 
|  | if cs.on100 != nil { | 
|  | cs.on100() // forces any write delay timer to fire | 
|  | } | 
|  | } | 
|  | cs.pastHeaders = false // do it all again | 
|  | return nil, nil | 
|  | } | 
|  |  | 
|  | streamEnded := f.StreamEnded() | 
|  | isHead := cs.req.Method == "HEAD" | 
|  | if !streamEnded || isHead { | 
|  | res.ContentLength = -1 | 
|  | if clens := res.Header["Content-Length"]; len(clens) == 1 { | 
|  | if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { | 
|  | res.ContentLength = clen64 | 
|  | } else { | 
|  | // TODO: care? unlike http/1, it won't mess up our framing, so it's | 
|  | // more safe smuggling-wise to ignore. | 
|  | } | 
|  | } else if len(clens) > 1 { | 
|  | // TODO: care? unlike http/1, it won't mess up our framing, so it's | 
|  | // more safe smuggling-wise to ignore. | 
|  | } | 
|  | } | 
|  |  | 
|  | if streamEnded || isHead { | 
|  | res.Body = http2noBody | 
|  | return res, nil | 
|  | } | 
|  |  | 
|  | cs.bufPipe = http2pipe{b: &http2dataBuffer{expected: res.ContentLength}} | 
|  | cs.bytesRemain = res.ContentLength | 
|  | res.Body = http2transportResponseBody{cs} | 
|  | go cs.awaitRequestCancel(cs.req) | 
|  |  | 
|  | if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { | 
|  | res.Header.Del("Content-Encoding") | 
|  | res.Header.Del("Content-Length") | 
|  | res.ContentLength = -1 | 
|  | res.Body = &http2gzipReader{body: res.Body} | 
|  | http2setResponseUncompressed(res) | 
|  | } | 
|  | return res, nil | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *http2MetaHeadersFrame) error { | 
|  | if cs.pastTrailers { | 
|  | // Too many HEADERS frames for this stream. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | cs.pastTrailers = true | 
|  | if !f.StreamEnded() { | 
|  | // We expect that any headers for trailers also | 
|  | // has END_STREAM. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | if len(f.PseudoFields()) > 0 { | 
|  | // No pseudo header fields are defined for trailers. | 
|  | // TODO: ConnectionError might be overly harsh? Check. | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  |  | 
|  | trailer := make(Header) | 
|  | for _, hf := range f.RegularFields() { | 
|  | key := CanonicalHeaderKey(hf.Name) | 
|  | trailer[key] = append(trailer[key], hf.Value) | 
|  | } | 
|  | cs.trailer = trailer | 
|  |  | 
|  | rl.endStream(cs) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // transportResponseBody is the concrete type of Transport.RoundTrip's | 
|  | // Response.Body. It is an io.ReadCloser. On Read, it reads from cs.body. | 
|  | // On Close it sends RST_STREAM if EOF wasn't already seen. | 
|  | type http2transportResponseBody struct { | 
|  | cs *http2clientStream | 
|  | } | 
|  |  | 
|  | func (b http2transportResponseBody) Read(p []byte) (n int, err error) { | 
|  | cs := b.cs | 
|  | cc := cs.cc | 
|  |  | 
|  | if cs.readErr != nil { | 
|  | return 0, cs.readErr | 
|  | } | 
|  | n, err = b.cs.bufPipe.Read(p) | 
|  | if cs.bytesRemain != -1 { | 
|  | if int64(n) > cs.bytesRemain { | 
|  | n = int(cs.bytesRemain) | 
|  | if err == nil { | 
|  | err = errors.New("net/http: server replied with more than declared Content-Length; truncated") | 
|  | cc.writeStreamReset(cs.ID, http2ErrCodeProtocol, err) | 
|  | } | 
|  | cs.readErr = err | 
|  | return int(cs.bytesRemain), err | 
|  | } | 
|  | cs.bytesRemain -= int64(n) | 
|  | if err == io.EOF && cs.bytesRemain > 0 { | 
|  | err = io.ErrUnexpectedEOF | 
|  | cs.readErr = err | 
|  | return n, err | 
|  | } | 
|  | } | 
|  | if n == 0 { | 
|  | // No flow control tokens to send back. | 
|  | return | 
|  | } | 
|  |  | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  |  | 
|  | var connAdd, streamAdd int32 | 
|  | // Check the conn-level first, before the stream-level. | 
|  | if v := cc.inflow.available(); v < http2transportDefaultConnFlow/2 { | 
|  | connAdd = http2transportDefaultConnFlow - v | 
|  | cc.inflow.add(connAdd) | 
|  | } | 
|  | if err == nil { // No need to refresh if the stream is over or failed. | 
|  | // Consider any buffered body data (read from the conn but not | 
|  | // consumed by the client) when computing flow control for this | 
|  | // stream. | 
|  | v := int(cs.inflow.available()) + cs.bufPipe.Len() | 
|  | if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh { | 
|  | streamAdd = int32(http2transportDefaultStreamFlow - v) | 
|  | cs.inflow.add(streamAdd) | 
|  | } | 
|  | } | 
|  | if connAdd != 0 || streamAdd != 0 { | 
|  | cc.wmu.Lock() | 
|  | defer cc.wmu.Unlock() | 
|  | if connAdd != 0 { | 
|  | cc.fr.WriteWindowUpdate(0, http2mustUint31(connAdd)) | 
|  | } | 
|  | if streamAdd != 0 { | 
|  | cc.fr.WriteWindowUpdate(cs.ID, http2mustUint31(streamAdd)) | 
|  | } | 
|  | cc.bw.Flush() | 
|  | } | 
|  | return | 
|  | } | 
|  |  | 
|  | var http2errClosedResponseBody = errors.New("http2: response body closed") | 
|  |  | 
|  | func (b http2transportResponseBody) Close() error { | 
|  | cs := b.cs | 
|  | cc := cs.cc | 
|  |  | 
|  | serverSentStreamEnd := cs.bufPipe.Err() == io.EOF | 
|  | unread := cs.bufPipe.Len() | 
|  |  | 
|  | if unread > 0 || !serverSentStreamEnd { | 
|  | cc.mu.Lock() | 
|  | cc.wmu.Lock() | 
|  | if !serverSentStreamEnd { | 
|  | cc.fr.WriteRSTStream(cs.ID, http2ErrCodeCancel) | 
|  | cs.didReset = true | 
|  | } | 
|  | // Return connection-level flow control. | 
|  | if unread > 0 { | 
|  | cc.inflow.add(int32(unread)) | 
|  | cc.fr.WriteWindowUpdate(0, uint32(unread)) | 
|  | } | 
|  | cc.bw.Flush() | 
|  | cc.wmu.Unlock() | 
|  | cc.mu.Unlock() | 
|  | } | 
|  |  | 
|  | cs.bufPipe.BreakWithError(http2errClosedResponseBody) | 
|  | cc.forgetStreamID(cs.ID) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error { | 
|  | cc := rl.cc | 
|  | cs := cc.streamByID(f.StreamID, f.StreamEnded()) | 
|  | data := f.Data() | 
|  | if cs == nil { | 
|  | cc.mu.Lock() | 
|  | neverSent := cc.nextStreamID | 
|  | cc.mu.Unlock() | 
|  | if f.StreamID >= neverSent { | 
|  | // We never asked for this. | 
|  | cc.logf("http2: Transport received unsolicited DATA frame; closing connection") | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  | // We probably did ask for this, but canceled. Just ignore it. | 
|  | // TODO: be stricter here? only silently ignore things which | 
|  | // we canceled, but not things which were closed normally | 
|  | // by the peer? Tough without accumulating too much state. | 
|  |  | 
|  | // But at least return their flow control: | 
|  | if f.Length > 0 { | 
|  | cc.mu.Lock() | 
|  | cc.inflow.add(int32(f.Length)) | 
|  | cc.mu.Unlock() | 
|  |  | 
|  | cc.wmu.Lock() | 
|  | cc.fr.WriteWindowUpdate(0, uint32(f.Length)) | 
|  | cc.bw.Flush() | 
|  | cc.wmu.Unlock() | 
|  | } | 
|  | return nil | 
|  | } | 
|  | if !cs.firstByte { | 
|  | cc.logf("protocol error: received DATA before a HEADERS frame") | 
|  | rl.endStreamError(cs, http2StreamError{ | 
|  | StreamID: f.StreamID, | 
|  | Code:     http2ErrCodeProtocol, | 
|  | }) | 
|  | return nil | 
|  | } | 
|  | if f.Length > 0 { | 
|  | if cs.req.Method == "HEAD" && len(data) > 0 { | 
|  | cc.logf("protocol error: received DATA on a HEAD request") | 
|  | rl.endStreamError(cs, http2StreamError{ | 
|  | StreamID: f.StreamID, | 
|  | Code:     http2ErrCodeProtocol, | 
|  | }) | 
|  | return nil | 
|  | } | 
|  | // Check connection-level flow control. | 
|  | cc.mu.Lock() | 
|  | if cs.inflow.available() >= int32(f.Length) { | 
|  | cs.inflow.take(int32(f.Length)) | 
|  | } else { | 
|  | cc.mu.Unlock() | 
|  | return http2ConnectionError(http2ErrCodeFlowControl) | 
|  | } | 
|  | // Return any padded flow control now, since we won't | 
|  | // refund it later on body reads. | 
|  | var refund int | 
|  | if pad := int(f.Length) - len(data); pad > 0 { | 
|  | refund += pad | 
|  | } | 
|  | // Return len(data) now if the stream is already closed, | 
|  | // since data will never be read. | 
|  | didReset := cs.didReset | 
|  | if didReset { | 
|  | refund += len(data) | 
|  | } | 
|  | if refund > 0 { | 
|  | cc.inflow.add(int32(refund)) | 
|  | cc.wmu.Lock() | 
|  | cc.fr.WriteWindowUpdate(0, uint32(refund)) | 
|  | if !didReset { | 
|  | cs.inflow.add(int32(refund)) | 
|  | cc.fr.WriteWindowUpdate(cs.ID, uint32(refund)) | 
|  | } | 
|  | cc.bw.Flush() | 
|  | cc.wmu.Unlock() | 
|  | } | 
|  | cc.mu.Unlock() | 
|  |  | 
|  | if len(data) > 0 && !didReset { | 
|  | if _, err := cs.bufPipe.Write(data); err != nil { | 
|  | rl.endStreamError(cs, err) | 
|  | return err | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if f.StreamEnded() { | 
|  | rl.endStream(cs) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | var http2errInvalidTrailers = errors.New("http2: invalid trailers") | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) { | 
|  | // TODO: check that any declared content-length matches, like | 
|  | // server.go's (*stream).endStream method. | 
|  | rl.endStreamError(cs, nil) | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err error) { | 
|  | var code func() | 
|  | if err == nil { | 
|  | err = io.EOF | 
|  | code = cs.copyTrailers | 
|  | } | 
|  | if http2isConnectionCloseRequest(cs.req) { | 
|  | rl.closeWhenIdle = true | 
|  | } | 
|  | cs.bufPipe.closeWithErrorAndCode(err, code) | 
|  |  | 
|  | select { | 
|  | case cs.resc <- http2resAndError{err: err}: | 
|  | default: | 
|  | } | 
|  | } | 
|  |  | 
|  | func (cs *http2clientStream) copyTrailers() { | 
|  | for k, vv := range cs.trailer { | 
|  | t := cs.resTrailer | 
|  | if *t == nil { | 
|  | *t = make(Header) | 
|  | } | 
|  | (*t)[k] = vv | 
|  | } | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processGoAway(f *http2GoAwayFrame) error { | 
|  | cc := rl.cc | 
|  | cc.t.connPool().MarkDead(cc) | 
|  | if f.ErrCode != 0 { | 
|  | // TODO: deal with GOAWAY more. particularly the error code | 
|  | cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode) | 
|  | } | 
|  | cc.setGoAway(f) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error { | 
|  | cc := rl.cc | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  |  | 
|  | if f.IsAck() { | 
|  | if cc.wantSettingsAck { | 
|  | cc.wantSettingsAck = false | 
|  | return nil | 
|  | } | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  |  | 
|  | err := f.ForeachSetting(func(s http2Setting) error { | 
|  | switch s.ID { | 
|  | case http2SettingMaxFrameSize: | 
|  | cc.maxFrameSize = s.Val | 
|  | case http2SettingMaxConcurrentStreams: | 
|  | cc.maxConcurrentStreams = s.Val | 
|  | case http2SettingMaxHeaderListSize: | 
|  | cc.peerMaxHeaderListSize = uint64(s.Val) | 
|  | case http2SettingInitialWindowSize: | 
|  | // 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. | 
|  | if s.Val > math.MaxInt32 { | 
|  | return http2ConnectionError(http2ErrCodeFlowControl) | 
|  | } | 
|  |  | 
|  | // Adjust flow control of currently-open | 
|  | // frames by the difference of the old initial | 
|  | // window size and this one. | 
|  | delta := int32(s.Val) - int32(cc.initialWindowSize) | 
|  | for _, cs := range cc.streams { | 
|  | cs.flow.add(delta) | 
|  | } | 
|  | cc.cond.Broadcast() | 
|  |  | 
|  | cc.initialWindowSize = s.Val | 
|  | default: | 
|  | // TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably. | 
|  | cc.vlogf("Unhandled Setting: %v", s) | 
|  | } | 
|  | return nil | 
|  | }) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | cc.wmu.Lock() | 
|  | defer cc.wmu.Unlock() | 
|  |  | 
|  | cc.fr.WriteSettingsAck() | 
|  | cc.bw.Flush() | 
|  | return cc.werr | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error { | 
|  | cc := rl.cc | 
|  | cs := cc.streamByID(f.StreamID, false) | 
|  | if f.StreamID != 0 && cs == nil { | 
|  | return nil | 
|  | } | 
|  |  | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  |  | 
|  | fl := &cc.flow | 
|  | if cs != nil { | 
|  | fl = &cs.flow | 
|  | } | 
|  | if !fl.add(int32(f.Increment)) { | 
|  | return http2ConnectionError(http2ErrCodeFlowControl) | 
|  | } | 
|  | cc.cond.Broadcast() | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) error { | 
|  | cs := rl.cc.streamByID(f.StreamID, true) | 
|  | if cs == nil { | 
|  | // TODO: return error if server tries to RST_STEAM an idle stream | 
|  | return nil | 
|  | } | 
|  | select { | 
|  | case <-cs.peerReset: | 
|  | // Already reset. | 
|  | // This is the only goroutine | 
|  | // which closes this, so there | 
|  | // isn't a race. | 
|  | default: | 
|  | err := http2streamError(cs.ID, f.ErrCode) | 
|  | cs.resetErr = err | 
|  | close(cs.peerReset) | 
|  | cs.bufPipe.CloseWithError(err) | 
|  | cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Ping sends a PING frame to the server and waits for the ack. | 
|  | // Public implementation is in go17.go and not_go17.go | 
|  | func (cc *http2ClientConn) ping(ctx http2contextContext) error { | 
|  | c := make(chan struct{}) | 
|  | // Generate a random payload | 
|  | var p [8]byte | 
|  | for { | 
|  | if _, err := rand.Read(p[:]); err != nil { | 
|  | return err | 
|  | } | 
|  | cc.mu.Lock() | 
|  | // check for dup before insert | 
|  | if _, found := cc.pings[p]; !found { | 
|  | cc.pings[p] = c | 
|  | cc.mu.Unlock() | 
|  | break | 
|  | } | 
|  | cc.mu.Unlock() | 
|  | } | 
|  | cc.wmu.Lock() | 
|  | if err := cc.fr.WritePing(false, p); err != nil { | 
|  | cc.wmu.Unlock() | 
|  | return err | 
|  | } | 
|  | if err := cc.bw.Flush(); err != nil { | 
|  | cc.wmu.Unlock() | 
|  | return err | 
|  | } | 
|  | cc.wmu.Unlock() | 
|  | select { | 
|  | case <-c: | 
|  | return nil | 
|  | case <-ctx.Done(): | 
|  | return ctx.Err() | 
|  | case <-cc.readerDone: | 
|  | // connection closed | 
|  | return cc.readerErr | 
|  | } | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error { | 
|  | if f.IsAck() { | 
|  | cc := rl.cc | 
|  | cc.mu.Lock() | 
|  | defer cc.mu.Unlock() | 
|  | // If ack, notify listener if any | 
|  | if c, ok := cc.pings[f.Data]; ok { | 
|  | close(c) | 
|  | delete(cc.pings, f.Data) | 
|  | } | 
|  | return nil | 
|  | } | 
|  | cc := rl.cc | 
|  | cc.wmu.Lock() | 
|  | defer cc.wmu.Unlock() | 
|  | if err := cc.fr.WritePing(true, f.Data); err != nil { | 
|  | return err | 
|  | } | 
|  | return cc.bw.Flush() | 
|  | } | 
|  |  | 
|  | func (rl *http2clientConnReadLoop) processPushPromise(f *http2PushPromiseFrame) error { | 
|  | // We told the peer we don't want them. | 
|  | // Spec says: | 
|  | // "PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH | 
|  | // setting of the peer endpoint is set to 0. An endpoint that | 
|  | // has set this setting and has received acknowledgement MUST | 
|  | // treat the receipt of a PUSH_PROMISE frame as a connection | 
|  | // error (Section 5.4.1) of type PROTOCOL_ERROR." | 
|  | return http2ConnectionError(http2ErrCodeProtocol) | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode, err error) { | 
|  | // TODO: map err to more interesting error codes, once the | 
|  | // HTTP community comes up with some. But currently for | 
|  | // RST_STREAM there's no equivalent to GOAWAY frame's debug | 
|  | // data, and the error codes are all pretty vague ("cancel"). | 
|  | cc.wmu.Lock() | 
|  | cc.fr.WriteRSTStream(streamID, code) | 
|  | cc.bw.Flush() | 
|  | cc.wmu.Unlock() | 
|  | } | 
|  |  | 
|  | var ( | 
|  | http2errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") | 
|  | http2errRequestHeaderListSize  = errors.New("http2: request header list larger than peer's advertised limit") | 
|  | http2errPseudoTrailers         = errors.New("http2: invalid pseudo header in trailers") | 
|  | ) | 
|  |  | 
|  | func (cc *http2ClientConn) logf(format string, args ...interface{}) { | 
|  | cc.t.logf(format, args...) | 
|  | } | 
|  |  | 
|  | func (cc *http2ClientConn) vlogf(format string, args ...interface{}) { | 
|  | cc.t.vlogf(format, args...) | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) vlogf(format string, args ...interface{}) { | 
|  | if http2VerboseLogs { | 
|  | t.logf(format, args...) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) logf(format string, args ...interface{}) { | 
|  | log.Printf(format, args...) | 
|  | } | 
|  |  | 
|  | var http2noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil)) | 
|  |  | 
|  | func http2strSliceContains(ss []string, s string) bool { | 
|  | for _, v := range ss { | 
|  | if v == s { | 
|  | return true | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | type http2erringRoundTripper struct{ err error } | 
|  |  | 
|  | func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { return nil, rt.err } | 
|  |  | 
|  | // gzipReader wraps a response body so it can lazily | 
|  | // call gzip.NewReader on the first call to Read | 
|  | type http2gzipReader struct { | 
|  | body io.ReadCloser // underlying Response.Body | 
|  | zr   *gzip.Reader  // lazily-initialized gzip reader | 
|  | zerr error         // sticky error | 
|  | } | 
|  |  | 
|  | func (gz *http2gzipReader) Read(p []byte) (n int, err error) { | 
|  | if gz.zerr != nil { | 
|  | return 0, gz.zerr | 
|  | } | 
|  | if gz.zr == nil { | 
|  | gz.zr, err = gzip.NewReader(gz.body) | 
|  | if err != nil { | 
|  | gz.zerr = err | 
|  | return 0, err | 
|  | } | 
|  | } | 
|  | return gz.zr.Read(p) | 
|  | } | 
|  |  | 
|  | func (gz *http2gzipReader) Close() error { | 
|  | return gz.body.Close() | 
|  | } | 
|  |  | 
|  | type http2errorReader struct{ err error } | 
|  |  | 
|  | func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err } | 
|  |  | 
|  | // bodyWriterState encapsulates various state around the Transport's writing | 
|  | // of the request body, particularly regarding doing delayed writes of the body | 
|  | // when the request contains "Expect: 100-continue". | 
|  | type http2bodyWriterState struct { | 
|  | cs     *http2clientStream | 
|  | timer  *time.Timer   // if non-nil, we're doing a delayed write | 
|  | fnonce *sync.Once    // to call fn with | 
|  | fn     func()        // the code to run in the goroutine, writing the body | 
|  | resc   chan error    // result of fn's execution | 
|  | delay  time.Duration // how long we should delay a delayed write for | 
|  | } | 
|  |  | 
|  | func (t *http2Transport) getBodyWriterState(cs *http2clientStream, body io.Reader) (s http2bodyWriterState) { | 
|  | s.cs = cs | 
|  | if body == nil { | 
|  | return | 
|  | } | 
|  | resc := make(chan error, 1) | 
|  | s.resc = resc | 
|  | s.fn = func() { | 
|  | cs.cc.mu.Lock() | 
|  | cs.startedWrite = true | 
|  | cs.cc.mu.Unlock() | 
|  | resc <- cs.writeRequestBody(body, cs.req.Body) | 
|  | } | 
|  | s.delay = t.expectContinueTimeout() | 
|  | if s.delay == 0 || | 
|  | !httpguts.HeaderValuesContainsToken( | 
|  | cs.req.Header["Expect"], | 
|  | "100-continue") { | 
|  | return | 
|  | } | 
|  | s.fnonce = new(sync.Once) | 
|  |  | 
|  | // Arm the timer with a very large duration, which we'll | 
|  | // intentionally lower later. It has to be large now because | 
|  | // we need a handle to it before writing the headers, but the | 
|  | // s.delay value is defined to not start until after the | 
|  | // request headers were written. | 
|  | const hugeDuration = 365 * 24 * time.Hour | 
|  | s.timer = time.AfterFunc(hugeDuration, func() { | 
|  | s.fnonce.Do(s.fn) | 
|  | }) | 
|  | return | 
|  | } | 
|  |  | 
|  | func (s http2bodyWriterState) cancel() { | 
|  | if s.timer != nil { | 
|  | s.timer.Stop() | 
|  | } | 
|  | } | 
|  |  | 
|  | func (s http2bodyWriterState) on100() { | 
|  | if s.timer == nil { | 
|  | // If we didn't do a delayed write, ignore the server's | 
|  | // bogus 100 continue response. | 
|  | return | 
|  | } | 
|  | s.timer.Stop() | 
|  | go func() { s.fnonce.Do(s.fn) }() | 
|  | } | 
|  |  | 
|  | // scheduleBodyWrite starts writing the body, either immediately (in | 
|  | // the common case) or after the delay timeout. It should not be | 
|  | // called until after the headers have been written. | 
|  | func (s http2bodyWriterState) scheduleBodyWrite() { | 
|  | if s.timer == nil { | 
|  | // We're not doing a delayed write (see | 
|  | // getBodyWriterState), so just start the writing | 
|  | // goroutine immediately. | 
|  | go s.fn() | 
|  | return | 
|  | } | 
|  | http2traceWait100Continue(s.cs.trace) | 
|  | if s.timer.Stop() { | 
|  | s.timer.Reset(s.delay) | 
|  | } | 
|  | } | 
|  |  | 
|  | // isConnectionCloseRequest reports whether req should use its own | 
|  | // connection for a single request and then close the connection. | 
|  | func http2isConnectionCloseRequest(req *Request) bool { | 
|  | return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close") | 
|  | } | 
|  |  | 
|  | // writeFramer is implemented by any type that is used to write frames. | 
|  | type http2writeFramer interface { | 
|  | writeFrame(http2writeContext) error | 
|  |  | 
|  | // staysWithinBuffer reports whether this writer promises that | 
|  | // it will only write less than or equal to size bytes, and it | 
|  | // won't Flush the write context. | 
|  | staysWithinBuffer(size int) bool | 
|  | } | 
|  |  | 
|  | // writeContext is the interface needed by the various frame writer | 
|  | // types below. All the writeFrame methods below are scheduled via the | 
|  | // frame writing scheduler (see writeScheduler in writesched.go). | 
|  | // | 
|  | // This interface is implemented by *serverConn. | 
|  | // | 
|  | // TODO: decide whether to a) use this in the client code (which didn't | 
|  | // end up using this yet, because it has a simpler design, not | 
|  | // currently implementing priorities), or b) delete this and | 
|  | // make the server code a bit more concrete. | 
|  | type http2writeContext interface { | 
|  | Framer() *http2Framer | 
|  | Flush() error | 
|  | CloseConn() error | 
|  | // HeaderEncoder returns an HPACK encoder that writes to the | 
|  | // returned buffer. | 
|  | HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) | 
|  | } | 
|  |  | 
|  | // writeEndsStream reports whether w writes a frame that will transition | 
|  | // the stream to a half-closed local state. This returns false for RST_STREAM, | 
|  | // which closes the entire stream (not just the local half). | 
|  | func http2writeEndsStream(w http2writeFramer) bool { | 
|  | switch v := w.(type) { | 
|  | case *http2writeData: | 
|  | return v.endStream | 
|  | case *http2writeResHeaders: | 
|  | return v.endStream | 
|  | case nil: | 
|  | // This can only happen if the caller reuses w after it's | 
|  | // been intentionally nil'ed out to prevent use. Keep this | 
|  | // here to catch future refactoring breaking it. | 
|  | panic("writeEndsStream called on nil writeFramer") | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | type http2flushFrameWriter struct{} | 
|  |  | 
|  | func (http2flushFrameWriter) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Flush() | 
|  | } | 
|  |  | 
|  | func (http2flushFrameWriter) staysWithinBuffer(max int) bool { return false } | 
|  |  | 
|  | type http2writeSettings []http2Setting | 
|  |  | 
|  | func (s http2writeSettings) staysWithinBuffer(max int) bool { | 
|  | const settingSize = 6 // uint16 + uint32 | 
|  | return http2frameHeaderLen+settingSize*len(s) <= max | 
|  |  | 
|  | } | 
|  |  | 
|  | func (s http2writeSettings) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WriteSettings([]http2Setting(s)...) | 
|  | } | 
|  |  | 
|  | type http2writeGoAway struct { | 
|  | maxStreamID uint32 | 
|  | code        http2ErrCode | 
|  | } | 
|  |  | 
|  | func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error { | 
|  | err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil) | 
|  | ctx.Flush() // ignore error: we're hanging up on them anyway | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (*http2writeGoAway) staysWithinBuffer(max int) bool { return false } // flushes | 
|  |  | 
|  | type http2writeData struct { | 
|  | streamID  uint32 | 
|  | p         []byte | 
|  | endStream bool | 
|  | } | 
|  |  | 
|  | func (w *http2writeData) String() string { | 
|  | return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream) | 
|  | } | 
|  |  | 
|  | func (w *http2writeData) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WriteData(w.streamID, w.endStream, w.p) | 
|  | } | 
|  |  | 
|  | func (w *http2writeData) staysWithinBuffer(max int) bool { | 
|  | return http2frameHeaderLen+len(w.p) <= max | 
|  | } | 
|  |  | 
|  | // handlerPanicRST is the message sent from handler goroutines when | 
|  | // the handler panics. | 
|  | type http2handlerPanicRST struct { | 
|  | StreamID uint32 | 
|  | } | 
|  |  | 
|  | func (hp http2handlerPanicRST) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WriteRSTStream(hp.StreamID, http2ErrCodeInternal) | 
|  | } | 
|  |  | 
|  | func (hp http2handlerPanicRST) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max } | 
|  |  | 
|  | func (se http2StreamError) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WriteRSTStream(se.StreamID, se.Code) | 
|  | } | 
|  |  | 
|  | func (se http2StreamError) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max } | 
|  |  | 
|  | type http2writePingAck struct{ pf *http2PingFrame } | 
|  |  | 
|  | func (w http2writePingAck) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WritePing(true, w.pf.Data) | 
|  | } | 
|  |  | 
|  | func (w http2writePingAck) staysWithinBuffer(max int) bool { | 
|  | return http2frameHeaderLen+len(w.pf.Data) <= max | 
|  | } | 
|  |  | 
|  | type http2writeSettingsAck struct{} | 
|  |  | 
|  | func (http2writeSettingsAck) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WriteSettingsAck() | 
|  | } | 
|  |  | 
|  | func (http2writeSettingsAck) staysWithinBuffer(max int) bool { return http2frameHeaderLen <= max } | 
|  |  | 
|  | // splitHeaderBlock splits headerBlock into fragments so that each fragment fits | 
|  | // in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true | 
|  | // for the first/last fragment, respectively. | 
|  | func http2splitHeaderBlock(ctx http2writeContext, headerBlock []byte, fn func(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error) error { | 
|  | // For now we're lazy and just pick the minimum MAX_FRAME_SIZE | 
|  | // that all peers must support (16KB). Later we could care | 
|  | // more and send larger frames if the peer advertised it, but | 
|  | // there's little point. Most headers are small anyway (so we | 
|  | // generally won't have CONTINUATION frames), and extra frames | 
|  | // only waste 9 bytes anyway. | 
|  | const maxFrameSize = 16384 | 
|  |  | 
|  | first := true | 
|  | for len(headerBlock) > 0 { | 
|  | frag := headerBlock | 
|  | if len(frag) > maxFrameSize { | 
|  | frag = frag[:maxFrameSize] | 
|  | } | 
|  | headerBlock = headerBlock[len(frag):] | 
|  | if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil { | 
|  | return err | 
|  | } | 
|  | first = false | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames | 
|  | // for HTTP response headers or trailers from a server handler. | 
|  | type http2writeResHeaders struct { | 
|  | streamID    uint32 | 
|  | httpResCode int      // 0 means no ":status" line | 
|  | h           Header   // may be nil | 
|  | trailers    []string // if non-nil, which keys of h to write. nil means all. | 
|  | endStream   bool | 
|  |  | 
|  | date          string | 
|  | contentType   string | 
|  | contentLength string | 
|  | } | 
|  |  | 
|  | func http2encKV(enc *hpack.Encoder, k, v string) { | 
|  | if http2VerboseLogs { | 
|  | log.Printf("http2: server encoding header %q = %q", k, v) | 
|  | } | 
|  | enc.WriteField(hpack.HeaderField{Name: k, Value: v}) | 
|  | } | 
|  |  | 
|  | func (w *http2writeResHeaders) staysWithinBuffer(max int) bool { | 
|  | // TODO: this is a common one. It'd be nice to return true | 
|  | // here and get into the fast path if we could be clever and | 
|  | // calculate the size fast enough, or at least a conservative | 
|  | // uppper bound that usually fires. (Maybe if w.h and | 
|  | // w.trailers are nil, so we don't need to enumerate it.) | 
|  | // Otherwise I'm afraid that just calculating the length to | 
|  | // answer this question would be slower than the ~2µs benefit. | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error { | 
|  | enc, buf := ctx.HeaderEncoder() | 
|  | buf.Reset() | 
|  |  | 
|  | if w.httpResCode != 0 { | 
|  | http2encKV(enc, ":status", http2httpCodeString(w.httpResCode)) | 
|  | } | 
|  |  | 
|  | http2encodeHeaders(enc, w.h, w.trailers) | 
|  |  | 
|  | if w.contentType != "" { | 
|  | http2encKV(enc, "content-type", w.contentType) | 
|  | } | 
|  | if w.contentLength != "" { | 
|  | http2encKV(enc, "content-length", w.contentLength) | 
|  | } | 
|  | if w.date != "" { | 
|  | http2encKV(enc, "date", w.date) | 
|  | } | 
|  |  | 
|  | headerBlock := buf.Bytes() | 
|  | if len(headerBlock) == 0 && w.trailers == nil { | 
|  | panic("unexpected empty hpack") | 
|  | } | 
|  |  | 
|  | return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock) | 
|  | } | 
|  |  | 
|  | func (w *http2writeResHeaders) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error { | 
|  | if firstFrag { | 
|  | return ctx.Framer().WriteHeaders(http2HeadersFrameParam{ | 
|  | StreamID:      w.streamID, | 
|  | BlockFragment: frag, | 
|  | EndStream:     w.endStream, | 
|  | EndHeaders:    lastFrag, | 
|  | }) | 
|  | } else { | 
|  | return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag) | 
|  | } | 
|  | } | 
|  |  | 
|  | // writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames. | 
|  | type http2writePushPromise struct { | 
|  | streamID uint32   // pusher stream | 
|  | method   string   // for :method | 
|  | url      *url.URL // for :scheme, :authority, :path | 
|  | h        Header | 
|  |  | 
|  | // Creates an ID for a pushed stream. This runs on serveG just before | 
|  | // the frame is written. The returned ID is copied to promisedID. | 
|  | allocatePromisedID func() (uint32, error) | 
|  | promisedID         uint32 | 
|  | } | 
|  |  | 
|  | func (w *http2writePushPromise) staysWithinBuffer(max int) bool { | 
|  | // TODO: see writeResHeaders.staysWithinBuffer | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (w *http2writePushPromise) writeFrame(ctx http2writeContext) error { | 
|  | enc, buf := ctx.HeaderEncoder() | 
|  | buf.Reset() | 
|  |  | 
|  | http2encKV(enc, ":method", w.method) | 
|  | http2encKV(enc, ":scheme", w.url.Scheme) | 
|  | http2encKV(enc, ":authority", w.url.Host) | 
|  | http2encKV(enc, ":path", w.url.RequestURI()) | 
|  | http2encodeHeaders(enc, w.h, nil) | 
|  |  | 
|  | headerBlock := buf.Bytes() | 
|  | if len(headerBlock) == 0 { | 
|  | panic("unexpected empty hpack") | 
|  | } | 
|  |  | 
|  | return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock) | 
|  | } | 
|  |  | 
|  | func (w *http2writePushPromise) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error { | 
|  | if firstFrag { | 
|  | return ctx.Framer().WritePushPromise(http2PushPromiseParam{ | 
|  | StreamID:      w.streamID, | 
|  | PromiseID:     w.promisedID, | 
|  | BlockFragment: frag, | 
|  | EndHeaders:    lastFrag, | 
|  | }) | 
|  | } else { | 
|  | return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag) | 
|  | } | 
|  | } | 
|  |  | 
|  | type http2write100ContinueHeadersFrame struct { | 
|  | streamID uint32 | 
|  | } | 
|  |  | 
|  | func (w http2write100ContinueHeadersFrame) writeFrame(ctx http2writeContext) error { | 
|  | enc, buf := ctx.HeaderEncoder() | 
|  | buf.Reset() | 
|  | http2encKV(enc, ":status", "100") | 
|  | return ctx.Framer().WriteHeaders(http2HeadersFrameParam{ | 
|  | StreamID:      w.streamID, | 
|  | BlockFragment: buf.Bytes(), | 
|  | EndStream:     false, | 
|  | EndHeaders:    true, | 
|  | }) | 
|  | } | 
|  |  | 
|  | func (w http2write100ContinueHeadersFrame) staysWithinBuffer(max int) bool { | 
|  | // Sloppy but conservative: | 
|  | return 9+2*(len(":status")+len("100")) <= max | 
|  | } | 
|  |  | 
|  | type http2writeWindowUpdate struct { | 
|  | streamID uint32 // or 0 for conn-level | 
|  | n        uint32 | 
|  | } | 
|  |  | 
|  | func (wu http2writeWindowUpdate) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max } | 
|  |  | 
|  | func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error { | 
|  | return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n) | 
|  | } | 
|  |  | 
|  | // encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k]) | 
|  | // is encoded only only if k is in keys. | 
|  | func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) { | 
|  | if keys == nil { | 
|  | sorter := http2sorterPool.Get().(*http2sorter) | 
|  | // Using defer here, since the returned keys from the | 
|  | // sorter.Keys method is only valid until the sorter | 
|  | // is returned: | 
|  | defer http2sorterPool.Put(sorter) | 
|  | keys = sorter.Keys(h) | 
|  | } | 
|  | for _, k := range keys { | 
|  | vv := h[k] | 
|  | k = http2lowerHeader(k) | 
|  | if !http2validWireHeaderFieldName(k) { | 
|  | // Skip it as backup paranoia. Per | 
|  | // golang.org/issue/14048, these should | 
|  | // already be rejected at a higher level. | 
|  | continue | 
|  | } | 
|  | isTE := k == "transfer-encoding" | 
|  | for _, v := range vv { | 
|  | if !httpguts.ValidHeaderFieldValue(v) { | 
|  | // TODO: return an error? golang.org/issue/14048 | 
|  | // For now just omit it. | 
|  | continue | 
|  | } | 
|  | // TODO: more of "8.1.2.2 Connection-Specific Header Fields" | 
|  | if isTE && v != "trailers" { | 
|  | continue | 
|  | } | 
|  | http2encKV(enc, k, v) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // WriteScheduler is the interface implemented by HTTP/2 write schedulers. | 
|  | // Methods are never called concurrently. | 
|  | type http2WriteScheduler interface { | 
|  | // OpenStream opens a new stream in the write scheduler. | 
|  | // It is illegal to call this with streamID=0 or with a streamID that is | 
|  | // already open -- the call may panic. | 
|  | OpenStream(streamID uint32, options http2OpenStreamOptions) | 
|  |  | 
|  | // CloseStream closes a stream in the write scheduler. Any frames queued on | 
|  | // this stream should be discarded. It is illegal to call this on a stream | 
|  | // that is not open -- the call may panic. | 
|  | CloseStream(streamID uint32) | 
|  |  | 
|  | // AdjustStream adjusts the priority of the given stream. This may be called | 
|  | // on a stream that has not yet been opened or has been closed. Note that | 
|  | // RFC 7540 allows PRIORITY frames to be sent on streams in any state. See: | 
|  | // https://tools.ietf.org/html/rfc7540#section-5.1 | 
|  | AdjustStream(streamID uint32, priority http2PriorityParam) | 
|  |  | 
|  | // Push queues a frame in the scheduler. In most cases, this will not be | 
|  | // called with wr.StreamID()!=0 unless that stream is currently open. The one | 
|  | // exception is RST_STREAM frames, which may be sent on idle or closed streams. | 
|  | Push(wr http2FrameWriteRequest) | 
|  |  | 
|  | // Pop dequeues the next frame to write. Returns false if no frames can | 
|  | // be written. Frames with a given wr.StreamID() are Pop'd in the same | 
|  | // order they are Push'd. | 
|  | Pop() (wr http2FrameWriteRequest, ok bool) | 
|  | } | 
|  |  | 
|  | // OpenStreamOptions specifies extra options for WriteScheduler.OpenStream. | 
|  | type http2OpenStreamOptions struct { | 
|  | // PusherID is zero if the stream was initiated by the client. Otherwise, | 
|  | // PusherID names the stream that pushed the newly opened stream. | 
|  | PusherID uint32 | 
|  | } | 
|  |  | 
|  | // FrameWriteRequest is a request to write a frame. | 
|  | type http2FrameWriteRequest struct { | 
|  | // write is the interface value that does the writing, once the | 
|  | // WriteScheduler has selected this frame to write. The write | 
|  | // functions are all defined in write.go. | 
|  | write http2writeFramer | 
|  |  | 
|  | // stream is the stream on which this frame will be written. | 
|  | // nil for non-stream frames like PING and SETTINGS. | 
|  | stream *http2stream | 
|  |  | 
|  | // done, if non-nil, must be a buffered channel with space for | 
|  | // 1 message and is sent the return value from write (or an | 
|  | // earlier error) when the frame has been written. | 
|  | done chan error | 
|  | } | 
|  |  | 
|  | // StreamID returns the id of the stream this frame will be written to. | 
|  | // 0 is used for non-stream frames such as PING and SETTINGS. | 
|  | func (wr http2FrameWriteRequest) StreamID() uint32 { | 
|  | if wr.stream == nil { | 
|  | if se, ok := wr.write.(http2StreamError); ok { | 
|  | // (*serverConn).resetStream doesn't set | 
|  | // stream because it doesn't necessarily have | 
|  | // one. So special case this type of write | 
|  | // message. | 
|  | return se.StreamID | 
|  | } | 
|  | return 0 | 
|  | } | 
|  | return wr.stream.id | 
|  | } | 
|  |  | 
|  | // DataSize returns the number of flow control bytes that must be consumed | 
|  | // to write this entire frame. This is 0 for non-DATA frames. | 
|  | func (wr http2FrameWriteRequest) DataSize() int { | 
|  | if wd, ok := wr.write.(*http2writeData); ok { | 
|  | return len(wd.p) | 
|  | } | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | // Consume consumes min(n, available) bytes from this frame, where available | 
|  | // is the number of flow control bytes available on the stream. Consume returns | 
|  | // 0, 1, or 2 frames, where the integer return value gives the number of frames | 
|  | // returned. | 
|  | // | 
|  | // If flow control prevents consuming any bytes, this returns (_, _, 0). If | 
|  | // the entire frame was consumed, this returns (wr, _, 1). Otherwise, this | 
|  | // returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and | 
|  | // 'rest' contains the remaining bytes. The consumed bytes are deducted from the | 
|  | // underlying stream's flow control budget. | 
|  | func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2FrameWriteRequest, int) { | 
|  | var empty http2FrameWriteRequest | 
|  |  | 
|  | // Non-DATA frames are always consumed whole. | 
|  | wd, ok := wr.write.(*http2writeData) | 
|  | if !ok || len(wd.p) == 0 { | 
|  | return wr, empty, 1 | 
|  | } | 
|  |  | 
|  | // Might need to split after applying limits. | 
|  | allowed := wr.stream.flow.available() | 
|  | if n < allowed { | 
|  | allowed = n | 
|  | } | 
|  | if wr.stream.sc.maxFrameSize < allowed { | 
|  | allowed = wr.stream.sc.maxFrameSize | 
|  | } | 
|  | if allowed <= 0 { | 
|  | return empty, empty, 0 | 
|  | } | 
|  | if len(wd.p) > int(allowed) { | 
|  | wr.stream.flow.take(allowed) | 
|  | consumed := http2FrameWriteRequest{ | 
|  | stream: wr.stream, | 
|  | write: &http2writeData{ | 
|  | streamID: wd.streamID, | 
|  | p:        wd.p[:allowed], | 
|  | // Even if the original had endStream set, there | 
|  | // are bytes remaining because len(wd.p) > allowed, | 
|  | // so we know endStream is false. | 
|  | endStream: false, | 
|  | }, | 
|  | // Our caller is blocking on the final DATA frame, not | 
|  | // this intermediate frame, so no need to wait. | 
|  | done: nil, | 
|  | } | 
|  | rest := http2FrameWriteRequest{ | 
|  | stream: wr.stream, | 
|  | write: &http2writeData{ | 
|  | streamID:  wd.streamID, | 
|  | p:         wd.p[allowed:], | 
|  | endStream: wd.endStream, | 
|  | }, | 
|  | done: wr.done, | 
|  | } | 
|  | return consumed, rest, 2 | 
|  | } | 
|  |  | 
|  | // The frame is consumed whole. | 
|  | // NB: This cast cannot overflow because allowed is <= math.MaxInt32. | 
|  | wr.stream.flow.take(int32(len(wd.p))) | 
|  | return wr, empty, 1 | 
|  | } | 
|  |  | 
|  | // String is for debugging only. | 
|  | func (wr http2FrameWriteRequest) String() string { | 
|  | var des string | 
|  | if s, ok := wr.write.(fmt.Stringer); ok { | 
|  | des = s.String() | 
|  | } else { | 
|  | des = fmt.Sprintf("%T", wr.write) | 
|  | } | 
|  | return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des) | 
|  | } | 
|  |  | 
|  | // replyToWriter sends err to wr.done and panics if the send must block | 
|  | // This does nothing if wr.done is nil. | 
|  | func (wr *http2FrameWriteRequest) replyToWriter(err error) { | 
|  | if wr.done == nil { | 
|  | return | 
|  | } | 
|  | select { | 
|  | case wr.done <- err: | 
|  | default: | 
|  | panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write)) | 
|  | } | 
|  | wr.write = nil // prevent use (assume it's tainted after wr.done send) | 
|  | } | 
|  |  | 
|  | // writeQueue is used by implementations of WriteScheduler. | 
|  | type http2writeQueue struct { | 
|  | s []http2FrameWriteRequest | 
|  | } | 
|  |  | 
|  | func (q *http2writeQueue) empty() bool { return len(q.s) == 0 } | 
|  |  | 
|  | func (q *http2writeQueue) push(wr http2FrameWriteRequest) { | 
|  | q.s = append(q.s, wr) | 
|  | } | 
|  |  | 
|  | func (q *http2writeQueue) shift() http2FrameWriteRequest { | 
|  | if len(q.s) == 0 { | 
|  | panic("invalid use of queue") | 
|  | } | 
|  | wr := q.s[0] | 
|  | // TODO: less copy-happy queue. | 
|  | copy(q.s, q.s[1:]) | 
|  | q.s[len(q.s)-1] = http2FrameWriteRequest{} | 
|  | q.s = q.s[:len(q.s)-1] | 
|  | return wr | 
|  | } | 
|  |  | 
|  | // consume consumes up to n bytes from q.s[0]. If the frame is | 
|  | // entirely consumed, it is removed from the queue. If the frame | 
|  | // is partially consumed, the frame is kept with the consumed | 
|  | // bytes removed. Returns true iff any bytes were consumed. | 
|  | func (q *http2writeQueue) consume(n int32) (http2FrameWriteRequest, bool) { | 
|  | if len(q.s) == 0 { | 
|  | return http2FrameWriteRequest{}, false | 
|  | } | 
|  | consumed, rest, numresult := q.s[0].Consume(n) | 
|  | switch numresult { | 
|  | case 0: | 
|  | return http2FrameWriteRequest{}, false | 
|  | case 1: | 
|  | q.shift() | 
|  | case 2: | 
|  | q.s[0] = rest | 
|  | } | 
|  | return consumed, true | 
|  | } | 
|  |  | 
|  | type http2writeQueuePool []*http2writeQueue | 
|  |  | 
|  | // put inserts an unused writeQueue into the pool. | 
|  |  | 
|  | // put inserts an unused writeQueue into the pool. | 
|  | func (p *http2writeQueuePool) put(q *http2writeQueue) { | 
|  | for i := range q.s { | 
|  | q.s[i] = http2FrameWriteRequest{} | 
|  | } | 
|  | q.s = q.s[:0] | 
|  | *p = append(*p, q) | 
|  | } | 
|  |  | 
|  | // get returns an empty writeQueue. | 
|  | func (p *http2writeQueuePool) get() *http2writeQueue { | 
|  | ln := len(*p) | 
|  | if ln == 0 { | 
|  | return new(http2writeQueue) | 
|  | } | 
|  | x := ln - 1 | 
|  | q := (*p)[x] | 
|  | (*p)[x] = nil | 
|  | *p = (*p)[:x] | 
|  | return q | 
|  | } | 
|  |  | 
|  | // RFC 7540, Section 5.3.5: the default weight is 16. | 
|  | const http2priorityDefaultWeight = 15 // 16 = 15 + 1 | 
|  |  | 
|  | // PriorityWriteSchedulerConfig configures a priorityWriteScheduler. | 
|  | type http2PriorityWriteSchedulerConfig struct { | 
|  | // MaxClosedNodesInTree controls the maximum number of closed streams to | 
|  | // retain in the priority tree. Setting this to zero saves a small amount | 
|  | // of memory at the cost of performance. | 
|  | // | 
|  | // See RFC 7540, Section 5.3.4: | 
|  | //   "It is possible for a stream to become closed while prioritization | 
|  | //   information ... is in transit. ... This potentially creates suboptimal | 
|  | //   prioritization, since the stream could be given a priority that is | 
|  | //   different from what is intended. To avoid these problems, an endpoint | 
|  | //   SHOULD retain stream prioritization state for a period after streams | 
|  | //   become closed. The longer state is retained, the lower the chance that | 
|  | //   streams are assigned incorrect or default priority values." | 
|  | MaxClosedNodesInTree int | 
|  |  | 
|  | // MaxIdleNodesInTree controls the maximum number of idle streams to | 
|  | // retain in the priority tree. Setting this to zero saves a small amount | 
|  | // of memory at the cost of performance. | 
|  | // | 
|  | // See RFC 7540, Section 5.3.4: | 
|  | //   Similarly, streams that are in the "idle" state can be assigned | 
|  | //   priority or become a parent of other streams. This allows for the | 
|  | //   creation of a grouping node in the dependency tree, which enables | 
|  | //   more flexible expressions of priority. Idle streams begin with a | 
|  | //   default priority (Section 5.3.5). | 
|  | MaxIdleNodesInTree int | 
|  |  | 
|  | // ThrottleOutOfOrderWrites enables write throttling to help ensure that | 
|  | // data is delivered in priority order. This works around a race where | 
|  | // stream B depends on stream A and both streams are about to call Write | 
|  | // to queue DATA frames. If B wins the race, a naive scheduler would eagerly | 
|  | // write as much data from B as possible, but this is suboptimal because A | 
|  | // is a higher-priority stream. With throttling enabled, we write a small | 
|  | // amount of data from B to minimize the amount of bandwidth that B can | 
|  | // steal from A. | 
|  | ThrottleOutOfOrderWrites bool | 
|  | } | 
|  |  | 
|  | // NewPriorityWriteScheduler constructs a WriteScheduler that schedules | 
|  | // frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3. | 
|  | // If cfg is nil, default options are used. | 
|  | func http2NewPriorityWriteScheduler(cfg *http2PriorityWriteSchedulerConfig) http2WriteScheduler { | 
|  | if cfg == nil { | 
|  | // For justification of these defaults, see: | 
|  | // https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY | 
|  | cfg = &http2PriorityWriteSchedulerConfig{ | 
|  | MaxClosedNodesInTree:     10, | 
|  | MaxIdleNodesInTree:       10, | 
|  | ThrottleOutOfOrderWrites: false, | 
|  | } | 
|  | } | 
|  |  | 
|  | ws := &http2priorityWriteScheduler{ | 
|  | nodes:                make(map[uint32]*http2priorityNode), | 
|  | maxClosedNodesInTree: cfg.MaxClosedNodesInTree, | 
|  | maxIdleNodesInTree:   cfg.MaxIdleNodesInTree, | 
|  | enableWriteThrottle:  cfg.ThrottleOutOfOrderWrites, | 
|  | } | 
|  | ws.nodes[0] = &ws.root | 
|  | if cfg.ThrottleOutOfOrderWrites { | 
|  | ws.writeThrottleLimit = 1024 | 
|  | } else { | 
|  | ws.writeThrottleLimit = math.MaxInt32 | 
|  | } | 
|  | return ws | 
|  | } | 
|  |  | 
|  | type http2priorityNodeState int | 
|  |  | 
|  | const ( | 
|  | http2priorityNodeOpen http2priorityNodeState = iota | 
|  | http2priorityNodeClosed | 
|  | http2priorityNodeIdle | 
|  | ) | 
|  |  | 
|  | // priorityNode is a node in an HTTP/2 priority tree. | 
|  | // Each node is associated with a single stream ID. | 
|  | // See RFC 7540, Section 5.3. | 
|  | type http2priorityNode struct { | 
|  | q            http2writeQueue        // queue of pending frames to write | 
|  | id           uint32                 // id of the stream, or 0 for the root of the tree | 
|  | weight       uint8                  // the actual weight is weight+1, so the value is in [1,256] | 
|  | state        http2priorityNodeState // open | closed | idle | 
|  | bytes        int64                  // number of bytes written by this node, or 0 if closed | 
|  | subtreeBytes int64                  // sum(node.bytes) of all nodes in this subtree | 
|  |  | 
|  | // These links form the priority tree. | 
|  | parent     *http2priorityNode | 
|  | kids       *http2priorityNode // start of the kids list | 
|  | prev, next *http2priorityNode // doubly-linked list of siblings | 
|  | } | 
|  |  | 
|  | func (n *http2priorityNode) setParent(parent *http2priorityNode) { | 
|  | if n == parent { | 
|  | panic("setParent to self") | 
|  | } | 
|  | if n.parent == parent { | 
|  | return | 
|  | } | 
|  | // Unlink from current parent. | 
|  | if parent := n.parent; parent != nil { | 
|  | if n.prev == nil { | 
|  | parent.kids = n.next | 
|  | } else { | 
|  | n.prev.next = n.next | 
|  | } | 
|  | if n.next != nil { | 
|  | n.next.prev = n.prev | 
|  | } | 
|  | } | 
|  | // Link to new parent. | 
|  | // If parent=nil, remove n from the tree. | 
|  | // Always insert at the head of parent.kids (this is assumed by walkReadyInOrder). | 
|  | n.parent = parent | 
|  | if parent == nil { | 
|  | n.next = nil | 
|  | n.prev = nil | 
|  | } else { | 
|  | n.next = parent.kids | 
|  | n.prev = nil | 
|  | if n.next != nil { | 
|  | n.next.prev = n | 
|  | } | 
|  | parent.kids = n | 
|  | } | 
|  | } | 
|  |  | 
|  | func (n *http2priorityNode) addBytes(b int64) { | 
|  | n.bytes += b | 
|  | for ; n != nil; n = n.parent { | 
|  | n.subtreeBytes += b | 
|  | } | 
|  | } | 
|  |  | 
|  | // walkReadyInOrder iterates over the tree in priority order, calling f for each node | 
|  | // with a non-empty write queue. When f returns true, this funcion returns true and the | 
|  | // walk halts. tmp is used as scratch space for sorting. | 
|  | // | 
|  | // f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true | 
|  | // if any ancestor p of n is still open (ignoring the root node). | 
|  | func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2priorityNode, f func(*http2priorityNode, bool) bool) bool { | 
|  | if !n.q.empty() && f(n, openParent) { | 
|  | return true | 
|  | } | 
|  | if n.kids == nil { | 
|  | return false | 
|  | } | 
|  |  | 
|  | // Don't consider the root "open" when updating openParent since | 
|  | // we can't send data frames on the root stream (only control frames). | 
|  | if n.id != 0 { | 
|  | openParent = openParent || (n.state == http2priorityNodeOpen) | 
|  | } | 
|  |  | 
|  | // Common case: only one kid or all kids have the same weight. | 
|  | // Some clients don't use weights; other clients (like web browsers) | 
|  | // use mostly-linear priority trees. | 
|  | w := n.kids.weight | 
|  | needSort := false | 
|  | for k := n.kids.next; k != nil; k = k.next { | 
|  | if k.weight != w { | 
|  | needSort = true | 
|  | break | 
|  | } | 
|  | } | 
|  | if !needSort { | 
|  | for k := n.kids; k != nil; k = k.next { | 
|  | if k.walkReadyInOrder(openParent, tmp, f) { | 
|  | return true | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // Uncommon case: sort the child nodes. We remove the kids from the parent, | 
|  | // then re-insert after sorting so we can reuse tmp for future sort calls. | 
|  | *tmp = (*tmp)[:0] | 
|  | for n.kids != nil { | 
|  | *tmp = append(*tmp, n.kids) | 
|  | n.kids.setParent(nil) | 
|  | } | 
|  | sort.Sort(http2sortPriorityNodeSiblings(*tmp)) | 
|  | for i := len(*tmp) - 1; i >= 0; i-- { | 
|  | (*tmp)[i].setParent(n) // setParent inserts at the head of n.kids | 
|  | } | 
|  | for k := n.kids; k != nil; k = k.next { | 
|  | if k.walkReadyInOrder(openParent, tmp, f) { | 
|  | return true | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | type http2sortPriorityNodeSiblings []*http2priorityNode | 
|  |  | 
|  | func (z http2sortPriorityNodeSiblings) Len() int { return len(z) } | 
|  |  | 
|  | func (z http2sortPriorityNodeSiblings) Swap(i, k int) { z[i], z[k] = z[k], z[i] } | 
|  |  | 
|  | func (z http2sortPriorityNodeSiblings) Less(i, k int) bool { | 
|  | // Prefer the subtree that has sent fewer bytes relative to its weight. | 
|  | // See sections 5.3.2 and 5.3.4. | 
|  | wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes) | 
|  | wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes) | 
|  | if bi == 0 && bk == 0 { | 
|  | return wi >= wk | 
|  | } | 
|  | if bk == 0 { | 
|  | return false | 
|  | } | 
|  | return bi/bk <= wi/wk | 
|  | } | 
|  |  | 
|  | type http2priorityWriteScheduler struct { | 
|  | // root is the root of the priority tree, where root.id = 0. | 
|  | // The root queues control frames that are not associated with any stream. | 
|  | root http2priorityNode | 
|  |  | 
|  | // nodes maps stream ids to priority tree nodes. | 
|  | nodes map[uint32]*http2priorityNode | 
|  |  | 
|  | // maxID is the maximum stream id in nodes. | 
|  | maxID uint32 | 
|  |  | 
|  | // lists of nodes that have been closed or are idle, but are kept in | 
|  | // the tree for improved prioritization. When the lengths exceed either | 
|  | // maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded. | 
|  | closedNodes, idleNodes []*http2priorityNode | 
|  |  | 
|  | // From the config. | 
|  | maxClosedNodesInTree int | 
|  | maxIdleNodesInTree   int | 
|  | writeThrottleLimit   int32 | 
|  | enableWriteThrottle  bool | 
|  |  | 
|  | // tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations. | 
|  | tmp []*http2priorityNode | 
|  |  | 
|  | // pool of empty queues for reuse. | 
|  | queuePool http2writeQueuePool | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) { | 
|  | // The stream may be currently idle but cannot be opened or closed. | 
|  | if curr := ws.nodes[streamID]; curr != nil { | 
|  | if curr.state != http2priorityNodeIdle { | 
|  | panic(fmt.Sprintf("stream %d already opened", streamID)) | 
|  | } | 
|  | curr.state = http2priorityNodeOpen | 
|  | return | 
|  | } | 
|  |  | 
|  | // RFC 7540, Section 5.3.5: | 
|  | //  "All streams are initially assigned a non-exclusive dependency on stream 0x0. | 
|  | //  Pushed streams initially depend on their associated stream. In both cases, | 
|  | //  streams are assigned a default weight of 16." | 
|  | parent := ws.nodes[options.PusherID] | 
|  | if parent == nil { | 
|  | parent = &ws.root | 
|  | } | 
|  | n := &http2priorityNode{ | 
|  | q:      *ws.queuePool.get(), | 
|  | id:     streamID, | 
|  | weight: http2priorityDefaultWeight, | 
|  | state:  http2priorityNodeOpen, | 
|  | } | 
|  | n.setParent(parent) | 
|  | ws.nodes[streamID] = n | 
|  | if streamID > ws.maxID { | 
|  | ws.maxID = streamID | 
|  | } | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) CloseStream(streamID uint32) { | 
|  | if streamID == 0 { | 
|  | panic("violation of WriteScheduler interface: cannot close stream 0") | 
|  | } | 
|  | if ws.nodes[streamID] == nil { | 
|  | panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID)) | 
|  | } | 
|  | if ws.nodes[streamID].state != http2priorityNodeOpen { | 
|  | panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID)) | 
|  | } | 
|  |  | 
|  | n := ws.nodes[streamID] | 
|  | n.state = http2priorityNodeClosed | 
|  | n.addBytes(-n.bytes) | 
|  |  | 
|  | q := n.q | 
|  | ws.queuePool.put(&q) | 
|  | n.q.s = nil | 
|  | if ws.maxClosedNodesInTree > 0 { | 
|  | ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n) | 
|  | } else { | 
|  | ws.removeNode(n) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) { | 
|  | if streamID == 0 { | 
|  | panic("adjustPriority on root") | 
|  | } | 
|  |  | 
|  | // If streamID does not exist, there are two cases: | 
|  | // - A closed stream that has been removed (this will have ID <= maxID) | 
|  | // - An idle stream that is being used for "grouping" (this will have ID > maxID) | 
|  | n := ws.nodes[streamID] | 
|  | if n == nil { | 
|  | if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 { | 
|  | return | 
|  | } | 
|  | ws.maxID = streamID | 
|  | n = &http2priorityNode{ | 
|  | q:      *ws.queuePool.get(), | 
|  | id:     streamID, | 
|  | weight: http2priorityDefaultWeight, | 
|  | state:  http2priorityNodeIdle, | 
|  | } | 
|  | n.setParent(&ws.root) | 
|  | ws.nodes[streamID] = n | 
|  | ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n) | 
|  | } | 
|  |  | 
|  | // Section 5.3.1: A dependency on a stream that is not currently in the tree | 
|  | // results in that stream being given a default priority (Section 5.3.5). | 
|  | parent := ws.nodes[priority.StreamDep] | 
|  | if parent == nil { | 
|  | n.setParent(&ws.root) | 
|  | n.weight = http2priorityDefaultWeight | 
|  | return | 
|  | } | 
|  |  | 
|  | // Ignore if the client tries to make a node its own parent. | 
|  | if n == parent { | 
|  | return | 
|  | } | 
|  |  | 
|  | // Section 5.3.3: | 
|  | //   "If a stream is made dependent on one of its own dependencies, the | 
|  | //   formerly dependent stream is first moved to be dependent on the | 
|  | //   reprioritized stream's previous parent. The moved dependency retains | 
|  | //   its weight." | 
|  | // | 
|  | // That is: if parent depends on n, move parent to depend on n.parent. | 
|  | for x := parent.parent; x != nil; x = x.parent { | 
|  | if x == n { | 
|  | parent.setParent(n.parent) | 
|  | break | 
|  | } | 
|  | } | 
|  |  | 
|  | // Section 5.3.3: The exclusive flag causes the stream to become the sole | 
|  | // dependency of its parent stream, causing other dependencies to become | 
|  | // dependent on the exclusive stream. | 
|  | if priority.Exclusive { | 
|  | k := parent.kids | 
|  | for k != nil { | 
|  | next := k.next | 
|  | if k != n { | 
|  | k.setParent(n) | 
|  | } | 
|  | k = next | 
|  | } | 
|  | } | 
|  |  | 
|  | n.setParent(parent) | 
|  | n.weight = priority.Weight | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) Push(wr http2FrameWriteRequest) { | 
|  | var n *http2priorityNode | 
|  | if id := wr.StreamID(); id == 0 { | 
|  | n = &ws.root | 
|  | } else { | 
|  | n = ws.nodes[id] | 
|  | if n == nil { | 
|  | // id is an idle or closed stream. wr should not be a HEADERS or | 
|  | // DATA frame. However, wr can be a RST_STREAM. In this case, we | 
|  | // push wr onto the root, rather than creating a new priorityNode, | 
|  | // since RST_STREAM is tiny and the stream's priority is unknown | 
|  | // anyway. See issue #17919. | 
|  | if wr.DataSize() > 0 { | 
|  | panic("add DATA on non-open stream") | 
|  | } | 
|  | n = &ws.root | 
|  | } | 
|  | } | 
|  | n.q.push(wr) | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) Pop() (wr http2FrameWriteRequest, ok bool) { | 
|  | ws.root.walkReadyInOrder(false, &ws.tmp, func(n *http2priorityNode, openParent bool) bool { | 
|  | limit := int32(math.MaxInt32) | 
|  | if openParent { | 
|  | limit = ws.writeThrottleLimit | 
|  | } | 
|  | wr, ok = n.q.consume(limit) | 
|  | if !ok { | 
|  | return false | 
|  | } | 
|  | n.addBytes(int64(wr.DataSize())) | 
|  | // If B depends on A and B continuously has data available but A | 
|  | // does not, gradually increase the throttling limit to allow B to | 
|  | // steal more and more bandwidth from A. | 
|  | if openParent { | 
|  | ws.writeThrottleLimit += 1024 | 
|  | if ws.writeThrottleLimit < 0 { | 
|  | ws.writeThrottleLimit = math.MaxInt32 | 
|  | } | 
|  | } else if ws.enableWriteThrottle { | 
|  | ws.writeThrottleLimit = 1024 | 
|  | } | 
|  | return true | 
|  | }) | 
|  | return wr, ok | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorityNode, maxSize int, n *http2priorityNode) { | 
|  | if maxSize == 0 { | 
|  | return | 
|  | } | 
|  | if len(*list) == maxSize { | 
|  | // Remove the oldest node, then shift left. | 
|  | ws.removeNode((*list)[0]) | 
|  | x := (*list)[1:] | 
|  | copy(*list, x) | 
|  | *list = (*list)[:len(x)] | 
|  | } | 
|  | *list = append(*list, n) | 
|  | } | 
|  |  | 
|  | func (ws *http2priorityWriteScheduler) removeNode(n *http2priorityNode) { | 
|  | for k := n.kids; k != nil; k = k.next { | 
|  | k.setParent(n.parent) | 
|  | } | 
|  | n.setParent(nil) | 
|  | delete(ws.nodes, n.id) | 
|  | } | 
|  |  | 
|  | // NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2 | 
|  | // priorities. Control frames like SETTINGS and PING are written before DATA | 
|  | // frames, but if no control frames are queued and multiple streams have queued | 
|  | // HEADERS or DATA frames, Pop selects a ready stream arbitrarily. | 
|  | func http2NewRandomWriteScheduler() http2WriteScheduler { | 
|  | return &http2randomWriteScheduler{sq: make(map[uint32]*http2writeQueue)} | 
|  | } | 
|  |  | 
|  | type http2randomWriteScheduler struct { | 
|  | // zero are frames not associated with a specific stream. | 
|  | zero http2writeQueue | 
|  |  | 
|  | // sq contains the stream-specific queues, keyed by stream ID. | 
|  | // When a stream is idle or closed, it's deleted from the map. | 
|  | sq map[uint32]*http2writeQueue | 
|  |  | 
|  | // pool of empty queues for reuse. | 
|  | queuePool http2writeQueuePool | 
|  | } | 
|  |  | 
|  | func (ws *http2randomWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) { | 
|  | // no-op: idle streams are not tracked | 
|  | } | 
|  |  | 
|  | func (ws *http2randomWriteScheduler) CloseStream(streamID uint32) { | 
|  | q, ok := ws.sq[streamID] | 
|  | if !ok { | 
|  | return | 
|  | } | 
|  | delete(ws.sq, streamID) | 
|  | ws.queuePool.put(q) | 
|  | } | 
|  |  | 
|  | func (ws *http2randomWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) { | 
|  | // no-op: priorities are ignored | 
|  | } | 
|  |  | 
|  | func (ws *http2randomWriteScheduler) Push(wr http2FrameWriteRequest) { | 
|  | id := wr.StreamID() | 
|  | if id == 0 { | 
|  | ws.zero.push(wr) | 
|  | return | 
|  | } | 
|  | q, ok := ws.sq[id] | 
|  | if !ok { | 
|  | q = ws.queuePool.get() | 
|  | ws.sq[id] = q | 
|  | } | 
|  | q.push(wr) | 
|  | } | 
|  |  | 
|  | func (ws *http2randomWriteScheduler) Pop() (http2FrameWriteRequest, bool) { | 
|  | // Control frames first. | 
|  | if !ws.zero.empty() { | 
|  | return ws.zero.shift(), true | 
|  | } | 
|  | // Iterate over all non-idle streams until finding one that can be consumed. | 
|  | for _, q := range ws.sq { | 
|  | if wr, ok := q.consume(math.MaxInt32); ok { | 
|  | return wr, true | 
|  | } | 
|  | } | 
|  | return http2FrameWriteRequest{}, false | 
|  | } |