Add ability to disable HTTP/2 in dynamic config

This commit is contained in:
jcuzzi 2021-03-29 05:32:03 -07:00 committed by GitHub
parent 31a5f3591f
commit d13d078351
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 126 additions and 10 deletions

View file

@ -275,6 +275,7 @@
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
maxIdleConnsPerHost = 42
disableHTTP2 = true
[[http.serversTransports.ServersTransport0.certificates]]
certFile = "foobar"
@ -292,6 +293,7 @@
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
maxIdleConnsPerHost = 42
disableHTTP2 = true
[[http.serversTransports.ServersTransport1.certificates]]
certFile = "foobar"

View file

@ -327,6 +327,7 @@ http:
dialTimeout: 42s
responseHeaderTimeout: 42s
idleConnTimeout: 42s
disableHTTP2: true
ServersTransport1:
serverName: foobar
insecureSkipVerify: true
@ -343,6 +344,7 @@ http:
dialTimeout: 42s
responseHeaderTimeout: 42s
idleConnTimeout: 42s
disableHTTP2: true
tcp:
routers:
TCPRouter0:

View file

@ -214,3 +214,4 @@ spec:
dialTimeout: 42s
responseHeaderTimeout: 42s
idleConnTimeout: 42s
disableHTTP2: true

View file

@ -37,6 +37,9 @@ spec:
items:
type: string
type: array
disableHTTP2:
description: Disable HTTP/2 for connections with backend servers.
type: boolean
forwardingTimeouts:
description: Timeouts for requests forwarded to the backend servers.
properties:

View file

@ -705,6 +705,37 @@ spec:
maxIdleConnsPerHost: 7
```
#### `disableHTTP2`
_Optional, Default=false_
`disableHTTP2` disables HTTP/2 for connections with backend servers.
```toml tab="File (TOML)"
## Dynamic configuration
[http.serversTransports.mytransport]
disableHTTP2 = true
```
```yaml tab="File (YAML)"
## Dynamic configuration
http:
serversTransports:
mytransport:
disableHTTP2: true
```
```yaml tab="Kubernetes"
apiVersion: traefik.containo.us/v1alpha1
kind: ServersTransport
metadata:
name: mytransport
namespace: default
spec:
disableHTTP2: true
```
#### `forwardingTimeouts`
`forwardingTimeouts` is about a number of timeouts relevant to when forwarding requests to the backend servers.

View file

@ -950,6 +950,9 @@ spec:
items:
type: string
type: array
disableHTTP2:
description: Disable HTTP/2 for connections with backend servers.
type: boolean
forwardingTimeouts:
description: Timeouts for requests forwarded to the backend servers.
properties:

View file

@ -208,6 +208,7 @@ type ServersTransport struct {
Certificates tls.Certificates `description:"Certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
DisableHTTP2 bool `description:"Disable HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true

View file

@ -33,6 +33,8 @@ type ServersTransportSpec struct {
MaxIdleConnsPerHost int `json:"maxIdleConnsPerHost,omitempty"`
// Timeouts for requests forwarded to the backend servers.
ForwardingTimeouts *ForwardingTimeouts `json:"forwardingTimeouts,omitempty"`
// Disable HTTP/2 for connections with backend servers.
DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
}
// +k8s:deepcopy-gen=true

View file

@ -100,7 +100,7 @@ func (r *RoundTripperManager) Get(name string) (http.RoundTripper, error) {
// createRoundTripper creates an http.RoundTripper configured with the Transport configuration settings.
// For the settings that can't be configured in Traefik it uses the default http.Transport settings.
// An exception to this is the MaxIdleConns setting as we only provide the option MaxIdleConnsPerHostin Traefik at this point in time.
// An exception to this is the MaxIdleConns setting as we only provide the option MaxIdleConnsPerHost in Traefik at this point in time.
// Setting this value to the default of 100 could lead to confusing behavior and backwards compatibility issues.
func createRoundTripper(cfg *dynamic.ServersTransport) (http.RoundTripper, error) {
if cfg == nil {
@ -127,15 +127,6 @@ func createRoundTripper(cfg *dynamic.ServersTransport) (http.RoundTripper, error
WriteBufferSize: 64 * 1024,
}
transport.RegisterProtocol("h2c", &h2cTransportWrapper{
Transport: &http2.Transport{
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
return net.Dial(netw, addr)
},
AllowHTTP: true,
},
})
if cfg.ForwardingTimeouts != nil {
transport.ResponseHeaderTimeout = time.Duration(cfg.ForwardingTimeouts.ResponseHeaderTimeout)
transport.IdleConnTimeout = time.Duration(cfg.ForwardingTimeouts.IdleConnTimeout)
@ -150,6 +141,20 @@ func createRoundTripper(cfg *dynamic.ServersTransport) (http.RoundTripper, error
}
}
// Return directly HTTP/1.1 transport when HTTP/2 is disabled
if cfg.DisableHTTP2 {
return transport, nil
}
transport.RegisterProtocol("h2c", &h2cTransportWrapper{
Transport: &http2.Transport{
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
return net.Dial(netw, addr)
},
AllowHTTP: true,
},
})
return newSmartRoundTripper(transport)
}

View file

@ -227,3 +227,69 @@ func TestMTLS(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestDisableHTTP2(t *testing.T) {
testCases := []struct {
desc string
disableHTTP2 bool
serverHTTP2 bool
expectedProto string
}{
{
desc: "HTTP1 capable client with HTTP1 server",
disableHTTP2: true,
expectedProto: "HTTP/1.1",
},
{
desc: "HTTP1 capable client with HTTP2 server",
disableHTTP2: true,
serverHTTP2: true,
expectedProto: "HTTP/1.1",
},
{
desc: "HTTP2 capable client with HTTP1 server",
expectedProto: "HTTP/1.1",
},
{
desc: "HTTP2 capable client with HTTP2 server",
serverHTTP2: true,
expectedProto: "HTTP/2.0",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
}))
srv.EnableHTTP2 = test.serverHTTP2
srv.StartTLS()
rtManager := NewRoundTripperManager()
dynamicConf := map[string]*dynamic.ServersTransport{
"test": {
DisableHTTP2: test.disableHTTP2,
InsecureSkipVerify: true,
},
}
rtManager.Update(dynamicConf)
tr, err := rtManager.Get("test")
require.NoError(t, err)
client := http.Client{Transport: tr}
resp, err := client.Get(srv.URL)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, test.expectedProto, resp.Proto)
})
}
}