feat: Add HTTP2 for unencrypted HTTP (v3) (#4248)

This commit is contained in:
Milos Gajdos 2024-01-18 20:51:58 +07:00 committed by GitHub
commit 945eed71e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 397 additions and 124 deletions

View file

@ -157,9 +157,15 @@ type Configuration struct {
// HTTP2 configuration options // HTTP2 configuration options
HTTP2 struct { HTTP2 struct {
// Specifies whether the registry should disallow clients attempting // Specifies whether the registry should disallow clients attempting
// to connect via http2. If set to true, only http/1.1 is supported. // to connect via HTTP/2. If set to true, only HTTP/1.1 is supported.
Disabled bool `yaml:"disabled,omitempty"` Disabled bool `yaml:"disabled,omitempty"`
} `yaml:"http2,omitempty"` } `yaml:"http2,omitempty"`
H2C struct {
// Enables H2C (HTTP/2 Cleartext). Enable to support HTTP/2 without needing to configure TLS
// Useful when deploying the registry behind a load balancer (e.g. Cloud Run)
Enabled bool `yaml:"enabled,omitempty"`
} `yaml:"h2c,omitempty"`
} `yaml:"http,omitempty"` } `yaml:"http,omitempty"`
// Notifications specifies configuration about various endpoint to which // Notifications specifies configuration about various endpoint to which

View file

@ -97,6 +97,9 @@ var configStruct = Configuration{
HTTP2 struct { HTTP2 struct {
Disabled bool `yaml:"disabled,omitempty"` Disabled bool `yaml:"disabled,omitempty"`
} `yaml:"http2,omitempty"` } `yaml:"http2,omitempty"`
H2C struct {
Enabled bool `yaml:"enabled,omitempty"`
} `yaml:"h2c,omitempty"`
}{ }{
TLS: struct { TLS: struct {
Certificate string `yaml:"certificate,omitempty"` Certificate string `yaml:"certificate,omitempty"`
@ -121,6 +124,11 @@ var configStruct = Configuration{
}{ }{
Disabled: false, Disabled: false,
}, },
H2C: struct {
Enabled bool `yaml:"enabled,omitempty"`
}{
Enabled: true,
},
}, },
Redis: Redis{ Redis: Redis{
Addr: "localhost:6379", Addr: "localhost:6379",

View file

@ -220,6 +220,8 @@ http:
X-Content-Type-Options: [nosniff] X-Content-Type-Options: [nosniff]
http2: http2:
disabled: false disabled: false
h2c:
enabled: false
notifications: notifications:
events: events:
includereferences: true includereferences: true
@ -724,6 +726,8 @@ http:
X-Content-Type-Options: [nosniff] X-Content-Type-Options: [nosniff]
http2: http2:
disabled: false disabled: false
h2c:
enabled: false
``` ```
The `http` option details the configuration for the HTTP server that hosts the The `http` option details the configuration for the HTTP server that hosts the
@ -870,13 +874,24 @@ registry. This header is included in the example configuration file.
### `http2` ### `http2`
The `http2` structure within `http` is **optional**. Use this to control http2 The `http2` structure within `http` is **optional**. Use this to control HTTP/2 over TLS
settings for the registry. settings for the registry.
If `tls` is not configured this option is ignored. To enable HTTP/2 over non TLS connections use `h2c` instead.
| Parameter | Required | Description | | Parameter | Required | Description |
|-----------|----------|-------------------------------------------------------| |-----------|----------|-------------------------------------------------------|
| `disabled` | no | If `true`, then `http2` support is disabled. | | `disabled` | no | If `true`, then `http2` support is disabled. |
### `h2c`
The `h2c` structure within `http` is **optional**. Use this to control H2C (HTTP/2 Cleartext)
settings for the registry.
Useful when deploying the registry behind a load balancer (e.g. Google Cloud Run)
| Parameter | Required | Description |
|-----------|----------|-------------------------------------------------------|
| `enabled` | no | If `true`, then `h2c` support is enabled. |
## `notifications` ## `notifications`
```yaml ```yaml

6
go.mod
View file

@ -30,7 +30,7 @@ require (
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
go.opentelemetry.io/contrib/exporters/autoexport v0.46.1 go.opentelemetry.io/contrib/exporters/autoexport v0.46.1
go.opentelemetry.io/otel/sdk v1.21.0 go.opentelemetry.io/otel/sdk v1.21.0
golang.org/x/crypto v0.17.0 golang.org/x/crypto v0.18.0
golang.org/x/oauth2 v0.11.0 golang.org/x/oauth2 v0.11.0
google.golang.org/api v0.126.0 google.golang.org/api v0.126.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
@ -87,9 +87,9 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/net v0.18.0 // indirect golang.org/x/net v0.20.0
golang.org/x/sync v0.3.0 // indirect golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect

12
go.sum
View file

@ -280,8 +280,8 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -302,8 +302,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
@ -332,8 +332,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -20,6 +20,8 @@ import (
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"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/http2"
"golang.org/x/net/http2/h2c"
"github.com/distribution/distribution/v3/configuration" "github.com/distribution/distribution/v3/configuration"
"github.com/distribution/distribution/v3/health" "github.com/distribution/distribution/v3/health"
@ -158,6 +160,9 @@ func NewRegistry(ctx context.Context, config *configuration.Configuration) (*Reg
if err != nil { if err != nil {
return nil, fmt.Errorf("error during open telemetry initialization: %v", err) return nil, fmt.Errorf("error during open telemetry initialization: %v", err)
} }
if config.HTTP.H2C.Enabled {
handler = h2c.NewHandler(handler, &http2.Server{})
}
handler = otelHandler(handler) handler = otelHandler(handler)
server := &http.Server{ server := &http.Server{

View file

@ -1,39 +0,0 @@
// Copyright 2019 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.
//go:build !go1.13
package poly1305
// Generic fallbacks for the math/bits intrinsics, copied from
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
// variable time fallbacks until Go 1.13.
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
sum = x + y + carry
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
return
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
diff = x - y - borrow
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
return
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
const mask32 = 1<<32 - 1
x0 := x & mask32
x1 := x >> 32
y0 := y & mask32
y1 := y >> 32
w0 := x0 * y0
t := x1*y0 + w0>>32
w1 := t & mask32
w2 := t >> 32
w1 += x0 * y1
hi = x1*y1 + w2 + w1>>32
lo = x * y
return
}

View file

@ -1,21 +0,0 @@
// Copyright 2019 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.
//go:build go1.13
package poly1305
import "math/bits"
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
return bits.Add64(x, y, carry)
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
return bits.Sub64(x, y, borrow)
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
return bits.Mul64(x, y)
}

View file

@ -7,7 +7,10 @@
package poly1305 package poly1305
import "encoding/binary" import (
"encoding/binary"
"math/bits"
)
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag // Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
// for a 64 bytes message is approximately // for a 64 bytes message is approximately
@ -114,13 +117,13 @@ type uint128 struct {
} }
func mul64(a, b uint64) uint128 { func mul64(a, b uint64) uint128 {
hi, lo := bitsMul64(a, b) hi, lo := bits.Mul64(a, b)
return uint128{lo, hi} return uint128{lo, hi}
} }
func add128(a, b uint128) uint128 { func add128(a, b uint128) uint128 {
lo, c := bitsAdd64(a.lo, b.lo, 0) lo, c := bits.Add64(a.lo, b.lo, 0)
hi, c := bitsAdd64(a.hi, b.hi, c) hi, c := bits.Add64(a.hi, b.hi, c)
if c != 0 { if c != 0 {
panic("poly1305: unexpected overflow") panic("poly1305: unexpected overflow")
} }
@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) {
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just // hide leading zeroes. For full chunks, that's 1 << 128, so we can just
// add 1 to the most significant (2¹²⁸) limb, h2. // add 1 to the most significant (2¹²⁸) limb, h2.
if len(msg) >= TagSize { if len(msg) >= TagSize {
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
h2 += c + 1 h2 += c + 1
msg = msg[TagSize:] msg = msg[TagSize:]
@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) {
copy(buf[:], msg) copy(buf[:], msg)
buf[len(msg)] = 1 buf[len(msg)] = 1
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
h2 += c h2 += c
msg = nil msg = nil
@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) {
m3 := h2r1 m3 := h2r1
t0 := m0.lo t0 := m0.lo
t1, c := bitsAdd64(m1.lo, m0.hi, 0) t1, c := bits.Add64(m1.lo, m0.hi, 0)
t2, c := bitsAdd64(m2.lo, m1.hi, c) t2, c := bits.Add64(m2.lo, m1.hi, c)
t3, _ := bitsAdd64(m3.lo, m2.hi, c) t3, _ := bits.Add64(m3.lo, m2.hi, c)
// Now we have the result as 4 64-bit limbs, and we need to reduce it // Now we have the result as 4 64-bit limbs, and we need to reduce it
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) {
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
h0, c = bitsAdd64(h0, cc.lo, 0) h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bitsAdd64(h1, cc.hi, c) h1, c = bits.Add64(h1, cc.hi, c)
h2 += c h2 += c
cc = shiftRightBy2(cc) cc = shiftRightBy2(cc)
h0, c = bitsAdd64(h0, cc.lo, 0) h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bitsAdd64(h1, cc.hi, c) h1, c = bits.Add64(h1, cc.hi, c)
h2 += c h2 += c
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
// result if the subtraction underflows, and t otherwise. // result if the subtraction underflows, and t otherwise.
hMinusP0, b := bitsSub64(h0, p0, 0) hMinusP0, b := bits.Sub64(h0, p0, 0)
hMinusP1, b := bitsSub64(h1, p1, b) hMinusP1, b := bits.Sub64(h1, p1, b)
_, b = bitsSub64(h2, p2, b) _, b = bits.Sub64(h2, p2, b)
// h = h if h < p else h - p // h = h if h < p else h - p
h0 = select64(b, h0, hMinusP0) h0 = select64(b, h0, hMinusP0)
@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
// //
// by just doing a wide addition with the 128 low bits of h and discarding // by just doing a wide addition with the 128 low bits of h and discarding
// the overflow. // the overflow.
h0, c := bitsAdd64(h0, s[0], 0) h0, c := bits.Add64(h0, s[0], 0)
h1, _ = bitsAdd64(h1, s[1], c) h1, _ = bits.Add64(h1, s[1], c)
binary.LittleEndian.PutUint64(out[0:8], h0) binary.LittleEndian.PutUint64(out[0:8], h0)
binary.LittleEndian.PutUint64(out[8:16], h1) binary.LittleEndian.PutUint64(out[8:16], h1)

240
vendor/golang.org/x/net/http2/h2c/h2c.go generated vendored Normal file
View file

@ -0,0 +1,240 @@
// Copyright 2018 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 h2c implements the unencrypted "h2c" form of HTTP/2.
//
// The h2c protocol is the non-TLS version of HTTP/2 which is not available from
// net/http or golang.org/x/net/http2.
package h2c
import (
"bufio"
"bytes"
"encoding/base64"
"errors"
"fmt"
"io"
"log"
"net"
"net/http"
"net/textproto"
"os"
"strings"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2"
)
var (
http2VerboseLogs bool
)
func init() {
e := os.Getenv("GODEBUG")
if strings.Contains(e, "http2debug=1") || strings.Contains(e, "http2debug=2") {
http2VerboseLogs = true
}
}
// h2cHandler is a Handler which implements h2c by hijacking the HTTP/1 traffic
// that should be h2c traffic. There are two ways to begin a h2c connection
// (RFC 7540 Section 3.2 and 3.4): (1) Starting with Prior Knowledge - this
// works by starting an h2c connection with a string of bytes that is valid
// HTTP/1, but unlikely to occur in practice and (2) Upgrading from HTTP/1 to
// h2c - this works by using the HTTP/1 Upgrade header to request an upgrade to
// h2c. When either of those situations occur we hijack the HTTP/1 connection,
// convert it to an HTTP/2 connection and pass the net.Conn to http2.ServeConn.
type h2cHandler struct {
Handler http.Handler
s *http2.Server
}
// NewHandler returns an http.Handler that wraps h, intercepting any h2c
// traffic. If a request is an h2c connection, it's hijacked and redirected to
// s.ServeConn. Otherwise the returned Handler just forwards requests to h. This
// works because h2c is designed to be parseable as valid HTTP/1, but ignored by
// any HTTP server that does not handle h2c. Therefore we leverage the HTTP/1
// compatible parts of the Go http library to parse and recognize h2c requests.
// Once a request is recognized as h2c, we hijack the connection and convert it
// to an HTTP/2 connection which is understandable to s.ServeConn. (s.ServeConn
// understands HTTP/2 except for the h2c part of it.)
//
// The first request on an h2c connection is read entirely into memory before
// the Handler is called. To limit the memory consumed by this request, wrap
// the result of NewHandler in an http.MaxBytesHandler.
func NewHandler(h http.Handler, s *http2.Server) http.Handler {
return &h2cHandler{
Handler: h,
s: s,
}
}
// extractServer extracts existing http.Server instance from http.Request or create an empty http.Server
func extractServer(r *http.Request) *http.Server {
server, ok := r.Context().Value(http.ServerContextKey).(*http.Server)
if ok {
return server
}
return new(http.Server)
}
// ServeHTTP implement the h2c support that is enabled by h2c.GetH2CHandler.
func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Handle h2c with prior knowledge (RFC 7540 Section 3.4)
if r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0" {
if http2VerboseLogs {
log.Print("h2c: attempting h2c with prior knowledge.")
}
conn, err := initH2CWithPriorKnowledge(w)
if err != nil {
if http2VerboseLogs {
log.Printf("h2c: error h2c with prior knowledge: %v", err)
}
return
}
defer conn.Close()
s.s.ServeConn(conn, &http2.ServeConnOpts{
Context: r.Context(),
BaseConfig: extractServer(r),
Handler: s.Handler,
SawClientPreface: true,
})
return
}
// Handle Upgrade to h2c (RFC 7540 Section 3.2)
if isH2CUpgrade(r.Header) {
conn, settings, err := h2cUpgrade(w, r)
if err != nil {
if http2VerboseLogs {
log.Printf("h2c: error h2c upgrade: %v", err)
}
w.WriteHeader(http.StatusInternalServerError)
return
}
defer conn.Close()
s.s.ServeConn(conn, &http2.ServeConnOpts{
Context: r.Context(),
BaseConfig: extractServer(r),
Handler: s.Handler,
UpgradeRequest: r,
Settings: settings,
})
return
}
s.Handler.ServeHTTP(w, r)
return
}
// initH2CWithPriorKnowledge implements creating a h2c connection with prior
// knowledge (Section 3.4) and creates a net.Conn suitable for http2.ServeConn.
// All we have to do is look for the client preface that is suppose to be part
// of the body, and reforward the client preface on the net.Conn this function
// creates.
func initH2CWithPriorKnowledge(w http.ResponseWriter) (net.Conn, error) {
hijacker, ok := w.(http.Hijacker)
if !ok {
return nil, errors.New("h2c: connection does not support Hijack")
}
conn, rw, err := hijacker.Hijack()
if err != nil {
return nil, err
}
const expectedBody = "SM\r\n\r\n"
buf := make([]byte, len(expectedBody))
n, err := io.ReadFull(rw, buf)
if err != nil {
return nil, fmt.Errorf("h2c: error reading client preface: %s", err)
}
if string(buf[:n]) == expectedBody {
return newBufConn(conn, rw), nil
}
conn.Close()
return nil, errors.New("h2c: invalid client preface")
}
// h2cUpgrade establishes a h2c connection using the HTTP/1 upgrade (Section 3.2).
func h2cUpgrade(w http.ResponseWriter, r *http.Request) (_ net.Conn, settings []byte, err error) {
settings, err = getH2Settings(r.Header)
if err != nil {
return nil, nil, err
}
hijacker, ok := w.(http.Hijacker)
if !ok {
return nil, nil, errors.New("h2c: connection does not support Hijack")
}
body, err := io.ReadAll(r.Body)
if err != nil {
return nil, nil, err
}
r.Body = io.NopCloser(bytes.NewBuffer(body))
conn, rw, err := hijacker.Hijack()
if err != nil {
return nil, nil, err
}
rw.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: h2c\r\n\r\n"))
return newBufConn(conn, rw), settings, nil
}
// isH2CUpgrade returns true if the header properly request an upgrade to h2c
// as specified by Section 3.2.
func isH2CUpgrade(h http.Header) bool {
return httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Upgrade")], "h2c") &&
httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Connection")], "HTTP2-Settings")
}
// getH2Settings returns the settings in the HTTP2-Settings header.
func getH2Settings(h http.Header) ([]byte, error) {
vals, ok := h[textproto.CanonicalMIMEHeaderKey("HTTP2-Settings")]
if !ok {
return nil, errors.New("missing HTTP2-Settings header")
}
if len(vals) != 1 {
return nil, fmt.Errorf("expected 1 HTTP2-Settings. Got: %v", vals)
}
settings, err := base64.RawURLEncoding.DecodeString(vals[0])
if err != nil {
return nil, err
}
return settings, nil
}
func newBufConn(conn net.Conn, rw *bufio.ReadWriter) net.Conn {
rw.Flush()
if rw.Reader.Buffered() == 0 {
// If there's no buffered data to be read,
// we can just discard the bufio.ReadWriter.
return conn
}
return &bufConn{conn, rw.Reader}
}
// bufConn wraps a net.Conn, but reads drain the bufio.Reader first.
type bufConn struct {
net.Conn
*bufio.Reader
}
func (c *bufConn) Read(p []byte) (int, error) {
if c.Reader == nil {
return c.Conn.Read(p)
}
n := c.Reader.Buffered()
if n == 0 {
c.Reader = nil
return c.Conn.Read(p)
}
if n < len(p) {
p = p[:n]
}
return c.Reader.Read(p)
}

View file

@ -248,6 +248,7 @@ struct ltchars {
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/net_namespace.h> #include <linux/net_namespace.h>
#include <linux/nfc.h> #include <linux/nfc.h>
@ -283,10 +284,6 @@ struct ltchars {
#include <asm/termbits.h> #include <asm/termbits.h>
#endif #endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#ifndef PTRACE_GETREGS #ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc #define PTRACE_GETREGS 0xc
#endif #endif
@ -295,14 +292,6 @@ struct ltchars {
#define PTRACE_SETREGS 0xd #define PTRACE_SETREGS 0xd
#endif #endif
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#ifndef SOL_SMC
#define SOL_SMC 286
#endif
#ifdef SOL_BLUETOOTH #ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h // SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go // but it is already in bluetooth_linux.go
@ -319,10 +308,23 @@ struct ltchars {
#undef TIPC_WAIT_FOREVER #undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff #define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/l2tp.h // Copied from linux/netfilter/nf_nat.h
// Including linux/l2tp.h here causes conflicts between linux/in.h // Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
// and netinet/in.h included via net/route.h above. // and netinet/in.h.
#define IPPROTO_L2TP 115 #define NF_NAT_RANGE_MAP_IPS (1 << 0)
#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h. // Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields. // Keep in sync with the size of the referenced fields.
@ -603,6 +605,9 @@ ccflags="$@"
$2 ~ /^FSOPT_/ || $2 ~ /^FSOPT_/ ||
$2 ~ /^WDIO[CFS]_/ || $2 ~ /^WDIO[CFS]_/ ||
$2 ~ /^NFN/ || $2 ~ /^NFN/ ||
$2 !~ /^NFT_META_IIFTYPE/ &&
$2 ~ /^NFT_/ ||
$2 ~ /^NF_NAT_/ ||
$2 ~ /^XDP_/ || $2 ~ /^XDP_/ ||
$2 ~ /^RWF_/ || $2 ~ /^RWF_/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ || $2 ~ /^(HDIO|WIN|SMART)_/ ||

View file

@ -2127,6 +2127,60 @@ const (
NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4 NFNL_SUBSYS_ULOG = 0x4
NFS_SUPER_MAGIC = 0x6969 NFS_SUPER_MAGIC = 0x6969
NFT_CHAIN_FLAGS = 0x7
NFT_CHAIN_MAXNAMELEN = 0x100
NFT_CT_MAX = 0x17
NFT_DATA_RESERVED_MASK = 0xffffff00
NFT_DATA_VALUE_MAXLEN = 0x40
NFT_EXTHDR_OP_MAX = 0x4
NFT_FIB_RESULT_MAX = 0x3
NFT_INNER_MASK = 0xf
NFT_LOGLEVEL_MAX = 0x8
NFT_NAME_MAXLEN = 0x100
NFT_NG_MAX = 0x1
NFT_OBJECT_CONNLIMIT = 0x5
NFT_OBJECT_COUNTER = 0x1
NFT_OBJECT_CT_EXPECT = 0x9
NFT_OBJECT_CT_HELPER = 0x3
NFT_OBJECT_CT_TIMEOUT = 0x7
NFT_OBJECT_LIMIT = 0x4
NFT_OBJECT_MAX = 0xa
NFT_OBJECT_QUOTA = 0x2
NFT_OBJECT_SECMARK = 0x8
NFT_OBJECT_SYNPROXY = 0xa
NFT_OBJECT_TUNNEL = 0x6
NFT_OBJECT_UNSPEC = 0x0
NFT_OBJ_MAXNAMELEN = 0x100
NFT_OSF_MAXGENRELEN = 0x10
NFT_QUEUE_FLAG_BYPASS = 0x1
NFT_QUEUE_FLAG_CPU_FANOUT = 0x2
NFT_QUEUE_FLAG_MASK = 0x3
NFT_REG32_COUNT = 0x10
NFT_REG32_SIZE = 0x4
NFT_REG_MAX = 0x4
NFT_REG_SIZE = 0x10
NFT_REJECT_ICMPX_MAX = 0x3
NFT_RT_MAX = 0x4
NFT_SECMARK_CTX_MAXLEN = 0x100
NFT_SET_MAXNAMELEN = 0x100
NFT_SOCKET_MAX = 0x3
NFT_TABLE_F_MASK = 0x3
NFT_TABLE_MAXNAMELEN = 0x100
NFT_TRACETYPE_MAX = 0x3
NFT_TUNNEL_F_MASK = 0x7
NFT_TUNNEL_MAX = 0x1
NFT_TUNNEL_MODE_MAX = 0x2
NFT_USERDATA_MAXLEN = 0x100
NFT_XFRM_KEY_MAX = 0x6
NF_NAT_RANGE_MAP_IPS = 0x1
NF_NAT_RANGE_MASK = 0x7f
NF_NAT_RANGE_NETMAP = 0x40
NF_NAT_RANGE_PERSISTENT = 0x8
NF_NAT_RANGE_PROTO_OFFSET = 0x20
NF_NAT_RANGE_PROTO_RANDOM = 0x4
NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14
NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10
NF_NAT_RANGE_PROTO_SPECIFIED = 0x2
NILFS_SUPER_MAGIC = 0x3434 NILFS_SUPER_MAGIC = 0x3434
NL0 = 0x0 NL0 = 0x0
NL1 = 0x100 NL1 = 0x100

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View file

@ -194,6 +194,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error) //sys SetEndOfFile(handle Handle) (err error)
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]

View file

@ -342,6 +342,7 @@ var (
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode") procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent") procSetEvent = modkernel32.NewProc("SetEvent")
@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) {
return return
} }
func SetFileValidData(handle Handle, validDataLength int64) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if r1 == 0 { if r1 == 0 {

7
vendor/modules.txt vendored
View file

@ -467,7 +467,7 @@ go.opentelemetry.io/proto/otlp/common/v1
go.opentelemetry.io/proto/otlp/metrics/v1 go.opentelemetry.io/proto/otlp/metrics/v1
go.opentelemetry.io/proto/otlp/resource/v1 go.opentelemetry.io/proto/otlp/resource/v1
go.opentelemetry.io/proto/otlp/trace/v1 go.opentelemetry.io/proto/otlp/trace/v1
# golang.org/x/crypto v0.17.0 # golang.org/x/crypto v0.18.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/crypto/acme golang.org/x/crypto/acme
golang.org/x/crypto/acme/autocert golang.org/x/crypto/acme/autocert
@ -483,11 +483,12 @@ golang.org/x/crypto/internal/poly1305
golang.org/x/crypto/pbkdf2 golang.org/x/crypto/pbkdf2
golang.org/x/crypto/pkcs12 golang.org/x/crypto/pkcs12
golang.org/x/crypto/pkcs12/internal/rc2 golang.org/x/crypto/pkcs12/internal/rc2
# golang.org/x/net v0.18.0 # golang.org/x/net v0.20.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/net/context golang.org/x/net/context
golang.org/x/net/http/httpguts golang.org/x/net/http/httpguts
golang.org/x/net/http2 golang.org/x/net/http2
golang.org/x/net/http2/h2c
golang.org/x/net/http2/hpack golang.org/x/net/http2/hpack
golang.org/x/net/idna golang.org/x/net/idna
golang.org/x/net/internal/timeseries golang.org/x/net/internal/timeseries
@ -504,7 +505,7 @@ golang.org/x/oauth2/jwt
# golang.org/x/sync v0.3.0 # golang.org/x/sync v0.3.0
## explicit; go 1.17 ## explicit; go 1.17
golang.org/x/sync/semaphore golang.org/x/sync/semaphore
# golang.org/x/sys v0.15.0 # golang.org/x/sys v0.16.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/sys/cpu golang.org/x/sys/cpu
golang.org/x/sys/unix golang.org/x/sys/unix