This commit is contained in:
parent
b06ab1c801
commit
3f8a7d5d6e
@ -5,17 +5,10 @@ dip is a small webservice designed to return public ip address
|
|||||||
|
|
||||||
## Howto
|
## Howto
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
Install packr to create embedded files in binary executable file
|
|
||||||
```bash
|
|
||||||
go get -u github.com/gobuffalo/packr/v2/packr2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make
|
go build cmd/dip/dip.go
|
||||||
```
|
```
|
||||||
|
|
||||||
### Play
|
### Play
|
||||||
|
14
go.mod
14
go.mod
@ -5,14 +5,14 @@ go 1.19
|
|||||||
require (
|
require (
|
||||||
github.com/labstack/echo/v4 v4.9.1
|
github.com/labstack/echo/v4 v4.9.1
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
golang.org/x/crypto v0.1.0 // indirect
|
golang.org/x/crypto v0.4.0 // indirect
|
||||||
golang.org/x/sys v0.1.0 // indirect
|
golang.org/x/sys v0.3.0 // indirect
|
||||||
golang.org/x/text v0.4.0 // indirect
|
golang.org/x/text v0.5.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/likexian/whois v1.14.2
|
github.com/likexian/whois v1.14.4
|
||||||
github.com/likexian/whois-parser v1.24.1
|
github.com/likexian/whois-parser v1.24.2
|
||||||
github.com/oschwald/geoip2-golang v1.8.0
|
github.com/oschwald/geoip2-golang v1.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +24,6 @@ require (
|
|||||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/net v0.1.0 // indirect
|
golang.org/x/net v0.4.0 // indirect
|
||||||
golang.org/x/time v0.1.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
14
go.sum
14
go.sum
@ -16,9 +16,13 @@ github.com/likexian/gokit v0.25.9 h1:rzSQ/dP7Qw+QUzSuWlrLF0AtZS3Di6uO5yWOKhx2Gk4
|
|||||||
github.com/likexian/gokit v0.25.9/go.mod h1:oDDqJUcnnF9uAKuw54F7s6oEG+OJ7eallfDW2dq0A/o=
|
github.com/likexian/gokit v0.25.9/go.mod h1:oDDqJUcnnF9uAKuw54F7s6oEG+OJ7eallfDW2dq0A/o=
|
||||||
github.com/likexian/whois v1.14.2 h1:RFtXK/2PSgl6vG1beXEwB2zCkwUWhy7A9zh258iQTqg=
|
github.com/likexian/whois v1.14.2 h1:RFtXK/2PSgl6vG1beXEwB2zCkwUWhy7A9zh258iQTqg=
|
||||||
github.com/likexian/whois v1.14.2/go.mod h1:uEy9dUtYzjm9aSu9Tzbp+c1YEmyjQC90tYWudwvunFk=
|
github.com/likexian/whois v1.14.2/go.mod h1:uEy9dUtYzjm9aSu9Tzbp+c1YEmyjQC90tYWudwvunFk=
|
||||||
|
github.com/likexian/whois v1.14.4 h1:yNQVugAHfeoylzyhitcs0vaPksDduvzW46HLjqXhpCg=
|
||||||
|
github.com/likexian/whois v1.14.4/go.mod h1:ijMqjPbtafr5TB49U3Hs3BsJx/93ixhRi/8YnCSK0iY=
|
||||||
github.com/likexian/whois-parser v1.24.0/go.mod h1:mDyeVdEg60cNU6VhXWjyvPc6oTHkigaNWIWZCiQ7kQk=
|
github.com/likexian/whois-parser v1.24.0/go.mod h1:mDyeVdEg60cNU6VhXWjyvPc6oTHkigaNWIWZCiQ7kQk=
|
||||||
github.com/likexian/whois-parser v1.24.1 h1:UVV/A0hr2X4lM3rXUwjMX6x9MGfPJdJ4hCz8EjzSGNE=
|
github.com/likexian/whois-parser v1.24.1 h1:UVV/A0hr2X4lM3rXUwjMX6x9MGfPJdJ4hCz8EjzSGNE=
|
||||||
github.com/likexian/whois-parser v1.24.1/go.mod h1:fT0m/HCa4PXuR4ddA5PIE9V7gTWldeiMG/AHpeAhLtg=
|
github.com/likexian/whois-parser v1.24.1/go.mod h1:fT0m/HCa4PXuR4ddA5PIE9V7gTWldeiMG/AHpeAhLtg=
|
||||||
|
github.com/likexian/whois-parser v1.24.2 h1:EaNwcXqWBfQPfLD5F6MxAA0o7FnzmGcN3mg7v7h0zfY=
|
||||||
|
github.com/likexian/whois-parser v1.24.2/go.mod h1:fT0m/HCa4PXuR4ddA5PIE9V7gTWldeiMG/AHpeAhLtg=
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
@ -49,6 +53,8 @@ golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUH
|
|||||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||||
|
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||||
|
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
@ -58,6 +64,8 @@ golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO
|
|||||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
|
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||||
|
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -72,6 +80,8 @@ golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6
|
|||||||
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -80,11 +90,15 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||||
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
|
||||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
|
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
46
vendor/github.com/likexian/whois-parser/util.go
generated
vendored
46
vendor/github.com/likexian/whois-parser/util.go
generated
vendored
@ -112,30 +112,30 @@ func keys(m map[string]string) []string {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseDateString
|
// parseDateString attempts to parse a given date using a collection of common
|
||||||
|
// format strings. Date formats containing time components are tried first
|
||||||
|
// before attempts are made using date-only formats.
|
||||||
func parseDateString(dateString string) (time.Time, error) {
|
func parseDateString(dateString string) (time.Time, error) {
|
||||||
formats := [...]string{
|
formats := [...]string{
|
||||||
"2006-01-02T15:04:05Z",
|
|
||||||
"2006-01-02",
|
// Date & time formats
|
||||||
"2006-01-02 15:04:05",
|
"2006-01-02 15:04:05",
|
||||||
"2006. 01. 02.",
|
|
||||||
"02-Jan-2006",
|
|
||||||
"02/01/2006 15:04:05",
|
"02/01/2006 15:04:05",
|
||||||
"02.01.2006",
|
|
||||||
"02-01-2006",
|
|
||||||
"02.01.2006 15:04:05",
|
"02.01.2006 15:04:05",
|
||||||
"02.1.2006 15:04:05",
|
"02.1.2006 15:04:05",
|
||||||
"2.1.2006 15:04:05",
|
"2.1.2006 15:04:05",
|
||||||
"2006-01-02 15:04:05-07",
|
|
||||||
"02-Jan-2006 15:04:05",
|
"02-Jan-2006 15:04:05",
|
||||||
"January _2 2006",
|
|
||||||
"02/01/2006",
|
|
||||||
"01/02/2006",
|
|
||||||
"2006-01-02 15:04:05 MST",
|
|
||||||
"2006-Jan-02",
|
|
||||||
"2006-Jan-02.",
|
|
||||||
"2006-01-02 15:04:05 (MST+3)",
|
|
||||||
time.ANSIC,
|
time.ANSIC,
|
||||||
|
time.Stamp,
|
||||||
|
time.StampMilli,
|
||||||
|
time.StampMicro,
|
||||||
|
time.StampNano,
|
||||||
|
|
||||||
|
// Date, time & time zone formats
|
||||||
|
"2006-01-02T15:04:05Z",
|
||||||
|
"2006-01-02 15:04:05-07",
|
||||||
|
"2006-01-02 15:04:05 MST",
|
||||||
|
"2006-01-02 15:04:05 (MST+3)",
|
||||||
time.UnixDate,
|
time.UnixDate,
|
||||||
time.RubyDate,
|
time.RubyDate,
|
||||||
time.RFC822,
|
time.RFC822,
|
||||||
@ -145,10 +145,18 @@ func parseDateString(dateString string) (time.Time, error) {
|
|||||||
time.RFC1123Z,
|
time.RFC1123Z,
|
||||||
time.RFC3339,
|
time.RFC3339,
|
||||||
time.RFC3339Nano,
|
time.RFC3339Nano,
|
||||||
time.Stamp,
|
|
||||||
time.StampMilli,
|
// Date only formats
|
||||||
time.StampMicro,
|
"2006-01-02",
|
||||||
time.StampNano,
|
"2006. 01. 02.",
|
||||||
|
"02-Jan-2006",
|
||||||
|
"02.01.2006",
|
||||||
|
"02-01-2006",
|
||||||
|
"January _2 2006",
|
||||||
|
"02/01/2006",
|
||||||
|
"01/02/2006",
|
||||||
|
"2006-Jan-02",
|
||||||
|
"2006-Jan-02.",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, format := range formats {
|
for _, format := range formats {
|
||||||
|
3
vendor/github.com/likexian/whois/whois.go
generated
vendored
3
vendor/github.com/likexian/whois/whois.go
generated
vendored
@ -53,7 +53,7 @@ type Client struct {
|
|||||||
|
|
||||||
// Version returns package version
|
// Version returns package version
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return "1.14.2"
|
return "1.14.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author returns package author
|
// Author returns package author
|
||||||
@ -227,6 +227,7 @@ func getServer(data string) (string, string) {
|
|||||||
start += len(token)
|
start += len(token)
|
||||||
end := strings.Index(data[start:], "\n")
|
end := strings.Index(data[start:], "\n")
|
||||||
server := strings.TrimSpace(data[start : start+end])
|
server := strings.TrimSpace(data[start : start+end])
|
||||||
|
server = strings.TrimPrefix(server, "http:")
|
||||||
server = strings.TrimPrefix(server, "whois:")
|
server = strings.TrimPrefix(server, "whois:")
|
||||||
server = strings.TrimPrefix(server, "rwhois:")
|
server = strings.TrimPrefix(server, "rwhois:")
|
||||||
server = strings.Trim(server, "/")
|
server = strings.Trim(server, "/")
|
||||||
|
6
vendor/golang.org/x/net/http2/h2c/h2c.go
generated
vendored
6
vendor/golang.org/x/net/http2/h2c/h2c.go
generated
vendored
@ -109,6 +109,7 @@ func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
if http2VerboseLogs {
|
if http2VerboseLogs {
|
||||||
log.Printf("h2c: error h2c upgrade: %v", err)
|
log.Printf("h2c: error h2c upgrade: %v", err)
|
||||||
}
|
}
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
@ -167,7 +168,10 @@ func h2cUpgrade(w http.ResponseWriter, r *http.Request) (_ net.Conn, settings []
|
|||||||
return nil, nil, errors.New("h2c: connection does not support Hijack")
|
return nil, nil, errors.New("h2c: connection does not support Hijack")
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := io.ReadAll(r.Body)
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
r.Body = io.NopCloser(bytes.NewBuffer(body))
|
r.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||||
|
|
||||||
conn, rw, err := hijacker.Hijack()
|
conn, rw, err := hijacker.Hijack()
|
||||||
|
18
vendor/golang.org/x/net/http2/headermap.go
generated
vendored
18
vendor/golang.org/x/net/http2/headermap.go
generated
vendored
@ -27,7 +27,14 @@ func buildCommonHeaderMaps() {
|
|||||||
"accept-language",
|
"accept-language",
|
||||||
"accept-ranges",
|
"accept-ranges",
|
||||||
"age",
|
"age",
|
||||||
|
"access-control-allow-credentials",
|
||||||
|
"access-control-allow-headers",
|
||||||
|
"access-control-allow-methods",
|
||||||
"access-control-allow-origin",
|
"access-control-allow-origin",
|
||||||
|
"access-control-expose-headers",
|
||||||
|
"access-control-max-age",
|
||||||
|
"access-control-request-headers",
|
||||||
|
"access-control-request-method",
|
||||||
"allow",
|
"allow",
|
||||||
"authorization",
|
"authorization",
|
||||||
"cache-control",
|
"cache-control",
|
||||||
@ -53,6 +60,7 @@ func buildCommonHeaderMaps() {
|
|||||||
"link",
|
"link",
|
||||||
"location",
|
"location",
|
||||||
"max-forwards",
|
"max-forwards",
|
||||||
|
"origin",
|
||||||
"proxy-authenticate",
|
"proxy-authenticate",
|
||||||
"proxy-authorization",
|
"proxy-authorization",
|
||||||
"range",
|
"range",
|
||||||
@ -68,6 +76,8 @@ func buildCommonHeaderMaps() {
|
|||||||
"vary",
|
"vary",
|
||||||
"via",
|
"via",
|
||||||
"www-authenticate",
|
"www-authenticate",
|
||||||
|
"x-forwarded-for",
|
||||||
|
"x-forwarded-proto",
|
||||||
}
|
}
|
||||||
commonLowerHeader = make(map[string]string, len(common))
|
commonLowerHeader = make(map[string]string, len(common))
|
||||||
commonCanonHeader = make(map[string]string, len(common))
|
commonCanonHeader = make(map[string]string, len(common))
|
||||||
@ -85,3 +95,11 @@ func lowerHeader(v string) (lower string, ascii bool) {
|
|||||||
}
|
}
|
||||||
return asciiToLower(v)
|
return asciiToLower(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canonicalHeader(v string) string {
|
||||||
|
buildCommonHeaderMapsOnce()
|
||||||
|
if s, ok := commonCanonHeader[v]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return http.CanonicalHeaderKey(v)
|
||||||
|
}
|
||||||
|
5
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
5
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
@ -116,6 +116,11 @@ func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
|
|||||||
e.dynTab.setMaxSize(v)
|
e.dynTab.setMaxSize(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaxDynamicTableSize returns the current dynamic header table size.
|
||||||
|
func (e *Encoder) MaxDynamicTableSize() (v uint32) {
|
||||||
|
return e.dynTab.maxSize
|
||||||
|
}
|
||||||
|
|
||||||
// SetMaxDynamicTableSizeLimit changes the maximum value that can be
|
// SetMaxDynamicTableSizeLimit changes the maximum value that can be
|
||||||
// specified in SetMaxDynamicTableSize to v. By default, it is set to
|
// specified in SetMaxDynamicTableSize to v. By default, it is set to
|
||||||
// 4096, which is the same size of the default dynamic header table
|
// 4096, which is the same size of the default dynamic header table
|
||||||
|
188
vendor/golang.org/x/net/http2/hpack/static_table.go
generated
vendored
Normal file
188
vendor/golang.org/x/net/http2/hpack/static_table.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// go generate gen.go
|
||||||
|
// Code generated by the command above; DO NOT EDIT.
|
||||||
|
|
||||||
|
package hpack
|
||||||
|
|
||||||
|
var staticTable = &headerFieldTable{
|
||||||
|
evictCount: 0,
|
||||||
|
byName: map[string]uint64{
|
||||||
|
":authority": 1,
|
||||||
|
":method": 3,
|
||||||
|
":path": 5,
|
||||||
|
":scheme": 7,
|
||||||
|
":status": 14,
|
||||||
|
"accept-charset": 15,
|
||||||
|
"accept-encoding": 16,
|
||||||
|
"accept-language": 17,
|
||||||
|
"accept-ranges": 18,
|
||||||
|
"accept": 19,
|
||||||
|
"access-control-allow-origin": 20,
|
||||||
|
"age": 21,
|
||||||
|
"allow": 22,
|
||||||
|
"authorization": 23,
|
||||||
|
"cache-control": 24,
|
||||||
|
"content-disposition": 25,
|
||||||
|
"content-encoding": 26,
|
||||||
|
"content-language": 27,
|
||||||
|
"content-length": 28,
|
||||||
|
"content-location": 29,
|
||||||
|
"content-range": 30,
|
||||||
|
"content-type": 31,
|
||||||
|
"cookie": 32,
|
||||||
|
"date": 33,
|
||||||
|
"etag": 34,
|
||||||
|
"expect": 35,
|
||||||
|
"expires": 36,
|
||||||
|
"from": 37,
|
||||||
|
"host": 38,
|
||||||
|
"if-match": 39,
|
||||||
|
"if-modified-since": 40,
|
||||||
|
"if-none-match": 41,
|
||||||
|
"if-range": 42,
|
||||||
|
"if-unmodified-since": 43,
|
||||||
|
"last-modified": 44,
|
||||||
|
"link": 45,
|
||||||
|
"location": 46,
|
||||||
|
"max-forwards": 47,
|
||||||
|
"proxy-authenticate": 48,
|
||||||
|
"proxy-authorization": 49,
|
||||||
|
"range": 50,
|
||||||
|
"referer": 51,
|
||||||
|
"refresh": 52,
|
||||||
|
"retry-after": 53,
|
||||||
|
"server": 54,
|
||||||
|
"set-cookie": 55,
|
||||||
|
"strict-transport-security": 56,
|
||||||
|
"transfer-encoding": 57,
|
||||||
|
"user-agent": 58,
|
||||||
|
"vary": 59,
|
||||||
|
"via": 60,
|
||||||
|
"www-authenticate": 61,
|
||||||
|
},
|
||||||
|
byNameValue: map[pairNameValue]uint64{
|
||||||
|
{name: ":authority", value: ""}: 1,
|
||||||
|
{name: ":method", value: "GET"}: 2,
|
||||||
|
{name: ":method", value: "POST"}: 3,
|
||||||
|
{name: ":path", value: "/"}: 4,
|
||||||
|
{name: ":path", value: "/index.html"}: 5,
|
||||||
|
{name: ":scheme", value: "http"}: 6,
|
||||||
|
{name: ":scheme", value: "https"}: 7,
|
||||||
|
{name: ":status", value: "200"}: 8,
|
||||||
|
{name: ":status", value: "204"}: 9,
|
||||||
|
{name: ":status", value: "206"}: 10,
|
||||||
|
{name: ":status", value: "304"}: 11,
|
||||||
|
{name: ":status", value: "400"}: 12,
|
||||||
|
{name: ":status", value: "404"}: 13,
|
||||||
|
{name: ":status", value: "500"}: 14,
|
||||||
|
{name: "accept-charset", value: ""}: 15,
|
||||||
|
{name: "accept-encoding", value: "gzip, deflate"}: 16,
|
||||||
|
{name: "accept-language", value: ""}: 17,
|
||||||
|
{name: "accept-ranges", value: ""}: 18,
|
||||||
|
{name: "accept", value: ""}: 19,
|
||||||
|
{name: "access-control-allow-origin", value: ""}: 20,
|
||||||
|
{name: "age", value: ""}: 21,
|
||||||
|
{name: "allow", value: ""}: 22,
|
||||||
|
{name: "authorization", value: ""}: 23,
|
||||||
|
{name: "cache-control", value: ""}: 24,
|
||||||
|
{name: "content-disposition", value: ""}: 25,
|
||||||
|
{name: "content-encoding", value: ""}: 26,
|
||||||
|
{name: "content-language", value: ""}: 27,
|
||||||
|
{name: "content-length", value: ""}: 28,
|
||||||
|
{name: "content-location", value: ""}: 29,
|
||||||
|
{name: "content-range", value: ""}: 30,
|
||||||
|
{name: "content-type", value: ""}: 31,
|
||||||
|
{name: "cookie", value: ""}: 32,
|
||||||
|
{name: "date", value: ""}: 33,
|
||||||
|
{name: "etag", value: ""}: 34,
|
||||||
|
{name: "expect", value: ""}: 35,
|
||||||
|
{name: "expires", value: ""}: 36,
|
||||||
|
{name: "from", value: ""}: 37,
|
||||||
|
{name: "host", value: ""}: 38,
|
||||||
|
{name: "if-match", value: ""}: 39,
|
||||||
|
{name: "if-modified-since", value: ""}: 40,
|
||||||
|
{name: "if-none-match", value: ""}: 41,
|
||||||
|
{name: "if-range", value: ""}: 42,
|
||||||
|
{name: "if-unmodified-since", value: ""}: 43,
|
||||||
|
{name: "last-modified", value: ""}: 44,
|
||||||
|
{name: "link", value: ""}: 45,
|
||||||
|
{name: "location", value: ""}: 46,
|
||||||
|
{name: "max-forwards", value: ""}: 47,
|
||||||
|
{name: "proxy-authenticate", value: ""}: 48,
|
||||||
|
{name: "proxy-authorization", value: ""}: 49,
|
||||||
|
{name: "range", value: ""}: 50,
|
||||||
|
{name: "referer", value: ""}: 51,
|
||||||
|
{name: "refresh", value: ""}: 52,
|
||||||
|
{name: "retry-after", value: ""}: 53,
|
||||||
|
{name: "server", value: ""}: 54,
|
||||||
|
{name: "set-cookie", value: ""}: 55,
|
||||||
|
{name: "strict-transport-security", value: ""}: 56,
|
||||||
|
{name: "transfer-encoding", value: ""}: 57,
|
||||||
|
{name: "user-agent", value: ""}: 58,
|
||||||
|
{name: "vary", value: ""}: 59,
|
||||||
|
{name: "via", value: ""}: 60,
|
||||||
|
{name: "www-authenticate", value: ""}: 61,
|
||||||
|
},
|
||||||
|
ents: []HeaderField{
|
||||||
|
{Name: ":authority", Value: "", Sensitive: false},
|
||||||
|
{Name: ":method", Value: "GET", Sensitive: false},
|
||||||
|
{Name: ":method", Value: "POST", Sensitive: false},
|
||||||
|
{Name: ":path", Value: "/", Sensitive: false},
|
||||||
|
{Name: ":path", Value: "/index.html", Sensitive: false},
|
||||||
|
{Name: ":scheme", Value: "http", Sensitive: false},
|
||||||
|
{Name: ":scheme", Value: "https", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "200", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "204", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "206", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "304", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "400", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "404", Sensitive: false},
|
||||||
|
{Name: ":status", Value: "500", Sensitive: false},
|
||||||
|
{Name: "accept-charset", Value: "", Sensitive: false},
|
||||||
|
{Name: "accept-encoding", Value: "gzip, deflate", Sensitive: false},
|
||||||
|
{Name: "accept-language", Value: "", Sensitive: false},
|
||||||
|
{Name: "accept-ranges", Value: "", Sensitive: false},
|
||||||
|
{Name: "accept", Value: "", Sensitive: false},
|
||||||
|
{Name: "access-control-allow-origin", Value: "", Sensitive: false},
|
||||||
|
{Name: "age", Value: "", Sensitive: false},
|
||||||
|
{Name: "allow", Value: "", Sensitive: false},
|
||||||
|
{Name: "authorization", Value: "", Sensitive: false},
|
||||||
|
{Name: "cache-control", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-disposition", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-encoding", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-language", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-length", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-location", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-range", Value: "", Sensitive: false},
|
||||||
|
{Name: "content-type", Value: "", Sensitive: false},
|
||||||
|
{Name: "cookie", Value: "", Sensitive: false},
|
||||||
|
{Name: "date", Value: "", Sensitive: false},
|
||||||
|
{Name: "etag", Value: "", Sensitive: false},
|
||||||
|
{Name: "expect", Value: "", Sensitive: false},
|
||||||
|
{Name: "expires", Value: "", Sensitive: false},
|
||||||
|
{Name: "from", Value: "", Sensitive: false},
|
||||||
|
{Name: "host", Value: "", Sensitive: false},
|
||||||
|
{Name: "if-match", Value: "", Sensitive: false},
|
||||||
|
{Name: "if-modified-since", Value: "", Sensitive: false},
|
||||||
|
{Name: "if-none-match", Value: "", Sensitive: false},
|
||||||
|
{Name: "if-range", Value: "", Sensitive: false},
|
||||||
|
{Name: "if-unmodified-since", Value: "", Sensitive: false},
|
||||||
|
{Name: "last-modified", Value: "", Sensitive: false},
|
||||||
|
{Name: "link", Value: "", Sensitive: false},
|
||||||
|
{Name: "location", Value: "", Sensitive: false},
|
||||||
|
{Name: "max-forwards", Value: "", Sensitive: false},
|
||||||
|
{Name: "proxy-authenticate", Value: "", Sensitive: false},
|
||||||
|
{Name: "proxy-authorization", Value: "", Sensitive: false},
|
||||||
|
{Name: "range", Value: "", Sensitive: false},
|
||||||
|
{Name: "referer", Value: "", Sensitive: false},
|
||||||
|
{Name: "refresh", Value: "", Sensitive: false},
|
||||||
|
{Name: "retry-after", Value: "", Sensitive: false},
|
||||||
|
{Name: "server", Value: "", Sensitive: false},
|
||||||
|
{Name: "set-cookie", Value: "", Sensitive: false},
|
||||||
|
{Name: "strict-transport-security", Value: "", Sensitive: false},
|
||||||
|
{Name: "transfer-encoding", Value: "", Sensitive: false},
|
||||||
|
{Name: "user-agent", Value: "", Sensitive: false},
|
||||||
|
{Name: "vary", Value: "", Sensitive: false},
|
||||||
|
{Name: "via", Value: "", Sensitive: false},
|
||||||
|
{Name: "www-authenticate", Value: "", Sensitive: false},
|
||||||
|
},
|
||||||
|
}
|
78
vendor/golang.org/x/net/http2/hpack/tables.go
generated
vendored
78
vendor/golang.org/x/net/http2/hpack/tables.go
generated
vendored
@ -96,8 +96,7 @@ func (t *headerFieldTable) evictOldest(n int) {
|
|||||||
// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
|
// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
|
||||||
// table, the return value i actually refers to the entry t.ents[t.len()-i].
|
// table, the return value i actually refers to the entry t.ents[t.len()-i].
|
||||||
//
|
//
|
||||||
// All tables are assumed to be a dynamic tables except for the global
|
// All tables are assumed to be a dynamic tables except for the global staticTable.
|
||||||
// staticTable pointer.
|
|
||||||
//
|
//
|
||||||
// See Section 2.3.3.
|
// See Section 2.3.3.
|
||||||
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
|
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
|
||||||
@ -125,81 +124,6 @@ func (t *headerFieldTable) idToIndex(id uint64) uint64 {
|
|||||||
return k + 1
|
return k + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
|
|
||||||
var staticTable = newStaticTable()
|
|
||||||
var staticTableEntries = [...]HeaderField{
|
|
||||||
{Name: ":authority"},
|
|
||||||
{Name: ":method", Value: "GET"},
|
|
||||||
{Name: ":method", Value: "POST"},
|
|
||||||
{Name: ":path", Value: "/"},
|
|
||||||
{Name: ":path", Value: "/index.html"},
|
|
||||||
{Name: ":scheme", Value: "http"},
|
|
||||||
{Name: ":scheme", Value: "https"},
|
|
||||||
{Name: ":status", Value: "200"},
|
|
||||||
{Name: ":status", Value: "204"},
|
|
||||||
{Name: ":status", Value: "206"},
|
|
||||||
{Name: ":status", Value: "304"},
|
|
||||||
{Name: ":status", Value: "400"},
|
|
||||||
{Name: ":status", Value: "404"},
|
|
||||||
{Name: ":status", Value: "500"},
|
|
||||||
{Name: "accept-charset"},
|
|
||||||
{Name: "accept-encoding", Value: "gzip, deflate"},
|
|
||||||
{Name: "accept-language"},
|
|
||||||
{Name: "accept-ranges"},
|
|
||||||
{Name: "accept"},
|
|
||||||
{Name: "access-control-allow-origin"},
|
|
||||||
{Name: "age"},
|
|
||||||
{Name: "allow"},
|
|
||||||
{Name: "authorization"},
|
|
||||||
{Name: "cache-control"},
|
|
||||||
{Name: "content-disposition"},
|
|
||||||
{Name: "content-encoding"},
|
|
||||||
{Name: "content-language"},
|
|
||||||
{Name: "content-length"},
|
|
||||||
{Name: "content-location"},
|
|
||||||
{Name: "content-range"},
|
|
||||||
{Name: "content-type"},
|
|
||||||
{Name: "cookie"},
|
|
||||||
{Name: "date"},
|
|
||||||
{Name: "etag"},
|
|
||||||
{Name: "expect"},
|
|
||||||
{Name: "expires"},
|
|
||||||
{Name: "from"},
|
|
||||||
{Name: "host"},
|
|
||||||
{Name: "if-match"},
|
|
||||||
{Name: "if-modified-since"},
|
|
||||||
{Name: "if-none-match"},
|
|
||||||
{Name: "if-range"},
|
|
||||||
{Name: "if-unmodified-since"},
|
|
||||||
{Name: "last-modified"},
|
|
||||||
{Name: "link"},
|
|
||||||
{Name: "location"},
|
|
||||||
{Name: "max-forwards"},
|
|
||||||
{Name: "proxy-authenticate"},
|
|
||||||
{Name: "proxy-authorization"},
|
|
||||||
{Name: "range"},
|
|
||||||
{Name: "referer"},
|
|
||||||
{Name: "refresh"},
|
|
||||||
{Name: "retry-after"},
|
|
||||||
{Name: "server"},
|
|
||||||
{Name: "set-cookie"},
|
|
||||||
{Name: "strict-transport-security"},
|
|
||||||
{Name: "transfer-encoding"},
|
|
||||||
{Name: "user-agent"},
|
|
||||||
{Name: "vary"},
|
|
||||||
{Name: "via"},
|
|
||||||
{Name: "www-authenticate"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStaticTable() *headerFieldTable {
|
|
||||||
t := &headerFieldTable{}
|
|
||||||
t.init()
|
|
||||||
for _, e := range staticTableEntries[:] {
|
|
||||||
t.addEntry(e)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
var huffmanCodes = [256]uint32{
|
var huffmanCodes = [256]uint32{
|
||||||
0x1ff8,
|
0x1ff8,
|
||||||
0x7fffd8,
|
0x7fffd8,
|
||||||
|
236
vendor/golang.org/x/net/http2/server.go
generated
vendored
236
vendor/golang.org/x/net/http2/server.go
generated
vendored
@ -98,6 +98,19 @@ type Server struct {
|
|||||||
// the HTTP/2 spec's recommendations.
|
// the HTTP/2 spec's recommendations.
|
||||||
MaxConcurrentStreams uint32
|
MaxConcurrentStreams uint32
|
||||||
|
|
||||||
|
// MaxDecoderHeaderTableSize optionally specifies the http2
|
||||||
|
// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It
|
||||||
|
// informs the remote endpoint of the maximum size of the header compression
|
||||||
|
// table used to decode header blocks, in octets. If zero, the default value
|
||||||
|
// of 4096 is used.
|
||||||
|
MaxDecoderHeaderTableSize uint32
|
||||||
|
|
||||||
|
// MaxEncoderHeaderTableSize optionally specifies an upper limit for the
|
||||||
|
// header compression table used for encoding request headers. Received
|
||||||
|
// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,
|
||||||
|
// the default value of 4096 is used.
|
||||||
|
MaxEncoderHeaderTableSize uint32
|
||||||
|
|
||||||
// MaxReadFrameSize optionally specifies the largest frame
|
// MaxReadFrameSize optionally specifies the largest frame
|
||||||
// this server is willing to read. A valid value is between
|
// this server is willing to read. A valid value is between
|
||||||
// 16k and 16M, inclusive. If zero or otherwise invalid, a
|
// 16k and 16M, inclusive. If zero or otherwise invalid, a
|
||||||
@ -170,6 +183,20 @@ func (s *Server) maxConcurrentStreams() uint32 {
|
|||||||
return defaultMaxStreams
|
return defaultMaxStreams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) maxDecoderHeaderTableSize() uint32 {
|
||||||
|
if v := s.MaxDecoderHeaderTableSize; v > 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return initialHeaderTableSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) maxEncoderHeaderTableSize() uint32 {
|
||||||
|
if v := s.MaxEncoderHeaderTableSize; v > 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return initialHeaderTableSize
|
||||||
|
}
|
||||||
|
|
||||||
// maxQueuedControlFrames is the maximum number of control frames like
|
// maxQueuedControlFrames is the maximum number of control frames like
|
||||||
// SETTINGS, PING and RST_STREAM that will be queued for writing before
|
// SETTINGS, PING and RST_STREAM that will be queued for writing before
|
||||||
// the connection is closed to prevent memory exhaustion attacks.
|
// the connection is closed to prevent memory exhaustion attacks.
|
||||||
@ -394,7 +421,6 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
|||||||
advMaxStreams: s.maxConcurrentStreams(),
|
advMaxStreams: s.maxConcurrentStreams(),
|
||||||
initialStreamSendWindowSize: initialWindowSize,
|
initialStreamSendWindowSize: initialWindowSize,
|
||||||
maxFrameSize: initialMaxFrameSize,
|
maxFrameSize: initialMaxFrameSize,
|
||||||
headerTableSize: initialHeaderTableSize,
|
|
||||||
serveG: newGoroutineLock(),
|
serveG: newGoroutineLock(),
|
||||||
pushEnabled: true,
|
pushEnabled: true,
|
||||||
sawClientPreface: opts.SawClientPreface,
|
sawClientPreface: opts.SawClientPreface,
|
||||||
@ -424,12 +450,13 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
|||||||
sc.flow.add(initialWindowSize)
|
sc.flow.add(initialWindowSize)
|
||||||
sc.inflow.add(initialWindowSize)
|
sc.inflow.add(initialWindowSize)
|
||||||
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
|
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
|
||||||
|
sc.hpackEncoder.SetMaxDynamicTableSizeLimit(s.maxEncoderHeaderTableSize())
|
||||||
|
|
||||||
fr := NewFramer(sc.bw, c)
|
fr := NewFramer(sc.bw, c)
|
||||||
if s.CountError != nil {
|
if s.CountError != nil {
|
||||||
fr.countError = s.CountError
|
fr.countError = s.CountError
|
||||||
}
|
}
|
||||||
fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
|
fr.ReadMetaHeaders = hpack.NewDecoder(s.maxDecoderHeaderTableSize(), nil)
|
||||||
fr.MaxHeaderListSize = sc.maxHeaderListSize()
|
fr.MaxHeaderListSize = sc.maxHeaderListSize()
|
||||||
fr.SetMaxReadFrameSize(s.maxReadFrameSize())
|
fr.SetMaxReadFrameSize(s.maxReadFrameSize())
|
||||||
sc.framer = fr
|
sc.framer = fr
|
||||||
@ -559,9 +586,9 @@ type serverConn struct {
|
|||||||
streams map[uint32]*stream
|
streams map[uint32]*stream
|
||||||
initialStreamSendWindowSize int32
|
initialStreamSendWindowSize int32
|
||||||
maxFrameSize int32
|
maxFrameSize int32
|
||||||
headerTableSize uint32
|
|
||||||
peerMaxHeaderListSize uint32 // zero means unknown (default)
|
peerMaxHeaderListSize uint32 // zero means unknown (default)
|
||||||
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
|
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
|
||||||
|
canonHeaderKeysSize int // canonHeader keys size in bytes
|
||||||
writingFrame bool // started writing a frame (on serve goroutine or separate)
|
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
|
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
|
needsFrameFlush bool // last frame write wasn't a flush
|
||||||
@ -622,7 +649,9 @@ type stream struct {
|
|||||||
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
|
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
|
||||||
gotTrailerHeader bool // HEADER frame for trailers was seen
|
gotTrailerHeader bool // HEADER frame for trailers was seen
|
||||||
wroteHeaders bool // whether we wrote headers (not status 100)
|
wroteHeaders bool // whether we wrote headers (not status 100)
|
||||||
|
readDeadline *time.Timer // nil if unused
|
||||||
writeDeadline *time.Timer // nil if unused
|
writeDeadline *time.Timer // nil if unused
|
||||||
|
closeErr error // set before cw is closed
|
||||||
|
|
||||||
trailer http.Header // accumulated trailers
|
trailer http.Header // accumulated trailers
|
||||||
reqTrailer http.Header // handler's Request.Trailer
|
reqTrailer http.Header // handler's Request.Trailer
|
||||||
@ -738,6 +767,13 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// maxCachedCanonicalHeadersKeysSize is an arbitrarily-chosen limit on the size
|
||||||
|
// of the entries in the canonHeader cache.
|
||||||
|
// This should be larger than the size of unique, uncommon header keys likely to
|
||||||
|
// be sent by the peer, while not so high as to permit unreasonable memory usage
|
||||||
|
// if the peer sends an unbounded number of unique header keys.
|
||||||
|
const maxCachedCanonicalHeadersKeysSize = 2048
|
||||||
|
|
||||||
func (sc *serverConn) canonicalHeader(v string) string {
|
func (sc *serverConn) canonicalHeader(v string) string {
|
||||||
sc.serveG.check()
|
sc.serveG.check()
|
||||||
buildCommonHeaderMapsOnce()
|
buildCommonHeaderMapsOnce()
|
||||||
@ -753,14 +789,10 @@ func (sc *serverConn) canonicalHeader(v string) string {
|
|||||||
sc.canonHeader = make(map[string]string)
|
sc.canonHeader = make(map[string]string)
|
||||||
}
|
}
|
||||||
cv = http.CanonicalHeaderKey(v)
|
cv = http.CanonicalHeaderKey(v)
|
||||||
// maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of
|
size := 100 + len(v)*2 // 100 bytes of map overhead + key + value
|
||||||
// entries in the canonHeader cache. This should be larger than the number
|
if sc.canonHeaderKeysSize+size <= maxCachedCanonicalHeadersKeysSize {
|
||||||
// of unique, uncommon header keys likely to be sent by the peer, while not
|
|
||||||
// so high as to permit unreasonable memory usage if the peer sends an unbounded
|
|
||||||
// number of unique header keys.
|
|
||||||
const maxCachedCanonicalHeaders = 32
|
|
||||||
if len(sc.canonHeader) < maxCachedCanonicalHeaders {
|
|
||||||
sc.canonHeader[v] = cv
|
sc.canonHeader[v] = cv
|
||||||
|
sc.canonHeaderKeysSize += size
|
||||||
}
|
}
|
||||||
return cv
|
return cv
|
||||||
}
|
}
|
||||||
@ -862,6 +894,7 @@ func (sc *serverConn) serve() {
|
|||||||
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
|
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
|
||||||
{SettingMaxConcurrentStreams, sc.advMaxStreams},
|
{SettingMaxConcurrentStreams, sc.advMaxStreams},
|
||||||
{SettingMaxHeaderListSize, sc.maxHeaderListSize()},
|
{SettingMaxHeaderListSize, sc.maxHeaderListSize()},
|
||||||
|
{SettingHeaderTableSize, sc.srv.maxDecoderHeaderTableSize()},
|
||||||
{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
|
{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -869,7 +902,9 @@ func (sc *serverConn) serve() {
|
|||||||
|
|
||||||
// Each connection starts with initialWindowSize inflow tokens.
|
// Each connection starts with initialWindowSize inflow tokens.
|
||||||
// If a higher value is configured, we add more tokens.
|
// If a higher value is configured, we add more tokens.
|
||||||
sc.sendWindowUpdate(nil)
|
if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 {
|
||||||
|
sc.sendWindowUpdate(nil, int(diff))
|
||||||
|
}
|
||||||
|
|
||||||
if err := sc.readPreface(); err != nil {
|
if err := sc.readPreface(); err != nil {
|
||||||
sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
|
sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
|
||||||
@ -946,6 +981,8 @@ func (sc *serverConn) serve() {
|
|||||||
}
|
}
|
||||||
case *startPushRequest:
|
case *startPushRequest:
|
||||||
sc.startPush(v)
|
sc.startPush(v)
|
||||||
|
case func(*serverConn):
|
||||||
|
v(sc)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected type %T", v))
|
panic(fmt.Sprintf("unexpected type %T", v))
|
||||||
}
|
}
|
||||||
@ -1459,6 +1496,21 @@ func (sc *serverConn) processFrame(f Frame) error {
|
|||||||
sc.sawFirstSettings = true
|
sc.sawFirstSettings = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Discard frames for streams initiated after the identified last
|
||||||
|
// stream sent in a GOAWAY, or all frames after sending an error.
|
||||||
|
// We still need to return connection-level flow control for DATA frames.
|
||||||
|
// RFC 9113 Section 6.8.
|
||||||
|
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || f.Header().StreamID > sc.maxClientStreamID) {
|
||||||
|
|
||||||
|
if f, ok := f.(*DataFrame); ok {
|
||||||
|
if sc.inflow.available() < int32(f.Length) {
|
||||||
|
return sc.countError("data_flow", streamError(f.Header().StreamID, ErrCodeFlowControl))
|
||||||
|
}
|
||||||
|
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
switch f := f.(type) {
|
switch f := f.(type) {
|
||||||
case *SettingsFrame:
|
case *SettingsFrame:
|
||||||
return sc.processSettings(f)
|
return sc.processSettings(f)
|
||||||
@ -1501,9 +1553,6 @@ func (sc *serverConn) processPing(f *PingFrame) error {
|
|||||||
// PROTOCOL_ERROR."
|
// PROTOCOL_ERROR."
|
||||||
return sc.countError("ping_on_stream", ConnectionError(ErrCodeProtocol))
|
return sc.countError("ping_on_stream", ConnectionError(ErrCodeProtocol))
|
||||||
}
|
}
|
||||||
if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})
|
sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1565,6 +1614,9 @@ func (sc *serverConn) closeStream(st *stream, err error) {
|
|||||||
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
|
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
|
||||||
}
|
}
|
||||||
st.state = stateClosed
|
st.state = stateClosed
|
||||||
|
if st.readDeadline != nil {
|
||||||
|
st.readDeadline.Stop()
|
||||||
|
}
|
||||||
if st.writeDeadline != nil {
|
if st.writeDeadline != nil {
|
||||||
st.writeDeadline.Stop()
|
st.writeDeadline.Stop()
|
||||||
}
|
}
|
||||||
@ -1586,10 +1638,18 @@ func (sc *serverConn) closeStream(st *stream, err error) {
|
|||||||
if p := st.body; p != nil {
|
if p := st.body; p != nil {
|
||||||
// Return any buffered unread bytes worth of conn-level flow control.
|
// Return any buffered unread bytes worth of conn-level flow control.
|
||||||
// See golang.org/issue/16481
|
// See golang.org/issue/16481
|
||||||
sc.sendWindowUpdate(nil)
|
sc.sendWindowUpdate(nil, p.Len())
|
||||||
|
|
||||||
p.CloseWithError(err)
|
p.CloseWithError(err)
|
||||||
}
|
}
|
||||||
|
if e, ok := err.(StreamError); ok {
|
||||||
|
if e.Cause != nil {
|
||||||
|
err = e.Cause
|
||||||
|
} else {
|
||||||
|
err = errStreamClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st.closeErr = err
|
||||||
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
|
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
|
||||||
sc.writeSched.CloseStream(st.id)
|
sc.writeSched.CloseStream(st.id)
|
||||||
}
|
}
|
||||||
@ -1632,7 +1692,6 @@ func (sc *serverConn) processSetting(s Setting) error {
|
|||||||
}
|
}
|
||||||
switch s.ID {
|
switch s.ID {
|
||||||
case SettingHeaderTableSize:
|
case SettingHeaderTableSize:
|
||||||
sc.headerTableSize = s.Val
|
|
||||||
sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
|
sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
|
||||||
case SettingEnablePush:
|
case SettingEnablePush:
|
||||||
sc.pushEnabled = s.Val != 0
|
sc.pushEnabled = s.Val != 0
|
||||||
@ -1686,16 +1745,6 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
|
|||||||
func (sc *serverConn) processData(f *DataFrame) error {
|
func (sc *serverConn) processData(f *DataFrame) error {
|
||||||
sc.serveG.check()
|
sc.serveG.check()
|
||||||
id := f.Header().StreamID
|
id := f.Header().StreamID
|
||||||
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || id > sc.maxClientStreamID) {
|
|
||||||
// Discard all DATA frames if the GOAWAY is due to an
|
|
||||||
// error, or:
|
|
||||||
//
|
|
||||||
// Section 6.8: After sending a GOAWAY frame, the sender
|
|
||||||
// can discard frames for streams initiated by the
|
|
||||||
// receiver with identifiers higher than the identified
|
|
||||||
// last stream.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
data := f.Data()
|
data := f.Data()
|
||||||
state, st := sc.state(id)
|
state, st := sc.state(id)
|
||||||
@ -1734,7 +1783,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
|||||||
// sendWindowUpdate, which also schedules sending the
|
// sendWindowUpdate, which also schedules sending the
|
||||||
// frames.
|
// frames.
|
||||||
sc.inflow.take(int32(f.Length))
|
sc.inflow.take(int32(f.Length))
|
||||||
sc.sendWindowUpdate(nil) // conn-level
|
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
|
||||||
|
|
||||||
if st != nil && st.resetQueued {
|
if st != nil && st.resetQueued {
|
||||||
// Already have a stream error in flight. Don't send another.
|
// Already have a stream error in flight. Don't send another.
|
||||||
@ -1752,7 +1801,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
|||||||
return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
|
return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
|
||||||
}
|
}
|
||||||
sc.inflow.take(int32(f.Length))
|
sc.inflow.take(int32(f.Length))
|
||||||
sc.sendWindowUpdate(nil) // conn-level
|
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
|
||||||
|
|
||||||
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
|
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
|
||||||
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
|
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
|
||||||
@ -1770,7 +1819,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
|||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
wrote, err := st.body.Write(data)
|
wrote, err := st.body.Write(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sc.sendWindowUpdate32(nil, int32(f.Length)-int32(wrote))
|
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
|
||||||
return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
|
return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
|
||||||
}
|
}
|
||||||
if wrote != len(data) {
|
if wrote != len(data) {
|
||||||
@ -1838,19 +1887,27 @@ func (st *stream) copyTrailersToHandlerRequest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// onReadTimeout is run on its own goroutine (from time.AfterFunc)
|
||||||
|
// when the stream's ReadTimeout has fired.
|
||||||
|
func (st *stream) onReadTimeout() {
|
||||||
|
// Wrap the ErrDeadlineExceeded to avoid callers depending on us
|
||||||
|
// returning the bare error.
|
||||||
|
st.body.CloseWithError(fmt.Errorf("%w", os.ErrDeadlineExceeded))
|
||||||
|
}
|
||||||
|
|
||||||
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
|
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
|
||||||
// when the stream's WriteTimeout has fired.
|
// when the stream's WriteTimeout has fired.
|
||||||
func (st *stream) onWriteTimeout() {
|
func (st *stream) onWriteTimeout() {
|
||||||
st.sc.writeFrameFromHandler(FrameWriteRequest{write: streamError(st.id, ErrCodeInternal)})
|
st.sc.writeFrameFromHandler(FrameWriteRequest{write: StreamError{
|
||||||
|
StreamID: st.id,
|
||||||
|
Code: ErrCodeInternal,
|
||||||
|
Cause: os.ErrDeadlineExceeded,
|
||||||
|
}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
|
func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
|
||||||
sc.serveG.check()
|
sc.serveG.check()
|
||||||
id := f.StreamID
|
id := f.StreamID
|
||||||
if sc.inGoAway {
|
|
||||||
// Ignore.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// http://tools.ietf.org/html/rfc7540#section-5.1.1
|
// http://tools.ietf.org/html/rfc7540#section-5.1.1
|
||||||
// Streams initiated by a client MUST use odd-numbered stream
|
// Streams initiated by a client MUST use odd-numbered stream
|
||||||
// identifiers. [...] An endpoint that receives an unexpected
|
// identifiers. [...] An endpoint that receives an unexpected
|
||||||
@ -1953,6 +2010,9 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
|
|||||||
// (in Go 1.8), though. That's a more sane option anyway.
|
// (in Go 1.8), though. That's a more sane option anyway.
|
||||||
if sc.hs.ReadTimeout != 0 {
|
if sc.hs.ReadTimeout != 0 {
|
||||||
sc.conn.SetReadDeadline(time.Time{})
|
sc.conn.SetReadDeadline(time.Time{})
|
||||||
|
if st.body != nil {
|
||||||
|
st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go sc.runHandler(rw, req, handler)
|
go sc.runHandler(rw, req, handler)
|
||||||
@ -2021,9 +2081,6 @@ func (sc *serverConn) checkPriority(streamID uint32, p PriorityParam) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sc *serverConn) processPriority(f *PriorityFrame) error {
|
func (sc *serverConn) processPriority(f *PriorityFrame) error {
|
||||||
if sc.inGoAway {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil {
|
if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -2322,39 +2379,24 @@ func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {
|
|||||||
|
|
||||||
func (sc *serverConn) noteBodyRead(st *stream, n int) {
|
func (sc *serverConn) noteBodyRead(st *stream, n int) {
|
||||||
sc.serveG.check()
|
sc.serveG.check()
|
||||||
sc.sendWindowUpdate(nil) // conn-level
|
sc.sendWindowUpdate(nil, n) // conn-level
|
||||||
if st.state != stateHalfClosedRemote && st.state != stateClosed {
|
if st.state != stateHalfClosedRemote && st.state != stateClosed {
|
||||||
// Don't send this WINDOW_UPDATE if the stream is closed
|
// Don't send this WINDOW_UPDATE if the stream is closed
|
||||||
// remotely.
|
// remotely.
|
||||||
sc.sendWindowUpdate(st)
|
sc.sendWindowUpdate(st, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// st may be nil for conn-level
|
// st may be nil for conn-level
|
||||||
func (sc *serverConn) sendWindowUpdate(st *stream) {
|
func (sc *serverConn) sendWindowUpdate(st *stream, n int) {
|
||||||
sc.serveG.check()
|
sc.serveG.check()
|
||||||
|
|
||||||
var n int32
|
|
||||||
if st == nil {
|
|
||||||
if avail, windowSize := sc.inflow.available(), sc.srv.initialConnRecvWindowSize(); avail > windowSize/2 {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
n = windowSize - avail
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if avail, windowSize := st.inflow.available(), sc.srv.initialStreamRecvWindowSize(); avail > windowSize/2 {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
n = windowSize - avail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// "The legal range for the increment to the flow control
|
// "The legal range for the increment to the flow control
|
||||||
// window is 1 to 2^31-1 (2,147,483,647) octets."
|
// window is 1 to 2^31-1 (2,147,483,647) octets."
|
||||||
// A Go Read call on 64-bit machines could in theory read
|
// A Go Read call on 64-bit machines could in theory read
|
||||||
// a larger Read than this. Very unlikely, but we handle it here
|
// a larger Read than this. Very unlikely, but we handle it here
|
||||||
// rather than elsewhere for now.
|
// rather than elsewhere for now.
|
||||||
const maxUint31 = 1<<31 - 1
|
const maxUint31 = 1<<31 - 1
|
||||||
for n >= maxUint31 {
|
for n > maxUint31 {
|
||||||
sc.sendWindowUpdate32(st, maxUint31)
|
sc.sendWindowUpdate32(st, maxUint31)
|
||||||
n -= maxUint31
|
n -= maxUint31
|
||||||
}
|
}
|
||||||
@ -2474,7 +2516,15 @@ type responseWriterState struct {
|
|||||||
|
|
||||||
type chunkWriter struct{ rws *responseWriterState }
|
type chunkWriter struct{ rws *responseWriterState }
|
||||||
|
|
||||||
func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
|
func (cw chunkWriter) Write(p []byte) (n int, err error) {
|
||||||
|
n, err = cw.rws.writeChunk(p)
|
||||||
|
if err == errStreamClosed {
|
||||||
|
// If writing failed because the stream has been closed,
|
||||||
|
// return the reason it was closed.
|
||||||
|
err = cw.rws.stream.closeErr
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
|
func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
|
||||||
|
|
||||||
@ -2668,23 +2718,85 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
|
||||||
|
st := w.rws.stream
|
||||||
|
if !deadline.IsZero() && deadline.Before(time.Now()) {
|
||||||
|
// If we're setting a deadline in the past, reset the stream immediately
|
||||||
|
// so writes after SetWriteDeadline returns will fail.
|
||||||
|
st.onReadTimeout()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.rws.conn.sendServeMsg(func(sc *serverConn) {
|
||||||
|
if st.readDeadline != nil {
|
||||||
|
if !st.readDeadline.Stop() {
|
||||||
|
// Deadline already exceeded, or stream has been closed.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if deadline.IsZero() {
|
||||||
|
st.readDeadline = nil
|
||||||
|
} else if st.readDeadline == nil {
|
||||||
|
st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout)
|
||||||
|
} else {
|
||||||
|
st.readDeadline.Reset(deadline.Sub(time.Now()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
|
||||||
|
st := w.rws.stream
|
||||||
|
if !deadline.IsZero() && deadline.Before(time.Now()) {
|
||||||
|
// If we're setting a deadline in the past, reset the stream immediately
|
||||||
|
// so writes after SetWriteDeadline returns will fail.
|
||||||
|
st.onWriteTimeout()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.rws.conn.sendServeMsg(func(sc *serverConn) {
|
||||||
|
if st.writeDeadline != nil {
|
||||||
|
if !st.writeDeadline.Stop() {
|
||||||
|
// Deadline already exceeded, or stream has been closed.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if deadline.IsZero() {
|
||||||
|
st.writeDeadline = nil
|
||||||
|
} else if st.writeDeadline == nil {
|
||||||
|
st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout)
|
||||||
|
} else {
|
||||||
|
st.writeDeadline.Reset(deadline.Sub(time.Now()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *responseWriter) Flush() {
|
func (w *responseWriter) Flush() {
|
||||||
|
w.FlushError()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *responseWriter) FlushError() error {
|
||||||
rws := w.rws
|
rws := w.rws
|
||||||
if rws == nil {
|
if rws == nil {
|
||||||
panic("Header called after Handler finished")
|
panic("Header called after Handler finished")
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
if rws.bw.Buffered() > 0 {
|
if rws.bw.Buffered() > 0 {
|
||||||
if err := rws.bw.Flush(); err != nil {
|
err = rws.bw.Flush()
|
||||||
// Ignore the error. The frame writer already knows.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// The bufio.Writer won't call chunkWriter.Write
|
// The bufio.Writer won't call chunkWriter.Write
|
||||||
// (writeChunk with zero bytes, so we have to do it
|
// (writeChunk with zero bytes, so we have to do it
|
||||||
// ourselves to force the HTTP response header and/or
|
// ourselves to force the HTTP response header and/or
|
||||||
// final DATA frame (with END_STREAM) to be sent.
|
// final DATA frame (with END_STREAM) to be sent.
|
||||||
rws.writeChunk(nil)
|
_, err = chunkWriter{rws}.Write(nil)
|
||||||
|
if err == nil {
|
||||||
|
select {
|
||||||
|
case <-rws.stream.cw:
|
||||||
|
err = rws.stream.closeErr
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *responseWriter) CloseNotify() <-chan bool {
|
func (w *responseWriter) CloseNotify() <-chan bool {
|
||||||
|
113
vendor/golang.org/x/net/http2/transport.go
generated
vendored
113
vendor/golang.org/x/net/http2/transport.go
generated
vendored
@ -16,6 +16,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
mathrand "math/rand"
|
mathrand "math/rand"
|
||||||
@ -117,6 +118,28 @@ type Transport struct {
|
|||||||
// to mean no limit.
|
// to mean no limit.
|
||||||
MaxHeaderListSize uint32
|
MaxHeaderListSize uint32
|
||||||
|
|
||||||
|
// MaxReadFrameSize is the http2 SETTINGS_MAX_FRAME_SIZE to send in the
|
||||||
|
// initial settings frame. It is the size in bytes of the largest frame
|
||||||
|
// payload that the sender is willing to receive. If 0, no setting is
|
||||||
|
// sent, and the value is provided by the peer, which should be 16384
|
||||||
|
// according to the spec:
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2.
|
||||||
|
// Values are bounded in the range 16k to 16M.
|
||||||
|
MaxReadFrameSize uint32
|
||||||
|
|
||||||
|
// MaxDecoderHeaderTableSize optionally specifies the http2
|
||||||
|
// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It
|
||||||
|
// informs the remote endpoint of the maximum size of the header compression
|
||||||
|
// table used to decode header blocks, in octets. If zero, the default value
|
||||||
|
// of 4096 is used.
|
||||||
|
MaxDecoderHeaderTableSize uint32
|
||||||
|
|
||||||
|
// MaxEncoderHeaderTableSize optionally specifies an upper limit for the
|
||||||
|
// header compression table used for encoding request headers. Received
|
||||||
|
// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,
|
||||||
|
// the default value of 4096 is used.
|
||||||
|
MaxEncoderHeaderTableSize uint32
|
||||||
|
|
||||||
// StrictMaxConcurrentStreams controls whether the server's
|
// StrictMaxConcurrentStreams controls whether the server's
|
||||||
// SETTINGS_MAX_CONCURRENT_STREAMS should be respected
|
// SETTINGS_MAX_CONCURRENT_STREAMS should be respected
|
||||||
// globally. If false, new TCP connections are created to the
|
// globally. If false, new TCP connections are created to the
|
||||||
@ -170,6 +193,19 @@ func (t *Transport) maxHeaderListSize() uint32 {
|
|||||||
return t.MaxHeaderListSize
|
return t.MaxHeaderListSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Transport) maxFrameReadSize() uint32 {
|
||||||
|
if t.MaxReadFrameSize == 0 {
|
||||||
|
return 0 // use the default provided by the peer
|
||||||
|
}
|
||||||
|
if t.MaxReadFrameSize < minMaxFrameSize {
|
||||||
|
return minMaxFrameSize
|
||||||
|
}
|
||||||
|
if t.MaxReadFrameSize > maxFrameSize {
|
||||||
|
return maxFrameSize
|
||||||
|
}
|
||||||
|
return t.MaxReadFrameSize
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Transport) disableCompression() bool {
|
func (t *Transport) disableCompression() bool {
|
||||||
return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
|
return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
|
||||||
}
|
}
|
||||||
@ -292,10 +328,11 @@ type ClientConn struct {
|
|||||||
lastActive time.Time
|
lastActive time.Time
|
||||||
lastIdle time.Time // time last idle
|
lastIdle time.Time // time last idle
|
||||||
// Settings from peer: (also guarded by wmu)
|
// Settings from peer: (also guarded by wmu)
|
||||||
maxFrameSize uint32
|
maxFrameSize uint32
|
||||||
maxConcurrentStreams uint32
|
maxConcurrentStreams uint32
|
||||||
peerMaxHeaderListSize uint64
|
peerMaxHeaderListSize uint64
|
||||||
initialWindowSize uint32
|
peerMaxHeaderTableSize uint32
|
||||||
|
initialWindowSize uint32
|
||||||
|
|
||||||
// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
|
// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
|
||||||
// Write to reqHeaderMu to lock it, read from it to unlock.
|
// Write to reqHeaderMu to lock it, read from it to unlock.
|
||||||
@ -501,6 +538,15 @@ func authorityAddr(scheme string, authority string) (addr string) {
|
|||||||
return net.JoinHostPort(host, port)
|
return net.JoinHostPort(host, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var retryBackoffHook func(time.Duration) *time.Timer
|
||||||
|
|
||||||
|
func backoffNewTimer(d time.Duration) *time.Timer {
|
||||||
|
if retryBackoffHook != nil {
|
||||||
|
return retryBackoffHook(d)
|
||||||
|
}
|
||||||
|
return time.NewTimer(d)
|
||||||
|
}
|
||||||
|
|
||||||
// RoundTripOpt is like RoundTrip, but takes options.
|
// RoundTripOpt is like RoundTrip, but takes options.
|
||||||
func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
|
func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
|
||||||
if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
|
if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
|
||||||
@ -526,11 +572,14 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
|
|||||||
}
|
}
|
||||||
backoff := float64(uint(1) << (uint(retry) - 1))
|
backoff := float64(uint(1) << (uint(retry) - 1))
|
||||||
backoff += backoff * (0.1 * mathrand.Float64())
|
backoff += backoff * (0.1 * mathrand.Float64())
|
||||||
|
d := time.Second * time.Duration(backoff)
|
||||||
|
timer := backoffNewTimer(d)
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Second * time.Duration(backoff)):
|
case <-timer.C:
|
||||||
t.vlogf("RoundTrip retrying after failure: %v", err)
|
t.vlogf("RoundTrip retrying after failure: %v", err)
|
||||||
continue
|
continue
|
||||||
case <-req.Context().Done():
|
case <-req.Context().Done():
|
||||||
|
timer.Stop()
|
||||||
err = req.Context().Err()
|
err = req.Context().Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -668,6 +717,20 @@ func (t *Transport) expectContinueTimeout() time.Duration {
|
|||||||
return t.t1.ExpectContinueTimeout
|
return t.t1.ExpectContinueTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Transport) maxDecoderHeaderTableSize() uint32 {
|
||||||
|
if v := t.MaxDecoderHeaderTableSize; v > 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return initialHeaderTableSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transport) maxEncoderHeaderTableSize() uint32 {
|
||||||
|
if v := t.MaxEncoderHeaderTableSize; v > 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return initialHeaderTableSize
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||||
return t.newClientConn(c, t.disableKeepAlives())
|
return t.newClientConn(c, t.disableKeepAlives())
|
||||||
}
|
}
|
||||||
@ -708,15 +771,19 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
|
|||||||
})
|
})
|
||||||
cc.br = bufio.NewReader(c)
|
cc.br = bufio.NewReader(c)
|
||||||
cc.fr = NewFramer(cc.bw, cc.br)
|
cc.fr = NewFramer(cc.bw, cc.br)
|
||||||
|
if t.maxFrameReadSize() != 0 {
|
||||||
|
cc.fr.SetMaxReadFrameSize(t.maxFrameReadSize())
|
||||||
|
}
|
||||||
if t.CountError != nil {
|
if t.CountError != nil {
|
||||||
cc.fr.countError = t.CountError
|
cc.fr.countError = t.CountError
|
||||||
}
|
}
|
||||||
cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
|
maxHeaderTableSize := t.maxDecoderHeaderTableSize()
|
||||||
|
cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil)
|
||||||
cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
|
cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
|
||||||
|
|
||||||
// TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
|
|
||||||
// henc in response to SETTINGS frames?
|
|
||||||
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
||||||
|
cc.henc.SetMaxDynamicTableSizeLimit(t.maxEncoderHeaderTableSize())
|
||||||
|
cc.peerMaxHeaderTableSize = initialHeaderTableSize
|
||||||
|
|
||||||
if t.AllowHTTP {
|
if t.AllowHTTP {
|
||||||
cc.nextStreamID = 3
|
cc.nextStreamID = 3
|
||||||
@ -731,9 +798,15 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
|
|||||||
{ID: SettingEnablePush, Val: 0},
|
{ID: SettingEnablePush, Val: 0},
|
||||||
{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow},
|
{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow},
|
||||||
}
|
}
|
||||||
|
if max := t.maxFrameReadSize(); max != 0 {
|
||||||
|
initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: max})
|
||||||
|
}
|
||||||
if max := t.maxHeaderListSize(); max != 0 {
|
if max := t.maxHeaderListSize(); max != 0 {
|
||||||
initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})
|
initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})
|
||||||
}
|
}
|
||||||
|
if maxHeaderTableSize != initialHeaderTableSize {
|
||||||
|
initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: maxHeaderTableSize})
|
||||||
|
}
|
||||||
|
|
||||||
cc.bw.Write(clientPreface)
|
cc.bw.Write(clientPreface)
|
||||||
cc.fr.WriteSettings(initialSettings...)
|
cc.fr.WriteSettings(initialSettings...)
|
||||||
@ -1075,7 +1148,7 @@ var errRequestCanceled = errors.New("net/http: request canceled")
|
|||||||
func commaSeparatedTrailers(req *http.Request) (string, error) {
|
func commaSeparatedTrailers(req *http.Request) (string, error) {
|
||||||
keys := make([]string, 0, len(req.Trailer))
|
keys := make([]string, 0, len(req.Trailer))
|
||||||
for k := range req.Trailer {
|
for k := range req.Trailer {
|
||||||
k = http.CanonicalHeaderKey(k)
|
k = canonicalHeader(k)
|
||||||
switch k {
|
switch k {
|
||||||
case "Transfer-Encoding", "Trailer", "Content-Length":
|
case "Transfer-Encoding", "Trailer", "Content-Length":
|
||||||
return "", fmt.Errorf("invalid Trailer key %q", k)
|
return "", fmt.Errorf("invalid Trailer key %q", k)
|
||||||
@ -1612,7 +1685,7 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
|
|||||||
|
|
||||||
var sawEOF bool
|
var sawEOF bool
|
||||||
for !sawEOF {
|
for !sawEOF {
|
||||||
n, err := body.Read(buf[:len(buf)])
|
n, err := body.Read(buf)
|
||||||
if hasContentLen {
|
if hasContentLen {
|
||||||
remainLen -= int64(n)
|
remainLen -= int64(n)
|
||||||
if remainLen == 0 && err == nil {
|
if remainLen == 0 && err == nil {
|
||||||
@ -1915,7 +1988,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|||||||
|
|
||||||
// Header list size is ok. Write the headers.
|
// Header list size is ok. Write the headers.
|
||||||
enumerateHeaders(func(name, value string) {
|
enumerateHeaders(func(name, value string) {
|
||||||
name, ascii := asciiToLower(name)
|
name, ascii := lowerHeader(name)
|
||||||
if !ascii {
|
if !ascii {
|
||||||
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
|
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
|
||||||
// field names have to be ASCII characters (just as in HTTP/1.x).
|
// field names have to be ASCII characters (just as in HTTP/1.x).
|
||||||
@ -1968,7 +2041,7 @@ func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, vv := range trailer {
|
for k, vv := range trailer {
|
||||||
lowKey, ascii := asciiToLower(k)
|
lowKey, ascii := lowerHeader(k)
|
||||||
if !ascii {
|
if !ascii {
|
||||||
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
|
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
|
||||||
// field names have to be ASCII characters (just as in HTTP/1.x).
|
// field names have to be ASCII characters (just as in HTTP/1.x).
|
||||||
@ -2301,7 +2374,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
|
|||||||
Status: status + " " + http.StatusText(statusCode),
|
Status: status + " " + http.StatusText(statusCode),
|
||||||
}
|
}
|
||||||
for _, hf := range regularFields {
|
for _, hf := range regularFields {
|
||||||
key := http.CanonicalHeaderKey(hf.Name)
|
key := canonicalHeader(hf.Name)
|
||||||
if key == "Trailer" {
|
if key == "Trailer" {
|
||||||
t := res.Trailer
|
t := res.Trailer
|
||||||
if t == nil {
|
if t == nil {
|
||||||
@ -2309,7 +2382,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
|
|||||||
res.Trailer = t
|
res.Trailer = t
|
||||||
}
|
}
|
||||||
foreachHeaderElement(hf.Value, func(v string) {
|
foreachHeaderElement(hf.Value, func(v string) {
|
||||||
t[http.CanonicalHeaderKey(v)] = nil
|
t[canonicalHeader(v)] = nil
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
vv := header[key]
|
vv := header[key]
|
||||||
@ -2414,7 +2487,7 @@ func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFr
|
|||||||
|
|
||||||
trailer := make(http.Header)
|
trailer := make(http.Header)
|
||||||
for _, hf := range f.RegularFields() {
|
for _, hf := range f.RegularFields() {
|
||||||
key := http.CanonicalHeaderKey(hf.Name)
|
key := canonicalHeader(hf.Name)
|
||||||
trailer[key] = append(trailer[key], hf.Value)
|
trailer[key] = append(trailer[key], hf.Value)
|
||||||
}
|
}
|
||||||
cs.trailer = trailer
|
cs.trailer = trailer
|
||||||
@ -2760,8 +2833,10 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
|
|||||||
cc.cond.Broadcast()
|
cc.cond.Broadcast()
|
||||||
|
|
||||||
cc.initialWindowSize = s.Val
|
cc.initialWindowSize = s.Val
|
||||||
|
case SettingHeaderTableSize:
|
||||||
|
cc.henc.SetMaxDynamicTableSize(s.Val)
|
||||||
|
cc.peerMaxHeaderTableSize = s.Val
|
||||||
default:
|
default:
|
||||||
// TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably.
|
|
||||||
cc.vlogf("Unhandled Setting: %v", s)
|
cc.vlogf("Unhandled Setting: %v", s)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -2985,7 +3060,11 @@ func (gz *gzipReader) Read(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gz *gzipReader) Close() error {
|
func (gz *gzipReader) Close() error {
|
||||||
return gz.body.Close()
|
if err := gz.body.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gz.zerr = fs.ErrClosed
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type errorReader struct{ err error }
|
type errorReader struct{ err error }
|
||||||
|
14
vendor/golang.org/x/sys/unix/sockcmsg_unix.go
generated
vendored
14
vendor/golang.org/x/sys/unix/sockcmsg_unix.go
generated
vendored
@ -52,6 +52,20 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
|
|||||||
return msgs, nil
|
return msgs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseOneSocketControlMessage parses a single socket control message from b, returning the message header,
|
||||||
|
// message data (a slice of b), and the remainder of b after that single message.
|
||||||
|
// When there are no remaining messages, len(remainder) == 0.
|
||||||
|
func ParseOneSocketControlMessage(b []byte) (hdr Cmsghdr, data []byte, remainder []byte, err error) {
|
||||||
|
h, dbuf, err := socketControlMessageHeaderAndData(b)
|
||||||
|
if err != nil {
|
||||||
|
return Cmsghdr{}, nil, nil, err
|
||||||
|
}
|
||||||
|
if i := cmsgAlignOf(int(h.Len)); i < len(b) {
|
||||||
|
remainder = b[i:]
|
||||||
|
}
|
||||||
|
return *h, dbuf, remainder, nil
|
||||||
|
}
|
||||||
|
|
||||||
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
|
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
|
||||||
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
|
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
|
||||||
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
|
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
|
||||||
|
1
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
@ -1554,6 +1554,7 @@ func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Sockle
|
|||||||
var iova [1]Iovec
|
var iova [1]Iovec
|
||||||
iova[0].Base = &dummy
|
iova[0].Base = &dummy
|
||||||
iova[0].SetLen(1)
|
iova[0].SetLen(1)
|
||||||
|
iov = iova[:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg.Control = &oob[0]
|
msg.Control = &oob[0]
|
||||||
|
1
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
1
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
@ -367,6 +367,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
|||||||
//sys IsWindowUnicode(hwnd HWND) (isUnicode bool) = user32.IsWindowUnicode
|
//sys IsWindowUnicode(hwnd HWND) (isUnicode bool) = user32.IsWindowUnicode
|
||||||
//sys IsWindowVisible(hwnd HWND) (isVisible bool) = user32.IsWindowVisible
|
//sys IsWindowVisible(hwnd HWND) (isVisible bool) = user32.IsWindowVisible
|
||||||
//sys GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) = user32.GetGUIThreadInfo
|
//sys GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) = user32.GetGUIThreadInfo
|
||||||
|
//sys GetLargePageMinimum() (size uintptr)
|
||||||
|
|
||||||
// Volume Management Functions
|
// Volume Management Functions
|
||||||
//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
|
//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
|
||||||
|
7
vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
7
vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
@ -252,6 +252,7 @@ var (
|
|||||||
procGetFileType = modkernel32.NewProc("GetFileType")
|
procGetFileType = modkernel32.NewProc("GetFileType")
|
||||||
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
|
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
|
||||||
procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
|
procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
|
||||||
|
procGetLargePageMinimum = modkernel32.NewProc("GetLargePageMinimum")
|
||||||
procGetLastError = modkernel32.NewProc("GetLastError")
|
procGetLastError = modkernel32.NewProc("GetLastError")
|
||||||
procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW")
|
procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW")
|
||||||
procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
|
procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
|
||||||
@ -2180,6 +2181,12 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLargePageMinimum() (size uintptr) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetLargePageMinimum.Addr(), 0, 0, 0, 0)
|
||||||
|
size = uintptr(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func GetLastError() (lasterr error) {
|
func GetLastError() (lasterr error) {
|
||||||
r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
|
r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
|
12
vendor/golang.org/x/text/unicode/bidi/trieval.go
generated
vendored
12
vendor/golang.org/x/text/unicode/bidi/trieval.go
generated
vendored
@ -37,18 +37,6 @@ const (
|
|||||||
unknownClass = ^Class(0)
|
unknownClass = ^Class(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
var controlToClass = map[rune]Class{
|
|
||||||
0x202D: LRO, // LeftToRightOverride,
|
|
||||||
0x202E: RLO, // RightToLeftOverride,
|
|
||||||
0x202A: LRE, // LeftToRightEmbedding,
|
|
||||||
0x202B: RLE, // RightToLeftEmbedding,
|
|
||||||
0x202C: PDF, // PopDirectionalFormat,
|
|
||||||
0x2066: LRI, // LeftToRightIsolate,
|
|
||||||
0x2067: RLI, // RightToLeftIsolate,
|
|
||||||
0x2068: FSI, // FirstStrongIsolate,
|
|
||||||
0x2069: PDI, // PopDirectionalIsolate,
|
|
||||||
}
|
|
||||||
|
|
||||||
// A trie entry has the following bits:
|
// A trie entry has the following bits:
|
||||||
// 7..5 XOR mask for brackets
|
// 7..5 XOR mask for brackets
|
||||||
// 4 1: Bracket open, 0: Bracket close
|
// 4 1: Bracket open, 0: Bracket close
|
||||||
|
20
vendor/golang.org/x/time/rate/rate.go
generated
vendored
20
vendor/golang.org/x/time/rate/rate.go
generated
vendored
@ -83,7 +83,7 @@ func (lim *Limiter) Burst() int {
|
|||||||
// TokensAt returns the number of tokens available at time t.
|
// TokensAt returns the number of tokens available at time t.
|
||||||
func (lim *Limiter) TokensAt(t time.Time) float64 {
|
func (lim *Limiter) TokensAt(t time.Time) float64 {
|
||||||
lim.mu.Lock()
|
lim.mu.Lock()
|
||||||
_, _, tokens := lim.advance(t) // does not mutute lim
|
_, tokens := lim.advance(t) // does not mutate lim
|
||||||
lim.mu.Unlock()
|
lim.mu.Unlock()
|
||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ func (r *Reservation) CancelAt(t time.Time) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// advance time to now
|
// advance time to now
|
||||||
t, _, tokens := r.lim.advance(t)
|
t, tokens := r.lim.advance(t)
|
||||||
// calculate new number of tokens
|
// calculate new number of tokens
|
||||||
tokens += restoreTokens
|
tokens += restoreTokens
|
||||||
if burst := float64(r.lim.burst); tokens > burst {
|
if burst := float64(r.lim.burst); tokens > burst {
|
||||||
@ -304,7 +304,7 @@ func (lim *Limiter) SetLimitAt(t time.Time, newLimit Limit) {
|
|||||||
lim.mu.Lock()
|
lim.mu.Lock()
|
||||||
defer lim.mu.Unlock()
|
defer lim.mu.Unlock()
|
||||||
|
|
||||||
t, _, tokens := lim.advance(t)
|
t, tokens := lim.advance(t)
|
||||||
|
|
||||||
lim.last = t
|
lim.last = t
|
||||||
lim.tokens = tokens
|
lim.tokens = tokens
|
||||||
@ -321,7 +321,7 @@ func (lim *Limiter) SetBurstAt(t time.Time, newBurst int) {
|
|||||||
lim.mu.Lock()
|
lim.mu.Lock()
|
||||||
defer lim.mu.Unlock()
|
defer lim.mu.Unlock()
|
||||||
|
|
||||||
t, _, tokens := lim.advance(t)
|
t, tokens := lim.advance(t)
|
||||||
|
|
||||||
lim.last = t
|
lim.last = t
|
||||||
lim.tokens = tokens
|
lim.tokens = tokens
|
||||||
@ -356,7 +356,7 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t, last, tokens := lim.advance(t)
|
t, tokens := lim.advance(t)
|
||||||
|
|
||||||
// Calculate the remaining number of tokens resulting from the request.
|
// Calculate the remaining number of tokens resulting from the request.
|
||||||
tokens -= float64(n)
|
tokens -= float64(n)
|
||||||
@ -379,15 +379,11 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
|
|||||||
if ok {
|
if ok {
|
||||||
r.tokens = n
|
r.tokens = n
|
||||||
r.timeToAct = t.Add(waitDuration)
|
r.timeToAct = t.Add(waitDuration)
|
||||||
}
|
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
if ok {
|
|
||||||
lim.last = t
|
lim.last = t
|
||||||
lim.tokens = tokens
|
lim.tokens = tokens
|
||||||
lim.lastEvent = r.timeToAct
|
lim.lastEvent = r.timeToAct
|
||||||
} else {
|
|
||||||
lim.last = last
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
@ -396,7 +392,7 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
|
|||||||
// advance calculates and returns an updated state for lim resulting from the passage of time.
|
// advance calculates and returns an updated state for lim resulting from the passage of time.
|
||||||
// lim is not changed.
|
// lim is not changed.
|
||||||
// advance requires that lim.mu is held.
|
// advance requires that lim.mu is held.
|
||||||
func (lim *Limiter) advance(t time.Time) (newT time.Time, newLast time.Time, newTokens float64) {
|
func (lim *Limiter) advance(t time.Time) (newT time.Time, newTokens float64) {
|
||||||
last := lim.last
|
last := lim.last
|
||||||
if t.Before(last) {
|
if t.Before(last) {
|
||||||
last = t
|
last = t
|
||||||
@ -409,7 +405,7 @@ func (lim *Limiter) advance(t time.Time) (newT time.Time, newLast time.Time, new
|
|||||||
if burst := float64(lim.burst); tokens > burst {
|
if burst := float64(lim.burst); tokens > burst {
|
||||||
tokens = burst
|
tokens = burst
|
||||||
}
|
}
|
||||||
return t, last, tokens
|
return t, tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
// durationFromTokens is a unit conversion function from the number of tokens to the duration
|
// durationFromTokens is a unit conversion function from the number of tokens to the duration
|
||||||
|
67
vendor/golang.org/x/time/rate/sometimes.go
generated
vendored
Normal file
67
vendor/golang.org/x/time/rate/sometimes.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package rate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sometimes will perform an action occasionally. The First, Every, and
|
||||||
|
// Interval fields govern the behavior of Do, which performs the action.
|
||||||
|
// A zero Sometimes value will perform an action exactly once.
|
||||||
|
//
|
||||||
|
// # Example: logging with rate limiting
|
||||||
|
//
|
||||||
|
// var sometimes = rate.Sometimes{First: 3, Interval: 10*time.Second}
|
||||||
|
// func Spammy() {
|
||||||
|
// sometimes.Do(func() { log.Info("here I am!") })
|
||||||
|
// }
|
||||||
|
type Sometimes struct {
|
||||||
|
First int // if non-zero, the first N calls to Do will run f.
|
||||||
|
Every int // if non-zero, every Nth call to Do will run f.
|
||||||
|
Interval time.Duration // if non-zero and Interval has elapsed since f's last run, Do will run f.
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
count int // number of Do calls
|
||||||
|
last time.Time // last time f was run
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do runs the function f as allowed by First, Every, and Interval.
|
||||||
|
//
|
||||||
|
// The model is a union (not intersection) of filters. The first call to Do
|
||||||
|
// always runs f. Subsequent calls to Do run f if allowed by First or Every or
|
||||||
|
// Interval.
|
||||||
|
//
|
||||||
|
// A non-zero First:N causes the first N Do(f) calls to run f.
|
||||||
|
//
|
||||||
|
// A non-zero Every:M causes every Mth Do(f) call, starting with the first, to
|
||||||
|
// run f.
|
||||||
|
//
|
||||||
|
// A non-zero Interval causes Do(f) to run f if Interval has elapsed since
|
||||||
|
// Do last ran f.
|
||||||
|
//
|
||||||
|
// Specifying multiple filters produces the union of these execution streams.
|
||||||
|
// For example, specifying both First:N and Every:M causes the first N Do(f)
|
||||||
|
// calls and every Mth Do(f) call, starting with the first, to run f. See
|
||||||
|
// Examples for more.
|
||||||
|
//
|
||||||
|
// If Do is called multiple times simultaneously, the calls will block and run
|
||||||
|
// serially. Therefore, Do is intended for lightweight operations.
|
||||||
|
//
|
||||||
|
// Because a call to Do may block until f returns, if f causes Do to be called,
|
||||||
|
// it will deadlock.
|
||||||
|
func (s *Sometimes) Do(f func()) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
if s.count == 0 ||
|
||||||
|
(s.First > 0 && s.count < s.First) ||
|
||||||
|
(s.Every > 0 && s.count%s.Every == 0) ||
|
||||||
|
(s.Interval > 0 && time.Since(s.last) >= s.Interval) {
|
||||||
|
f()
|
||||||
|
s.last = time.Now()
|
||||||
|
}
|
||||||
|
s.count++
|
||||||
|
}
|
14
vendor/modules.txt
vendored
14
vendor/modules.txt
vendored
@ -15,10 +15,10 @@ github.com/labstack/gommon/random
|
|||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/likexian/gokit/assert
|
github.com/likexian/gokit/assert
|
||||||
github.com/likexian/gokit/xslice
|
github.com/likexian/gokit/xslice
|
||||||
# github.com/likexian/whois v1.14.2
|
# github.com/likexian/whois v1.14.4
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/likexian/whois
|
github.com/likexian/whois
|
||||||
# github.com/likexian/whois-parser v1.24.1
|
# github.com/likexian/whois-parser v1.24.2
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/likexian/whois-parser
|
github.com/likexian/whois-parser
|
||||||
# github.com/mattn/go-colorable v0.1.13
|
# github.com/mattn/go-colorable v0.1.13
|
||||||
@ -39,11 +39,11 @@ github.com/valyala/bytebufferpool
|
|||||||
# github.com/valyala/fasttemplate v1.2.2
|
# github.com/valyala/fasttemplate v1.2.2
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/valyala/fasttemplate
|
github.com/valyala/fasttemplate
|
||||||
# golang.org/x/crypto v0.1.0
|
# golang.org/x/crypto v0.4.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/crypto/acme
|
golang.org/x/crypto/acme
|
||||||
golang.org/x/crypto/acme/autocert
|
golang.org/x/crypto/acme/autocert
|
||||||
# golang.org/x/net v0.1.0
|
# golang.org/x/net v0.4.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/net/http/httpguts
|
golang.org/x/net/http/httpguts
|
||||||
golang.org/x/net/http2
|
golang.org/x/net/http2
|
||||||
@ -52,17 +52,17 @@ golang.org/x/net/http2/hpack
|
|||||||
golang.org/x/net/idna
|
golang.org/x/net/idna
|
||||||
golang.org/x/net/internal/socks
|
golang.org/x/net/internal/socks
|
||||||
golang.org/x/net/proxy
|
golang.org/x/net/proxy
|
||||||
# golang.org/x/sys v0.1.0
|
# golang.org/x/sys v0.3.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/sys/internal/unsafeheader
|
golang.org/x/sys/internal/unsafeheader
|
||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
# golang.org/x/text v0.4.0
|
# golang.org/x/text v0.5.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/text/secure/bidirule
|
golang.org/x/text/secure/bidirule
|
||||||
golang.org/x/text/transform
|
golang.org/x/text/transform
|
||||||
golang.org/x/text/unicode/bidi
|
golang.org/x/text/unicode/bidi
|
||||||
golang.org/x/text/unicode/norm
|
golang.org/x/text/unicode/norm
|
||||||
# golang.org/x/time v0.1.0
|
# golang.org/x/time v0.3.0
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/time/rate
|
golang.org/x/time/rate
|
||||||
|
Loading…
Reference in New Issue
Block a user