From 4a641f6c6fb441a8301eeb8cab0c0b61de70ff7f Mon Sep 17 00:00:00 2001
From: Francis Lavoie <lavofr@gmail.com>
Date: Mon, 23 Nov 2020 14:18:26 -0500
Subject: [PATCH] reverseproxy: Add Caddyfile scheme shorthand for h2c (#3629)

* reverseproxy: Add Caddyfile scheme shorthand for h2c

* reverseproxy: Use parentheses for condition

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
---
 .../reverse_proxy_h2c_shorthand.txt           | 38 +++++++++++++++++++
 modules/caddyhttp/reverseproxy/caddyfile.go   | 13 +++++--
 2 files changed, 48 insertions(+), 3 deletions(-)
 create mode 100644 caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.txt

diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.txt
new file mode 100644
index 000000000..94f22086f
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.txt
@@ -0,0 +1,38 @@
+:8884
+
+reverse_proxy h2c://localhost:8080
+----------
+{
+	"apps": {
+		"http": {
+			"servers": {
+				"srv0": {
+					"listen": [
+						":8884"
+					],
+					"routes": [
+						{
+							"handle": [
+								{
+									"handler": "reverse_proxy",
+									"transport": {
+										"protocol": "http",
+										"versions": [
+											"h2c",
+											"2"
+										]
+									},
+									"upstreams": [
+										{
+											"dial": "localhost:8080"
+										}
+									]
+								}
+							]
+						}
+					]
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go
index 003f67646..f4556ea22 100644
--- a/modules/caddyhttp/reverseproxy/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/caddyfile.go
@@ -131,12 +131,15 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
 			if toURL.Scheme == "https" && urlPort == "80" {
 				return "", d.Err("upstream address has conflicting scheme (https://) and port (:80, the HTTP port)")
 			}
+			if toURL.Scheme == "h2c" && urlPort == "443" {
+				return "", d.Err("upstream address has conflicting scheme (h2c://) and port (:443, the HTTPS port)")
+			}
 
 			// if port is missing, attempt to infer from scheme
 			if toURL.Port() == "" {
 				var toPort string
 				switch toURL.Scheme {
-				case "", "http":
+				case "", "http", "h2c":
 					toPort = "80"
 				case "https":
 					toPort = "443"
@@ -565,8 +568,9 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
 	}
 
 	// if the scheme inferred from the backends' addresses is
-	// HTTPS, we will need a non-nil transport to enable TLS
-	if commonScheme == "https" && transport == nil {
+	// HTTPS, we will need a non-nil transport to enable TLS,
+	// or if H2C, to set the transport versions.
+	if (commonScheme == "https" || commonScheme == "h2c") && transport == nil {
 		transport = new(HTTPTransport)
 		transportModuleName = "http"
 	}
@@ -583,6 +587,9 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
 			if commonScheme == "http" && te.TLSEnabled() {
 				return d.Errf("upstream address scheme is HTTP but transport is configured for HTTP+TLS (HTTPS)")
 			}
+			if te, ok := transport.(*HTTPTransport); ok && commonScheme == "h2c" {
+				te.Versions = []string{"h2c", "2"}
+			}
 		} else if commonScheme == "https" {
 			return d.Errf("upstreams are configured for HTTPS but transport module does not support TLS: %T", transport)
 		}