mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 21:31:07 +00:00 
			
		
		
		
	 ddb1d2c2b1
			
		
	
	
		ddb1d2c2b1
		
			
		
	
	
	
	
		
			
			* caddyhttp: add `http.request.local{,.host,.port}` placeholder
This is the counterpart of `http.request.remote{,.host,.port}`.
`http.request.remote` operates on the remote client's address, while
`http.request.local` operates on the address the connection arrived on.
Take the following example:
- Caddy serving on `203.0.113.1:80`
- Client on `203.0.113.2`
`http.request.remote.host` would return `203.0.113.2` (client IP)
`http.request.local.host` would return `203.0.113.1` (server IP)
`http.request.local.port` would return `80` (server port)
I find this helpful for debugging setups with multiple servers and/or
multiple network paths (multiple IPs, AnyIP, Anycast).
Co-authored-by: networkException <git@nwex.de>
* caddyhttp: add unit test for `http.request.local{,.host,.port}`
* caddyhttp: add integration test for `http.request.local.port`
* caddyhttp: fix `http.request.local.host` placeholder handling with unix sockets
The implementation matches the one of `http.request.remote.host` now and
returns the unix socket path (just like `http.request.local` already did)
instead of an empty string.
---------
Co-authored-by: networkException <git@nwex.de>
		
	
			
		
			
				
	
	
		
			811 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			811 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package integration
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/caddyserver/caddy/v2/caddytest"
 | |
| )
 | |
| 
 | |
| func TestRespond(t *testing.T) {
 | |
| 	// arrange
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(` 
 | |
|   {
 | |
|     admin localhost:2999
 | |
|     http_port     9080
 | |
|     https_port    9443
 | |
|     grace_period  1ns
 | |
|   }
 | |
|   
 | |
|   localhost:9080 {
 | |
|     respond /version 200 {
 | |
|       body "hello from localhost"
 | |
|     }	
 | |
|     }
 | |
|   `, "caddyfile")
 | |
| 
 | |
| 	// act and assert
 | |
| 	tester.AssertGetResponse("http://localhost:9080/version", 200, "hello from localhost")
 | |
| }
 | |
| 
 | |
| func TestRedirect(t *testing.T) {
 | |
| 	// arrange
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`
 | |
|   {
 | |
|     admin localhost:2999
 | |
|     http_port     9080
 | |
|     https_port    9443
 | |
|     grace_period  1ns
 | |
|   }
 | |
|   
 | |
|   localhost:9080 {
 | |
|     
 | |
|     redir / http://localhost:9080/hello 301
 | |
|     
 | |
|     respond /hello 200 {
 | |
|       body "hello from localhost"
 | |
|     }	
 | |
|     }
 | |
|   `, "caddyfile")
 | |
| 
 | |
| 	// act and assert
 | |
| 	tester.AssertRedirect("http://localhost:9080/", "http://localhost:9080/hello", 301)
 | |
| 
 | |
| 	// follow redirect
 | |
| 	tester.AssertGetResponse("http://localhost:9080/", 200, "hello from localhost")
 | |
| }
 | |
| 
 | |
| func TestDuplicateHosts(t *testing.T) {
 | |
| 	// act and assert
 | |
| 	caddytest.AssertLoadError(t,
 | |
| 		`
 | |
|     localhost:9080 {
 | |
|     }
 | |
|   
 | |
|     localhost:9080 { 
 | |
|     }
 | |
|     `,
 | |
| 		"caddyfile",
 | |
| 		"ambiguous site definition")
 | |
| }
 | |
| 
 | |
| func TestReadCookie(t *testing.T) {
 | |
| 	localhost, _ := url.Parse("http://localhost")
 | |
| 	cookie := http.Cookie{
 | |
| 		Name:  "clientname",
 | |
| 		Value: "caddytest",
 | |
| 	}
 | |
| 
 | |
| 	// arrange
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.Client.Jar.SetCookies(localhost, []*http.Cookie{&cookie})
 | |
| 	tester.InitServer(` 
 | |
|   {
 | |
|     skip_install_trust
 | |
|     admin localhost:2999
 | |
|     http_port     9080
 | |
|     https_port    9443
 | |
|     grace_period  1ns
 | |
|   }
 | |
|   
 | |
|   localhost:9080 {
 | |
|     templates {
 | |
|       root testdata
 | |
|     }
 | |
|     file_server {
 | |
|       root testdata
 | |
|     }
 | |
|   }
 | |
|   `, "caddyfile")
 | |
| 
 | |
| 	// act and assert
 | |
| 	tester.AssertGetResponse("http://localhost:9080/cookie.html", 200, "<h2>Cookie.ClientName caddytest</h2>")
 | |
| }
 | |
| 
 | |
| func TestReplIndex(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`
 | |
|   {
 | |
|     skip_install_trust
 | |
|     admin localhost:2999
 | |
|     http_port     9080
 | |
|     https_port    9443
 | |
|     grace_period  1ns
 | |
|   }
 | |
| 
 | |
|   localhost:9080 {
 | |
|     templates {
 | |
|       root testdata
 | |
|     }
 | |
|     file_server {
 | |
|       root testdata
 | |
|       index "index.{host}.html"
 | |
|     }
 | |
|   }
 | |
|   `, "caddyfile")
 | |
| 
 | |
| 	// 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)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestUriReplace(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri replace "\}" %7D
 | |
| 	uri replace "\{" %7B
 | |
| 	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?test={%20content%20}", 200, "test=%7B%20content%20%7D")
 | |
| }
 | |
| 
 | |
| func TestUriOps(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query +foo bar
 | |
| 	uri query -baz
 | |
| 	uri query taz test
 | |
| 	uri query key=value example
 | |
| 	uri query changethis>changed
 | |
| 	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar0&baz=buz&taz=nottest&changethis=val", 200, "changed=val&foo=bar0&foo=bar&key%3Dvalue=example&taz=test")
 | |
| }
 | |
| 
 | |
| // Tests the `http.request.local.port` placeholder.
 | |
| // We don't test the very similar `http.request.local.host` placeholder,
 | |
| // because depending on the host the test is running on, localhost might
 | |
| // refer to 127.0.0.1 or ::1.
 | |
| // TODO: Test each http version separately (especially http/3)
 | |
| func TestHttpRequestLocalPortPlaceholder(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	respond "{http.request.local.port}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/", 200, "9080")
 | |
| }
 | |
| 
 | |
| func TestSetThenAddQueryParams(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query foo bar
 | |
| 	uri query +foo baz
 | |
| 	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint", 200, "foo=bar&foo=baz")
 | |
| }
 | |
| 
 | |
| func TestSetThenDeleteParams(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query bar foo{query.foo}
 | |
| 	uri query -foo
 | |
| 	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar", 200, "bar=foobar")
 | |
| }
 | |
| 
 | |
| func TestRenameAndOtherOps(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query foo>bar
 | |
| 	uri query bar taz
 | |
| 	uri query +bar baz
 | |
| 	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar", 200, "bar=taz&bar=baz")
 | |
| }
 | |
| 
 | |
| func TestReplaceOps(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query foo bar baz	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar", 200, "foo=baz")
 | |
| }
 | |
| 
 | |
| func TestReplaceWithReplacementPlaceholder(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query foo bar {query.placeholder}	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?placeholder=baz&foo=bar", 200, "foo=baz&placeholder=baz")
 | |
| 
 | |
| }
 | |
| 
 | |
| func TestReplaceWithKeyPlaceholder(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query {query.placeholder} bar baz	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?placeholder=foo&foo=bar", 200, "foo=baz&placeholder=foo")
 | |
| }
 | |
| 
 | |
| func TestPartialReplacement(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query foo ar az	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar", 200, "foo=baz")
 | |
| }
 | |
| 
 | |
| func TestNonExistingSearch(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query foo var baz	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar", 200, "foo=bar")
 | |
| }
 | |
| 
 | |
| func TestReplaceAllOps(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query * bar baz	
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar&baz=bar", 200, "baz=baz&foo=baz")
 | |
| }
 | |
| 
 | |
| func TestUriOpsBlock(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 
 | |
| 	tester.InitServer(`
 | |
| 	{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	:9080
 | |
| 	uri query {
 | |
| 		+foo bar
 | |
| 		-baz
 | |
| 		taz test
 | |
| 	} 
 | |
| 	respond "{query}"`, "caddyfile")
 | |
| 
 | |
| 	tester.AssertGetResponse("http://localhost:9080/endpoint?foo=bar0&baz=buz&taz=nottest", 200, "foo=bar0&foo=bar&taz=test")
 | |
| }
 | |
| 
 | |
| func TestHandleErrorSimpleCodes(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	localhost:9080 {
 | |
| 		root * /srv
 | |
| 		error /private* "Unauthorized" 410
 | |
| 		error /hidden* "Not found" 404
 | |
| 	
 | |
| 		handle_errors 404 410 {
 | |
| 			respond "404 or 410 error"
 | |
| 		}
 | |
| 	}`, "caddyfile")
 | |
| 	// act and assert
 | |
| 	tester.AssertGetResponse("http://localhost:9080/private", 410, "404 or 410 error")
 | |
| 	tester.AssertGetResponse("http://localhost:9080/hidden", 404, "404 or 410 error")
 | |
| }
 | |
| 
 | |
| func TestHandleErrorRange(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	localhost:9080 {
 | |
| 		root * /srv
 | |
| 		error /private* "Unauthorized" 410
 | |
| 		error /hidden* "Not found" 404
 | |
| 
 | |
| 		handle_errors 4xx {
 | |
| 			respond "Error in the [400 .. 499] range"
 | |
| 		}
 | |
| 	}`, "caddyfile")
 | |
| 	// act and assert
 | |
| 	tester.AssertGetResponse("http://localhost:9080/private", 410, "Error in the [400 .. 499] range")
 | |
| 	tester.AssertGetResponse("http://localhost:9080/hidden", 404, "Error in the [400 .. 499] range")
 | |
| }
 | |
| 
 | |
| func TestHandleErrorSort(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	localhost:9080 {
 | |
| 		root * /srv
 | |
| 		error /private* "Unauthorized" 410
 | |
| 		error /hidden* "Not found" 404
 | |
| 		error /internalerr* "Internal Server Error" 500
 | |
| 
 | |
| 		handle_errors {
 | |
| 			respond "Fallback route: code outside the [400..499] range"
 | |
| 		}
 | |
| 		handle_errors 4xx {
 | |
| 			respond "Error in the [400 .. 499] range"
 | |
| 		}
 | |
| 	}`, "caddyfile")
 | |
| 	// act and assert
 | |
| 	tester.AssertGetResponse("http://localhost:9080/internalerr", 500, "Fallback route: code outside the [400..499] range")
 | |
| 	tester.AssertGetResponse("http://localhost:9080/hidden", 404, "Error in the [400 .. 499] range")
 | |
| }
 | |
| 
 | |
| func TestHandleErrorRangeAndCodes(t *testing.T) {
 | |
| 	tester := caddytest.NewTester(t)
 | |
| 	tester.InitServer(`{
 | |
| 		admin localhost:2999
 | |
| 		http_port     9080
 | |
| 	}
 | |
| 	localhost:9080 {
 | |
| 		root * /srv
 | |
| 		error /private* "Unauthorized" 410
 | |
| 		error /threehundred* "Moved Permanently" 301
 | |
| 		error /internalerr* "Internal Server Error" 500
 | |
| 
 | |
| 		handle_errors 500 3xx {
 | |
| 			respond "Error code is equal to 500 or in the [300..399] range"
 | |
| 		}
 | |
| 		handle_errors 4xx {
 | |
| 			respond "Error in the [400 .. 499] range"
 | |
| 		}
 | |
| 	}`, "caddyfile")
 | |
| 	// act and assert
 | |
| 	tester.AssertGetResponse("http://localhost:9080/internalerr", 500, "Error code is equal to 500 or in the [300..399] range")
 | |
| 	tester.AssertGetResponse("http://localhost:9080/threehundred", 301, "Error code is equal to 500 or in the [300..399] range")
 | |
| 	tester.AssertGetResponse("http://localhost:9080/private", 410, "Error in the [400 .. 499] range")
 | |
| }
 | |
| 
 | |
| func TestInvalidSiteAddressesAsDirectives(t *testing.T) {
 | |
| 	type testCase struct {
 | |
| 		config, expectedError string
 | |
| 	}
 | |
| 
 | |
| 	failureCases := []testCase{
 | |
| 		{
 | |
| 			config: `
 | |
| 			handle {
 | |
| 				file_server
 | |
| 			}`,
 | |
| 			expectedError: `Caddyfile:2: parsed 'handle' as a site address, but it is a known directive; directives must appear in a site block`,
 | |
| 		},
 | |
| 		{
 | |
| 			config: `
 | |
| 			reverse_proxy localhost:9000 localhost:9001 {
 | |
| 				file_server
 | |
| 			}`,
 | |
| 			expectedError: `Caddyfile:2: parsed 'reverse_proxy' as a site address, but it is a known directive; directives must appear in a site block`,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, failureCase := range failureCases {
 | |
| 		caddytest.AssertLoadError(t, failureCase.config, "caddyfile", failureCase.expectedError)
 | |
| 	}
 | |
| }
 |