Merge pull request #656 from nikr-canva/http2-origins
Add Http2Origin option to force HTTP/2 origin connections
This commit is contained in:
		
						commit
						ee87c43eb9
					
				|  | @ -837,6 +837,13 @@ func configureProxyFlags(shouldHide bool) []cli.Flag { | ||||||
| 			EnvVars: []string{"TUNNEL_NO_CHUNKED_ENCODING"}, | 			EnvVars: []string{"TUNNEL_NO_CHUNKED_ENCODING"}, | ||||||
| 			Hidden:  shouldHide, | 			Hidden:  shouldHide, | ||||||
| 		}), | 		}), | ||||||
|  | 		altsrc.NewBoolFlag(&cli.BoolFlag{ | ||||||
|  | 			Name:    ingress.Http2OriginFlag, | ||||||
|  | 			Usage:   "Enables HTTP/2 origin servers.", | ||||||
|  | 			EnvVars: []string{"TUNNEL_ORIGIN_ENABLE_HTTP2"}, | ||||||
|  | 			Hidden:  shouldHide, | ||||||
|  | 			Value:   false, | ||||||
|  | 		}), | ||||||
| 	} | 	} | ||||||
| 	return append(flags, sshFlags(shouldHide)...) | 	return append(flags, sshFlags(shouldHide)...) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -227,6 +227,8 @@ type OriginRequestConfig struct { | ||||||
| 	ProxyType *string `yaml:"proxyType" json:"proxyType,omitempty"` | 	ProxyType *string `yaml:"proxyType" json:"proxyType,omitempty"` | ||||||
| 	// IP rules for the proxy service
 | 	// IP rules for the proxy service
 | ||||||
| 	IPRules []IngressIPRule `yaml:"ipRules" json:"ipRules,omitempty"` | 	IPRules []IngressIPRule `yaml:"ipRules" json:"ipRules,omitempty"` | ||||||
|  | 	// Attempt to connect to origin with HTTP/2
 | ||||||
|  | 	Http2Origin *bool `yaml:"http2Origin" json:"http2Origin,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type IngressIPRule struct { | type IngressIPRule struct { | ||||||
|  |  | ||||||
|  | @ -144,7 +144,8 @@ var rawJsonConfig = []byte(` | ||||||
| 			"ports": [443, 4443], | 			"ports": [443, 4443], | ||||||
| 			"allow": true | 			"allow": true | ||||||
| 		} | 		} | ||||||
| 	] | 	], | ||||||
|  | 	"http2Origin": true | ||||||
| } | } | ||||||
| `) | `) | ||||||
| 
 | 
 | ||||||
|  | @ -191,6 +192,7 @@ func assertConfig( | ||||||
| 	assert.Equal(t, true, *config.NoTLSVerify) | 	assert.Equal(t, true, *config.NoTLSVerify) | ||||||
| 	assert.Equal(t, uint(9000), *config.ProxyPort) | 	assert.Equal(t, uint(9000), *config.ProxyPort) | ||||||
| 	assert.Equal(t, "socks", *config.ProxyType) | 	assert.Equal(t, "socks", *config.ProxyType) | ||||||
|  | 	assert.Equal(t, true, *config.Http2Origin) | ||||||
| 
 | 
 | ||||||
| 	privateV4 := "10.0.0.0/8" | 	privateV4 := "10.0.0.0/8" | ||||||
| 	privateV6 := "fc00::/7" | 	privateV6 := "fc00::/7" | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ const ( | ||||||
| 	NoChunkedEncodingFlag         = "no-chunked-encoding" | 	NoChunkedEncodingFlag         = "no-chunked-encoding" | ||||||
| 	ProxyAddressFlag              = "proxy-address" | 	ProxyAddressFlag              = "proxy-address" | ||||||
| 	ProxyPortFlag                 = "proxy-port" | 	ProxyPortFlag                 = "proxy-port" | ||||||
|  | 	Http2OriginFlag               = "http2-origin" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
|  | @ -128,6 +129,7 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig { | ||||||
| 	var proxyAddress = defaultProxyAddress | 	var proxyAddress = defaultProxyAddress | ||||||
| 	var proxyPort uint | 	var proxyPort uint | ||||||
| 	var proxyType string | 	var proxyType string | ||||||
|  | 	var http2Origin bool | ||||||
| 	if flag := ProxyConnectTimeoutFlag; c.IsSet(flag) { | 	if flag := ProxyConnectTimeoutFlag; c.IsSet(flag) { | ||||||
| 		connectTimeout = config.CustomDuration{Duration: c.Duration(flag)} | 		connectTimeout = config.CustomDuration{Duration: c.Duration(flag)} | ||||||
| 	} | 	} | ||||||
|  | @ -171,9 +173,13 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig { | ||||||
| 		// Note TUN-3758 , we use Int because UInt is not supported with altsrc
 | 		// Note TUN-3758 , we use Int because UInt is not supported with altsrc
 | ||||||
| 		proxyPort = uint(c.Int(flag)) | 		proxyPort = uint(c.Int(flag)) | ||||||
| 	} | 	} | ||||||
|  | 	if flag := Http2OriginFlag; c.IsSet(flag) { | ||||||
|  | 		http2Origin = c.Bool(flag) | ||||||
|  | 	} | ||||||
| 	if c.IsSet(Socks5Flag) { | 	if c.IsSet(Socks5Flag) { | ||||||
| 		proxyType = socksProxy | 		proxyType = socksProxy | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return OriginRequestConfig{ | 	return OriginRequestConfig{ | ||||||
| 		ConnectTimeout:         connectTimeout, | 		ConnectTimeout:         connectTimeout, | ||||||
| 		TLSTimeout:             tlsTimeout, | 		TLSTimeout:             tlsTimeout, | ||||||
|  | @ -190,6 +196,7 @@ func originRequestFromSingeRule(c *cli.Context) OriginRequestConfig { | ||||||
| 		ProxyAddress:           proxyAddress, | 		ProxyAddress:           proxyAddress, | ||||||
| 		ProxyPort:              proxyPort, | 		ProxyPort:              proxyPort, | ||||||
| 		ProxyType:              proxyType, | 		ProxyType:              proxyType, | ||||||
|  | 		Http2Origin:            http2Origin, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -255,6 +262,9 @@ func originRequestFromConfig(c config.OriginRequestConfig) OriginRequestConfig { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if c.Http2Origin != nil { | ||||||
|  | 		out.Http2Origin = *c.Http2Origin | ||||||
|  | 	} | ||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -298,6 +308,8 @@ type OriginRequestConfig struct { | ||||||
| 	ProxyType string `yaml:"proxyType" json:"proxyType"` | 	ProxyType string `yaml:"proxyType" json:"proxyType"` | ||||||
| 	// IP rules for the proxy service
 | 	// IP rules for the proxy service
 | ||||||
| 	IPRules []ipaccess.Rule `yaml:"ipRules" json:"ipRules"` | 	IPRules []ipaccess.Rule `yaml:"ipRules" json:"ipRules"` | ||||||
|  | 	// Attempt to connect to origin with HTTP/2
 | ||||||
|  | 	Http2Origin bool `yaml:"http2Origin" json:"http2Origin"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (defaults *OriginRequestConfig) setConnectTimeout(overrides config.OriginRequestConfig) { | func (defaults *OriginRequestConfig) setConnectTimeout(overrides config.OriginRequestConfig) { | ||||||
|  | @ -403,6 +415,12 @@ func (defaults *OriginRequestConfig) setIPRules(overrides config.OriginRequestCo | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (defaults *OriginRequestConfig) setHttp2Origin(overrides config.OriginRequestConfig) { | ||||||
|  | 	if val := overrides.Http2Origin; val != nil { | ||||||
|  | 		defaults.Http2Origin = *val | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // SetConfig gets config for the requests that cloudflared sends to origins.
 | // SetConfig gets config for the requests that cloudflared sends to origins.
 | ||||||
| // Each field has a setter method which sets a value for the field by trying to find:
 | // Each field has a setter method which sets a value for the field by trying to find:
 | ||||||
| //   1. The user config for this rule
 | //   1. The user config for this rule
 | ||||||
|  | @ -428,6 +446,7 @@ func setConfig(defaults OriginRequestConfig, overrides config.OriginRequestConfi | ||||||
| 	cfg.setProxyAddress(overrides) | 	cfg.setProxyAddress(overrides) | ||||||
| 	cfg.setProxyType(overrides) | 	cfg.setProxyType(overrides) | ||||||
| 	cfg.setIPRules(overrides) | 	cfg.setIPRules(overrides) | ||||||
|  | 	cfg.setHttp2Origin(overrides) | ||||||
| 	return cfg | 	return cfg | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -475,6 +494,7 @@ func ConvertToRawOriginConfig(c OriginRequestConfig) config.OriginRequestConfig | ||||||
| 		ProxyPort:              zeroUIntToNil(c.ProxyPort), | 		ProxyPort:              zeroUIntToNil(c.ProxyPort), | ||||||
| 		ProxyType:              emptyStringToNil(c.ProxyType), | 		ProxyType:              emptyStringToNil(c.ProxyType), | ||||||
| 		IPRules:                convertToRawIPRules(c.IPRules), | 		IPRules:                convertToRawIPRules(c.IPRules), | ||||||
|  | 		Http2Origin:            defaultBoolToNil(c.Http2Origin), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -290,6 +290,7 @@ func newHTTPTransport(service OriginService, cfg OriginRequestConfig, log *zerol | ||||||
| 		TLSHandshakeTimeout:   cfg.TLSTimeout.Duration, | 		TLSHandshakeTimeout:   cfg.TLSTimeout.Duration, | ||||||
| 		ExpectContinueTimeout: 1 * time.Second, | 		ExpectContinueTimeout: 1 * time.Second, | ||||||
| 		TLSClientConfig:       &tls.Config{RootCAs: originCertPool, InsecureSkipVerify: cfg.NoTLSVerify}, | 		TLSClientConfig:       &tls.Config{RootCAs: originCertPool, InsecureSkipVerify: cfg.NoTLSVerify}, | ||||||
|  | 		ForceAttemptHTTP2:     cfg.Http2Origin, | ||||||
| 	} | 	} | ||||||
| 	if _, isHelloWorld := service.(*helloWorld); !isHelloWorld && cfg.OriginServerName != "" { | 	if _, isHelloWorld := service.(*helloWorld); !isHelloWorld && cfg.OriginServerName != "" { | ||||||
| 		httpTransport.TLSClientConfig.ServerName = cfg.OriginServerName | 		httpTransport.TLSClientConfig.ServerName = cfg.OriginServerName | ||||||
|  |  | ||||||
|  | @ -182,25 +182,25 @@ func TestMarshalJSON(t *testing.T) { | ||||||
| 		{ | 		{ | ||||||
| 			name:     "Nil", | 			name:     "Nil", | ||||||
| 			path:     nil, | 			path:     nil, | ||||||
| 			expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, | 			expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, | ||||||
| 			want:     true, | 			want:     true, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name:     "Nil regex", | 			name:     "Nil regex", | ||||||
| 			path:     &Regexp{Regexp: nil}, | 			path:     &Regexp{Regexp: nil}, | ||||||
| 			expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, | 			expected: `{"hostname":"example.com","path":null,"service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, | ||||||
| 			want:     true, | 			want:     true, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name:     "Empty", | 			name:     "Empty", | ||||||
| 			path:     &Regexp{Regexp: regexp.MustCompile("")}, | 			path:     &Regexp{Regexp: regexp.MustCompile("")}, | ||||||
| 			expected: `{"hostname":"example.com","path":"","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, | 			expected: `{"hostname":"example.com","path":"","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, | ||||||
| 			want:     true, | 			want:     true, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name:     "Basic", | 			name:     "Basic", | ||||||
| 			path:     &Regexp{Regexp: regexp.MustCompile("/echo")}, | 			path:     &Regexp{Regexp: regexp.MustCompile("/echo")}, | ||||||
| 			expected: `{"hostname":"example.com","path":"/echo","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null}}`, | 			expected: `{"hostname":"example.com","path":"/echo","service":"https://localhost:8000","originRequest":{"connectTimeout":30,"tlsTimeout":10,"tcpKeepAlive":30,"noHappyEyeballs":false,"keepAliveTimeout":90,"keepAliveConnections":100,"httpHostHeader":"","originServerName":"","caPool":"","noTLSVerify":false,"disableChunkedEncoding":false,"bastionMode":false,"proxyAddress":"127.0.0.1","proxyPort":0,"proxyType":"","ipRules":null,"http2Origin":false}}`, | ||||||
| 			want:     true, | 			want:     true, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue