mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 06:03:48 +03:00
caddyhttp: Clean up internal auto-HTTPS redirect code
Refactor redirect route creation into own function. Improve condition for appending port. Fixes a bug manifested through new test case: TestAutoHTTPRedirectsWithHTTPListenerFirstInAddresses
This commit is contained in:
parent
b8a799df9f
commit
63bda6a0dc
3 changed files with 104 additions and 44 deletions
|
@ -314,9 +314,13 @@ func (tc *Tester) AssertRedirect(requestURI string, expectedToLocation string, e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got error: %s", requestURI, expectedToLocation, err)
|
tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got error: %s", requestURI, expectedToLocation, err)
|
||||||
}
|
}
|
||||||
|
if loc == nil && expectedToLocation != "" {
|
||||||
if expectedToLocation != loc.String() {
|
tc.t.Errorf("requesting \"%s\" expected a Location header, but didn't get one", requestURI)
|
||||||
tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got \"%s\"", requestURI, expectedToLocation, loc.String())
|
}
|
||||||
|
if loc != nil {
|
||||||
|
if expectedToLocation != loc.String() {
|
||||||
|
tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got \"%s\"", requestURI, expectedToLocation, loc.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
|
@ -7,7 +7,21 @@ import (
|
||||||
"github.com/caddyserver/caddy/v2/caddytest"
|
"github.com/caddyserver/caddy/v2/caddytest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAutoHTTPtoHTTPSRedirects(t *testing.T) {
|
func TestAutoHTTPtoHTTPSRedirectsImplicitPort(t *testing.T) {
|
||||||
|
tester := caddytest.NewTester(t)
|
||||||
|
tester.InitServer(`
|
||||||
|
{
|
||||||
|
http_port 9080
|
||||||
|
https_port 9443
|
||||||
|
}
|
||||||
|
localhost
|
||||||
|
respond "Yahaha! You found me!"
|
||||||
|
`, "caddyfile")
|
||||||
|
|
||||||
|
tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoHTTPtoHTTPSRedirectsExplicitPortSameAsHTTPSPort(t *testing.T) {
|
||||||
tester := caddytest.NewTester(t)
|
tester := caddytest.NewTester(t)
|
||||||
tester.InitServer(`
|
tester.InitServer(`
|
||||||
{
|
{
|
||||||
|
@ -20,3 +34,49 @@ func TestAutoHTTPtoHTTPSRedirects(t *testing.T) {
|
||||||
|
|
||||||
tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
|
tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAutoHTTPtoHTTPSRedirectsExplicitPortDifferentFromHTTPSPort(t *testing.T) {
|
||||||
|
tester := caddytest.NewTester(t)
|
||||||
|
tester.InitServer(`
|
||||||
|
{
|
||||||
|
http_port 9080
|
||||||
|
https_port 9443
|
||||||
|
}
|
||||||
|
localhost:1234
|
||||||
|
respond "Yahaha! You found me!"
|
||||||
|
`, "caddyfile")
|
||||||
|
|
||||||
|
tester.AssertRedirect("http://localhost:9080/", "https://localhost:1234/", http.StatusPermanentRedirect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoHTTPRedirectsWithHTTPListenerFirstInAddresses(t *testing.T) {
|
||||||
|
tester := caddytest.NewTester(t)
|
||||||
|
tester.InitServer(`
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"http_port": 9080,
|
||||||
|
"https_port": 9443,
|
||||||
|
"servers": {
|
||||||
|
"ingress_server": {
|
||||||
|
"listen": [
|
||||||
|
":9080",
|
||||||
|
":9443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": ["localhost"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, "json")
|
||||||
|
tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
|
||||||
|
}
|
||||||
|
|
|
@ -303,31 +303,11 @@ uniqueDomainsLoop:
|
||||||
matcherSet = append(matcherSet, MatchHost(domains))
|
matcherSet = append(matcherSet, MatchHost(domains))
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the address to which to redirect
|
|
||||||
addr, err := caddy.ParseNetworkAddress(addrStr)
|
addr, err := caddy.ParseNetworkAddress(addrStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
redirTo := "https://{http.request.host}"
|
redirRoute := app.makeRedirRoute(addr.StartPort, matcherSet)
|
||||||
if addr.StartPort != uint(app.httpsPort()) {
|
|
||||||
redirTo += ":" + strconv.Itoa(int(addr.StartPort))
|
|
||||||
}
|
|
||||||
redirTo += "{http.request.uri}"
|
|
||||||
|
|
||||||
// build the route
|
|
||||||
redirRoute := Route{
|
|
||||||
MatcherSets: []MatcherSet{matcherSet},
|
|
||||||
Handlers: []MiddlewareHandler{
|
|
||||||
StaticResponse{
|
|
||||||
StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
|
|
||||||
Headers: http.Header{
|
|
||||||
"Location": []string{redirTo},
|
|
||||||
"Connection": []string{"close"},
|
|
||||||
},
|
|
||||||
Close: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the network/host information from the address,
|
// use the network/host information from the address,
|
||||||
// but change the port to the HTTP port then rebuild
|
// but change the port to the HTTP port then rebuild
|
||||||
|
@ -355,25 +335,7 @@ uniqueDomainsLoop:
|
||||||
// it's not something that should be relied on. We can change this
|
// it's not something that should be relied on. We can change this
|
||||||
// if we want to.
|
// if we want to.
|
||||||
appendCatchAll := func(routes []Route) []Route {
|
appendCatchAll := func(routes []Route) []Route {
|
||||||
redirTo := "https://{http.request.host}"
|
return append(routes, app.makeRedirRoute(uint(app.httpsPort()), MatcherSet{MatchProtocol("http")}))
|
||||||
if app.httpsPort() != DefaultHTTPSPort {
|
|
||||||
redirTo += ":" + strconv.Itoa(app.httpsPort())
|
|
||||||
}
|
|
||||||
redirTo += "{http.request.uri}"
|
|
||||||
routes = append(routes, Route{
|
|
||||||
MatcherSets: []MatcherSet{{MatchProtocol("http")}},
|
|
||||||
Handlers: []MiddlewareHandler{
|
|
||||||
StaticResponse{
|
|
||||||
StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
|
|
||||||
Headers: http.Header{
|
|
||||||
"Location": []string{redirTo},
|
|
||||||
"Connection": []string{"close"},
|
|
||||||
},
|
|
||||||
Close: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return routes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
redirServersLoop:
|
redirServersLoop:
|
||||||
|
@ -422,6 +384,40 @@ redirServersLoop:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *App) makeRedirRoute(redirToPort uint, matcherSet MatcherSet) Route {
|
||||||
|
redirTo := "https://{http.request.host}"
|
||||||
|
|
||||||
|
// since this is an external redirect, we should only append an explicit
|
||||||
|
// port if we know it is not the officially standardized HTTPS port, and,
|
||||||
|
// notably, also not the port that Caddy thinks is the HTTPS port (the
|
||||||
|
// configurable HTTPSPort parameter) - we can't change the standard HTTPS
|
||||||
|
// port externally, so that config parameter is for internal use only;
|
||||||
|
// we also do not append the port if it happens to be the HTTP port as
|
||||||
|
// well, obviously (for example, user defines the HTTP port explicitly
|
||||||
|
// in the list of listen addresses for a server)
|
||||||
|
if redirToPort != uint(app.httpPort()) &&
|
||||||
|
redirToPort != uint(app.httpsPort()) &&
|
||||||
|
redirToPort != DefaultHTTPPort &&
|
||||||
|
redirToPort != DefaultHTTPSPort {
|
||||||
|
redirTo += ":" + strconv.Itoa(int(redirToPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
redirTo += "{http.request.uri}"
|
||||||
|
return Route{
|
||||||
|
MatcherSets: []MatcherSet{matcherSet},
|
||||||
|
Handlers: []MiddlewareHandler{
|
||||||
|
StaticResponse{
|
||||||
|
StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
|
||||||
|
Headers: http.Header{
|
||||||
|
"Location": []string{redirTo},
|
||||||
|
"Connection": []string{"close"},
|
||||||
|
},
|
||||||
|
Close: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// createAutomationPolicy ensures that automated certificates for this
|
// createAutomationPolicy ensures that automated certificates for this
|
||||||
// app are managed properly. This adds up to two automation policies:
|
// app are managed properly. This adds up to two automation policies:
|
||||||
// one for the public names, and one for the internal names. If a catch-all
|
// one for the public names, and one for the internal names. If a catch-all
|
||||||
|
|
Loading…
Reference in a new issue