summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/reverseproxy
diff options
context:
space:
mode:
authorMatt Holt <mholt@users.noreply.github.com>2020-05-05 12:33:21 -0600
committerGitHub <noreply@github.com>2020-05-05 12:33:21 -0600
commit41c7bd27b495ab9b5edca7afb0cf99d5e1b52944 (patch)
treed282b0e87ff626a417a3314f83744037ff211aba /modules/caddyhttp/reverseproxy
parent96d6d277a453a602b9ec49131d8e332ce7aefcad (diff)
httpserver: Add experimental H2C support (#3289)
* reverse_proxy: Initial attempt at H2C transport/client support (#3218) I have not tested this yet * Experimentally enabling H2C server support (closes #3227) See also #3218 I have not tested this * reverseproxy: Clean up H2C transport a bit * caddyhttp: Update godoc for h2c server; clarify experimental status * caddyhttp: Fix trailers when recording responses (fixes #3236) * caddyhttp: Tweak h2c config settings and docs
Diffstat (limited to 'modules/caddyhttp/reverseproxy')
-rw-r--r--modules/caddyhttp/reverseproxy/caddyfile.go7
-rw-r--r--modules/caddyhttp/reverseproxy/httptransport.go36
2 files changed, 42 insertions, 1 deletions
diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go
index 9636936..56e2698 100644
--- a/modules/caddyhttp/reverseproxy/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/caddyfile.go
@@ -584,6 +584,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// tls_trusted_ca_certs <cert_files...>
// keepalive [off|<duration>]
// keepalive_idle_conns <max_count>
+// versions <versions...>
// }
//
func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
@@ -701,6 +702,12 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
h.KeepAlive.MaxIdleConns = num
h.KeepAlive.MaxIdleConnsPerHost = num
+ case "versions":
+ h.Versions = d.RemainingArgs()
+ if len(h.Versions) == 0 {
+ return d.ArgErr()
+ }
+
default:
return d.Errf("unrecognized subdirective %s", d.Val())
}
diff --git a/modules/caddyhttp/reverseproxy/httptransport.go b/modules/caddyhttp/reverseproxy/httptransport.go
index 4b5111c..f0fbbd6 100644
--- a/modules/caddyhttp/reverseproxy/httptransport.go
+++ b/modules/caddyhttp/reverseproxy/httptransport.go
@@ -82,11 +82,16 @@ type HTTPTransport struct {
// The size of the read buffer in bytes.
ReadBufferSize int `json:"read_buffer_size,omitempty"`
- // The versions of HTTP to support. Default: ["1.1", "2"]
+ // The versions of HTTP to support. As a special case, "h2c"
+ // can be specified to use H2C (HTTP/2 over Cleartext) to the
+ // upstream (this feature is experimental and subject to
+ // change or removal). Default: ["1.1", "2"]
Versions []string `json:"versions,omitempty"`
// The pre-configured underlying HTTP transport.
Transport *http.Transport `json:"-"`
+
+ h2cTransport *http2.Transport
}
// CaddyModule returns the Caddy module information.
@@ -110,6 +115,28 @@ func (h *HTTPTransport) Provision(ctx caddy.Context) error {
}
h.Transport = rt
+ // if h2c is enabled, configure its transport (std lib http.Transport
+ // does not "HTTP/2 over cleartext TCP")
+ if sliceContains(h.Versions, "h2c") {
+ // crafting our own http2.Transport doesn't allow us to utilize
+ // most of the customizations/preferences on the http.Transport,
+ // because, for some reason, only http2.ConfigureTransport()
+ // is allowed to set the unexported field that refers to a base
+ // http.Transport config; oh well
+ h2t := &http2.Transport{
+ // kind of a hack, but for plaintext/H2C requests, pretend to dial TLS
+ DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) {
+ // TODO: no context, thus potentially wrong dial info
+ return net.Dial(network, addr)
+ },
+ AllowHTTP: true,
+ }
+ if h.Compression != nil {
+ h2t.DisableCompression = !*h.Compression
+ }
+ h.h2cTransport = h2t
+ }
+
return nil
}
@@ -182,6 +209,13 @@ func (h *HTTPTransport) NewTransport(_ caddy.Context) (*http.Transport, error) {
// RoundTrip implements http.RoundTripper.
func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
h.SetScheme(req)
+
+ // if H2C ("HTTP/2 over cleartext") is enabled and the upstream request is
+ // HTTP/2 without TLS, use the alternate H2C-capable transport instead
+ if req.ProtoMajor == 2 && req.URL.Scheme == "http" && h.h2cTransport != nil {
+ return h.h2cTransport.RoundTrip(req)
+ }
+
return h.Transport.RoundTrip(req)
}