summaryrefslogtreecommitdiff
path: root/caddytest
diff options
context:
space:
mode:
Diffstat (limited to 'caddytest')
-rw-r--r--caddytest/caddytest.go21
-rw-r--r--caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.txt37
-rw-r--r--caddytest/integration/caddyfile_adapt/encode_options.txt2
-rw-r--r--caddytest/integration/caddyfile_adapt/global_options.txt4
-rw-r--r--caddytest/integration/caddyfile_adapt/global_options_acme.txt4
-rw-r--r--caddytest/integration/caddyfile_adapt/global_options_admin.txt4
-rw-r--r--caddytest/integration/caddyfile_adapt/global_server_options_single.txt9
-rw-r--r--caddytest/integration/caddyfile_adapt/header.txt27
-rw-r--r--caddytest/integration/caddyfile_adapt/heredoc.txt50
-rw-r--r--caddytest/integration/caddyfile_adapt/import_args_snippet.txt2
-rw-r--r--caddytest/integration/caddyfile_adapt/invoke_named_routes.txt154
-rw-r--r--caddytest/integration/caddyfile_adapt/log_override_hostname.txt71
-rw-r--r--caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.txt86
-rw-r--r--caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.txt91
-rw-r--r--caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt8
-rw-r--r--caddytest/integration/caddyfile_adapt/matcher_syntax.txt25
-rw-r--r--caddytest/integration/caddyfile_adapt/replaceable_upstream.txt100
-rw-r--r--caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.txt100
-rw-r--r--caddytest/integration/caddyfile_adapt/replaceable_upstream_port.txt100
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.txt58
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt8
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt10
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.txt71
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt4
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.txt67
-rw-r--r--caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt50
-rw-r--r--caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt20
-rw-r--r--caddytest/integration/caddyfile_test.go349
-rw-r--r--caddytest/integration/reverseproxy_test.go231
-rw-r--r--caddytest/integration/stream_test.go4
-rw-r--r--caddytest/integration/testdata/import_respond.txt2
31 files changed, 1564 insertions, 205 deletions
diff --git a/caddytest/caddytest.go b/caddytest/caddytest.go
index 0958e6c..39aca23 100644
--- a/caddytest/caddytest.go
+++ b/caddytest/caddytest.go
@@ -22,9 +22,10 @@ import (
"time"
"github.com/aryann/difflib"
- "github.com/caddyserver/caddy/v2/caddyconfig"
+
caddycmd "github.com/caddyserver/caddy/v2/cmd"
+ "github.com/caddyserver/caddy/v2/caddyconfig"
// plug in Caddy modules here
_ "github.com/caddyserver/caddy/v2/modules/standard"
)
@@ -63,7 +64,6 @@ type Tester struct {
// NewTester will create a new testing client with an attached cookie jar
func NewTester(t *testing.T) *Tester {
-
jar, err := cookiejar.New(nil)
if err != nil {
t.Fatalf("failed to create cookiejar: %s", err)
@@ -94,7 +94,6 @@ func timeElapsed(start time.Time, name string) {
// InitServer this will configure the server with a configurion of a specific
// type. The configType must be either "json" or the adapter type.
func (tc *Tester) InitServer(rawConfig string, configType string) {
-
if err := tc.initServer(rawConfig, configType); err != nil {
tc.t.Logf("failed to load config: %s", err)
tc.t.Fail()
@@ -108,7 +107,6 @@ func (tc *Tester) InitServer(rawConfig string, configType string) {
// InitServer this will configure the server with a configurion of a specific
// type. The configType must be either "json" or the adapter type.
func (tc *Tester) initServer(rawConfig string, configType string) error {
-
if testing.Short() {
tc.t.SkipNow()
return nil
@@ -232,7 +230,6 @@ const initConfig = `{
// validateTestPrerequisites ensures the certificates are available in the
// designated path and Caddy sub-process is running.
func validateTestPrerequisites(t *testing.T) error {
-
// check certificates are found
for _, certName := range Default.Certifcates {
if _, err := os.Stat(getIntegrationDir() + certName); os.IsNotExist(err) {
@@ -284,7 +281,6 @@ func isCaddyAdminRunning() error {
}
func getIntegrationDir() string {
-
_, filename, _, ok := runtime.Caller(1)
if !ok {
panic("unable to determine the current file path")
@@ -304,7 +300,6 @@ func prependCaddyFilePath(rawConfig string) string {
// CreateTestingTransport creates a testing transport that forces call dialing connections to happen locally
func CreateTestingTransport() *http.Transport {
-
dialer := net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
@@ -332,7 +327,6 @@ func CreateTestingTransport() *http.Transport {
// AssertLoadError will load a config and expect an error
func AssertLoadError(t *testing.T, rawConfig string, configType string, expectedError string) {
-
tc := NewTester(t)
err := tc.initServer(rawConfig, configType)
@@ -343,7 +337,6 @@ func AssertLoadError(t *testing.T, rawConfig string, configType string, expected
// AssertRedirect makes a request and asserts the redirection happens
func (tc *Tester) AssertRedirect(requestURI string, expectedToLocation string, expectedStatusCode int) *http.Response {
-
redirectPolicyFunc := func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
@@ -381,7 +374,6 @@ func (tc *Tester) AssertRedirect(requestURI string, expectedToLocation string, e
// CompareAdapt adapts a config and then compares it against an expected result
func CompareAdapt(t *testing.T, filename, rawConfig string, adapterName string, expectedResponse string) bool {
-
cfgAdapter := caddyconfig.GetAdapter(adapterName)
if cfgAdapter == nil {
t.Logf("unrecognized config adapter '%s'", adapterName)
@@ -469,14 +461,13 @@ func applyHeaders(t *testing.T, req *http.Request, requestHeaders []string) {
// AssertResponseCode will execute the request and verify the status code, returns a response for additional assertions
func (tc *Tester) AssertResponseCode(req *http.Request, expectedStatusCode int) *http.Response {
-
resp, err := tc.Client.Do(req)
if err != nil {
tc.t.Fatalf("failed to call server %s", err)
}
if expectedStatusCode != resp.StatusCode {
- tc.t.Errorf("requesting \"%s\" expected status code: %d but got %d", req.RequestURI, expectedStatusCode, resp.StatusCode)
+ tc.t.Errorf("requesting \"%s\" expected status code: %d but got %d", req.URL.RequestURI(), expectedStatusCode, resp.StatusCode)
}
return resp
@@ -484,7 +475,6 @@ func (tc *Tester) AssertResponseCode(req *http.Request, expectedStatusCode int)
// AssertResponse request a URI and assert the status code and the body contains a string
func (tc *Tester) AssertResponse(req *http.Request, expectedStatusCode int, expectedBody string) (*http.Response, string) {
-
resp := tc.AssertResponseCode(req, expectedStatusCode)
defer resp.Body.Close()
@@ -506,7 +496,6 @@ func (tc *Tester) AssertResponse(req *http.Request, expectedStatusCode int, expe
// AssertGetResponse GET a URI and expect a statusCode and body text
func (tc *Tester) AssertGetResponse(requestURI string, expectedStatusCode int, expectedBody string) (*http.Response, string) {
-
req, err := http.NewRequest("GET", requestURI, nil)
if err != nil {
tc.t.Fatalf("unable to create request %s", err)
@@ -517,7 +506,6 @@ func (tc *Tester) AssertGetResponse(requestURI string, expectedStatusCode int, e
// AssertDeleteResponse request a URI and expect a statusCode and body text
func (tc *Tester) AssertDeleteResponse(requestURI string, expectedStatusCode int, expectedBody string) (*http.Response, string) {
-
req, err := http.NewRequest("DELETE", requestURI, nil)
if err != nil {
tc.t.Fatalf("unable to create request %s", err)
@@ -528,7 +516,6 @@ func (tc *Tester) AssertDeleteResponse(requestURI string, expectedStatusCode int
// AssertPostResponseBody POST to a URI and assert the response code and body
func (tc *Tester) AssertPostResponseBody(requestURI string, requestHeaders []string, requestBody *bytes.Buffer, expectedStatusCode int, expectedBody string) (*http.Response, string) {
-
req, err := http.NewRequest("POST", requestURI, requestBody)
if err != nil {
tc.t.Errorf("failed to create request %s", err)
@@ -542,7 +529,6 @@ func (tc *Tester) AssertPostResponseBody(requestURI string, requestHeaders []str
// AssertPutResponseBody PUT to a URI and assert the response code and body
func (tc *Tester) AssertPutResponseBody(requestURI string, requestHeaders []string, requestBody *bytes.Buffer, expectedStatusCode int, expectedBody string) (*http.Response, string) {
-
req, err := http.NewRequest("PUT", requestURI, requestBody)
if err != nil {
tc.t.Errorf("failed to create request %s", err)
@@ -556,7 +542,6 @@ func (tc *Tester) AssertPutResponseBody(requestURI string, requestHeaders []stri
// AssertPatchResponseBody PATCH to a URI and assert the response code and body
func (tc *Tester) AssertPatchResponseBody(requestURI string, requestHeaders []string, requestBody *bytes.Buffer, expectedStatusCode int, expectedBody string) (*http.Response, string) {
-
req, err := http.NewRequest("PATCH", requestURI, requestBody)
if err != nil {
tc.t.Errorf("failed to create request %s", err)
diff --git a/caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.txt b/caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.txt
new file mode 100644
index 0000000..b37b40c
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.txt
@@ -0,0 +1,37 @@
+:8443 {
+ tls internal {
+ on_demand
+ }
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8443"
+ ],
+ "tls_connection_policies": [
+ {}
+ ]
+ }
+ }
+ },
+ "tls": {
+ "automation": {
+ "policies": [
+ {
+ "issuers": [
+ {
+ "module": "internal"
+ }
+ ],
+ "on_demand": true
+ }
+ ]
+ }
+ }
+ }
+}
+
diff --git a/caddytest/integration/caddyfile_adapt/encode_options.txt b/caddytest/integration/caddyfile_adapt/encode_options.txt
index 6f811ab..181bc22 100644
--- a/caddytest/integration/caddyfile_adapt/encode_options.txt
+++ b/caddytest/integration/caddyfile_adapt/encode_options.txt
@@ -11,6 +11,7 @@ encode gzip zstd {
header Content-Type application/xhtml+xml*
header Content-Type application/atom+xml*
header Content-Type application/rss+xml*
+ header Content-Type application/wasm*
header Content-Type image/svg+xml*
}
}
@@ -47,6 +48,7 @@ encode {
"application/xhtml+xml*",
"application/atom+xml*",
"application/rss+xml*",
+ "application/wasm*",
"image/svg+xml*"
]
},
diff --git a/caddytest/integration/caddyfile_adapt/global_options.txt b/caddytest/integration/caddyfile_adapt/global_options.txt
index 57831a4..6032098 100644
--- a/caddytest/integration/caddyfile_adapt/global_options.txt
+++ b/caddytest/integration/caddyfile_adapt/global_options.txt
@@ -69,11 +69,11 @@
}
],
"on_demand": {
+ "ask": "https://example.com",
"rate_limit": {
"interval": 30000000000,
"burst": 20
- },
- "ask": "https://example.com"
+ }
}
},
"disable_ocsp_stapling": true
diff --git a/caddytest/integration/caddyfile_adapt/global_options_acme.txt b/caddytest/integration/caddyfile_adapt/global_options_acme.txt
index 1949d17..03aee2c 100644
--- a/caddytest/integration/caddyfile_adapt/global_options_acme.txt
+++ b/caddytest/integration/caddyfile_adapt/global_options_acme.txt
@@ -78,11 +78,11 @@
}
],
"on_demand": {
+ "ask": "https://example.com",
"rate_limit": {
"interval": 30000000000,
"burst": 20
- },
- "ask": "https://example.com"
+ }
},
"ocsp_interval": 172800000000000,
"renew_interval": 86400000000000,
diff --git a/caddytest/integration/caddyfile_adapt/global_options_admin.txt b/caddytest/integration/caddyfile_adapt/global_options_admin.txt
index 67cf5ad..2b90d6d 100644
--- a/caddytest/integration/caddyfile_adapt/global_options_admin.txt
+++ b/caddytest/integration/caddyfile_adapt/global_options_admin.txt
@@ -71,11 +71,11 @@
}
],
"on_demand": {
+ "ask": "https://example.com",
"rate_limit": {
"interval": 30000000000,
"burst": 20
- },
- "ask": "https://example.com"
+ }
}
}
}
diff --git a/caddytest/integration/caddyfile_adapt/global_server_options_single.txt b/caddytest/integration/caddyfile_adapt/global_server_options_single.txt
index d963604..2f3306f 100644
--- a/caddytest/integration/caddyfile_adapt/global_server_options_single.txt
+++ b/caddytest/integration/caddyfile_adapt/global_server_options_single.txt
@@ -11,10 +11,13 @@
idle 30s
}
max_header_size 100MB
+ enable_full_duplex
log_credentials
protocols h1 h2 h2c h3
strict_sni_host
trusted_proxies static private_ranges
+ client_ip_headers Custom-Real-Client-IP X-Forwarded-For
+ client_ip_headers A-Third-One
}
}
@@ -43,6 +46,7 @@ foo.com {
"write_timeout": 30000000000,
"idle_timeout": 30000000000,
"max_header_bytes": 100000000,
+ "enable_full_duplex": true,
"routes": [
{
"match": [
@@ -67,6 +71,11 @@ foo.com {
],
"source": "static"
},
+ "client_ip_headers": [
+ "Custom-Real-Client-IP",
+ "X-Forwarded-For",
+ "A-Third-One"
+ ],
"logs": {
"should_log_credentials": true
},
diff --git a/caddytest/integration/caddyfile_adapt/header.txt b/caddytest/integration/caddyfile_adapt/header.txt
index 34a044d..ec2a842 100644
--- a/caddytest/integration/caddyfile_adapt/header.txt
+++ b/caddytest/integration/caddyfile_adapt/header.txt
@@ -17,6 +17,8 @@
+Link "Foo"
+Link "Bar"
}
+ header >Set Defer
+ header >Replace Deferred Replacement
}
----------
{
@@ -136,6 +138,31 @@
]
}
}
+ },
+ {
+ "handler": "headers",
+ "response": {
+ "deferred": true,
+ "set": {
+ "Set": [
+ "Defer"
+ ]
+ }
+ }
+ },
+ {
+ "handler": "headers",
+ "response": {
+ "deferred": true,
+ "replace": {
+ "Replace": [
+ {
+ "replace": "Replacement",
+ "search_regexp": "Deferred"
+ }
+ ]
+ }
+ }
}
]
}
diff --git a/caddytest/integration/caddyfile_adapt/heredoc.txt b/caddytest/integration/caddyfile_adapt/heredoc.txt
new file mode 100644
index 0000000..cc1174d
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/heredoc.txt
@@ -0,0 +1,50 @@
+example.com {
+ respond <<EOF
+ <html>
+ <head><title>Foo</title>
+ <body>Foo</body>
+ </html>
+ EOF 200
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "example.com"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "\u003chtml\u003e\n \u003chead\u003e\u003ctitle\u003eFoo\u003c/title\u003e\n \u003cbody\u003eFoo\u003c/body\u003e\n\u003c/html\u003e",
+ "handler": "static_response",
+ "status_code": 200
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/import_args_snippet.txt b/caddytest/integration/caddyfile_adapt/import_args_snippet.txt
index 9fce9ab..10d9f4c 100644
--- a/caddytest/integration/caddyfile_adapt/import_args_snippet.txt
+++ b/caddytest/integration/caddyfile_adapt/import_args_snippet.txt
@@ -1,6 +1,6 @@
(logging) {
log {
- output file /var/log/caddy/{args.0}.access.log
+ output file /var/log/caddy/{args[0]}.access.log
}
}
diff --git a/caddytest/integration/caddyfile_adapt/invoke_named_routes.txt b/caddytest/integration/caddyfile_adapt/invoke_named_routes.txt
new file mode 100644
index 0000000..83d9859
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/invoke_named_routes.txt
@@ -0,0 +1,154 @@
+&(first) {
+ @first path /first
+ vars @first first 1
+ respond "first"
+}
+
+&(second) {
+ respond "second"
+}
+
+:8881 {
+ invoke first
+ route {
+ invoke second
+ }
+}
+
+:8882 {
+ handle {
+ invoke second
+ }
+}
+
+:8883 {
+ respond "no invoke"
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8881"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "invoke",
+ "name": "first"
+ },
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "invoke",
+ "name": "second"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "named_routes": {
+ "first": {
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "first": 1,
+ "handler": "vars"
+ }
+ ],
+ "match": [
+ {
+ "path": [
+ "/first"
+ ]
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "body": "first",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "second": {
+ "handle": [
+ {
+ "body": "second",
+ "handler": "static_response"
+ }
+ ]
+ }
+ }
+ },
+ "srv1": {
+ "listen": [
+ ":8882"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "invoke",
+ "name": "second"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "named_routes": {
+ "second": {
+ "handle": [
+ {
+ "body": "second",
+ "handler": "static_response"
+ }
+ ]
+ }
+ }
+ },
+ "srv2": {
+ "listen": [
+ ":8883"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "no invoke",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/log_override_hostname.txt b/caddytest/integration/caddyfile_adapt/log_override_hostname.txt
new file mode 100644
index 0000000..4511fd4
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/log_override_hostname.txt
@@ -0,0 +1,71 @@
+*.example.com {
+ log {
+ hostnames foo.example.com bar.example.com
+ output file /foo-bar.txt
+ }
+ log {
+ hostnames baz.example.com
+ output file /baz.txt
+ }
+}
+----------
+{
+ "logging": {
+ "logs": {
+ "default": {
+ "exclude": [
+ "http.log.access.log0",
+ "http.log.access.log1"
+ ]
+ },
+ "log0": {
+ "writer": {
+ "filename": "/foo-bar.txt",
+ "output": "file"
+ },
+ "include": [
+ "http.log.access.log0"
+ ]
+ },
+ "log1": {
+ "writer": {
+ "filename": "/baz.txt",
+ "output": "file"
+ },
+ "include": [
+ "http.log.access.log1"
+ ]
+ }
+ }
+ },
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "*.example.com"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ],
+ "logs": {
+ "logger_names": {
+ "bar.example.com": "log0",
+ "baz.example.com": "log1",
+ "foo.example.com": "log0"
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.txt b/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.txt
new file mode 100644
index 0000000..a3b0cec
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.txt
@@ -0,0 +1,86 @@
+{
+ log access-console {
+ include http.log.access.foo
+ output file access-localhost.log
+ format console
+ }
+
+ log access-json {
+ include http.log.access.foo
+ output file access-localhost.json
+ format json
+ }
+}
+
+http://localhost:8881 {
+ log foo
+}
+----------
+{
+ "logging": {
+ "logs": {
+ "access-console": {
+ "writer": {
+ "filename": "access-localhost.log",
+ "output": "file"
+ },
+ "encoder": {
+ "format": "console"
+ },
+ "include": [
+ "http.log.access.foo"
+ ]
+ },
+ "access-json": {
+ "writer": {
+ "filename": "access-localhost.json",
+ "output": "file"
+ },
+ "encoder": {
+ "format": "json"
+ },
+ "include": [
+ "http.log.access.foo"
+ ]
+ },
+ "default": {
+ "exclude": [
+ "http.log.access.foo"
+ ]
+ }
+ }
+ },
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8881"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ],
+ "automatic_https": {
+ "skip": [
+ "localhost"
+ ]
+ },
+ "logs": {
+ "logger_names": {
+ "localhost:8881": "foo"
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.txt b/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.txt
new file mode 100644
index 0000000..e6698e4
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.txt
@@ -0,0 +1,91 @@
+{
+ debug
+
+ log access-console {
+ include http.log.access.foo
+ output file access-localhost.log
+ format console
+ }
+
+ log access-json {
+ include http.log.access.foo
+ output file access-localhost.json
+ format json
+ }
+}
+
+http://localhost:8881 {
+ log foo
+}
+----------
+{
+ "logging": {
+ "logs": {
+ "access-console": {
+ "writer": {
+ "filename": "access-localhost.log",
+ "output": "file"
+ },
+ "encoder": {
+ "format": "console"
+ },
+ "level": "DEBUG",
+ "include": [
+ "http.log.access.foo"
+ ]
+ },
+ "access-json": {
+ "writer": {
+ "filename": "access-localhost.json",
+ "output": "file"
+ },
+ "encoder": {
+ "format": "json"
+ },
+ "level": "DEBUG",
+ "include": [
+ "http.log.access.foo"
+ ]
+ },
+ "default": {
+ "level": "DEBUG",
+ "exclude": [
+ "http.log.access.foo"
+ ]
+ }
+ }
+ },
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8881"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ],
+ "automatic_https": {
+ "skip": [
+ "localhost"
+ ]
+ },
+ "logs": {
+ "logger_names": {
+ "localhost:8881": "foo"
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt b/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
index af9faf4..cc75630 100644
--- a/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
+++ b/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
@@ -101,15 +101,15 @@ vars {
"source": "{http.request.host}"
},
{
- "foo": "bar",
- "handler": "vars"
- },
- {
"abc": true,
"def": 1,
"ghi": 2.3,
"handler": "vars",
"jkl": "mn op"
+ },
+ {
+ "foo": "bar",
+ "handler": "vars"
}
]
}
diff --git a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt b/caddytest/integration/caddyfile_adapt/matcher_syntax.txt
index fb3dfb6..ffab2c7 100644
--- a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt
+++ b/caddytest/integration/caddyfile_adapt/matcher_syntax.txt
@@ -43,6 +43,9 @@
@matcher11 remote_ip private_ranges
respond @matcher11 "remote_ip matcher with private ranges"
+
+ @matcher12 client_ip private_ranges
+ respond @matcher12 "client_ip matcher with private ranges"
}
----------
{
@@ -250,6 +253,28 @@
"handler": "static_response"
}
]
+ },
+ {
+ "match": [
+ {
+ "client_ip": {
+ "ranges": [
+ "192.168.0.0/16",
+ "172.16.0.0/12",
+ "10.0.0.0/8",
+ "127.0.0.1/8",
+ "fd00::/8",
+ "::1"
+ ]
+ }
+ }
+ ],
+ "handle": [
+ {
+ "body": "client_ip matcher with private ranges",
+ "handler": "static_response"
+ }
+ ]
}
]
}
diff --git a/caddytest/integration/caddyfile_adapt/replaceable_upstream.txt b/caddytest/integration/caddyfile_adapt/replaceable_upstream.txt
new file mode 100644
index 0000000..202e330
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/replaceable_upstream.txt
@@ -0,0 +1,100 @@
+*.sandbox.localhost {
+ @sandboxPort {
+ header_regexp first_label Host ^([0-9]{3})\.sandbox\.
+ }
+ handle @sandboxPort {
+ reverse_proxy {re.first_label.1}
+ }
+ handle {
+ redir {scheme}://application.localhost
+ }
+}
+
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "*.sandbox.localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "group": "group2",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "{http.regexp.first_label.1}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "match": [
+ {
+ "header_regexp": {
+ "Host": {
+ "name": "first_label",
+ "pattern": "^([0-9]{3})\\.sandbox\\."
+ }
+ }
+ }
+ ]
+ },
+ {
+ "group": "group2",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "static_response",
+ "headers": {
+ "Location": [
+ "{http.request.scheme}://application.localhost"
+ ]
+ },
+ "status_code": 302
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.txt b/caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.txt
new file mode 100644
index 0000000..7fbcb5c
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.txt
@@ -0,0 +1,100 @@
+*.sandbox.localhost {
+ @sandboxPort {
+ header_regexp port Host ^([0-9]{3})\.sandbox\.
+ }
+ handle @sandboxPort {
+ reverse_proxy app:6{re.port.1}
+ }
+ handle {
+ redir {scheme}://application.localhost
+ }
+}
+
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "*.sandbox.localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "group": "group2",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "app:6{http.regexp.port.1}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "match": [
+ {
+ "header_regexp": {
+ "Host": {
+ "name": "port",
+ "pattern": "^([0-9]{3})\\.sandbox\\."
+ }
+ }
+ }
+ ]
+ },
+ {
+ "group": "group2",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "static_response",
+ "headers": {
+ "Location": [
+ "{http.request.scheme}://application.localhost"
+ ]
+ },
+ "status_code": 302
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/replaceable_upstream_port.txt b/caddytest/integration/caddyfile_adapt/replaceable_upstream_port.txt
new file mode 100644
index 0000000..8f75c5b
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/replaceable_upstream_port.txt
@@ -0,0 +1,100 @@
+*.sandbox.localhost {
+ @sandboxPort {
+ header_regexp port Host ^([0-9]{3})\.sandbox\.
+ }
+ handle @sandboxPort {
+ reverse_proxy app:{re.port.1}
+ }
+ handle {
+ redir {scheme}://application.localhost
+ }
+}
+
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "*.sandbox.localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "group": "group2",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "app:{http.regexp.port.1}"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "match": [
+ {
+ "header_regexp": {
+ "Host": {
+ "name": "port",
+ "pattern": "^([0-9]{3})\\.sandbox\\."
+ }
+ }
+ }
+ ]
+ },
+ {
+ "group": "group2",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "static_response",
+ "headers": {
+ "Location": [
+ "{http.request.scheme}://application.localhost"
+ ]
+ },
+ "status_code": 302
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.txt
new file mode 100644
index 0000000..3178994
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.txt
@@ -0,0 +1,58 @@
+https://example.com {
+ reverse_proxy https://localhost:54321 {
+ request_buffers unlimited
+ response_buffers unlimited
+ }
+}
+
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "example.com"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "request_buffers": -1,
+ "response_buffers": -1,
+ "transport": {
+ "protocol": "http",
+ "tls": {}
+ },
+ "upstreams": [
+ {
+ "dial": "localhost:54321"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt
index 2f2cbcd..384cc05 100644
--- a/caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt
@@ -11,6 +11,7 @@
resolvers 8.8.8.8 8.8.4.4
dial_timeout 2s
dial_fallback_delay 300ms
+ versions ipv6
}
}
}
@@ -66,7 +67,10 @@
"8.8.4.4"
]
},
- "source": "a"
+ "source": "a",
+ "versions": {
+ "ipv6": true
+ }
},
"handler": "reverse_proxy"
}
@@ -113,4 +117,4 @@
}
}
}
-} \ No newline at end of file
+}
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt
index 17adcaa..800c11f 100644
--- a/caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt
@@ -6,6 +6,9 @@ reverse_proxy 127.0.0.1:65535 {
X-Header-Key 95ca39e3cbe7
X-Header-Keys VbG4NZwWnipo 335Q9/MhqcNU3s2TO
X-Empty-Value
+ Same-Key 1
+ Same-Key 2
+ X-System-Hostname {system.hostname}
}
health_uri /health
}
@@ -29,6 +32,10 @@ reverse_proxy 127.0.0.1:65535 {
"Host": [
"example.com"
],
+ "Same-Key": [
+ "1",
+ "2"
+ ],
"X-Empty-Value": [
""
],
@@ -38,6 +45,9 @@ reverse_proxy 127.0.0.1:65535 {
"X-Header-Keys": [
"VbG4NZwWnipo",
"335Q9/MhqcNU3s2TO"
+ ],
+ "X-System-Hostname": [
+ "{system.hostname}"
]
},
"uri": "/health"
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.txt
new file mode 100644
index 0000000..d41c4b8
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.txt
@@ -0,0 +1,71 @@
+:8884
+
+reverse_proxy 127.0.0.1:65535 127.0.0.1:35535 {
+ lb_policy weighted_round_robin 10 1
+ lb_retries 5
+ lb_try_duration 10s
+ lb_try_interval 500ms
+ lb_retry_match {
+ path /foo*
+ method POST
+ }
+ lb_retry_match path /bar*
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8884"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "load_balancing": {
+ "retries": 5,
+ "retry_match": [
+ {
+ "method": [
+ "POST"
+ ],
+ "path": [
+ "/foo*"
+ ]
+ },
+ {
+ "path": [
+ "/bar*"
+ ]
+ }
+ ],
+ "selection_policy": {
+ "policy": "weighted_round_robin",
+ "weights": [
+ 10,
+ 1
+ ]
+ },
+ "try_duration": 10000000000,
+ "try_interval": 500000000
+ },
+ "upstreams": [
+ {
+ "dial": "127.0.0.1:65535"
+ },
+ {
+ "dial": "127.0.0.1:35535"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt
index b22333a..f6420ca 100644
--- a/caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt
@@ -6,7 +6,7 @@ https://example.com {
method GET
rewrite /rewritten?uri={uri}
- buffer_requests
+ request_buffers 4KB
transport http {
read_buffer 10MB
@@ -54,7 +54,6 @@ https://example.com {
{
"handle": [
{
- "buffer_requests": true,
"handler": "reverse_proxy",
"headers": {
"request": {
@@ -68,6 +67,7 @@ https://example.com {
}
}
},
+ "request_buffers": 4000,
"rewrite": {
"method": "GET",
"uri": "/rewritten?uri={http.request.uri}"
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.txt
new file mode 100644
index 0000000..978d8c9
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.txt
@@ -0,0 +1,67 @@
+:8884 {
+ # Port range
+ reverse_proxy localhost:8001-8002
+
+ # Port range with placeholder
+ reverse_proxy {host}:8001-8002
+
+ # Port range with scheme
+ reverse_proxy https://localhost:8001-8002
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8884"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "localhost:8001"
+ },
+ {
+ "dial": "localhost:8002"
+ }
+ ]
+ },
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "{http.request.host}:8001"
+ },
+ {
+ "dial": "{http.request.host}:8002"
+ }
+ ]
+ },
+ {
+ "handler": "reverse_proxy",
+ "transport": {
+ "protocol": "http",
+ "tls": {}
+ },
+ "upstreams": [
+ {
+ "dial": "localhost:8001"
+ },
+ {
+ "dial": "localhost:8002"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt b/caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt
index 0cf9d88..ac0d53c 100644
--- a/caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt
+++ b/caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt
@@ -1,12 +1,15 @@
*.example.com {
@foo host foo.example.com
handle @foo {
- handle_path /strip* {
+ handle_path /strip {
respond "this should be first"
}
- handle {
+ handle_path /strip* {
respond "this should be second"
}
+ handle {
+ respond "this should be last"
+ }
}
handle {
respond "this should be last"
@@ -35,13 +38,13 @@
"handler": "subroute",
"routes": [
{
- "group": "group5",
+ "group": "group6",
"handle": [
{
"handler": "subroute",
"routes": [
{
- "group": "group2",
+ "group": "group3",
"handle": [
{
"handler": "subroute",
@@ -68,13 +71,13 @@
"match": [
{
"path": [
- "/strip*"
+ "/strip"
]
}
]
},
{
- "group": "group2",
+ "group": "group3",
"handle": [
{
"handler": "subroute",
@@ -82,6 +85,14 @@
{
"handle": [
{
+ "handler": "rewrite",
+ "strip_path_prefix": "/strip"
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
"body": "this should be second",
"handler": "static_response"
}
@@ -89,6 +100,31 @@
}
]
}
+ ],
+ "match": [
+ {
+ "path": [
+ "/strip*"
+ ]
+ }
+ ]
+ },
+ {
+ "group": "group3",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "this should be last",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
]
}
]
@@ -103,7 +139,7 @@
]
},
{
- "group": "group5",
+ "group": "group6",
"handle": [
{
"handler": "subroute",
diff --git a/caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt b/caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt
index dff75e1..38a912f 100644
--- a/caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt
+++ b/caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt
@@ -1,7 +1,8 @@
:80
vars /foobar foo last
-vars /foo foo middle
+vars /foo foo middle-last
+vars /foo* foo middle-first
vars * foo first
----------
{
@@ -25,13 +26,28 @@ vars * foo first
"match": [
{
"path": [
+ "/foo*"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "foo": "middle-first",
+ "handler": "vars"
+ }
+ ]
+ },
+ {
+ "match": [
+ {
+ "path": [
"/foo"
]
}
],
"handle": [
{
- "foo": "middle",
+ "foo": "middle-last",
"handler": "vars"
}
]
diff --git a/caddytest/integration/caddyfile_test.go b/caddytest/integration/caddyfile_test.go
index 3f3ba0a..205bc5b 100644
--- a/caddytest/integration/caddyfile_test.go
+++ b/caddytest/integration/caddyfile_test.go
@@ -135,3 +135,352 @@ func TestReplIndex(t *testing.T) {
// act and assert
tester.AssertGetResponse("http://localhost:9080/", 200, "")
}
+
+func TestInvalidPrefix(t *testing.T) {
+ type testCase struct {
+ config, expectedError string
+ }
+
+ failureCases := []testCase{
+ {
+ config: `wss://localhost`,
+ expectedError: `the scheme wss:// is only supported in browsers; use https:// instead`,
+ },
+ {
+ config: `ws://localhost`,
+ expectedError: `the scheme ws:// is only supported in browsers; use http:// instead`,
+ },
+ {
+ config: `someInvalidPrefix://localhost`,
+ expectedError: "unsupported URL scheme someinvalidprefix://",
+ },
+ {
+ config: `h2c://localhost`,
+ expectedError: `unsupported URL scheme h2c://`,
+ },
+ {
+ config: `localhost, wss://localhost`,
+ expectedError: `the scheme wss:// is only supported in browsers; use https:// instead`,
+ },
+ {
+ config: `localhost {
+ reverse_proxy ws://localhost"
+ }`,
+ expectedError: `the scheme ws:// is only supported in browsers; use http:// instead`,
+ },
+ {
+ config: `localhost {
+ reverse_proxy someInvalidPrefix://localhost"
+ }`,
+ expectedError: `unsupported URL scheme someinvalidprefix://`,
+ },
+ }
+
+ for _, failureCase := range failureCases {
+ caddytest.AssertLoadError(t, failureCase.config, "caddyfile", failureCase.expectedError)
+ }
+}
+
+func TestValidPrefix(t *testing.T) {
+ type testCase struct {
+ rawConfig, expectedResponse string
+ }
+
+ successCases := []testCase{
+ {
+ "localhost",
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ {
+ "https://localhost",
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ {
+ "http://localhost",
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ {
+ `localhost {
+ reverse_proxy http://localhost:3000
+ }`,
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "localhost:3000"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ {
+ `localhost {
+ reverse_proxy https://localhost:3000
+ }`,
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "transport": {
+ "protocol": "http",
+ "tls": {}
+ },
+ "upstreams": [
+ {
+ "dial": "localhost:3000"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ {
+ `localhost {
+ reverse_proxy h2c://localhost:3000
+ }`,
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "transport": {
+ "protocol": "http",
+ "versions": [
+ "h2c",
+ "2"
+ ]
+ },
+ "upstreams": [
+ {
+ "dial": "localhost:3000"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ {
+ `localhost {
+ reverse_proxy localhost:3000
+ }`,
+ `{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "localhost"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "localhost:3000"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
+}`,
+ },
+ }
+
+ for _, successCase := range successCases {
+ caddytest.AssertAdapt(t, successCase.rawConfig, "caddyfile", successCase.expectedResponse)
+ }
+}
diff --git a/caddytest/integration/reverseproxy_test.go b/caddytest/integration/reverseproxy_test.go
index f7b1967..4f4261b 100644
--- a/caddytest/integration/reverseproxy_test.go
+++ b/caddytest/integration/reverseproxy_test.go
@@ -22,80 +22,38 @@ func TestSRVReverseProxy(t *testing.T) {
},
"apps": {
"pki": {
- "certificate_authorities" : {
- "local" : {
- "install_trust": false
+ "certificate_authorities": {
+ "local": {
+ "install_trust": false
}
}
},
- "http": {
- "grace_period": 1,
- "servers": {
- "srv0": {
- "listen": [
- ":8080"
- ],
- "routes": [
- {
- "handle": [
- {
- "handler": "reverse_proxy",
- "upstreams": [
- {
- "lookup_srv": "srv.host.service.consul"
- }
+ "http": {
+ "grace_period": 1,
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":18080"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "dynamic_upstreams": {
+ "source": "srv",
+ "name": "srv.host.service.consul"
+ }
+ }
+ ]
+ }
]
- }
- ]
- }
- ]
- }
- }
- }
- }
- }
- `, "json")
-}
-
-func TestSRVWithDial(t *testing.T) {
- caddytest.AssertLoadError(t, `
- {
- "apps": {
- "pki": {
- "certificate_authorities" : {
- "local" : {
- "install_trust": false
- }
+ }
}
- },
- "http": {
- "grace_period": 1,
- "servers": {
- "srv0": {
- "listen": [
- ":8080"
- ],
- "routes": [
- {
- "handle": [
- {
- "handler": "reverse_proxy",
- "upstreams": [
- {
- "dial": "tcp/address.to.upstream:80",
- "lookup_srv": "srv.host.service.consul"
- }
- ]
- }
- ]
- }
- ]
- }
}
- }
}
- }
- `, "json", `upstream: specifying dial address is incompatible with lookup_srv: 0: {\"dial\": \"tcp/address.to.upstream:80\", \"lookup_srv\": \"srv.host.service.consul\"}`)
+ }
+ `, "json")
}
func TestDialWithPlaceholderUnix(t *testing.T) {
@@ -138,41 +96,41 @@ func TestDialWithPlaceholderUnix(t *testing.T) {
},
"apps": {
"pki": {
- "certificate_authorities" : {
- "local" : {
- "install_trust": false
- }
+ "certificate_authorities": {
+ "local": {
+ "install_trust": false
+ }
}
- },
- "http": {
- "grace_period": 1,
- "servers": {
- "srv0": {
- "listen": [
- ":8080"
- ],
- "routes": [
- {
- "handle": [
- {
- "handler": "reverse_proxy",
- "upstreams": [
- {
- "dial": "unix/{http.request.header.X-Caddy-Upstream-Dial}"
- }
+ },
+ "http": {
+ "grace_period": 1,
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":18080"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "upstreams": [
+ {
+ "dial": "unix/{http.request.header.X-Caddy-Upstream-Dial}"
+ }
+ ]
+ }
+ ]
+ }
]
- }
- ]
- }
- ]
- }
- }
- }
+ }
+ }
+ }
}
- }
+ }
`, "json")
- req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil)
+ req, err := http.NewRequest(http.MethodGet, "http://localhost:18080", nil)
if err != nil {
t.Fail()
return
@@ -190,18 +148,18 @@ func TestReverseProxyWithPlaceholderDialAddress(t *testing.T) {
},
"apps": {
"pki": {
- "certificate_authorities" : {
- "local" : {
- "install_trust": false
- }
+ "certificate_authorities": {
+ "local": {
+ "install_trust": false
+ }
}
- },
+ },
"http": {
"grace_period": 1,
"servers": {
"srv0": {
"listen": [
- ":8080"
+ ":18080"
],
"routes": [
{
@@ -264,14 +222,14 @@ func TestReverseProxyWithPlaceholderDialAddress(t *testing.T) {
}
}
}
- `, "json")
+ `, "json")
req, err := http.NewRequest(http.MethodGet, "http://localhost:9080", nil)
if err != nil {
t.Fail()
return
}
- req.Header.Set("X-Caddy-Upstream-Dial", "localhost:8080")
+ req.Header.Set("X-Caddy-Upstream-Dial", "localhost:18080")
tester.AssertResponse(req, 200, "Hello, World!")
}
@@ -284,18 +242,18 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
},
"apps": {
"pki": {
- "certificate_authorities" : {
- "local" : {
- "install_trust": false
- }
+ "certificate_authorities": {
+ "local": {
+ "install_trust": false
+ }
}
- },
+ },
"http": {
"grace_period": 1,
"servers": {
"srv0": {
"listen": [
- ":8080"
+ ":18080"
],
"routes": [
{
@@ -340,7 +298,7 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
"handler": "reverse_proxy",
"upstreams": [
{
- "dial": "tcp/{http.request.header.X-Caddy-Upstream-Dial}:8080"
+ "dial": "tcp/{http.request.header.X-Caddy-Upstream-Dial}:18080"
}
]
}
@@ -358,7 +316,7 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
}
}
}
- `, "json")
+ `, "json")
req, err := http.NewRequest(http.MethodGet, "http://localhost:9080", nil)
if err != nil {
@@ -369,51 +327,6 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
tester.AssertResponse(req, 200, "Hello, World!")
}
-func TestSRVWithActiveHealthcheck(t *testing.T) {
- caddytest.AssertLoadError(t, `
- {
- "apps": {
- "pki": {
- "certificate_authorities" : {
- "local" : {
- "install_trust": false
- }
- }
- },
- "http": {
- "grace_period": 1,
- "servers": {
- "srv0": {
- "listen": [
- ":8080"
- ],
- "routes": [
- {
- "handle": [
- {
- "handler": "reverse_proxy",
- "health_checks": {
- "active": {
- "path": "/ok"
- }
- },
- "upstreams": [
- {
- "lookup_srv": "srv.host.service.consul"
- }
- ]
- }
- ]
- }
- ]
- }
- }
- }
- }
- }
- `, "json", `upstream: lookup_srv is incompatible with active health checks: 0: {\"dial\": \"\", \"lookup_srv\": \"srv.host.service.consul\"}`)
-}
-
func TestReverseProxyHealthCheck(t *testing.T) {
tester := caddytest.NewTester(t)
tester.InitServer(`
@@ -440,7 +353,7 @@ func TestReverseProxyHealthCheck(t *testing.T) {
health_timeout 100ms
}
}
- `, "caddyfile")
+ `, "caddyfile")
time.Sleep(100 * time.Millisecond) // TODO: for some reason this test seems particularly flaky, getting 503 when it should be 200, unless we wait
tester.AssertGetResponse("http://localhost:9080/", 200, "Hello, World!")
diff --git a/caddytest/integration/stream_test.go b/caddytest/integration/stream_test.go
index 09d4f64..6bc612d 100644
--- a/caddytest/integration/stream_test.go
+++ b/caddytest/integration/stream_test.go
@@ -176,9 +176,7 @@ func testH2ToH2CStreamServeH2C(t *testing.T) *http.Server {
w.Header().Set("Cache-Control", "no-store")
w.WriteHeader(200)
- if f, ok := w.(http.Flusher); ok {
- f.Flush()
- }
+ http.NewResponseController(w).Flush()
buf := make([]byte, 4*1024)
diff --git a/caddytest/integration/testdata/import_respond.txt b/caddytest/integration/testdata/import_respond.txt
index 0907fbe..4513088 100644
--- a/caddytest/integration/testdata/import_respond.txt
+++ b/caddytest/integration/testdata/import_respond.txt
@@ -1 +1 @@
-respond "'I am {args.0}', hears {args.1}" \ No newline at end of file
+respond "'I am {args[0]}', hears {args[1]}" \ No newline at end of file