Source File
h2_bundle.go
Belonging Package
net/http
package http
import (
mathrand
)
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_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_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_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_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_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
)
func ( uint16) bool {
switch {
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
}
}
type http2ClientConnPool interface {
GetClientConn(req *Request, addr string) (*http2ClientConn, error)
MarkDead(*http2ClientConn)
}
type http2clientConnPoolIdleCloser interface {
http2ClientConnPool
closeIdleConnections()
}
var (
_ http2clientConnPoolIdleCloser = (*http2clientConnPool)(nil)
_ http2clientConnPoolIdleCloser = http2noDialClientConnPool{}
)
type http2clientConnPool struct {
t *http2Transport
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 ( *http2clientConnPool) ( *Request, string) (*http2ClientConn, error) {
return .getClientConn(, , http2dialOnMiss)
}
const (
http2dialOnMiss = true
http2noDialOnMiss = false
)
if , := .t.ConnPool.(http2noDialClientConnPool); ! {
return true
return !.freshConn
}
func ( *http2clientConnPool) ( *Request, string, bool) (*http2ClientConn, error) {
http2traceGetConn(, )
const = true
, := .t.dialClientConn(, )
if != nil {
return nil,
}
return , nil
}
.mu.Lock()
for , := range .conns[] {
if := .idleState(); .canTakeNewRequest {
if .shouldTraceGetConn() {
http2traceGetConn(, )
}
.mu.Unlock()
return , nil
}
}
if ! {
.mu.Unlock()
return nil, http2ErrNoCachedConn
}
http2traceGetConn(, )
:= .getStartDialLocked()
.mu.Unlock()
<-.done
return .res, .err
}
type http2dialCall struct {
_ http2incomparable
p *http2clientConnPool
done chan struct{} // closed when done
res *http2ClientConn // valid after done is closed
err error // valid after done is closed
}
func ( *http2clientConnPool) ( string) *http2dialCall {
func ( *http2clientConnPool) ( string, *http2Transport, *tls.Conn) ( bool, error) {
.mu.Lock()
for , := range .conns[] {
if .CanTakeNewRequest() {
.mu.Unlock()
return false, nil
}
}
, := .addConnCalls[]
if ! {
if .addConnCalls == nil {
.addConnCalls = make(map[string]*http2addConnCall)
}
= &http2addConnCall{
p: ,
done: make(chan struct{}),
}
.addConnCalls[] =
go .run(, , )
}
.mu.Unlock()
<-.done
if .err != nil {
return false, .err
}
return !, nil
}
type http2addConnCall struct {
_ http2incomparable
p *http2clientConnPool
done chan struct{} // closed when done
err error
}
func ( *http2addConnCall) ( *http2Transport, string, *tls.Conn) {
, := .NewClientConn()
:= .p
.mu.Lock()
if != nil {
.err =
} else {
.addConnLocked(, )
}
delete(.addConnCalls, )
.mu.Unlock()
close(.done)
}
func ( *http2clientConnPool) ( string, *http2ClientConn) {
for , := range .conns[] {
if == {
return
}
}
if .conns == nil {
.conns = make(map[string][]*http2ClientConn)
}
if .keys == nil {
.keys = make(map[*http2ClientConn][]string)
}
.conns[] = append(.conns[], )
.keys[] = append(.keys[], )
}
func ( *http2clientConnPool) ( *http2ClientConn) {
.mu.Lock()
defer .mu.Unlock()
for , := range .keys[] {
, := .conns[]
if ! {
continue
}
:= http2filterOutClientConn(, )
if len() > 0 {
.conns[] =
} else {
delete(.conns, )
}
}
delete(.keys, )
}
func ( *http2clientConnPool) () {
.mu.Lock()
for , := range .conns {
for , := range {
.closeIfIdle()
}
}
}
func ( []*http2ClientConn, *http2ClientConn) []*http2ClientConn {
:= [:0]
for , := range {
if != {
= append(, )
}
type http2noDialClientConnPool struct{ *http2clientConnPool }
func ( http2noDialClientConnPool) ( *Request, string) (*http2ClientConn, error) {
return .getClientConn(, , http2noDialOnMiss)
}
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 ( int64) []byte {
:= 0
for ; < len(http2dataChunkSizeClasses)-1; ++ {
if <= int64(http2dataChunkSizeClasses[]) {
break
}
}
return http2dataChunkPools[].Get().([]byte)
}
func ( []byte) {
for , := range http2dataChunkSizeClasses {
if len() == {
http2dataChunkPools[].Put()
return
}
}
panic(fmt.Sprintf("unexpected buffer len=%v", len()))
}
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")
func ( *http2dataBuffer) ( []byte) (int, error) {
if .size == 0 {
return 0, http2errReadEmpty
}
var int
for len() > 0 && .size > 0 {
:= .bytesFromFirstChunk()
:= copy(, )
= [:]
+=
.r +=
func ( *http2dataBuffer) () int {
return .size
}
func ( *http2dataBuffer) ( []byte) (int, error) {
:= len()
:= int64(len())
if .expected > {
= .expected
}
:= .lastChunkOrAlloc()
:= copy([.w:], )
= [:]
.w +=
.size +=
.expected -= int64()
}
return , nil
}
func ( *http2dataBuffer) ( int64) []byte {
if len(.chunks) != 0 {
:= .chunks[len(.chunks)-1]
if .w < len() {
return
}
}
:= http2getDataBufferChunk()
.chunks = append(.chunks, )
.w = 0
return
}
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 ( http2ErrCode) () string {
if , := http2errCodeName[]; {
return
}
return fmt.Sprintf("unknown error code 0x%x", uint32())
}
type http2ConnectionError http2ErrCode
func ( http2ConnectionError) () string {
return fmt.Sprintf("connection error: %s", http2ErrCode())
}
type http2StreamError struct {
StreamID uint32
Code http2ErrCode
Cause error // optional additional detail
}
func ( uint32, http2ErrCode) http2StreamError {
return http2StreamError{StreamID: , Code: }
}
func ( http2StreamError) () string {
if .Cause != nil {
return fmt.Sprintf("stream error: stream ID %d; %v; %v", .StreamID, .Code, .Cause)
}
return fmt.Sprintf("stream error: stream ID %d; %v", .StreamID, .Code)
}
type http2goAwayFlowError struct{}
func (http2goAwayFlowError) () string { return "connection exceeded flow control window size" }
type http2connError struct {
Code http2ErrCode // the ConnectionError error code
Reason string // additional reason
}
func ( http2connError) () string {
return fmt.Sprintf("http2: connection error: %v: %v", .Code, .Reason)
}
type http2pseudoHeaderError string
func ( http2pseudoHeaderError) () string {
return fmt.Sprintf("invalid pseudo-header %q", string())
}
type http2duplicatePseudoHeaderError string
func ( http2duplicatePseudoHeaderError) () string {
return fmt.Sprintf("duplicate pseudo-header %q", string())
}
type http2headerFieldNameError string
func ( http2headerFieldNameError) () string {
return fmt.Sprintf("invalid header field name %q", string())
}
type http2headerFieldValueError string
func ( http2headerFieldValueError) () string {
return fmt.Sprintf("invalid header field value %q", string())
}
var (
http2errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
http2errPseudoAfterRegular = errors.New("pseudo header field after regular")
)
type http2flow struct {
_ http2incomparable
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 ( http2FrameType) () string {
if , := http2frameName[]; {
return
}
return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8())
}
type http2Flags uint8
func ( http2Flags) ( http2Flags) bool {
return ( & ) ==
}
http2FlagPingAck http2Flags = 0x1
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",
},
}
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 ( http2FrameType) http2frameParser {
if := http2frameParsers[]; != nil {
return
}
return http2parseUnknownFrame
}
type http2FrameHeader struct {
valid bool // caller can access []byte fields in the Frame
func ( http2FrameHeader) () http2FrameHeader { return }
func ( http2FrameHeader) () string {
var bytes.Buffer
.WriteString("[FrameHeader ")
.writeDebug(&)
.WriteByte(']')
return .String()
}
func ( http2FrameHeader) ( *bytes.Buffer) {
.WriteString(.Type.String())
if .Flags != 0 {
.WriteString(" flags=")
:= 0
for := uint8(0); < 8; ++ {
if .Flags&(1<<) == 0 {
continue
}
++
if > 1 {
.WriteByte('|')
}
:= http2flagName[.Type][http2Flags(1<<)]
if != "" {
.WriteString()
} else {
fmt.Fprintf(, "0x%x", 1<<)
}
}
}
if .StreamID != 0 {
fmt.Fprintf(, " stream=%d", .StreamID)
}
fmt.Fprintf(, " len=%d", .Length)
}
func ( *http2FrameHeader) () {
if !.valid {
panic("Frame accessor called on non-owned Frame")
}
}
func ( *http2FrameHeader) () { .valid = false }
var http2fhBytes = sync.Pool{
New: func() interface{} {
:= make([]byte, http2frameHeaderLen)
return &
},
}
func ( io.Reader) (http2FrameHeader, error) {
:= http2fhBytes.Get().(*[]byte)
defer http2fhBytes.Put()
return http2readFrameHeader(*, )
}
func ( []byte, io.Reader) (http2FrameHeader, error) {
, := io.ReadFull(, [:http2frameHeaderLen])
if != nil {
return http2FrameHeader{},
}
return http2FrameHeader{
Length: (uint32([0])<<16 | uint32([1])<<8 | uint32([2])),
Type: http2FrameType([3]),
Flags: http2Flags([4]),
StreamID: binary.BigEndian.Uint32([5:]) & (1<<31 - 1),
valid: true,
}, nil
}
type http2Frame interface {
Header() http2FrameHeader
invalidate()
}
type http2Framer struct {
r io.Reader
lastFrame http2Frame
errDetail error
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 ( *http2Framer) () uint32 {
if .MaxHeaderListSize == 0 {
return 16 << 20 // sane default, per docs
}
return .MaxHeaderListSize
}
:= len(.wbuf) - http2frameHeaderLen
if >= (1 << 24) {
return http2ErrFrameTooLarge
}
_ = append(.wbuf[:0],
byte(>>16),
byte(>>8),
byte())
if .logWrites {
.logWrite()
}
, := .w.Write(.wbuf)
if == nil && != len(.wbuf) {
= io.ErrShortWrite
}
return
}
func ( *http2Framer) () {
if .debugFramer == nil {
.debugFramerBuf = new(bytes.Buffer)
.debugFramer = http2NewFramer(nil, .debugFramerBuf)
.debugFramer.AllowIllegalReads = true
}
.debugFramerBuf.Write(.wbuf)
, := .debugFramer.ReadFrame()
if != nil {
.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", )
return
}
.debugWriteLoggerf("http2: Framer %p: wrote %v", , http2summarizeFrame())
}
func ( *http2Framer) ( byte) { .wbuf = append(.wbuf, ) }
func ( *http2Framer) ( []byte) { .wbuf = append(.wbuf, ...) }
func ( *http2Framer) ( uint16) { .wbuf = append(.wbuf, byte(>>8), byte()) }
func ( *http2Framer) ( uint32) {
.wbuf = append(.wbuf, byte(>>24), byte(>>16), byte(>>8), byte())
}
const (
http2minMaxFrameSize = 1 << 14
http2maxFrameSize = 1<<24 - 1
)
func ( *http2Framer) () {
if .frameCache != nil {
return
}
.frameCache = &http2frameCache{}
}
type http2frameCache struct {
dataFrame http2DataFrame
}
func ( *http2frameCache) () *http2DataFrame {
if == nil {
return &http2DataFrame{}
}
return &.dataFrame
}
func ( io.Writer, io.Reader) *http2Framer {
:= &http2Framer{
w: ,
r: ,
logReads: http2logFrameReads,
logWrites: http2logFrameWrites,
debugReadLoggerf: log.Printf,
debugWriteLoggerf: log.Printf,
}
.getReadBuf = func( uint32) []byte {
if cap(.readBuf) >= int() {
return .readBuf[:]
}
.readBuf = make([]byte, )
return .readBuf
}
.SetMaxReadFrameSize(http2maxFrameSize)
return
}
func ( *http2Framer) ( uint32) {
if > http2maxFrameSize {
= http2maxFrameSize
}
.maxReadSize =
}
func ( *http2Framer) () error {
return .errDetail
}
var http2ErrFrameTooLarge = errors.New("http2: frame too large")
func ( error) bool {
if , := .(http2StreamError); {
return false
}
return != nil
}
func ( *http2Framer) () (http2Frame, error) {
.errDetail = nil
if .lastFrame != nil {
.lastFrame.invalidate()
}
, := http2readFrameHeader(.headerBuf[:], .r)
if != nil {
return nil,
}
if .Length > .maxReadSize {
return nil, http2ErrFrameTooLarge
}
:= .getReadBuf(.Length)
if , := io.ReadFull(.r, ); != nil {
return nil,
}
, := http2typeFrameParser(.Type)(.frameCache, , )
if != nil {
if , := .(http2connError); {
return nil, .connError(.Code, .Reason)
}
return nil,
}
if := .checkFrameOrder(); != nil {
return nil,
}
if .logReads {
.debugReadLoggerf("http2: Framer %p: read %v", , http2summarizeFrame())
}
if .Type == http2FrameHeaders && .ReadMetaHeaders != nil {
return .readMetaFrame(.(*http2HeadersFrame))
}
return , nil
}
func ( *http2Framer) ( http2ErrCode, string) error {
.errDetail = errors.New()
return http2ConnectionError()
}
func ( *http2Framer) ( http2Frame) error {
:= .lastFrame
.lastFrame =
if .AllowIllegalReads {
return nil
}
:= .Header()
if .lastHeaderStream != 0 {
if .Type != http2FrameContinuation {
return .connError(http2ErrCodeProtocol,
fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
.Type, .StreamID,
.Header().Type, .lastHeaderStream))
}
if .StreamID != .lastHeaderStream {
return .connError(http2ErrCodeProtocol,
fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
.StreamID, .lastHeaderStream))
}
} else if .Type == http2FrameContinuation {
return .connError(http2ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", .StreamID))
}
switch .Type {
case http2FrameHeaders, http2FrameContinuation:
if .Flags.Has(http2FlagHeadersEndHeaders) {
.lastHeaderStream = 0
} else {
.lastHeaderStream = .StreamID
}
}
return nil
}
type http2DataFrame struct {
http2FrameHeader
data []byte
}
func ( *http2DataFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagDataEndStream)
}
func ( *http2DataFrame) () []byte {
.checkValid()
return .data
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
return nil, http2connError{http2ErrCodeProtocol, "DATA frame with stream ID 0"}
}
:= .getDataFrame()
.http2FrameHeader =
var byte
if .Flags.Has(http2FlagDataPadded) {
var error
, , = http2readByte()
if != nil {
return nil,
}
}
return nil, http2connError{http2ErrCodeProtocol, "pad size larger than data payload"}
}
.data = [:len()-int()]
return , 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 ( uint32) bool {
return &(1<<31) == 0
}
func ( uint32) bool {
return != 0 && &(1<<31) == 0
}
func ( *http2Framer) ( uint32, bool, []byte) error {
return .WriteDataPadded(, , , nil)
}
func ( *http2Framer) ( uint32, bool, , []byte) error {
if !http2validStreamID() && !.AllowIllegalWrites {
return http2errStreamID
}
if len() > 0 {
if len() > 255 {
return http2errPadLength
}
if !.AllowIllegalWrites {
for , := range {
return http2errPadBytes
}
}
}
}
var http2Flags
if {
|= http2FlagDataEndStream
}
if != nil {
|= http2FlagDataPadded
}
.startWrite(http2FrameData, , )
if != nil {
.wbuf = append(.wbuf, byte(len()))
}
.wbuf = append(.wbuf, ...)
.wbuf = append(.wbuf, ...)
return .endWrite()
}
type http2SettingsFrame struct {
http2FrameHeader
p []byte
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
return nil, http2ConnectionError(http2ErrCodeFrameSize)
}
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
return nil, http2ConnectionError(http2ErrCodeFrameSize)
}
:= &http2SettingsFrame{http2FrameHeader: , p: }
return nil, http2ConnectionError(http2ErrCodeFlowControl)
}
return , nil
}
func ( *http2SettingsFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagSettingsAck)
}
func ( *http2SettingsFrame) ( http2SettingID) ( uint32, bool) {
.checkValid()
for := 0; < .NumSettings(); ++ {
if := .Setting(); .ID == {
return .Val, true
}
}
return 0, false
}
func ( *http2SettingsFrame) ( int) http2Setting {
:= .p
return http2Setting{
ID: http2SettingID(binary.BigEndian.Uint16([*6 : *6+2])),
Val: binary.BigEndian.Uint32([*6+2 : *6+6]),
}
}
func ( *http2SettingsFrame) () int { return len(.p) / 6 }
func ( *http2SettingsFrame) () bool {
:= .NumSettings()
if == 0 {
return false
func ( *http2SettingsFrame) ( func(http2Setting) error) error {
.checkValid()
for := 0; < .NumSettings(); ++ {
if := (.Setting()); != nil {
return
}
}
return nil
}
func ( *http2Framer) ( ...http2Setting) error {
.startWrite(http2FrameSettings, 0, 0)
for , := range {
.writeUint16(uint16(.ID))
.writeUint32(.Val)
}
return .endWrite()
}
func ( *http2Framer) () error {
.startWrite(http2FrameSettings, http2FlagSettingsAck, 0)
return .endWrite()
}
type http2PingFrame struct {
http2FrameHeader
Data [8]byte
}
func ( *http2PingFrame) () bool { return .Flags.Has(http2FlagPingAck) }
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
if len() != 8 {
return nil, http2ConnectionError(http2ErrCodeFrameSize)
}
if .StreamID != 0 {
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
:= &http2PingFrame{http2FrameHeader: }
copy(.Data[:], )
return , nil
}
func ( *http2Framer) ( bool, [8]byte) error {
var http2Flags
if {
= http2FlagPingAck
}
.startWrite(http2FramePing, , 0)
.writeBytes([:])
return .endWrite()
}
type http2GoAwayFrame struct {
http2FrameHeader
LastStreamID uint32
ErrCode http2ErrCode
debugData []byte
}
func ( *http2GoAwayFrame) () []byte {
.checkValid()
return .debugData
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
if .StreamID != 0 {
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
if len() < 8 {
return nil, http2ConnectionError(http2ErrCodeFrameSize)
}
return &http2GoAwayFrame{
http2FrameHeader: ,
LastStreamID: binary.BigEndian.Uint32([:4]) & (1<<31 - 1),
ErrCode: http2ErrCode(binary.BigEndian.Uint32([4:8])),
debugData: [8:],
}, nil
}
func ( *http2Framer) ( uint32, http2ErrCode, []byte) error {
.startWrite(http2FrameGoAway, 0, 0)
.writeUint32( & (1<<31 - 1))
.writeUint32(uint32())
.writeBytes()
return .endWrite()
}
type http2UnknownFrame struct {
http2FrameHeader
p []byte
}
func ( *http2UnknownFrame) () []byte {
.checkValid()
return .p
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
return &http2UnknownFrame{, }, nil
}
type http2WindowUpdateFrame struct {
http2FrameHeader
Increment uint32 // never read with high bit set
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
if len() != 4 {
return nil, http2ConnectionError(http2ErrCodeFrameSize)
}
:= binary.BigEndian.Uint32([:4]) & 0x7fffffff // mask off high reserved bit
if .StreamID == 0 {
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
return nil, http2streamError(.StreamID, http2ErrCodeProtocol)
}
return &http2WindowUpdateFrame{
http2FrameHeader: ,
Increment: ,
}, nil
}
if ( < 1 || > 2147483647) && !.AllowIllegalWrites {
return errors.New("illegal window increment value")
}
.startWrite(http2FrameWindowUpdate, 0, )
.writeUint32()
return .endWrite()
}
type http2HeadersFrame struct {
http2FrameHeader
Priority http2PriorityParam
headerFragBuf []byte // not owned
}
func ( *http2HeadersFrame) () []byte {
.checkValid()
return .headerFragBuf
}
func ( *http2HeadersFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagHeadersEndHeaders)
}
func ( *http2HeadersFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagHeadersEndStream)
}
func ( *http2HeadersFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagHeadersPriority)
}
func ( *http2frameCache, http2FrameHeader, []byte) ( http2Frame, error) {
:= &http2HeadersFrame{
http2FrameHeader: ,
}
return nil, http2connError{http2ErrCodeProtocol, "HEADERS frame with stream ID 0"}
}
var uint8
if .Flags.Has(http2FlagHeadersPadded) {
if , , = http2readByte(); != nil {
return
}
}
if .Flags.Has(http2FlagHeadersPriority) {
var uint32
, , = http2readUint32()
if != nil {
return nil,
}
.Priority.StreamDep = & 0x7fffffff
.Priority.Exclusive = ( != .Priority.StreamDep) // high bit was set
, .Priority.Weight, = http2readByte()
if != nil {
return nil,
}
}
if len()-int() <= 0 {
return nil, http2streamError(.StreamID, http2ErrCodeProtocol)
}
.headerFragBuf = [:len()-int()]
return , nil
}
func ( *http2Framer) ( http2HeadersFrameParam) error {
if !http2validStreamID(.StreamID) && !.AllowIllegalWrites {
return http2errStreamID
}
var http2Flags
if .PadLength != 0 {
|= http2FlagHeadersPadded
}
if .EndStream {
|= http2FlagHeadersEndStream
}
if .EndHeaders {
|= http2FlagHeadersEndHeaders
}
if !.Priority.IsZero() {
|= http2FlagHeadersPriority
}
.startWrite(http2FrameHeaders, , .StreamID)
if .PadLength != 0 {
.writeByte(.PadLength)
}
if !.Priority.IsZero() {
:= .Priority.StreamDep
if !http2validStreamIDOrZero() && !.AllowIllegalWrites {
return http2errDepStreamID
}
if .Priority.Exclusive {
|= 1 << 31
}
.writeUint32()
.writeByte(.Priority.Weight)
}
.wbuf = append(.wbuf, .BlockFragment...)
.wbuf = append(.wbuf, http2padZeros[:.PadLength]...)
return .endWrite()
}
type http2PriorityFrame struct {
http2FrameHeader
http2PriorityParam
}
Weight uint8
}
func ( http2PriorityParam) () bool {
return == http2PriorityParam{}
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
if .StreamID == 0 {
return nil, http2connError{http2ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
}
if len() != 5 {
return nil, http2connError{http2ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len())}
}
:= binary.BigEndian.Uint32([:4])
:= & 0x7fffffff // mask off high bit
return &http2PriorityFrame{
http2FrameHeader: ,
http2PriorityParam: http2PriorityParam{
Weight: [4],
StreamDep: ,
Exclusive: != , // was high bit set?
},
}, nil
}
func ( *http2Framer) ( uint32, http2PriorityParam) error {
if !http2validStreamID() && !.AllowIllegalWrites {
return http2errStreamID
}
if !http2validStreamIDOrZero(.StreamDep) {
return http2errDepStreamID
}
.startWrite(http2FramePriority, 0, )
:= .StreamDep
if .Exclusive {
|= 1 << 31
}
.writeUint32()
.writeByte(.Weight)
return .endWrite()
}
type http2RSTStreamFrame struct {
http2FrameHeader
ErrCode http2ErrCode
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
if len() != 4 {
return nil, http2ConnectionError(http2ErrCodeFrameSize)
}
if .StreamID == 0 {
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
return &http2RSTStreamFrame{, http2ErrCode(binary.BigEndian.Uint32([:4]))}, nil
}
func ( *http2Framer) ( uint32, http2ErrCode) error {
if !http2validStreamID() && !.AllowIllegalWrites {
return http2errStreamID
}
.startWrite(http2FrameRSTStream, 0, )
.writeUint32(uint32())
return .endWrite()
}
type http2ContinuationFrame struct {
http2FrameHeader
headerFragBuf []byte
}
func ( *http2frameCache, http2FrameHeader, []byte) (http2Frame, error) {
if .StreamID == 0 {
return nil, http2connError{http2ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
}
return &http2ContinuationFrame{, }, nil
}
func ( *http2ContinuationFrame) () []byte {
.checkValid()
return .headerFragBuf
}
func ( *http2ContinuationFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagContinuationEndHeaders)
}
func ( *http2Framer) ( uint32, bool, []byte) error {
if !http2validStreamID() && !.AllowIllegalWrites {
return http2errStreamID
}
var http2Flags
if {
|= http2FlagContinuationEndHeaders
}
.startWrite(http2FrameContinuation, , )
.wbuf = append(.wbuf, ...)
return .endWrite()
}
type http2PushPromiseFrame struct {
http2FrameHeader
PromiseID uint32
headerFragBuf []byte // not owned
}
func ( *http2PushPromiseFrame) () []byte {
.checkValid()
return .headerFragBuf
}
func ( *http2PushPromiseFrame) () bool {
return .http2FrameHeader.Flags.Has(http2FlagPushPromiseEndHeaders)
}
func ( *http2frameCache, http2FrameHeader, []byte) ( http2Frame, error) {
:= &http2PushPromiseFrame{
http2FrameHeader: ,
}
return nil, http2ConnectionError(http2ErrCodeProtocol)
var uint8
if .Flags.Has(http2FlagPushPromisePadded) {
if , , = http2readByte(); != nil {
return
}
}
, .PromiseID, = http2readUint32()
if != nil {
return
}
.PromiseID = .PromiseID & (1<<31 - 1)
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
.headerFragBuf = [:len()-int()]
return , nil
}
func ( *http2Framer) ( http2PushPromiseParam) error {
if !http2validStreamID(.StreamID) && !.AllowIllegalWrites {
return http2errStreamID
}
var http2Flags
if .PadLength != 0 {
|= http2FlagPushPromisePadded
}
if .EndHeaders {
|= http2FlagPushPromiseEndHeaders
}
.startWrite(http2FramePushPromise, , .StreamID)
if .PadLength != 0 {
.writeByte(.PadLength)
}
if !http2validStreamID(.PromiseID) && !.AllowIllegalWrites {
return http2errStreamID
}
.writeUint32(.PromiseID)
.wbuf = append(.wbuf, .BlockFragment...)
.wbuf = append(.wbuf, http2padZeros[:.PadLength]...)
return .endWrite()
}
func ( *http2Framer) ( http2FrameType, http2Flags, uint32, []byte) error {
.startWrite(, , )
.writeBytes()
return .endWrite()
}
func ( []byte) ( []byte, byte, error) {
if len() == 0 {
return nil, 0, io.ErrUnexpectedEOF
}
return [1:], [0], nil
}
func ( []byte) ( []byte, uint32, error) {
if len() < 4 {
return nil, 0, io.ErrUnexpectedEOF
}
return [4:], binary.BigEndian.Uint32([:4]), nil
}
type http2streamEnder interface {
StreamEnded() bool
}
type http2headersEnder interface {
HeadersEnded() bool
}
type http2headersOrContinuation interface {
http2headersEnder
HeaderBlockFragment() []byte
}
type http2MetaHeadersFrame struct {
*http2HeadersFrame
func ( *http2MetaHeadersFrame) () []hpack.HeaderField {
for , := range .Fields {
if !.IsPseudo() {
return .Fields[:]
}
}
return nil
}
func ( *http2MetaHeadersFrame) () []hpack.HeaderField {
for , := range .Fields {
if !.IsPseudo() {
return .Fields[:]
}
}
return .Fields
}
func ( *http2MetaHeadersFrame) () error {
var , bool
:= .PseudoFields()
for , := range {
switch .Name {
case ":method", ":path", ":scheme", ":authority":
= true
case ":status":
= true
default:
return http2pseudoHeaderError(.Name)
for , := range [:] {
if .Name == .Name {
return http2duplicatePseudoHeaderError(.Name)
}
}
}
if && {
return http2errMixPseudoHeaderTypes
}
return nil
}
func ( *http2Framer) () int {
:= .maxHeaderListSize()
if uint32(int()) == {
return int()
return 0
}
func ( *http2Framer) ( *http2HeadersFrame) (*http2MetaHeadersFrame, error) {
if .AllowIllegalReads {
return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
}
:= &http2MetaHeadersFrame{
http2HeadersFrame: ,
}
var = .maxHeaderListSize()
var bool
var error // pseudo header field errors
:= .ReadMetaHeaders
.SetEmitEnabled(true)
.SetMaxStringLength(.maxHeaderStringLen())
.SetEmitFunc(func( hpack.HeaderField) {
if http2VerboseLogs && .logReads {
.debugReadLoggerf("http2: decoded hpack field %+v", )
}
if !httpguts.ValidHeaderFieldValue(.Value) {
= http2headerFieldValueError(.Value)
}
:= strings.HasPrefix(.Name, ":")
if {
if {
= http2errPseudoAfterRegular
}
} else {
= true
if !http2validWireHeaderFieldName(.Name) {
= http2headerFieldNameError(.Name)
}
}
if != nil {
.SetEmitEnabled(false)
return
}
:= .Size()
if > {
.SetEmitEnabled(false)
.Truncated = true
return
}
-=
.Fields = append(.Fields, )
defer .SetEmitFunc(func( hpack.HeaderField) {})
var http2headersOrContinuation =
for {
:= .HeaderBlockFragment()
if , := .Write(); != nil {
return nil, http2ConnectionError(http2ErrCodeCompression)
}
if .HeadersEnded() {
break
}
if , := .ReadFrame(); != nil {
return nil,
} else {
= .(*http2ContinuationFrame) // guaranteed by checkFrameOrder
}
}
.http2HeadersFrame.headerFragBuf = nil
.http2HeadersFrame.invalidate()
if := .Close(); != nil {
return nil, http2ConnectionError(http2ErrCodeCompression)
}
if != nil {
.errDetail =
if http2VerboseLogs {
log.Printf("http2: invalid header: %v", )
}
return nil, http2StreamError{.StreamID, http2ErrCodeProtocol, }
}
if := .checkPseudos(); != nil {
.errDetail =
if http2VerboseLogs {
log.Printf("http2: invalid pseudo headers: %v", )
}
return nil, http2StreamError{.StreamID, http2ErrCodeProtocol, }
}
return , nil
}
func ( http2Frame) string {
var bytes.Buffer
.Header().writeDebug(&)
switch f := .(type) {
case *http2SettingsFrame:
:= 0
.ForeachSetting(func( http2Setting) error {
++
if == 1 {
.WriteString(", settings:")
}
fmt.Fprintf(&, " %v=%v,", .ID, .Val)
return nil
})
if > 0 {
.Truncate(.Len() - 1) // remove trailing comma
}
case *http2DataFrame:
:= .Data()
const = 256
if len() > {
= [:]
}
fmt.Fprintf(&, " data=%q", )
if len(.Data()) > {
fmt.Fprintf(&, " (%d bytes omitted)", len(.Data())-)
}
case *http2WindowUpdateFrame:
if .StreamID == 0 {
.WriteString(" (conn)")
}
fmt.Fprintf(&, " incr=%v", .Increment)
case *http2PingFrame:
fmt.Fprintf(&, " ping=%q", .Data[:])
case *http2GoAwayFrame:
fmt.Fprintf(&, " LastStreamID=%v ErrCode=%v Debug=%q",
.LastStreamID, .ErrCode, .debugData)
case *http2RSTStreamFrame:
fmt.Fprintf(&, " ErrCode=%v", .ErrCode)
}
return .String()
}
func ( *httptrace.ClientTrace) bool {
return != nil && .WroteHeaderField != nil
}
func ( *httptrace.ClientTrace, , string) {
if != nil && .WroteHeaderField != nil {
.WroteHeaderField(, []string{})
}
}
func ( *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if != nil {
return .Got1xxResponse
}
return nil
}
var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
type http2goroutineLock uint64
func () http2goroutineLock {
if !http2DebugGoroutines {
return 0
}
return http2goroutineLock(http2curGoroutineID())
}
func ( http2goroutineLock) () {
if !http2DebugGoroutines {
return
}
if http2curGoroutineID() != uint64() {
panic("running on the wrong goroutine")
}
}
func ( http2goroutineLock) () {
if !http2DebugGoroutines {
return
}
if http2curGoroutineID() == uint64() {
panic("running on the wrong goroutine")
}
}
var http2goroutineSpace = []byte("goroutine ")
func () uint64 {
:= http2littleBuf.Get().(*[]byte)
defer http2littleBuf.Put()
:= *
= bytes.TrimPrefix(, http2goroutineSpace)
:= bytes.IndexByte(, ' ')
if < 0 {
panic(fmt.Sprintf("No space found in %q", ))
}
= [:]
, := http2parseUintBytes(, 10, 64)
if != nil {
panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", , ))
}
return
}
var http2littleBuf = sync.Pool{
New: func() interface{} {
:= make([]byte, 64)
return &
},
}
switch {
case [0] == '0' && len() > 1 && ([1] == 'x' || [1] == 'X'):
= 16
= [2:]
if len() < 1 {
= strconv.ErrSyntax
goto
}
case [0] == '0':
= 8
default:
= 10
}
default:
= errors.New("invalid base " + strconv.Itoa())
goto
}
= 0
= http2cutoff64()
= 1<<uint() - 1
for := 0; < len(); ++ {
var byte
:= []
switch {
case '0' <= && <= '9':
= - '0'
case 'a' <= && <= 'z':
= - 'a' + 10
case 'A' <= && <= 'Z':
= - 'A' + 10
default:
= 0
= strconv.ErrSyntax
goto
}
if int() >= {
= 0
= strconv.ErrSyntax
goto
}
func ( int) uint64 {
if < 2 {
return 0
}
return (1<<64-1)/uint64() + 1
}
var (
http2commonBuildOnce sync.Once
http2commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case
http2commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case
)
func () {
http2commonBuildOnce.Do(http2buildCommonHeaderMaps)
}
func () {
:= []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",
}
http2commonLowerHeader = make(map[string]string, len())
http2commonCanonHeader = make(map[string]string, len())
for , := range {
:= CanonicalHeaderKey()
http2commonLowerHeader[] =
http2commonCanonHeader[] =
}
}
func ( string) string {
http2buildCommonHeaderMapsOnce()
if , := http2commonLowerHeader[]; {
return
}
return strings.ToLower()
}
var (
http2VerboseLogs bool
http2logFrameWrites bool
http2logFrameReads bool
http2inTests bool
)
func () {
:= os.Getenv("GODEBUG")
if strings.Contains(, "http2debug=1") {
http2VerboseLogs = true
}
if strings.Contains(, "http2debug=2") {
http2VerboseLogs = true
http2logFrameWrites = true
http2logFrameReads = true
}
}
http2ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
http2initialMaxFrameSize = 16384
http2NextProtoTLS = "h2"
http2initialHeaderTableSize = 4096
http2initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
http2defaultMaxReadFrameSize = 1 << 20
)
var (
http2clientPreface = []byte(http2ClientPreface)
)
type http2streamState int
const (
http2stateIdle http2streamState = iota
http2stateOpen
http2stateHalfClosedLocal
http2stateHalfClosedRemote
http2stateClosed
)
var http2stateName = [...]string{
http2stateIdle: "Idle",
http2stateOpen: "Open",
http2stateHalfClosedLocal: "HalfClosedLocal",
http2stateHalfClosedRemote: "HalfClosedRemote",
http2stateClosed: "Closed",
}
func ( http2streamState) () string {
return http2stateName[]
}
switch .ID {
case http2SettingEnablePush:
if .Val != 1 && .Val != 0 {
return http2ConnectionError(http2ErrCodeProtocol)
}
case http2SettingInitialWindowSize:
if .Val > 1<<31-1 {
return http2ConnectionError(http2ErrCodeFlowControl)
}
case http2SettingMaxFrameSize:
if .Val < 16384 || .Val > 1<<24-1 {
return http2ConnectionError(http2ErrCodeProtocol)
}
}
return nil
}
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 ( http2SettingID) () string {
if , := http2settingName[]; {
return
}
return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16())
}
type http2stringWriter interface {
WriteString(s string) (n int, err error)
}
type http2closeWaiter chan struct{}
func ( *http2closeWaiter) () {
* = make(chan struct{})
}
func ( http2closeWaiter) () {
close()
}
func ( http2closeWaiter) () {
<-
}
type http2bufferedWriter struct {
_ http2incomparable
w io.Writer // immutable
bw *bufio.Writer // non-nil when data is buffered
}
func ( io.Writer) *http2bufferedWriter {
return &http2bufferedWriter{w: }
}
const http2bufWriterPoolBufferSize = 4 << 10
var http2bufWriterPool = sync.Pool{
New: func() interface{} {
return bufio.NewWriterSize(nil, http2bufWriterPoolBufferSize)
},
}
func ( *http2bufferedWriter) () int {
if .bw == nil {
return http2bufWriterPoolBufferSize
}
return .bw.Available()
}
func ( *http2bufferedWriter) ( []byte) ( int, error) {
if .bw == nil {
:= http2bufWriterPool.Get().(*bufio.Writer)
.Reset(.w)
.bw =
}
return .bw.Write()
}
func ( *http2bufferedWriter) () error {
:= .bw
if == nil {
return nil
}
:= .Flush()
.Reset(nil)
http2bufWriterPool.Put()
.bw = nil
return
}
func ( int32) uint32 {
if < 0 || > 2147483647 {
panic("out of range")
}
return uint32()
}
func ( int) bool {
switch {
case >= 100 && <= 199:
return false
case == 204:
return false
case == 304:
return false
}
return true
}
type http2httpError struct {
_ http2incomparable
msg string
timeout bool
}
func ( *http2httpError) () string { return .msg }
func ( *http2httpError) () bool { return .timeout }
func ( *http2httpError) () 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 ( *http2sorter) () int { return len(.v) }
func ( *http2sorter) (, int) { .v[], .v[] = .v[], .v[] }
func ( *http2sorter) (, int) bool { return .v[] < .v[] }
type http2incomparable [0]func()
type http2pipe struct {
mu sync.Mutex
c sync.Cond // c.L lazily initialized to &p.mu
b http2pipeBuffer // nil when done reading
unread int // bytes unread when done
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 ( *http2pipe) () int {
.mu.Lock()
defer .mu.Unlock()
if .b == nil {
return .unread
}
return .b.Len()
}
func ( *http2pipe) ( []byte) ( int, error) {
.mu.Lock()
defer .mu.Unlock()
if .c.L == nil {
.c.L = &.mu
}
for {
if .breakErr != nil {
return 0, .breakErr
}
if .b != nil && .b.Len() > 0 {
return .b.Read()
}
if .err != nil {
if .readFn != nil {
.readFn() // e.g. copy trailers
.readFn = nil // not sticky like p.err
}
.b = nil
return 0, .err
}
.c.Wait()
}
}
var http2errClosedPipeWrite = errors.New("write on closed buffer")
func ( *http2pipe) ( error) { .closeWithError(&.err, , nil) }
func ( *http2pipe) ( error) { .closeWithError(&.breakErr, , nil) }
.closeDoneLocked()
}
}
return .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?
http2maxQueuedControlFrames = 10000
)
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{} {
:= &http2responseWriterState{}
.bw = bufio.NewWriterSize(http2chunkWriter{}, http2handlerChunkWriteSize)
return
},
}
var (
http2testHookOnConn func()
http2testHookGetServerConn func(*http2serverConn)
http2testHookOnPanicMu *sync.Mutex // nil except in tests
http2testHookOnPanic func(sc *http2serverConn, panicVal interface{}) (rePanic bool)
)
state *http2serverInternalState
}
func ( *http2Server) () int32 {
if .MaxUploadBufferPerConnection > http2initialWindowSize {
return .MaxUploadBufferPerConnection
}
return 1 << 20
}
func ( *http2Server) () int32 {
if .MaxUploadBufferPerStream > 0 {
return .MaxUploadBufferPerStream
}
return 1 << 20
}
func ( *http2Server) () uint32 {
if := .MaxReadFrameSize; >= http2minMaxFrameSize && <= http2maxFrameSize {
return
}
return http2defaultMaxReadFrameSize
}
func ( *http2Server) () uint32 {
if := .MaxConcurrentStreams; > 0 {
return
}
return http2defaultMaxStreams
}
return http2maxQueuedControlFrames
}
type http2serverInternalState struct {
mu sync.Mutex
activeConns map[*http2serverConn]struct{}
}
func ( *http2serverInternalState) ( *http2serverConn) {
if == nil {
return // if the Server was used without calling ConfigureServer
}
.mu.Lock()
.activeConns[] = struct{}{}
.mu.Unlock()
}
func ( *http2serverInternalState) ( *http2serverConn) {
if == nil {
return // if the Server was used without calling ConfigureServer
}
.mu.Lock()
delete(.activeConns, )
.mu.Unlock()
}
func ( *http2serverInternalState) () {
if == nil {
return // if the Server was used without calling ConfigureServer
}
.mu.Lock()
for := range .activeConns {
.startGracefulShutdown()
}
.mu.Unlock()
}
func ( *Server, *http2Server) error {
if == nil {
panic("nil *http.Server")
}
if == nil {
= new(http2Server)
}
.state = &http2serverInternalState{activeConns: make(map[*http2serverConn]struct{})}
if , := , ; .IdleTimeout == 0 {
if .IdleTimeout != 0 {
.IdleTimeout = .IdleTimeout
} else {
.IdleTimeout = .ReadTimeout
}
}
.RegisterOnShutdown(.state.startGracefulShutdown)
if .TLSConfig == nil {
.TLSConfig = new(tls.Config)
:= false
:= false
for , := range .TLSConfig.CipherSuites {
switch {
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
= true
}
if http2isBadCipher() {
= true
} else if {
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.", , )
}
}
if ! {
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).")
}
}
.TLSConfig.PreferServerCipherSuites = true
:= false
for , := range .TLSConfig.NextProtos {
if == http2NextProtoTLS {
= true
break
}
}
if ! {
.TLSConfig.NextProtos = append(.TLSConfig.NextProtos, http2NextProtoTLS)
}
if .TLSNextProto == nil {
.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
}
:= func( *Server, *tls.Conn, Handler) {
if http2testHookOnConn != nil {
http2testHookOnConn()
var context.Context
type interface {
() context.Context
}
if , := .(); {
= .()
}
.ServeConn(, &http2ServeConnOpts{
Context: ,
Handler: ,
BaseConfig: ,
})
}
.TLSNextProto[http2NextProtoTLS] =
return nil
}
Handler Handler
}
func ( *http2ServeConnOpts) () context.Context {
if != nil && .Context != nil {
return .Context
}
return context.Background()
}
func ( *http2ServeConnOpts) () *Server {
if != nil && .BaseConfig != nil {
return .BaseConfig
}
return new(Server)
}
func ( *http2ServeConnOpts) () Handler {
if != nil {
if .Handler != nil {
return .Handler
}
if .BaseConfig != nil && .BaseConfig.Handler != nil {
return .BaseConfig.Handler
}
}
return DefaultServeMux
}
func ( *http2Server) ( net.Conn, *http2ServeConnOpts) {
, := http2serverConnBaseContext(, )
defer ()
:= &http2serverConn{
srv: ,
hs: .baseConfig(),
conn: ,
baseCtx: ,
remoteAddrStr: .RemoteAddr().String(),
bw: http2newBufferedWriter(),
handler: .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: .maxConcurrentStreams(),
initialStreamSendWindowSize: http2initialWindowSize,
maxFrameSize: http2initialMaxFrameSize,
headerTableSize: http2initialHeaderTableSize,
serveG: http2newGoroutineLock(),
pushEnabled: true,
}
.state.registerConn()
defer .state.unregisterConn()
if .hs.WriteTimeout != 0 {
.conn.SetWriteDeadline(time.Time{})
}
if .NewWriteScheduler != nil {
.writeSched = .NewWriteScheduler()
} else {
.writeSched = http2NewRandomWriteScheduler()
}
.flow.add(http2initialWindowSize)
.inflow.add(http2initialWindowSize)
.hpackEncoder = hpack.NewEncoder(&.headerWriteBuf)
:= http2NewFramer(.bw, )
.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
.MaxHeaderListSize = .maxHeaderListSize()
.SetMaxReadFrameSize(.maxReadFrameSize())
.framer =
if , := .(http2connectionStater); {
.tlsState = new(tls.ConnectionState)
if .tlsState.Version < tls.VersionTLS12 {
.rejectConn(http2ErrCodeInadequateSecurity, "TLS version too low")
return
}
}
.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", .tlsState.CipherSuite))
return
}
}
if := http2testHookGetServerConn; != nil {
()
}
.serve()
}
func ( net.Conn, *http2ServeConnOpts) ( context.Context, func()) {
, = context.WithCancel(.context())
= context.WithValue(, LocalAddrContextKey, .LocalAddr())
if := .baseConfig(); != nil {
= context.WithValue(, ServerContextKey, )
}
return
}
func ( *http2serverConn) ( http2ErrCode, string) {
srv *http2Server
hs *Server
conn net.Conn
bw *http2bufferedWriter // writing to conn
handler Handler
baseCtx context.Context
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
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?
queuedControlFrames int // control frames in the writeSched queue
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
shutdownOnce sync.Once
}
func ( *http2serverConn) () uint32 {
:= .hs.MaxHeaderBytes
if <= 0 {
= DefaultMaxHeaderBytes
const = 32 // per http2 spec
const = 10 // conservative
return uint32( + *)
}
func ( *http2serverConn) () uint32 {
.serveG.check()
return .curClientStreams + .curPushedStreams
}
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
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 ( *http2serverConn) () *http2Framer { return .framer }
func ( *http2serverConn) () error { return .conn.Close() }
func ( *http2serverConn) () error { return .bw.Flush() }
func ( *http2serverConn) () (*hpack.Encoder, *bytes.Buffer) {
return .hpackEncoder, &.headerWriteBuf
}
func ( *http2serverConn) ( uint32) (http2streamState, *http2stream) {
if %2 == 1 {
if <= .maxClientStreamID {
return http2stateClosed, nil
}
} else {
if <= .maxPushPromiseID {
return http2stateClosed, nil
}
}
return http2stateIdle, nil
}
func ( *http2serverConn) ( ConnState) {
if .hs.ConnState != nil {
.hs.ConnState(.conn, )
}
}
func ( *http2serverConn) ( string, ...interface{}) {
if http2VerboseLogs {
.logf(, ...)
}
}
func ( *http2serverConn) ( string, ...interface{}) {
if := .hs.ErrorLog; != nil {
.Printf(, ...)
} else {
log.Printf(, ...)
}
}
if runtime.GOOS == "windows" {
if , := .(*net.OpError); && .Op == "read" {
if , := .Err.(*os.SyscallError); && .Syscall == "wsarecv" {
const = 10053
const = 10054
if := http2errno(.Err); == || == {
return true
}
}
}
}
return false
}
func ( *http2serverConn) ( error, string, ...interface{}) {
if == nil {
return
}
.vlogf(, ...)
} else {
.logf(, ...)
}
}
func ( *http2serverConn) ( string) string {
.serveG.check()
http2buildCommonHeaderMapsOnce()
, := http2commonCanonHeader[]
if {
return
}
, = .canonHeader[]
if {
return
}
if .canonHeader == nil {
.canonHeader = make(map[string]string)
}
= CanonicalHeaderKey()
.canonHeader[] =
return
}
type http2readFrameResult struct {
f http2Frame // valid until readMore is called
err error
readMore func()
}
func ( *http2serverConn) () {
:= make(http2gate)
:= .Done
for {
, := .framer.ReadFrame()
select {
case .readFrameCh <- http2readFrameResult{, , }:
case <-.doneServing:
return
}
select {
case <-:
case <-.doneServing:
return
}
if http2terminalReadFrameError() {
return
}
}
}
type http2frameWriteResult struct {
_ http2incomparable
wr http2FrameWriteRequest // what was written (or attempted)
err error // result of the writeFrame call
}
func ( *http2serverConn) ( http2FrameWriteRequest) {
:= .write.writeFrame()
.wroteFrameCh <- http2frameWriteResult{wr: , err: }
}
func ( *http2serverConn) () {
.serveG.check()
for , := range .streams {
.closeStream(, http2errClientDisconnected)
}
}
func ( *http2serverConn) () {
.serveG.check()
if := .shutdownTimer; != nil {
.Stop()
}
}
if http2testHookOnPanicMu != nil {
http2testHookOnPanicMu.Lock()
defer http2testHookOnPanicMu.Unlock()
}
if http2testHookOnPanic != nil {
if := recover(); != nil {
if http2testHookOnPanic(, ) {
panic()
}
}
}
}
func ( *http2serverConn) () {
.serveG.check()
defer .notePanic()
defer .conn.Close()
defer .closeAllStreamsOnConnClose()
defer .stopShutdownTimer()
defer close(.doneServing) // unblocks handlers trying to send
if http2VerboseLogs {
.vlogf("http2: server connection from %v on %p", .conn.RemoteAddr(), .hs)
}
.writeFrame(http2FrameWriteRequest{
write: http2writeSettings{
{http2SettingMaxFrameSize, .srv.maxReadFrameSize()},
{http2SettingMaxConcurrentStreams, .advMaxStreams},
{http2SettingMaxHeaderListSize, .maxHeaderListSize()},
{http2SettingInitialWindowSize, uint32(.srv.initialStreamRecvWindowSize())},
},
})
.unackedSettings++
if := .srv.initialConnRecvWindowSize() - http2initialWindowSize; > 0 {
.sendWindowUpdate(nil, int())
}
if := .readPreface(); != nil {
.condlogf(, "http2: server: error reading preface from client %v: %v", .conn.RemoteAddr(), )
return
.setConnState(StateActive)
.setConnState(StateIdle)
if .srv.IdleTimeout != 0 {
.idleTimer = time.AfterFunc(.srv.IdleTimeout, .onIdleTimer)
defer .idleTimer.Stop()
}
go .readFrames() // closed by defer sc.conn.Close above
:= time.AfterFunc(http2firstSettingsTimeout, .onSettingsTimer)
defer .Stop()
:= 0
for {
++
select {
case := <-.wantWriteFrameCh:
if , := .write.(http2StreamError); {
.resetStream()
break
}
.writeFrame()
case := <-.wroteFrameCh:
.wroteFrame()
case := <-.readFrameCh:
if !.processFrameFromReader() {
return
}
.readMore()
if != nil {
.Stop()
= nil
}
case := <-.bodyReadCh:
.noteBodyRead(.st, .n)
case := <-.serveMsgCh:
switch v := .(type) {
case func(int):
() // for testing
case *http2serverMessage:
switch {
case http2settingsTimerMsg:
.logf("timeout waiting for SETTINGS frames from %v", .conn.RemoteAddr())
return
case http2idleTimerMsg:
.vlogf("connection is idle")
.goAway(http2ErrCodeNo)
case http2shutdownTimerMsg:
.vlogf("GOAWAY close timer fired; closing conn from %v", .conn.RemoteAddr())
return
case http2gracefulShutdownMsg:
.startGracefulShutdownInternal()
default:
panic("unknown timer")
}
case *http2startPushRequest:
.startPush()
default:
panic(fmt.Sprintf("unexpected type %T", ))
}
}
if .queuedControlFrames > .srv.maxQueuedControlFrames() {
.vlogf("http2: too many control frames in send queue, closing connection")
return
}
:= .inGoAway && !.needToSendGoAway && !.writingFrame
:= .goAwayCode == http2ErrCodeNo && .curOpenStreams() == 0
if && .shutdownTimer == nil && (.goAwayCode != http2ErrCodeNo || ) {
.shutDownIn(http2goAwayTimeout)
}
}
}
func ( *http2serverConn) ( <-chan struct{}, chan struct{}) {
select {
case <-.doneServing:
case <-:
close()
}
}
type http2serverMessage int
var (
http2settingsTimerMsg = new(http2serverMessage)
http2idleTimerMsg = new(http2serverMessage)
http2shutdownTimerMsg = new(http2serverMessage)
http2gracefulShutdownMsg = new(http2serverMessage)
)
func ( *http2serverConn) () { .sendServeMsg(http2settingsTimerMsg) }
func ( *http2serverConn) () { .sendServeMsg(http2idleTimerMsg) }
func ( *http2serverConn) () { .sendServeMsg(http2shutdownTimerMsg) }
func ( *http2serverConn) ( interface{}) {
.serveG.checkNotOn() // NOT
select {
case .serveMsgCh <- :
case <-.doneServing:
}
}
var http2errPrefaceTimeout = errors.New("timeout waiting for client preface")
func ( *http2serverConn) () error {
:= make(chan error, 1)
:= make([]byte, len(http2ClientPreface))
if , := io.ReadFull(.conn, ); != nil {
<-
} else if !bytes.Equal(, http2clientPreface) {
<- fmt.Errorf("bogus greeting %q", )
} else {
<- nil
}
}()
:= time.NewTimer(http2prefaceTimeout) // TODO: configurable on *Server?
defer .Stop()
select {
case <-.C:
return http2errPrefaceTimeout
case := <-:
if == nil {
if http2VerboseLogs {
.vlogf("http2: server: client %v said hello", .conn.RemoteAddr())
}
}
return
}
}
var http2errChanPool = sync.Pool{
New: func() interface{} { return make(chan error, 1) },
}
var http2writeDataPool = sync.Pool{
New: func() interface{} { return new(http2writeData) },
}
func ( *http2serverConn) ( *http2stream, []byte, bool) error {
:= http2errChanPool.Get().(chan error)
:= http2writeDataPool.Get().(*http2writeData)
* = http2writeData{.id, , }
:= .writeFrameFromHandler(http2FrameWriteRequest{
write: ,
stream: ,
done: ,
})
if != nil {
return
}
var bool // the frame write is done (successfully or not)
select {
case = <-:
= true
case <-.doneServing:
return http2errClientDisconnected
select {
case = <-:
= true
default:
return http2errStreamClosed
}
}
http2errChanPool.Put()
if {
http2writeDataPool.Put()
}
return
}
func ( *http2serverConn) ( http2FrameWriteRequest) error {
.serveG.checkNotOn() // NOT
select {
case .wantWriteFrameCh <- :
return nil
return http2errClientDisconnected
}
}
func ( *http2serverConn) ( http2FrameWriteRequest) {
.serveG.check()
var bool
if .StreamID() != 0 {
, := .write.(http2StreamError)
if , := .state(.StreamID()); == http2stateClosed && ! {
= true
}
}
switch .write.(type) {
case *http2writeResHeaders:
.stream.wroteHeaders = true
case http2write100ContinueHeadersFrame:
if .queuedControlFrames < 0 {
.conn.Close()
}
}
.writeSched.Push()
}
.scheduleFrameWrite()
}
func ( *http2serverConn) ( http2FrameWriteRequest) {
.serveG.check()
if .writingFrame {
panic("internal error: can only be writing one frame at a time")
}
:= .stream
if != nil {
switch .state {
case http2stateHalfClosedLocal:
switch .write.(type) {
default:
panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", ))
}
case http2stateClosed:
panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", ))
}
}
if , := .write.(*http2writePushPromise); {
var error
.promisedID, = .allocatePromisedID()
if != nil {
.writingFrameAsync = false
.replyToWriter()
return
}
}
.writingFrame = true
.needsFrameFlush = true
if .write.staysWithinBuffer(.bw.Available()) {
.writingFrameAsync = false
:= .write.writeFrame()
.wroteFrame(http2frameWriteResult{wr: , err: })
} else {
.writingFrameAsync = true
go .writeFrameAsync()
}
}
var http2errHandlerPanicked = errors.New("http2: handler panicked")
func ( *http2serverConn) ( http2frameWriteResult) {
.serveG.check()
if !.writingFrame {
panic("internal error: expected to be already writing a frame")
}
.writingFrame = false
.writingFrameAsync = false
:= .wr
if http2writeEndsStream(.write) {
:= .stream
if == nil {
panic("internal error: expecting non-nil stream")
}
switch .state {
.resetStream(http2streamError(.id, http2ErrCodeNo))
case http2stateHalfClosedRemote:
.closeStream(, http2errHandlerComplete)
}
} else {
switch v := .write.(type) {
if , := .streams[.StreamID]; {
.closeStream(, )
}
case http2handlerPanicRST:
.closeStream(.stream, http2errHandlerPanicked)
}
}
.replyToWriter(.err)
.scheduleFrameWrite()
}
func ( *http2serverConn) () {
.serveG.check()
if .writingFrame || .inFrameScheduleLoop {
return
}
.inFrameScheduleLoop = true
for !.writingFrameAsync {
if .needToSendGoAway {
.needToSendGoAway = false
.startFrameWrite(http2FrameWriteRequest{
write: &http2writeGoAway{
maxStreamID: .maxClientStreamID,
code: .goAwayCode,
},
})
continue
}
if .needToSendSettingsAck {
.needToSendSettingsAck = false
.startFrameWrite(http2FrameWriteRequest{write: http2writeSettingsAck{}})
continue
}
if !.inGoAway || .goAwayCode == http2ErrCodeNo {
if , := .writeSched.Pop(); {
if .isControl() {
.queuedControlFrames--
}
.startFrameWrite()
continue
}
}
if .needsFrameFlush {
.startFrameWrite(http2FrameWriteRequest{write: http2flushFrameWriter{}})
.needsFrameFlush = false // after startFrameWrite, since it sets this true
continue
}
break
}
.inFrameScheduleLoop = false
}
func ( *http2serverConn) () {
.serveG.checkNotOn() // NOT
.shutdownOnce.Do(func() { .sendServeMsg(http2gracefulShutdownMsg) })
}
var http2goAwayTimeout = 1 * time.Second
func ( *http2serverConn) () {
.goAway(http2ErrCodeNo)
}
func ( *http2serverConn) ( http2ErrCode) {
.serveG.check()
if .inGoAway {
return
}
.inGoAway = true
.needToSendGoAway = true
.goAwayCode =
.scheduleFrameWrite()
}
func ( *http2serverConn) ( time.Duration) {
.serveG.check()
.shutdownTimer = time.AfterFunc(, .onShutdownTimer)
}
func ( *http2serverConn) ( http2StreamError) {
.serveG.check()
.writeFrame(http2FrameWriteRequest{write: })
if , := .streams[.StreamID]; {
.resetQueued = true
}
}
func ( *http2serverConn) ( http2readFrameResult) bool {
.serveG.check()
:= .err
if != nil {
if == http2ErrFrameTooLarge {
.goAway(http2ErrCodeFrameSize)
return true // goAway will close the loop
}
:= == io.EOF || == io.ErrUnexpectedEOF || http2isClosedConnError()
return false
}
} else {
:= .f
if http2VerboseLogs {
.vlogf("http2: server read frame %v", http2summarizeFrame())
}
= .processFrame()
if == nil {
return true
}
}
switch ev := .(type) {
case http2StreamError:
.resetStream()
return true
case http2goAwayFlowError:
.goAway(http2ErrCodeFlowControl)
return true
case http2ConnectionError:
.logf("http2: server connection error from %v: %v", .conn.RemoteAddr(), )
.goAway(http2ErrCode())
return true // goAway will handle shutdown
default:
if .err != nil {
.vlogf("http2: server closing client connection; error reading frame from client %s: %v", .conn.RemoteAddr(), )
} else {
.logf("http2: server closing client connection: %v", )
}
return false
}
}
func ( *http2serverConn) ( http2Frame) error {
.serveG.check()
if !.sawFirstSettings {
if , := .(*http2SettingsFrame); ! {
return http2ConnectionError(http2ErrCodeProtocol)
}
.sawFirstSettings = true
}
switch f := .(type) {
case *http2SettingsFrame:
return .processSettings()
case *http2MetaHeadersFrame:
return .processHeaders()
case *http2WindowUpdateFrame:
return .processWindowUpdate()
case *http2PingFrame:
return .processPing()
case *http2DataFrame:
return .processData()
case *http2RSTStreamFrame:
return .processResetStream()
case *http2PriorityFrame:
return .processPriority()
case *http2GoAwayFrame:
return .processGoAway()
return http2ConnectionError(http2ErrCodeProtocol)
default:
.vlogf("http2: server ignoring frame: %v", .Header())
return nil
}
}
func ( *http2serverConn) ( *http2PingFrame) error {
.serveG.check()
return nil
}
return http2ConnectionError(http2ErrCodeProtocol)
}
if .inGoAway && .goAwayCode != http2ErrCodeNo {
return nil
}
.writeFrame(http2FrameWriteRequest{write: http2writePingAck{}})
return nil
}
func ( *http2serverConn) ( *http2WindowUpdateFrame) error {
.serveG.check()
switch {
case .StreamID != 0: // stream-level flow control
, := .state(.StreamID)
return http2ConnectionError(http2ErrCodeProtocol)
}
return nil
}
if !.flow.add(int32(.Increment)) {
return http2streamError(.StreamID, http2ErrCodeFlowControl)
}
default: // connection-level flow control
if !.flow.add(int32(.Increment)) {
return http2goAwayFlowError{}
}
}
.scheduleFrameWrite()
return nil
}
func ( *http2serverConn) ( *http2RSTStreamFrame) error {
.serveG.check()
, := .state(.StreamID)
return http2ConnectionError(http2ErrCodeProtocol)
}
if != nil {
.cancelCtx()
.closeStream(, http2streamError(.StreamID, .ErrCode))
}
return nil
}
func ( *http2serverConn) ( *http2stream, error) {
.serveG.check()
if .state == http2stateIdle || .state == http2stateClosed {
panic(fmt.Sprintf("invariant; can't close stream in state %v", .state))
}
.state = http2stateClosed
if .writeDeadline != nil {
.writeDeadline.Stop()
}
if .isPushed() {
.curPushedStreams--
} else {
.curClientStreams--
}
delete(.streams, .id)
if len(.streams) == 0 {
.setConnState(StateIdle)
if .srv.IdleTimeout != 0 {
.idleTimer.Reset(.srv.IdleTimeout)
}
if http2h1ServerKeepAlivesDisabled(.hs) {
.startGracefulShutdownInternal()
}
}
.sendWindowUpdate(nil, .Len())
.CloseWithError()
}
.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
.writeSched.CloseStream(.id)
}
func ( *http2serverConn) ( *http2SettingsFrame) error {
.serveG.check()
if .IsAck() {
.unackedSettings--
return http2ConnectionError(http2ErrCodeProtocol)
}
return nil
}
return http2ConnectionError(http2ErrCodeProtocol)
}
if := .ForeachSetting(.processSetting); != nil {
return
.needToSendSettingsAck = true
.scheduleFrameWrite()
return nil
}
func ( *http2serverConn) ( http2Setting) error {
.serveG.check()
if := .Valid(); != nil {
return
}
if http2VerboseLogs {
.vlogf("http2: server processing setting %v", )
}
switch .ID {
case http2SettingHeaderTableSize:
.headerTableSize = .Val
.hpackEncoder.SetMaxDynamicTableSize(.Val)
case http2SettingEnablePush:
.pushEnabled = .Val != 0
case http2SettingMaxConcurrentStreams:
.clientMaxStreams = .Val
case http2SettingInitialWindowSize:
return .processSettingInitialWindowSize(.Val)
case http2SettingMaxFrameSize:
.maxFrameSize = int32(.Val) // the maximum valid s.Val is < 2^31
case http2SettingMaxHeaderListSize:
.peerMaxHeaderListSize = .Val
if http2VerboseLogs {
.vlogf("http2: server ignoring unknown setting %v", )
}
}
return nil
}
func ( *http2serverConn) ( uint32) error {
:= .initialStreamSendWindowSize
.initialStreamSendWindowSize = int32()
:= int32() - // may be negative
for , := range .streams {
return http2ConnectionError(http2ErrCodeFlowControl)
}
}
return nil
}
func ( *http2serverConn) ( *http2DataFrame) error {
.serveG.check()
if .inGoAway && .goAwayCode != http2ErrCodeNo {
return nil
}
:= .Data()
return http2ConnectionError(http2ErrCodeProtocol)
}
if .inflow.available() < int32(.Length) {
return http2streamError(, http2ErrCodeFlowControl)
return nil
}
return http2streamError(, http2ErrCodeStreamClosed)
}
if .body == nil {
panic("internal error: should have a body in this state")
}
if .declBodyBytes != -1 && .bodyBytes+int64(len()) > .declBodyBytes {
return http2streamError(, http2ErrCodeProtocol)
}
if .inflow.available() < int32(.Length) {
return http2streamError(, http2ErrCodeFlowControl)
}
.inflow.take(int32(.Length))
if len() > 0 {
, := .body.Write()
if != nil {
.sendWindowUpdate(nil, int(.Length)-)
return http2streamError(, http2ErrCodeStreamClosed)
}
if != len() {
panic("internal error: bad Writer")
}
.bodyBytes += int64(len())
}
if := int32(.Length) - int32(len()); > 0 {
.sendWindowUpdate32(nil, )
.sendWindowUpdate32(, )
}
}
if .StreamEnded() {
.endStream()
}
return nil
}
func ( *http2serverConn) ( *http2GoAwayFrame) error {
.serveG.check()
if .ErrCode != http2ErrCodeNo {
.logf("http2: received GOAWAY %+v, starting graceful shutdown", )
} else {
.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", )
}
.pushEnabled = false
return nil
}
func ( *http2stream) () bool {
return .id%2 == 0
}
func ( *http2stream) () {
:= .sc
.serveG.check()
if .declBodyBytes != -1 && .declBodyBytes != .bodyBytes {
.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
.declBodyBytes, .bodyBytes))
} else {
.body.closeWithErrorAndCode(io.EOF, .copyTrailersToHandlerRequest)
.body.CloseWithError(io.EOF)
}
.state = http2stateHalfClosedRemote
}
func ( *http2stream) () {
for , := range .trailer {
.reqTrailer[] =
}
}
}
func ( *http2stream) () {
.sc.writeFrameFromHandler(http2FrameWriteRequest{write: http2streamError(.id, http2ErrCodeInternal)})
}
func ( *http2serverConn) ( *http2MetaHeadersFrame) error {
.serveG.check()
:= .StreamID
return nil
if %2 != 1 {
return http2ConnectionError(http2ErrCodeProtocol)
return nil
if .state == http2stateHalfClosedRemote {
return http2streamError(, http2ErrCodeStreamClosed)
}
return .processTrailerHeaders()
}
if <= .maxClientStreamID {
return http2ConnectionError(http2ErrCodeProtocol)
}
.maxClientStreamID =
if .idleTimer != nil {
.idleTimer.Stop()
}
if .curClientStreams+1 > .advMaxStreams {
return http2streamError(, http2ErrCodeProtocol)
return http2streamError(, http2ErrCodeRefusedStream)
}
:= http2stateOpen
if .StreamEnded() {
= http2stateHalfClosedRemote
}
:= .newStream(, 0, )
if .HasPriority() {
if := http2checkPriority(.StreamID, .Priority); != nil {
return
}
.writeSched.AdjustStream(.id, .Priority)
}
, , := .newWriterAndRequest(, )
if != nil {
return
}
.reqTrailer = .Trailer
if .reqTrailer != nil {
.trailer = make(Header)
}
.body = .Body.(*http2requestBody).pipe // may be nil
.declBodyBytes = .ContentLength
:= .handler.ServeHTTP
= http2handleHeaderListTooLong
} else if := http2checkValidHTTP2RequestHeaders(.Header); != nil {
= http2new400Handler()
}
if .hs.ReadTimeout != 0 {
.conn.SetReadDeadline(time.Time{})
}
go .runHandler(, , )
return nil
}
func ( *http2stream) ( *http2MetaHeadersFrame) error {
:= .sc
.serveG.check()
if .gotTrailerHeader {
return http2ConnectionError(http2ErrCodeProtocol)
}
.gotTrailerHeader = true
if !.StreamEnded() {
return http2streamError(.id, http2ErrCodeProtocol)
}
if len(.PseudoFields()) > 0 {
return http2streamError(.id, http2ErrCodeProtocol)
}
if .trailer != nil {
for , := range .RegularFields() {
:= .canonicalHeader(.Name)
return http2streamError(.id, http2ErrCodeProtocol)
}
.trailer[] = append(.trailer[], .Value)
}
}
.endStream()
return nil
}
func ( uint32, http2PriorityParam) error {
return http2streamError(, http2ErrCodeProtocol)
}
return nil
}
func ( *http2serverConn) ( *http2PriorityFrame) error {
if .inGoAway {
return nil
}
if := http2checkPriority(.StreamID, .http2PriorityParam); != nil {
return
}
.writeSched.AdjustStream(.StreamID, .http2PriorityParam)
return nil
}
func ( *http2serverConn) (, uint32, http2streamState) *http2stream {
.serveG.check()
if == 0 {
panic("internal error: cannot create stream with id 0")
}
, := context.WithCancel(.baseCtx)
:= &http2stream{
sc: ,
id: ,
state: ,
ctx: ,
cancelCtx: ,
}
.cw.Init()
.flow.conn = &.flow // link to conn-level counter
.flow.add(.initialStreamSendWindowSize)
.inflow.conn = &.inflow // link to conn-level counter
.inflow.add(.srv.initialStreamRecvWindowSize())
if .hs.WriteTimeout != 0 {
.writeDeadline = time.AfterFunc(.hs.WriteTimeout, .onWriteTimeout)
}
.streams[] =
.writeSched.OpenStream(.id, http2OpenStreamOptions{PusherID: })
if .isPushed() {
.curPushedStreams++
} else {
.curClientStreams++
}
if .curOpenStreams() == 1 {
.setConnState(StateActive)
}
return
}
func ( *http2serverConn) ( *http2stream, *http2MetaHeadersFrame) (*http2responseWriter, *Request, error) {
.serveG.check()
:= http2requestParam{
method: .PseudoValue("method"),
scheme: .PseudoValue("scheme"),
authority: .PseudoValue("authority"),
path: .PseudoValue("path"),
}
:= .method == "CONNECT"
if {
if .path != "" || .scheme != "" || .authority == "" {
return nil, nil, http2streamError(.StreamID, http2ErrCodeProtocol)
}
return nil, nil, http2streamError(.StreamID, http2ErrCodeProtocol)
}
:= !.StreamEnded()
return nil, nil, http2streamError(.StreamID, http2ErrCodeProtocol)
}
.header = make(Header)
for , := range .RegularFields() {
.header.Add(.canonicalHeader(.Name), .Value)
}
if .authority == "" {
.authority = .header.Get("Host")
}
, , := .newWriterAndRequestNoBody(, )
if != nil {
return nil, nil,
}
if {
if , := .header["Content-Length"]; {
if , := strconv.ParseUint([0], 10, 63); == nil {
.ContentLength = int64()
} else {
.ContentLength = 0
}
} else {
.ContentLength = -1
}
.Body.(*http2requestBody).pipe = &http2pipe{
b: &http2dataBuffer{expected: .ContentLength},
}
}
return , , nil
}
type http2requestParam struct {
method string
scheme, authority, path string
header Header
}
func ( *http2serverConn) ( *http2stream, http2requestParam) (*http2responseWriter, *Request, error) {
.serveG.check()
var *tls.ConnectionState // nil if not scheme https
if .scheme == "https" {
= .tlsState
}
:= .header.Get("Expect") == "100-continue"
if {
.header.Del("Expect")
var Header
for , := range .header["Trailer"] {
for , := range strings.Split(, ",") {
= CanonicalHeaderKey(textproto.TrimString())
switch {
default:
if == nil {
= make(Header)
}
[] = nil
}
}
}
delete(.header, "Trailer")
var *url.URL
var string
if .method == "CONNECT" {
= &url.URL{Host: .authority}
= .authority // mimic HTTP/1 server behavior
} else {
var error
, = url.ParseRequestURI(.path)
if != nil {
return nil, nil, http2streamError(.id, http2ErrCodeProtocol)
}
= .path
}
:= &http2requestBody{
conn: ,
stream: ,
needsContinue: ,
}
:= &Request{
Method: .method,
URL: ,
RemoteAddr: .remoteAddrStr,
Header: .header,
RequestURI: ,
Proto: "HTTP/2.0",
ProtoMajor: 2,
ProtoMinor: 0,
TLS: ,
Host: .authority,
Body: ,
Trailer: ,
}
= .WithContext(.ctx)
:= http2responseWriterStatePool.Get().(*http2responseWriterState)
:= .bw
* = http2responseWriterState{} // zero all the fields
.conn =
.bw =
.bw.Reset(http2chunkWriter{})
.stream =
.req =
.body =
:= &http2responseWriter{rws: }
return , , nil
}
func ( *http2serverConn) ( *http2responseWriter, *Request, func(ResponseWriter, *Request)) {
:= true
defer func() {
.rws.stream.cancelCtx()
if {
:= recover()
.writeFrameFromHandler(http2FrameWriteRequest{
write: http2handlerPanicRST{.rws.stream.id},
stream: .rws.stream,
if != nil && != ErrAbortHandler {
const = 64 << 10
:= make([]byte, )
= [:runtime.Stack(, false)]
.logf("http2: panic serving %v: %v\n%s", .conn.RemoteAddr(), , )
}
return
}
.handlerDone()
}()
(, )
= false
}
const = 431 // only in Go 1.6+
.WriteHeader()
io.WriteString(, "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>")
}
func ( *http2serverConn) ( *http2stream, *http2writeResHeaders) error {
.serveG.checkNotOn() // NOT on
var chan error
= http2errChanPool.Get().(chan error)
}
if := .writeFrameFromHandler(http2FrameWriteRequest{
write: ,
stream: ,
done: ,
}); != nil {
return
}
if != nil {
select {
case := <-:
http2errChanPool.Put()
return
case <-.doneServing:
return http2errClientDisconnected
case <-.cw:
return http2errStreamClosed
}
}
return nil
}
func ( *http2serverConn) ( *http2stream) {
.writeFrameFromHandler(http2FrameWriteRequest{
write: http2write100ContinueHeadersFrame{.id},
stream: ,
})
}
type http2bodyReadMsg struct {
st *http2stream
n int
}
func ( *http2serverConn) ( *http2stream, int, error) {
.serveG.checkNotOn() // NOT on
if > 0 {
select {
case .bodyReadCh <- http2bodyReadMsg{, }:
case <-.doneServing:
}
}
}
func ( *http2serverConn) ( *http2stream, int) {
.serveG.check()
.sendWindowUpdate(nil, ) // conn-level
.sendWindowUpdate(, )
}
}
func ( *http2serverConn) ( *http2stream, int) {
const = 1<<31 - 1
for >= {
.sendWindowUpdate32(, )
-=
}
.sendWindowUpdate32(, int32())
}
func ( *http2serverConn) ( *http2stream, int32) {
.serveG.check()
if == 0 {
return
}
if < 0 {
panic("negative update")
}
var uint32
if != nil {
= .id
}
.writeFrame(http2FrameWriteRequest{
write: http2writeWindowUpdate{streamID: , n: uint32()},
stream: ,
})
var bool
if == nil {
= .inflow.add()
} else {
= .inflow.add()
}
if ! {
panic("internal error; sent too many window updates without decrements?")
}
}
type http2requestBody struct {
_ http2incomparable
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 ( *http2requestBody) () error {
if .pipe != nil && !.closed {
.pipe.BreakWithError(http2errClosedBody)
}
.closed = true
return nil
}
func ( *http2requestBody) ( []byte) ( int, error) {
if .needsContinue {
.needsContinue = false
.conn.write100ContinueHeaders(.stream)
}
if .pipe == nil || .sawEOF {
return 0, io.EOF
}
, = .pipe.Read()
if == io.EOF {
.sawEOF = true
}
if .conn == nil && http2inTests {
return
}
.conn.noteBodyReadFromHandler(.stream, , )
return
}
type http2responseWriter struct {
rws *http2responseWriterState
}
var (
_ CloseNotifier = (*http2responseWriter)(nil)
_ Flusher = (*http2responseWriter)(nil)
_ http2stringWriter = (*http2responseWriter)(nil)
)
stream *http2stream
req *Request
body *http2requestBody // to close at end of request, if DATA frames didn't
conn *http2serverConn
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 ( http2chunkWriter) ( []byte) ( int, error) { return .rws.writeChunk() }
func ( *http2responseWriterState) () bool { return len(.trailers) > 0 }
func ( *http2responseWriterState) () bool {
for , := range .trailers {
if , := .handlerHeader[]; {
return true
}
}
return false
}
func ( *http2responseWriterState) ( string) {
= CanonicalHeaderKey()
func ( *http2responseWriterState) ( []byte) ( int, error) {
if !.wroteHeader {
.writeHeader(200)
}
:= .req.Method == "HEAD"
if !.sentHeader {
.sentHeader = true
var , string
if = .snapHeader.Get("Content-Length"); != "" {
.snapHeader.Del("Content-Length")
if , := strconv.ParseUint(, 10, 63); == nil {
.sentContentLen = int64()
} else {
= ""
}
}
if == "" && .handlerDone && http2bodyAllowedForStatus(.status) && (len() > 0 || !) {
= strconv.Itoa(len())
}
:= .snapHeader.Get("Content-Encoding")
:= len() > 0
if ! && ! && http2bodyAllowedForStatus(.status) && len() > 0 {
= DetectContentType()
}
var string
= time.Now().UTC().Format(TimeFormat)
}
for , := range .snapHeader["Trailer"] {
http2foreachHeaderElement(, .declareTrailer)
}
if , := .snapHeader["Connection"]; {
:= .snapHeader.Get("Connection")
delete(.snapHeader, "Connection")
if == "close" {
.conn.startGracefulShutdown()
}
}
:= (.handlerDone && !.hasTrailers() && len() == 0) ||
= .conn.writeHeaders(.stream, &http2writeResHeaders{
streamID: .stream.id,
httpResCode: .status,
h: .snapHeader,
endStream: ,
contentType: ,
contentLength: ,
date: ,
})
if != nil {
.dirty = true
return 0,
}
if {
return 0, nil
}
}
if {
return len(), nil
}
if len() == 0 && !.handlerDone {
return 0, nil
}
if .handlerDone {
.promoteUndeclaredTrailers()
}
:= .hasNonemptyTrailers()
:= .handlerDone && !
if := .conn.writeDataFromHandler(.stream, , ); != nil {
.dirty = true
return 0,
}
}
if .handlerDone && {
= .conn.writeHeaders(.stream, &http2writeResHeaders{
streamID: .stream.id,
h: .handlerHeader,
trailers: .trailers,
endStream: true,
})
if != nil {
.dirty = true
}
return len(),
}
return len(), nil
}
const http2TrailerPrefix = "Trailer:"
func ( *http2responseWriterState) () {
for , := range .handlerHeader {
if !strings.HasPrefix(, http2TrailerPrefix) {
continue
}
:= strings.TrimPrefix(, http2TrailerPrefix)
.declareTrailer()
.handlerHeader[CanonicalHeaderKey()] =
}
if len(.trailers) > 1 {
:= http2sorterPool.Get().(*http2sorter)
.SortStrings(.trailers)
http2sorterPool.Put()
}
}
func ( *http2responseWriter) () {
:= .rws
if == nil {
panic("Header called after Handler finished")
}
if .bw.Buffered() > 0 {
return
}
.writeChunk(nil)
}
}
func ( *http2responseWriter) () <-chan bool {
:= .rws
if == nil {
panic("CloseNotify called after Handler finished")
}
.closeNotifierMu.Lock()
:= .closeNotifierCh
if == nil {
= make(chan bool, 1)
.closeNotifierCh =
:= .stream.cw
go func() {
.Wait() // wait for close
<- true
}()
}
.closeNotifierMu.Unlock()
return
}
func ( *http2responseWriter) () Header {
:= .rws
if == nil {
panic("Header called after Handler finished")
}
if .handlerHeader == nil {
.handlerHeader = make(Header)
}
return .handlerHeader
}
if < 100 || > 999 {
panic(fmt.Sprintf("invalid WriteHeader code %v", ))
}
}
func ( *http2responseWriter) ( int) {
:= .rws
if == nil {
panic("WriteHeader called after Handler finished")
}
.writeHeader()
}
func ( *http2responseWriterState) ( int) {
if !.wroteHeader {
http2checkWriteHeaderCode()
.wroteHeader = true
.status =
if len(.handlerHeader) > 0 {
.snapHeader = http2cloneHeader(.handlerHeader)
}
}
}
func ( Header) Header {
:= make(Header, len())
for , := range {
:= make([]string, len())
copy(, )
[] =
}
return
}
func ( *http2responseWriter) ( int, []byte, string) ( int, error) {
:= .rws
if == nil {
panic("Write called after Handler finished")
}
if !.wroteHeader {
.WriteHeader(200)
}
if !http2bodyAllowedForStatus(.status) {
return 0, ErrBodyNotAllowed
}
.wroteBytes += int64(len()) + int64(len()) // only one can be set
return 0, errors.New("http2: handler wrote more than declared Content-Length")
}
if != nil {
return .bw.Write()
} else {
return .bw.WriteString()
}
}
func ( *http2responseWriter) () {
:= .rws
:= .dirty
.handlerDone = true
.Flush()
.rws = nil
var (
http2ErrRecursivePush = errors.New("http2: recursive push not allowed")
http2ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
)
var _ Pusher = (*http2responseWriter)(nil)
func ( *http2responseWriter) ( string, *PushOptions) error {
:= .rws.stream
:= .sc
.serveG.checkNotOn()
if .isPushed() {
return http2ErrRecursivePush
}
if == nil {
= new(PushOptions)
}
, := url.Parse()
if != nil {
return
}
if .Scheme == "" {
if !strings.HasPrefix(, "/") {
return fmt.Errorf("target must be an absolute URL or an absolute path: %q", )
}
.Scheme =
.Host = .rws.req.Host
} else {
if .Scheme != {
return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", .Scheme, )
}
if .Host == "" {
return errors.New("URL must have a host")
}
}
for := range .Header {
if strings.HasPrefix(, ":") {
return fmt.Errorf("promised request headers cannot include pseudo header %q", )
if .Method != "GET" && .Method != "HEAD" {
return fmt.Errorf("method %q must be GET or HEAD", .Method)
}
:= &http2startPushRequest{
parent: ,
method: .Method,
url: ,
header: http2cloneHeader(.Header),
done: http2errChanPool.Get().(chan error),
}
select {
case <-.doneServing:
return http2errClientDisconnected
case <-.cw:
return http2errStreamClosed
case .serveMsgCh <- :
}
select {
case <-.doneServing:
return http2errClientDisconnected
case <-.cw:
return http2errStreamClosed
case := <-.done:
http2errChanPool.Put(.done)
return
}
}
type http2startPushRequest struct {
parent *http2stream
method string
url *url.URL
header Header
done chan error
}
func ( *http2serverConn) ( *http2startPushRequest) {
.serveG.check()
.done <- http2errStreamClosed
return
}
if !.pushEnabled {
.done <- ErrNotSupported
return
}
if !.pushEnabled {
return 0, ErrNotSupported
if .curPushedStreams+1 > .clientMaxStreams {
return 0, http2ErrPushLimitReached
}
if .maxPushPromiseID+2 >= 1<<31 {
.startGracefulShutdownInternal()
return 0, http2ErrPushLimitReached
}
.maxPushPromiseID += 2
:= .maxPushPromiseID
:= .newStream(, .parent.id, http2stateHalfClosedRemote)
, , := .newWriterAndRequestNoBody(, http2requestParam{
method: .method,
scheme: .url.Scheme,
authority: .url.Host,
path: .url.RequestURI(),
header: http2cloneHeader(.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
})
panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", .url, ))
}
go .runHandler(, , .handler.ServeHTTP)
return , nil
}
.writeFrame(http2FrameWriteRequest{
write: &http2writePushPromise{
streamID: .parent.id,
method: .method,
url: .url,
h: .header,
allocatePromisedID: ,
},
stream: .parent,
done: .done,
})
}
func ( string, func(string)) {
= textproto.TrimString()
if == "" {
return
}
if !strings.Contains(, ",") {
()
return
}
for , := range strings.Split(, ",") {
if = textproto.TrimString(); != "" {
()
}
}
}
var http2connHeaders = []string{
"Connection",
"Keep-Alive",
"Proxy-Connection",
"Transfer-Encoding",
"Upgrade",
}
func ( Header) error {
for , := range http2connHeaders {
if , := []; {
return fmt.Errorf("request header %q is not valid in HTTP/2", )
}
}
:= ["Te"]
if len() > 0 && (len() > 1 || ([0] != "trailers" && [0] != "")) {
return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
}
return nil
}
func ( error) HandlerFunc {
return func( ResponseWriter, *Request) {
Error(, .Error(), StatusBadRequest)
}
}
http2transportDefaultConnFlow = 1 << 30
http2transportDefaultStreamFlow = 4 << 20
http2transportDefaultStreamMinRefresh = 4 << 10
http2defaultUserAgent = "Go-http-client/2.0"
)
t1 *Transport
connPoolOnce sync.Once
connPoolOrDef http2ClientConnPool // non-nil version of ConnPool
}
func ( *http2Transport) () uint32 {
if .MaxHeaderListSize == 0 {
return 10 << 20
}
if .MaxHeaderListSize == 0xffffffff {
return 0
}
return .MaxHeaderListSize
}
func ( *http2Transport) () bool {
return .DisableCompression || (.t1 != nil && .t1.DisableCompression)
}
func ( *http2Transport) () time.Duration {
if .PingTimeout == 0 {
return 15 * time.Second
}
return .PingTimeout
}
func ( *Transport) error {
, := http2ConfigureTransports()
return
}
func ( *Transport) (*http2Transport, error) {
return http2configureTransports()
}
func ( *Transport) (*http2Transport, error) {
:= new(http2clientConnPool)
:= &http2Transport{
ConnPool: http2noDialClientConnPool{},
t1: ,
}
.t =
if := http2registerHTTPSProtocol(, http2noDialH2RoundTripper{}); != nil {
return nil,
}
if .TLSClientConfig == nil {
.TLSClientConfig = new(tls.Config)
}
if !http2strSliceContains(.TLSClientConfig.NextProtos, "h2") {
.TLSClientConfig.NextProtos = append([]string{"h2"}, .TLSClientConfig.NextProtos...)
}
if !http2strSliceContains(.TLSClientConfig.NextProtos, "http/1.1") {
.TLSClientConfig.NextProtos = append(.TLSClientConfig.NextProtos, "http/1.1")
}
:= func( string, *tls.Conn) RoundTripper {
:= http2authorityAddr("https", )
if , := .addConnIfNeeded(, , ); != nil {
go .Close()
return http2erringRoundTripper{}
go .Close()
}
return
}
if := .TLSNextProto; len() == 0 {
.TLSNextProto = map[string]func(string, *tls.Conn) RoundTripper{
"h2": ,
}
} else {
["h2"] =
}
return , nil
}
func ( *http2Transport) () http2ClientConnPool {
.connPoolOnce.Do(.initConnPool)
return .connPoolOrDef
}
func ( *http2Transport) () {
if .ConnPool != nil {
.connPoolOrDef = .ConnPool
} else {
.connPoolOrDef = &http2clientConnPool{t: }
}
}
type http2ClientConn struct {
t *http2Transport
tconn net.Conn // usually *tls.Conn, except specialized impls
tlsState *tls.ConnectionState // nil only for specialized impls
reused uint32 // whether conn is being reused; atomic
singleUse bool // whether being used for a single http.Request
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
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
}
type http2clientStream struct {
cc *http2ClientConn
req *Request
trace *httptrace.ClientTrace // 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
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
}
func ( *http2clientStream) () func(int, textproto.MIMEHeader) error {
if := http2got1xxFuncForTests; != nil {
return
}
return http2traceGot1xxResponseFunc(.trace)
}
func ( *http2clientStream) ( *Request) {
if := http2awaitRequestCancel(, .done); != nil {
.cancelStream()
.bufPipe.CloseWithError()
}
}
func ( *http2clientStream) () {
:= .cc
.mu.Lock()
:= .didReset
.didReset = true
.mu.Unlock()
if ! {
.writeStreamReset(.ID, http2ErrCodeCancel, nil)
.forgetStreamID(.ID)
}
}
func ( *http2clientStream) () error {
select {
case <-.peerReset:
return .resetErr
case <-.done:
return http2errStreamClosed
default:
return nil
}
}
func ( *http2clientStream) () bool {
:= .cc
.mu.Lock()
defer .mu.Unlock()
return .startedWrite
}
func ( *http2clientStream) ( error) {
if == nil {
panic("nil error")
}
:= .cc
.mu.Lock()
.stopReqBody =
.cond.Broadcast()
.mu.Unlock()
}
type http2stickyErrWriter struct {
w io.Writer
err *error
}
func ( http2stickyErrWriter) ( []byte) ( int, error) {
if *.err != nil {
return 0, *.err
}
, = .w.Write()
*.err =
return
}
type http2noCachedConnError struct{}
func (http2noCachedConnError) () {}
func (http2noCachedConnError) () string { return "http2: no cached connection was available" }
func ( error) bool {
, := .(interface{ () })
return
}
var http2ErrNoCachedConn error = http2noCachedConnError{}
OnlyCachedConn bool
}
func ( *http2Transport) ( *Request) (*Response, error) {
return .RoundTripOpt(, http2RoundTripOpt{})
}
func ( *http2Transport) ( *Request, http2RoundTripOpt) (*Response, error) {
if !(.URL.Scheme == "https" || (.URL.Scheme == "http" && .AllowHTTP)) {
return nil, errors.New("http2: unsupported scheme")
}
:= http2authorityAddr(.URL.Scheme, .URL.Host)
for := 0; ; ++ {
, := .connPool().GetClientConn(, )
if != nil {
.vlogf("http2: Transport failed to get client conn for %s: %v", , )
return nil,
}
:= !atomic.CompareAndSwapUint32(&.reused, 0, 1)
http2traceGotConn(, , )
, , := .roundTrip()
if != nil && <= 6 {
func ( *http2Transport) () {
if , := .connPool().(http2clientConnPoolIdleCloser); {
.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")
)
if ! {
return , nil
}
return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", )
}
func ( error) bool {
if == http2errClientConnUnusable || == http2errClientConnGotGoAway {
return true
}
if , := .(http2StreamError); {
return .Code == http2ErrCodeRefusedStream
}
return false
}
func ( *http2Transport) ( string, bool) (*http2ClientConn, error) {
, , := net.SplitHostPort()
if != nil {
return nil,
}
, := .dialTLS()("tcp", , .newTLSConfig())
if != nil {
return nil,
}
return .newClientConn(, )
}
func ( *http2Transport) ( string) *tls.Config {
:= new(tls.Config)
if .TLSClientConfig != nil {
* = *.TLSClientConfig.Clone()
}
if !http2strSliceContains(.NextProtos, http2NextProtoTLS) {
.NextProtos = append([]string{http2NextProtoTLS}, .NextProtos...)
}
if .ServerName == "" {
.ServerName =
}
return
}
func ( *http2Transport) () func(string, string, *tls.Config) (net.Conn, error) {
if .DialTLS != nil {
return .DialTLS
}
return .dialTLSDefault
}
func ( *http2Transport) (, string, *tls.Config) (net.Conn, error) {
, := tls.Dial(, , )
if != nil {
return nil,
}
if := .Handshake(); != nil {
return nil,
}
if !.InsecureSkipVerify {
if := .VerifyHostname(.ServerName); != nil {
return nil,
}
}
:= .ConnectionState()
if := .NegotiatedProtocol; != http2NextProtoTLS {
return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", , http2NextProtoTLS)
}
if !.NegotiatedProtocolIsMutual {
return nil, errors.New("http2: could not negotiate protocol mutually")
}
return , nil
}
func ( *http2Transport) () bool {
return .t1 != nil && .t1.DisableKeepAlives
}
func ( *http2Transport) () time.Duration {
if .t1 == nil {
return 0
}
return .t1.ExpectContinueTimeout
}
func ( *http2Transport) ( net.Conn) (*http2ClientConn, error) {
return .newClientConn(, .disableKeepAlives())
}
func ( *http2Transport) ( net.Conn, bool) (*http2ClientConn, error) {
:= &http2ClientConn{
t: ,
tconn: ,
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: ,
wantSettingsAck: true,
pings: make(map[[8]byte]chan struct{}),
}
if := .idleConnTimeout(); != 0 {
.idleTimeout =
.idleTimer = time.AfterFunc(, .onIdleTimeout)
}
if http2VerboseLogs {
.vlogf("http2: Transport creating client conn %p to %v", , .RemoteAddr())
}
.cond = sync.NewCond(&.mu)
.flow.add(int32(http2initialWindowSize))
.bw = bufio.NewWriter(http2stickyErrWriter{, &.werr})
.br = bufio.NewReader()
.fr = http2NewFramer(.bw, .br)
.fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
.fr.MaxHeaderListSize = .maxHeaderListSize()
.henc = hpack.NewEncoder(&.hbuf)
if .AllowHTTP {
.nextStreamID = 3
}
if , := .(http2connectionStater); {
:= .ConnectionState()
.tlsState = &
}
:= []http2Setting{
{ID: http2SettingEnablePush, Val: 0},
{ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
}
if := .maxHeaderListSize(); != 0 {
= append(, http2Setting{ID: http2SettingMaxHeaderListSize, Val: })
}
.bw.Write(http2clientPreface)
.fr.WriteSettings(...)
.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow)
.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
.bw.Flush()
if .werr != nil {
.Close()
return nil, .werr
}
go .readLoop()
return , nil
}
func ( *http2ClientConn) () {
, := context.WithTimeout(context.Background(), )
defer ()
:= .Ping()
if != nil {
.closeForLostPing()
.t.connPool().MarkDead()
return
}
}
func ( *http2ClientConn) ( *http2GoAwayFrame) {
.mu.Lock()
defer .mu.Unlock()
:= .goAway
.goAway =
if .goAwayDebug == "" {
.goAwayDebug = string(.DebugData())
}
if != nil && .ErrCode != http2ErrCodeNo {
.goAway.ErrCode = .ErrCode
}
:= .LastStreamID
for , := range .streams {
if > {
select {
case .resc <- http2resAndError{err: http2errClientConnGotGoAway}:
default:
}
}
}
}
func ( *http2ClientConn) () bool {
.mu.Lock()
defer .mu.Unlock()
return .canTakeNewRequestLocked()
}
type http2clientConnIdleState struct {
canTakeNewRequest bool
freshConn bool // whether it's unused by any previous request
}
func ( *http2ClientConn) () http2clientConnIdleState {
.mu.Lock()
defer .mu.Unlock()
return .idleStateLocked()
}
func ( *http2ClientConn) () ( http2clientConnIdleState) {
if .singleUse && .nextStreamID > 1 {
return
}
var bool
= true
} else {
= int64(len(.streams)+1) < int64(.maxConcurrentStreams)
}
.canTakeNewRequest = .goAway == nil && !.closed && !.closing && &&
int64(.nextStreamID)+2*int64(.pendingRequests) < math.MaxInt32 &&
!.tooIdleLocked()
.freshConn = .nextStreamID == 1 && .canTakeNewRequest
return
}
func ( *http2ClientConn) () bool {
:= .idleStateLocked()
return .canTakeNewRequest
}
return .idleTimeout != 0 && !.lastIdle.IsZero() && time.Since(.lastIdle.Round(0)) > .idleTimeout
}
func ( *http2ClientConn) () {
.closeIfIdle()
}
func ( *http2ClientConn) () {
.mu.Lock()
if len(.streams) > 0 {
.mu.Unlock()
return
}
.closed = true
.mu.Unlock()
if http2VerboseLogs {
.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", , .singleUse, -2)
}
.tconn.Close()
}
var http2shutdownEnterWaitStateHook = func() {}
func ( *http2ClientConn) ( context.Context) error {
if := .sendGoAway(); != nil {
return
return nil
:= .nextStreamID
if := .fr.WriteGoAway(, http2ErrCodeNo, nil); != nil {
return
}
if := .bw.Flush(); != nil {
return
func ( *http2ClientConn) () error {
:= errors.New("http2: client connection force closed via ClientConn.Close")
return .closeForError()
}
func ( *http2ClientConn) () error {
:= errors.New("http2: client connection lost")
return .closeForError()
}
const http2maxAllocFrameSize = 512 << 10
func ( *http2ClientConn) () []byte {
.mu.Lock()
:= .maxFrameSize
if > http2maxAllocFrameSize {
= http2maxAllocFrameSize
}
for , := range .freeBuf {
if len() >= int() {
.freeBuf[] = nil
.mu.Unlock()
return [:]
}
}
.mu.Unlock()
return make([]byte, )
}
func ( *http2ClientConn) ( []byte) {
.mu.Lock()
defer .mu.Unlock()
const = 4 // arbitrary; 4 concurrent requests per conn? investigate.
if len(.freeBuf) < {
.freeBuf = append(.freeBuf, )
return
}
for , := range .freeBuf {
if == nil {
.freeBuf[] =
return
}
}
var http2errRequestCanceled = errors.New("net/http: request canceled")
func ( *Request) (string, error) {
:= make([]string, 0, len(.Trailer))
for := range .Trailer {
= CanonicalHeaderKey()
switch {
case "Transfer-Encoding", "Trailer", "Content-Length":
return "", fmt.Errorf("invalid Trailer key %q", )
}
= append(, )
}
if len() > 0 {
sort.Strings()
return strings.Join(, ","), nil
}
return "", nil
}
func ( *http2ClientConn) () time.Duration {
if .t.t1 != nil {
return .t.t1.ResponseHeaderTimeout
return 0
}
func ( *Request) error {
if := .Header.Get("Upgrade"); != "" {
return fmt.Errorf("http2: invalid Upgrade request header: %q", .Header["Upgrade"])
}
if := .Header["Transfer-Encoding"]; len() > 0 && (len() > 1 || [0] != "" && [0] != "chunked") {
return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", )
}
if := .Header["Connection"]; len() > 0 && (len() > 1 || [0] != "" && !strings.EqualFold([0], "close") && !strings.EqualFold([0], "keep-alive")) {
return fmt.Errorf("http2: invalid Connection request header: %q", )
}
return nil
}
func ( *Request) int64 {
if .Body == nil || .Body == NoBody {
return 0
}
if .ContentLength != 0 {
return .ContentLength
}
return -1
}
func ( *http2ClientConn) ( *Request) (*Response, error) {
, , := .roundTrip()
return ,
}
func ( *http2ClientConn) ( *Request) ( *Response, bool, error) {
if := http2checkConnHeaders(); != nil {
return nil, false,
}
if .idleTimer != nil {
.idleTimer.Stop()
}
, := http2commaSeparatedTrailers()
if != nil {
return nil, false,
}
:= != ""
.mu.Lock()
if := .awaitOpenSlotForRequest(); != nil {
.mu.Unlock()
return nil, false,
}
:= .Body
:= http2actualContentLength()
:= != 0
= true
}
, := .encodeHeaders(, , , )
if != nil {
.mu.Unlock()
return nil, false,
}
:= .newStream()
.req =
.trace = httptrace.ContextClientTrace(.Context())
.requestedGzip =
:= .t.getBodyWriterState(, )
.on100 = .on100
defer func() {
.wmu.Lock()
:= .werr
.wmu.Unlock()
if != nil {
.Close()
}
}()
.wmu.Lock()
:= ! && !
:= .writeHeaders(.ID, , int(.maxFrameSize), )
.wmu.Unlock()
http2traceWroteHeaders(.trace)
.mu.Unlock()
if != nil {
if {
.Body.Close() // per RoundTripper contract
.cancel()
}
http2traceWroteRequest(.trace, )
return nil, false,
}
var <-chan time.Time
if {
.scheduleBodyWrite()
} else {
http2traceWroteRequest(.trace, nil)
if := .responseHeaderTimeout(); != 0 {
:= time.NewTimer()
defer .Stop()
= .C
}
}
:= .resc
:= false
:= .Context()
:= func( http2resAndError) (*Response, bool, error) {
:= .res
.cancel()
.abortRequestBodyWrite(http2errStopReqBodyWrite)
if && ! {
<-.resc
}
}
if .err != nil {
.forgetStreamID(.ID)
return nil, .getStartedWrite(), .err
}
.Request =
.TLS = .tlsState
return , false, nil
}
for {
select {
case := <-:
return ()
case <-:
if ! || {
.writeStreamReset(.ID, http2ErrCodeCancel, nil)
} else {
.cancel()
.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
<-.resc
}
.forgetStreamID(.ID)
return nil, .getStartedWrite(), http2errTimeout
case <-.Done():
if ! || {
.writeStreamReset(.ID, http2ErrCodeCancel, nil)
} else {
.cancel()
.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
<-.resc
}
.forgetStreamID(.ID)
return nil, .getStartedWrite(), .Err()
case <-.Cancel:
if ! || {
.writeStreamReset(.ID, http2ErrCodeCancel, nil)
} else {
.cancel()
.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
<-.resc
}
.forgetStreamID(.ID)
return nil, .getStartedWrite(), http2errRequestCanceled
return nil, .getStartedWrite(), .resetErr
case := <-.resc:
select {
case := <-:
return ()
default:
}
if != nil {
.forgetStreamID(.ID)
return nil, .getStartedWrite(),
}
if := .responseHeaderTimeout(); != 0 {
:= time.NewTimer()
defer .Stop()
= .C
}
}
}
}
func ( *http2ClientConn) ( *Request) error {
var chan struct{}
var error // guarded by cc.mu
for {
.lastActive = time.Now()
if .closed || !.canTakeNewRequestLocked() {
if != nil {
close()
}
return http2errClientConnUnusable
}
.lastIdle = time.Time{}
if int64(len(.streams))+1 <= int64(.maxConcurrentStreams) {
if != nil {
close()
}
return nil
if == nil {
= make(chan struct{})
go func() {
if := http2awaitRequestCancel(, ); != nil {
.mu.Lock()
=
.cond.Broadcast()
.mu.Unlock()
}
}()
}
.pendingRequests++
.cond.Wait()
.pendingRequests--
if != nil {
return
}
}
}
func ( *http2ClientConn) ( uint32, bool, int, []byte) error {
:= true // first frame written (HEADERS is first, then CONTINUATION)
for len() > 0 && .werr == nil {
:=
if len() > {
= [:]
}
= [len():]
:= len() == 0
if {
.fr.WriteHeaders(http2HeadersFrameParam{
StreamID: ,
BlockFragment: ,
EndStream: ,
EndHeaders: ,
})
= false
} else {
.fr.WriteContinuation(, , )
}
http2errStopReqBodyWrite = errors.New("http2: aborting request body write")
http2errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")
http2errReqBodyTooLong = errors.New("http2: request body larger than specified content length")
)
func ( *http2clientStream) ( io.Reader, io.Closer) ( error) {
:= .cc
:= false // whether we sent the final DATA frame w/ END_STREAM
:= .frameScratchBuffer()
defer .putFrameScratchBuffer()
defer func() {
var int
, = .Read([:])
-= int64()
}
if < 0 {
= http2errReqBodyTooLong
.writeStreamReset(.ID, http2ErrCodeCancel, )
return
}
}
if == io.EOF {
= true
= nil
} else if != nil {
.writeStreamReset(.ID, http2ErrCodeCancel, )
return
}
:= [:]
for len() > 0 && == nil {
var int32
, = .awaitFlowControl(len())
switch {
case == http2errStopReqBodyWrite:
return
case == http2errStopReqBodyWriteAndCancel:
.writeStreamReset(.ID, http2ErrCodeCancel, nil)
return
case != nil:
return
}
.wmu.Lock()
:= [:]
= [:]
= && len() == 0 && !
= .fr.WriteData(.ID, , )
return nil
}
var []byte
if {
.mu.Lock()
, = .encodeTrailers()
.mu.Unlock()
if != nil {
.writeStreamReset(.ID, http2ErrCodeInternal, )
.forgetStreamID(.ID)
return
}
}
.mu.Lock()
:= int(.maxFrameSize)
.mu.Unlock()
.wmu.Lock()
defer .wmu.Unlock()
func ( *http2clientStream) ( int) ( int32, error) {
:= .cc
.mu.Lock()
defer .mu.Unlock()
for {
if .closed {
return 0, http2errClientConnClosed
}
if .stopReqBody != nil {
return 0, .stopReqBody
}
if := .checkResetOrDone(); != nil {
return 0,
}
if := .flow.available(); > 0 {
:=
if int() > {
= int32() // can't truncate int; take is int32
}
if > int32(.maxFrameSize) {
= int32(.maxFrameSize)
}
.flow.take()
return , nil
}
.cond.Wait()
}
}
func ( *http2ClientConn) ( *Request, bool, string, int64) ([]byte, error) {
.hbuf.Reset()
:= .Host
if == "" {
= .URL.Host
}
, := httpguts.PunycodeHostPort()
if != nil {
return nil,
}
var string
if .Method != "CONNECT" {
= .URL.RequestURI()
if !http2validPseudoPath() {
:=
= strings.TrimPrefix(, .URL.Scheme+"://"+)
if !http2validPseudoPath() {
if .URL.Opaque != "" {
return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", , .URL.Opaque)
} else {
return nil, fmt.Errorf("invalid request :path %q", )
}
}
}
}
continue
for +1 <= len() && [] == ' ' {
++
}
= [:]
}
if len() > 0 {
("cookie", )
}
}
continue
}
for , := range {
(, )
}
}
if http2shouldSendReqContentLength(.Method, ) {
("content-length", strconv.FormatInt(, 10))
}
if {
("accept-encoding", "gzip")
}
if ! {
("user-agent", http2defaultUserAgent)
}
}
:= uint64(0)
(func(, string) {
:= hpack.HeaderField{Name: , Value: }
+= uint64(.Size())
})
if > .peerMaxHeaderListSize {
return nil, http2errRequestHeaderListSize
}
:= httptrace.ContextClientTrace(.Context())
:= http2traceHasWroteHeaderField()
(func(, string) {
= strings.ToLower()
.writeHeader(, )
if {
http2traceWroteHeaderField(, , )
}
})
return .hbuf.Bytes(), nil
}
func ( *http2ClientConn) ( *Request) ([]byte, error) {
.hbuf.Reset()
:= uint64(0)
for , := range .Trailer {
for , := range {
:= hpack.HeaderField{Name: , Value: }
+= uint64(.Size())
}
}
if > .peerMaxHeaderListSize {
return nil, http2errRequestHeaderListSize
}
:= strings.ToLower()
for , := range {
.writeHeader(, )
}
}
return .hbuf.Bytes(), nil
}
func ( *http2ClientConn) (, string) {
if http2VerboseLogs {
log.Printf("http2: Transport encoding header %q = %q", , )
}
.henc.WriteField(hpack.HeaderField{Name: , Value: })
}
type http2resAndError struct {
_ http2incomparable
res *Response
err error
}
func ( *http2ClientConn) () *http2clientStream {
:= &http2clientStream{
cc: ,
ID: .nextStreamID,
resc: make(chan http2resAndError, 1),
peerReset: make(chan struct{}),
done: make(chan struct{}),
}
.flow.add(int32(.initialWindowSize))
.flow.setConnFlow(&.flow)
.inflow.add(http2transportDefaultStreamFlow)
.inflow.setConnFlow(&.inflow)
.nextStreamID += 2
.streams[.ID] =
return
}
func ( *http2ClientConn) ( uint32) {
.streamByID(, true)
}
func ( *http2ClientConn) ( uint32, bool) *http2clientStream {
.mu.Lock()
defer .mu.Unlock()
:= .streams[]
if && != nil && !.closed {
.lastActive = time.Now()
delete(.streams, )
if len(.streams) == 0 && .idleTimer != nil {
.idleTimer.Reset(.idleTimeout)
.lastIdle = time.Now()
}
type http2clientConnReadLoop struct {
_ http2incomparable
cc *http2ClientConn
closeWhenIdle bool
}
func ( *http2ClientConn) () {
:= &http2clientConnReadLoop{cc: }
defer .cleanup()
.readerErr = .run()
if , := .readerErr.(http2ConnectionError); {
.wmu.Lock()
.fr.WriteGoAway(0, http2ErrCode(), nil)
.wmu.Unlock()
}
}
type http2GoAwayError struct {
LastStreamID uint32
ErrCode http2ErrCode
DebugData string
}
func ( http2GoAwayError) () string {
return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
.LastStreamID, .ErrCode, .DebugData)
}
func ( error) bool {
if == io.EOF {
return true
}
, := .(*net.OpError)
return && .Op == "read"
}
func ( *http2clientConnReadLoop) () {
:= .cc
defer .tconn.Close()
defer .t.connPool().MarkDead()
defer close(.readerDone)
if .idleTimer != nil {
.idleTimer.Stop()
}
:= .readerErr
.mu.Lock()
if .goAway != nil && http2isEOFOrNetReadError() {
= http2GoAwayError{
LastStreamID: .goAway.LastStreamID,
ErrCode: .goAway.ErrCode,
DebugData: .goAwayDebug,
}
} else if == io.EOF {
= io.ErrUnexpectedEOF
}
for , := range .streams {
.bufPipe.CloseWithError() // no-op if already closed
select {
case .resc <- http2resAndError{err: }:
default:
}
close(.done)
}
.closed = true
.cond.Broadcast()
.mu.Unlock()
}
func ( *http2clientConnReadLoop) () error {
:= .cc
.closeWhenIdle = .t.disableKeepAlives() || .singleUse
:= false // ever saw a HEADERS reply
:= false
:= .t.ReadIdleTimeout
var *time.Timer
if != 0 {
= time.AfterFunc(, .healthCheck)
defer .Stop()
}
for {
, := .fr.ReadFrame()
if != nil {
.Reset()
}
if != nil {
.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", , , )
}
if , := .(http2StreamError); {
if := .streamByID(.StreamID, false); != nil {
.cc.writeStreamReset(.ID, .Code, )
.cc.forgetStreamID(.ID)
if .Cause == nil {
.Cause = .fr.errDetail
}
.endStreamError(, )
}
continue
} else if != nil {
return
}
if http2VerboseLogs {
.vlogf("http2: Transport received %s", http2summarizeFrame())
}
if ! {
if , := .(*http2SettingsFrame); ! {
.logf("protocol error: received %T before a SETTINGS frame", )
return http2ConnectionError(http2ErrCodeProtocol)
}
= true
}
:= false // whether frame might transition us to idle
switch f := .(type) {
case *http2MetaHeadersFrame:
= .processHeaders()
= true
= true
case *http2DataFrame:
= .processData()
= true
case *http2GoAwayFrame:
= .processGoAway()
= true
case *http2RSTStreamFrame:
= .processResetStream()
= true
case *http2SettingsFrame:
= .processSettings()
case *http2PushPromiseFrame:
= .processPushPromise()
case *http2WindowUpdateFrame:
= .processWindowUpdate()
case *http2PingFrame:
= .processPing()
default:
.logf("Transport: unhandled response frame type %T", )
}
if != nil {
if http2VerboseLogs {
.vlogf("http2: Transport conn %p received error from processing frame %v: %v", , http2summarizeFrame(), )
}
return
}
if .closeWhenIdle && && {
.closeIfIdle()
}
}
}
func ( *http2clientConnReadLoop) ( *http2MetaHeadersFrame) error {
:= .cc
:= .streamByID(.StreamID, false)
return nil
}
if .req.Body != nil {
defer .forgetStreamID(.StreamID)
} else {
.forgetStreamID(.StreamID)
}
}
if !.firstByte {
http2traceFirstResponseByte(.trace)
}
.firstByte = true
}
if !.pastHeaders {
.pastHeaders = true
} else {
return .processTrailers(, )
}
, := .handleResponse(, )
if != nil {
if , := .(http2ConnectionError); {
return
.cc.writeStreamReset(.StreamID, http2ErrCodeProtocol, )
.forgetStreamID(.ID)
.resc <- http2resAndError{err: }
return nil // return nil from process* funcs to keep conn alive
}
return nil
}
.resTrailer = &.Trailer
.resc <- http2resAndError{res: }
return nil
}
func ( *http2clientConnReadLoop) ( *http2clientStream, *http2MetaHeadersFrame) (*Response, error) {
if .Truncated {
return nil, http2errResponseHeaderListSize
}
:= .PseudoValue("status")
if == "" {
return nil, errors.New("malformed response from server: missing status pseudo header")
}
, := strconv.Atoi()
if != nil {
return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
}
:= .RegularFields()
:= make([]string, len())
:= make(Header, len())
:= &Response{
Proto: "HTTP/2.0",
ProtoMajor: 2,
Header: ,
StatusCode: ,
Status: + " " + StatusText(),
}
for , := range {
:= CanonicalHeaderKey(.Name)
if == "Trailer" {
:= .Trailer
if == nil {
= make(Header)
.Trailer =
}
http2foreachHeaderElement(.Value, func( string) {
[CanonicalHeaderKey()] = nil
})
} else {
:= []
, = [:1:1], [1:]
[0] = .Value
[] =
} else {
[] = append(, .Value)
}
}
}
if >= 100 && <= 199 {
.num1xx++
const = 5 // arbitrary bound on number of informational responses, same as net/http
if .num1xx > {
return nil, errors.New("http2: too many 1xx informational responses")
}
if := .get1xxTraceFunc(); != nil {
if := (, textproto.MIMEHeader()); != nil {
return nil,
}
}
if == 100 {
http2traceGot100Continue(.trace)
if .on100 != nil {
.on100() // forces any write delay timer to fire
}
}
.pastHeaders = false // do it all again
return nil, nil
}
:= .StreamEnded()
:= .req.Method == "HEAD"
if ! || {
.ContentLength = -1
if := .Header["Content-Length"]; len() == 1 {
if , := strconv.ParseUint([0], 10, 63); == nil {
.ContentLength = int64()
}
}
}
if || {
.Body = http2noBody
return , nil
}
.bufPipe = http2pipe{b: &http2dataBuffer{expected: .ContentLength}}
.bytesRemain = .ContentLength
.Body = http2transportResponseBody{}
go .awaitRequestCancel(.req)
if .requestedGzip && .Header.Get("Content-Encoding") == "gzip" {
.Header.Del("Content-Encoding")
.Header.Del("Content-Length")
.ContentLength = -1
.Body = &http2gzipReader{body: .Body}
.Uncompressed = true
}
return , nil
}
func ( *http2clientConnReadLoop) ( *http2clientStream, *http2MetaHeadersFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
.pastTrailers = true
return http2ConnectionError(http2ErrCodeProtocol)
}
return http2ConnectionError(http2ErrCodeProtocol)
}
:= make(Header)
for , := range .RegularFields() {
:= CanonicalHeaderKey(.Name)
[] = append([], .Value)
}
.trailer =
.endStream()
return nil
}
type http2transportResponseBody struct {
cs *http2clientStream
}
func ( http2transportResponseBody) ( []byte) ( int, error) {
:= .cs
:= .cc
if .readErr != nil {
return 0, .readErr
}
, = .cs.bufPipe.Read()
if .bytesRemain != -1 {
if int64() > .bytesRemain {
= int(.bytesRemain)
if == nil {
= errors.New("net/http: server replied with more than declared Content-Length; truncated")
.writeStreamReset(.ID, http2ErrCodeProtocol, )
}
.readErr =
return int(.bytesRemain),
}
.bytesRemain -= int64()
if == io.EOF && .bytesRemain > 0 {
= io.ErrUnexpectedEOF
.readErr =
return ,
}
}
if := .inflow.available(); < http2transportDefaultConnFlow/2 {
= http2transportDefaultConnFlow -
.inflow.add()
}
:= int(.inflow.available()) + .bufPipe.Len()
if < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
= int32(http2transportDefaultStreamFlow - )
.inflow.add()
}
}
if != 0 || != 0 {
.wmu.Lock()
defer .wmu.Unlock()
if != 0 {
.fr.WriteWindowUpdate(0, http2mustUint31())
}
if != 0 {
.fr.WriteWindowUpdate(.ID, http2mustUint31())
}
.bw.Flush()
}
return
}
var http2errClosedResponseBody = errors.New("http2: response body closed")
func ( http2transportResponseBody) () error {
:= .cs
:= .cc
:= .bufPipe.Err() == io.EOF
:= .bufPipe.Len()
if > 0 || ! {
.mu.Lock()
.wmu.Lock()
if ! {
.fr.WriteRSTStream(.ID, http2ErrCodeCancel)
.didReset = true
if > 0 {
.inflow.add(int32())
.fr.WriteWindowUpdate(0, uint32())
}
.bw.Flush()
.wmu.Unlock()
.mu.Unlock()
}
.bufPipe.BreakWithError(http2errClosedResponseBody)
.forgetStreamID(.ID)
return nil
}
func ( *http2clientConnReadLoop) ( *http2DataFrame) error {
:= .cc
:= .streamByID(.StreamID, .StreamEnded())
:= .Data()
if == nil {
.mu.Lock()
:= .nextStreamID
.mu.Unlock()
.logf("http2: Transport received unsolicited DATA frame; closing connection")
return http2ConnectionError(http2ErrCodeProtocol)
if .Length > 0 {
.mu.Lock()
.inflow.add(int32(.Length))
.mu.Unlock()
.wmu.Lock()
.fr.WriteWindowUpdate(0, uint32(.Length))
.bw.Flush()
.wmu.Unlock()
}
return nil
}
if !.firstByte {
.logf("protocol error: received DATA before a HEADERS frame")
.endStreamError(, http2StreamError{
StreamID: .StreamID,
Code: http2ErrCodeProtocol,
})
return nil
}
if .Length > 0 {
if .req.Method == "HEAD" && len() > 0 {
.logf("protocol error: received DATA on a HEAD request")
.endStreamError(, http2StreamError{
StreamID: .StreamID,
Code: http2ErrCodeProtocol,
})
return nil
:= .didReset
if {
+= len()
}
if > 0 {
.inflow.add(int32())
.wmu.Lock()
.fr.WriteWindowUpdate(0, uint32())
if ! {
.inflow.add(int32())
.fr.WriteWindowUpdate(.ID, uint32())
}
.bw.Flush()
.wmu.Unlock()
}
.mu.Unlock()
if len() > 0 && ! {
if , := .bufPipe.Write(); != nil {
.endStreamError(, )
return
}
}
}
if .StreamEnded() {
.endStream()
}
return nil
}
.endStreamError(, nil)
}
func ( *http2clientConnReadLoop) ( *http2clientStream, error) {
var func()
if == nil {
= io.EOF
= .copyTrailers
}
if http2isConnectionCloseRequest(.req) {
.closeWhenIdle = true
}
.bufPipe.closeWithErrorAndCode(, )
select {
case .resc <- http2resAndError{err: }:
default:
}
}
func ( *http2clientStream) () {
for , := range .trailer {
:= .resTrailer
if * == nil {
* = make(Header)
}
(*)[] =
}
}
func ( *http2clientConnReadLoop) ( *http2GoAwayFrame) error {
:= .cc
.t.connPool().MarkDead()
.vlogf("transport got GOAWAY with error code = %v", .ErrCode)
}
.setGoAway()
return nil
}
func ( *http2clientConnReadLoop) ( *http2SettingsFrame) error {
:= .cc
.mu.Lock()
defer .mu.Unlock()
if .IsAck() {
if .wantSettingsAck {
.wantSettingsAck = false
return nil
}
return http2ConnectionError(http2ErrCodeProtocol)
}
:= .ForeachSetting(func( http2Setting) error {
switch .ID {
case http2SettingMaxFrameSize:
.maxFrameSize = .Val
case http2SettingMaxConcurrentStreams:
.maxConcurrentStreams = .Val
case http2SettingMaxHeaderListSize:
.peerMaxHeaderListSize = uint64(.Val)
if .Val > math.MaxInt32 {
return http2ConnectionError(http2ErrCodeFlowControl)
}
.vlogf("Unhandled Setting: %v", )
}
return nil
})
if != nil {
return
}
.wmu.Lock()
defer .wmu.Unlock()
.fr.WriteSettingsAck()
.bw.Flush()
return .werr
}
func ( *http2clientConnReadLoop) ( *http2WindowUpdateFrame) error {
:= .cc
:= .streamByID(.StreamID, false)
if .StreamID != 0 && == nil {
return nil
}
.mu.Lock()
defer .mu.Unlock()
:= &.flow
if != nil {
= &.flow
}
if !.add(int32(.Increment)) {
return http2ConnectionError(http2ErrCodeFlowControl)
}
.cond.Broadcast()
return nil
}
func ( *http2clientConnReadLoop) ( *http2RSTStreamFrame) error {
:= .cc.streamByID(.StreamID, true)
func ( *http2ClientConn) ( context.Context) error {
return .readerErr
}
}
func ( *http2clientConnReadLoop) ( *http2PingFrame) error {
if .IsAck() {
:= .cc
.mu.Lock()
return http2ConnectionError(http2ErrCodeProtocol)
}
.wmu.Lock()
.fr.WriteRSTStream(, )
.bw.Flush()
.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")
)
func ( *http2ClientConn) ( string, ...interface{}) {
.t.logf(, ...)
}
func ( *http2ClientConn) ( string, ...interface{}) {
.t.vlogf(, ...)
}
func ( *http2Transport) ( string, ...interface{}) {
if http2VerboseLogs {
.logf(, ...)
}
}
func ( *http2Transport) ( string, ...interface{}) {
log.Printf(, ...)
}
var http2noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil))
func ( []string, string) bool {
for , := range {
if == {
return true
}
}
return false
}
type http2erringRoundTripper struct{ err error }
func ( http2erringRoundTripper) () error { return .err }
func ( http2erringRoundTripper) (*Request) (*Response, error) { return nil, .err }
type http2gzipReader struct {
_ http2incomparable
body io.ReadCloser // underlying Response.Body
zr *gzip.Reader // lazily-initialized gzip reader
zerr error // sticky error
}
func ( *http2gzipReader) ( []byte) ( int, error) {
if .zerr != nil {
return 0, .zerr
}
if .zr == nil {
.zr, = gzip.NewReader(.body)
if != nil {
.zerr =
return 0,
}
}
return .zr.Read()
}
func ( *http2gzipReader) () error {
return .body.Close()
}
type http2errorReader struct{ err error }
func ( http2errorReader) ( []byte) (int, error) { return 0, .err }
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 ( *http2Transport) ( *http2clientStream, io.Reader) ( http2bodyWriterState) {
.cs =
if == nil {
return
}
:= make(chan error, 1)
.resc =
.fn = func() {
.cc.mu.Lock()
.startedWrite = true
.cc.mu.Unlock()
<- .writeRequestBody(, .req.Body)
}
.delay = .expectContinueTimeout()
if .delay == 0 ||
!httpguts.HeaderValuesContainsToken(
.req.Header["Expect"],
"100-continue") {
return
}
.fnonce = new(sync.Once)
func ( http2bodyWriterState) () {
func ( *Transport, http2noDialH2RoundTripper) ( error) {
defer func() {
if := recover(); != nil {
= fmt.Errorf("%v", )
}
}()
.RegisterProtocol("https", )
return nil
}
type http2noDialH2RoundTripper struct{ *http2Transport }
func ( http2noDialH2RoundTripper) ( *Request) (*Response, error) {
, := .http2Transport.RoundTrip()
if http2isNoCachedConnError() {
return nil, ErrSkipAltProtocol
}
return ,
}
func ( *http2Transport) () time.Duration {
if .t1 != nil {
return .t1.IdleConnTimeout
}
return 0
}
func ( *Request, string) {
:= httptrace.ContextClientTrace(.Context())
if == nil || .GetConn == nil {
return
}
.GetConn()
}
func ( *Request, *http2ClientConn, bool) {
:= httptrace.ContextClientTrace(.Context())
if == nil || .GotConn == nil {
return
}
:= httptrace.GotConnInfo{Conn: .tconn}
.Reused =
.mu.Lock()
.WasIdle = len(.streams) == 0 &&
if .WasIdle && !.lastActive.IsZero() {
.IdleTime = time.Now().Sub(.lastActive)
}
.mu.Unlock()
.GotConn()
}
func ( *httptrace.ClientTrace) {
if != nil && .WroteHeaders != nil {
.WroteHeaders()
}
}
func ( *httptrace.ClientTrace) {
if != nil && .Got100Continue != nil {
.Got100Continue()
}
}
func ( *httptrace.ClientTrace) {
if != nil && .Wait100Continue != nil {
.Wait100Continue()
}
}
func ( *httptrace.ClientTrace, error) {
if != nil && .WroteRequest != nil {
.WroteRequest(httptrace.WroteRequestInfo{Err: })
}
}
func ( *httptrace.ClientTrace) {
if != nil && .GotFirstResponseByte != nil {
.GotFirstResponseByte()
}
}
type http2writeFramer interface {
writeFrame(http2writeContext) error
type http2writeContext interface {
Framer() *http2Framer
Flush() error
func ( http2writeFramer) bool {
switch v := .(type) {
case *http2writeData:
return .endStream
case *http2writeResHeaders:
return .endStream
panic("writeEndsStream called on nil writeFramer")
}
return false
}
type http2flushFrameWriter struct{}
func (http2flushFrameWriter) ( http2writeContext) error {
return .Flush()
}
func (http2flushFrameWriter) ( int) bool { return false }
type http2writeSettings []http2Setting
func ( http2writeSettings) ( int) bool {
const = 6 // uint16 + uint32
return http2frameHeaderLen+*len() <=
}
func ( http2writeSettings) ( http2writeContext) error {
return .Framer().WriteSettings([]http2Setting()...)
}
type http2writeGoAway struct {
maxStreamID uint32
code http2ErrCode
}
func ( *http2writeGoAway) ( http2writeContext) error {
:= .Framer().WriteGoAway(.maxStreamID, .code, nil)
.Flush() // ignore error: we're hanging up on them anyway
return
}
func (*http2writeGoAway) ( int) bool { return false } // flushes
type http2writeData struct {
streamID uint32
p []byte
endStream bool
}
func ( *http2writeData) () string {
return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", .streamID, len(.p), .endStream)
}
func ( *http2writeData) ( http2writeContext) error {
return .Framer().WriteData(.streamID, .endStream, .p)
}
func ( *http2writeData) ( int) bool {
return http2frameHeaderLen+len(.p) <=
}
type http2handlerPanicRST struct {
StreamID uint32
}
func ( http2handlerPanicRST) ( http2writeContext) error {
return .Framer().WriteRSTStream(.StreamID, http2ErrCodeInternal)
}
func ( http2handlerPanicRST) ( int) bool { return http2frameHeaderLen+4 <= }
func ( http2StreamError) ( http2writeContext) error {
return .Framer().WriteRSTStream(.StreamID, .Code)
}
func ( http2StreamError) ( int) bool { return http2frameHeaderLen+4 <= }
type http2writePingAck struct{ pf *http2PingFrame }
func ( http2writePingAck) ( http2writeContext) error {
return .Framer().WritePing(true, .pf.Data)
}
func ( http2writePingAck) ( int) bool {
return http2frameHeaderLen+len(.pf.Data) <=
}
type http2writeSettingsAck struct{}
func (http2writeSettingsAck) ( http2writeContext) error {
return .Framer().WriteSettingsAck()
}
func (http2writeSettingsAck) ( int) bool { return http2frameHeaderLen <= }
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 ( *hpack.Encoder, , string) {
if http2VerboseLogs {
log.Printf("http2: server encoding header %q = %q", , )
}
.WriteField(hpack.HeaderField{Name: , Value: })
}
return false
}
func ( *http2writeResHeaders) ( http2writeContext) error {
, := .HeaderEncoder()
.Reset()
if .httpResCode != 0 {
http2encKV(, ":status", http2httpCodeString(.httpResCode))
}
http2encodeHeaders(, .h, .trailers)
if .contentType != "" {
http2encKV(, "content-type", .contentType)
}
if .contentLength != "" {
http2encKV(, "content-length", .contentLength)
}
if .date != "" {
http2encKV(, "date", .date)
}
:= .Bytes()
if len() == 0 && .trailers == nil {
panic("unexpected empty hpack")
}
return http2splitHeaderBlock(, , .writeHeaderBlock)
}
func ( *http2writeResHeaders) ( http2writeContext, []byte, , bool) error {
if {
return .Framer().WriteHeaders(http2HeadersFrameParam{
StreamID: .streamID,
BlockFragment: ,
EndStream: .endStream,
EndHeaders: ,
})
} else {
return .Framer().WriteContinuation(.streamID, , )
}
}
allocatePromisedID func() (uint32, error)
promisedID uint32
}
return false
}
func ( *http2writePushPromise) ( http2writeContext) error {
, := .HeaderEncoder()
.Reset()
http2encKV(, ":method", .method)
http2encKV(, ":scheme", .url.Scheme)
http2encKV(, ":authority", .url.Host)
http2encKV(, ":path", .url.RequestURI())
http2encodeHeaders(, .h, nil)
:= .Bytes()
if len() == 0 {
panic("unexpected empty hpack")
}
return http2splitHeaderBlock(, , .writeHeaderBlock)
}
func ( *http2writePushPromise) ( http2writeContext, []byte, , bool) error {
if {
return .Framer().WritePushPromise(http2PushPromiseParam{
StreamID: .streamID,
PromiseID: .promisedID,
BlockFragment: ,
EndHeaders: ,
})
} else {
return .Framer().WriteContinuation(.streamID, , )
}
}
type http2write100ContinueHeadersFrame struct {
streamID uint32
}
func ( http2write100ContinueHeadersFrame) ( http2writeContext) error {
, := .HeaderEncoder()
.Reset()
http2encKV(, ":status", "100")
return .Framer().WriteHeaders(http2HeadersFrameParam{
StreamID: .streamID,
BlockFragment: .Bytes(),
EndStream: false,
EndHeaders: true,
})
}
return 9+2*(len(":status")+len("100")) <=
}
type http2writeWindowUpdate struct {
streamID uint32 // or 0 for conn-level
n uint32
}
func ( http2writeWindowUpdate) ( int) bool { return http2frameHeaderLen+4 <= }
func ( http2writeWindowUpdate) ( http2writeContext) error {
return .Framer().WriteWindowUpdate(.streamID, .n)
}
defer http2sorterPool.Put()
= .Keys()
}
for , := range {
:= []
= http2lowerHeader()
continue
}
:= == "transfer-encoding"
for , := range {
continue
if && != "trailers" {
continue
}
http2encKV(, , )
}
}
}
OpenStream(streamID uint32, options http2OpenStreamOptions)
CloseStream(streamID uint32)
AdjustStream(streamID uint32, priority http2PriorityParam)
Push(wr http2FrameWriteRequest)
Pop() (wr http2FrameWriteRequest, ok bool)
}
func ( http2FrameWriteRequest) () uint32 {
if .stream == nil {
func ( http2FrameWriteRequest) () bool {
return .stream == nil
}
func ( http2FrameWriteRequest) () int {
if , := .write.(*http2writeData); {
return len(.p)
}
return 0
}
func ( http2FrameWriteRequest) ( int32) (http2FrameWriteRequest, http2FrameWriteRequest, int) {
var http2FrameWriteRequest
, := .write.(*http2writeData)
if ! || len(.p) == 0 {
return , , 1
}
type http2writeQueue struct {
s []http2FrameWriteRequest
}
func ( *http2writeQueue) () bool { return len(.s) == 0 }
func ( *http2writeQueue) ( http2FrameWriteRequest) {
.s = append(.s, )
}
func ( *http2writeQueue) () http2FrameWriteRequest {
if len(.s) == 0 {
panic("invalid use of queue")
}
func ( *http2writeQueue) ( int32) (http2FrameWriteRequest, bool) {
if len(.s) == 0 {
return http2FrameWriteRequest{}, false
}
, , := .s[0].Consume()
switch {
case 0:
return http2FrameWriteRequest{}, false
case 1:
.shift()
case 2:
.s[0] =
}
return , true
}
type http2writeQueuePool []*http2writeQueue
func ( *http2writeQueuePool) ( *http2writeQueue) {
for := range .s {
.s[] = http2FrameWriteRequest{}
}
.s = .s[:0]
* = append(*, )
}
func ( *http2writeQueuePool) () *http2writeQueue {
:= len(*)
if == 0 {
return new(http2writeQueue)
}
:= - 1
:= (*)[]
(*)[] = nil
* = (*)[:]
return
}
const http2priorityDefaultWeight = 15 // 16 = 15 + 1
= &http2PriorityWriteSchedulerConfig{
MaxClosedNodesInTree: 10,
MaxIdleNodesInTree: 10,
ThrottleOutOfOrderWrites: false,
}
}
:= &http2priorityWriteScheduler{
nodes: make(map[uint32]*http2priorityNode),
maxClosedNodesInTree: .MaxClosedNodesInTree,
maxIdleNodesInTree: .MaxIdleNodesInTree,
enableWriteThrottle: .ThrottleOutOfOrderWrites,
}
.nodes[0] = &.root
if .ThrottleOutOfOrderWrites {
.writeThrottleLimit = 1024
} else {
.writeThrottleLimit = math.MaxInt32
}
return
}
type http2priorityNodeState int
const (
http2priorityNodeOpen http2priorityNodeState = iota
http2priorityNodeClosed
http2priorityNodeIdle
)
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
parent *http2priorityNode
kids *http2priorityNode // start of the kids list
prev, next *http2priorityNode // doubly-linked list of siblings
}
func ( *http2priorityNode) ( *http2priorityNode) {
if == {
panic("setParent to self")
}
if .parent == {
return
func ( *http2priorityNode) ( bool, *[]*http2priorityNode, func(*http2priorityNode, bool) bool) bool {
if !.q.empty() && (, ) {
return true
}
if .kids == nil {
return false
}
if .id != 0 {
= || (.state == http2priorityNodeOpen)
}
* = (*)[:0]
for .kids != nil {
* = append(*, .kids)
.kids.setParent(nil)
}
sort.Sort(http2sortPriorityNodeSiblings(*))
for := len(*) - 1; >= 0; -- {
(*)[].setParent() // setParent inserts at the head of n.kids
}
for := .kids; != nil; = .next {
if .(, , ) {
return true
}
}
return false
}
type http2sortPriorityNodeSiblings []*http2priorityNode
func ( http2sortPriorityNodeSiblings) () int { return len() }
func ( http2sortPriorityNodeSiblings) (, int) { [], [] = [], [] }
, := float64([].weight+1), float64([].subtreeBytes)
, := float64([].weight+1), float64([].subtreeBytes)
if == 0 && == 0 {
return >=
}
if == 0 {
return false
}
return / <= /
}
nodes map[uint32]*http2priorityNode
if := .nodes[]; != nil {
if .state != http2priorityNodeIdle {
panic(fmt.Sprintf("stream %d already opened", ))
}
.state = http2priorityNodeOpen
return
}
:= .nodes[.PusherID]
if == nil {
= &.root
}
:= &http2priorityNode{
q: *.queuePool.get(),
id: ,
weight: http2priorityDefaultWeight,
state: http2priorityNodeOpen,
}
.setParent()
.nodes[] =
if > .maxID {
.maxID =
}
}
func ( *http2priorityWriteScheduler) ( uint32) {
if == 0 {
panic("violation of WriteScheduler interface: cannot close stream 0")
}
if .nodes[] == nil {
panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", ))
}
if .nodes[].state != http2priorityNodeOpen {
panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", ))
}
:= .nodes[]
.state = http2priorityNodeClosed
.addBytes(-.bytes)
:= .q
.queuePool.put(&)
.q.s = nil
if .maxClosedNodesInTree > 0 {
.addClosedOrIdleNode(&.closedNodes, .maxClosedNodesInTree, )
} else {
.removeNode()
}
}
func ( *http2priorityWriteScheduler) ( uint32, http2PriorityParam) {
if == 0 {
panic("adjustPriority on root")
}
:= .nodes[]
if == nil {
if <= .maxID || .maxIdleNodesInTree == 0 {
return
}
.maxID =
= &http2priorityNode{
q: *.queuePool.get(),
id: ,
weight: http2priorityDefaultWeight,
state: http2priorityNodeIdle,
}
.setParent(&.root)
.nodes[] =
.addClosedOrIdleNode(&.idleNodes, .maxIdleNodesInTree, )
}
if == {
return
}
if .Exclusive {
:= .kids
for != nil {
:= .next
if != {
.setParent()
}
=
}
}
.setParent()
.weight = .Weight
}
func ( *http2priorityWriteScheduler) ( http2FrameWriteRequest) {
var *http2priorityNode
if := .StreamID(); == 0 {
= &.root
} else {
= .nodes[]
if .DataSize() > 0 {
panic("add DATA on non-open stream")
}
= &.root
}
}
.q.push()
}
func ( *http2priorityWriteScheduler) () ( http2FrameWriteRequest, bool) {
.root.walkReadyInOrder(false, &.tmp, func( *http2priorityNode, bool) bool {
:= int32(math.MaxInt32)
if {
= .writeThrottleLimit
}
, = .q.consume()
if ! {
return false
}
if {
.writeThrottleLimit += 1024
if .writeThrottleLimit < 0 {
.writeThrottleLimit = math.MaxInt32
}
} else if .enableWriteThrottle {
.writeThrottleLimit = 1024
}
return true
})
return ,
}
func ( *http2priorityWriteScheduler) ( *[]*http2priorityNode, int, *http2priorityNode) {
if == 0 {
return
}
func () http2WriteScheduler {
return &http2randomWriteScheduler{sq: make(map[uint32]*http2writeQueue)}
}
sq map[uint32]*http2writeQueue
}
func ( *http2randomWriteScheduler) ( http2FrameWriteRequest) {
:= .StreamID()
if == 0 {
.zero.push()
return
}
, := .sq[]
if ! {
= .queuePool.get()
.sq[] =
}
.push()
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |