Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
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
Matthew Holt committed
Dec 10, 2020 at 14:36 UTC
63bda6a0dc97e02d32865c31b5e46d2ead86ac7b
3 files changed
+104
-44
caddytest/caddytest.go
+7
-3
@@ -314,9 +314,13 @@ func (tc *Tester) AssertRedirect(requestURI string, expectedToLocation string, e
314
if err != nil {
315
tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got error: %s", requestURI, expectedToLocation, err)
316
}
317
-
318
- if expectedToLocation != loc.String() {
319
- tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got \"%s\"", requestURI, expectedToLocation, loc.String())
317
+ if loc == nil && expectedToLocation != "" {
318
+ tc.t.Errorf("requesting \"%s\" expected a Location header, but didn't get one", requestURI)
319
+ }
320
+ if loc != nil {
321
+ if expectedToLocation != loc.String() {
322
+ tc.t.Errorf("requesting \"%s\" expected location: \"%s\" but got \"%s\"", requestURI, expectedToLocation, loc.String())
323
+ }
324
}
325
326
return resp
caddytest/integration/autohttps_test.go
+61
-1
@@ -7,7 +7,21 @@ import (
7
"github.com/caddyserver/caddy/v2/caddytest"
8
)
9
10
-func TestAutoHTTPtoHTTPSRedirects(t *testing.T) {
10
+func TestAutoHTTPtoHTTPSRedirectsImplicitPort(t *testing.T) {
11
+ tester := caddytest.NewTester(t)
12
+ tester.InitServer(`
13
+ {
14
+ http_port 9080
15
+ https_port 9443
16
+ }
17
+ localhost
18
+ respond "Yahaha! You found me!"
19
+ `, "caddyfile")
20
+
21
+ tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
22
+}
23
+
24
+func TestAutoHTTPtoHTTPSRedirectsExplicitPortSameAsHTTPSPort(t *testing.T) {
25
tester := caddytest.NewTester(t)
26
tester.InitServer(`
27
{
@@ -20,3 +34,49 @@ func TestAutoHTTPtoHTTPSRedirects(t *testing.T) {
34
35
tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
36
}
37
+
38
+func TestAutoHTTPtoHTTPSRedirectsExplicitPortDifferentFromHTTPSPort(t *testing.T) {
39
+ tester := caddytest.NewTester(t)
40
+ tester.InitServer(`
41
+ {
42
+ http_port 9080
43
+ https_port 9443
44
+ }
45
+ localhost:1234
46
+ respond "Yahaha! You found me!"
47
+ `, "caddyfile")
48
+
49
+ tester.AssertRedirect("http://localhost:9080/", "https://localhost:1234/", http.StatusPermanentRedirect)
50
+}
51
+
52
+func TestAutoHTTPRedirectsWithHTTPListenerFirstInAddresses(t *testing.T) {
53
+ tester := caddytest.NewTester(t)
54
+ tester.InitServer(`
55
+{
56
+ "apps": {
57
+ "http": {
58
+ "http_port": 9080,
59
+ "https_port": 9443,
60
+ "servers": {
61
+ "ingress_server": {
62
+ "listen": [
63
+ ":9080",
64
+ ":9443"
65
+ ],
66
+ "routes": [
67
+ {
68
+ "match": [
69
+ {
70
+ "host": ["localhost"]
71
+ }
72
+ ]
73
+ }
74
+ ]
75
+ }
76
+ }
77
+ }
78
+ }
79
+}
80
+`, "json")
81
+ tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
82
+}
modules/caddyhttp/autohttps.go
+36
-40
@@ -303,31 +303,11 @@ uniqueDomainsLoop:
303
matcherSet = append(matcherSet, MatchHost(domains))
304
}
305
306
- // build the address to which to redirect
306
addr, err := caddy.ParseNetworkAddress(addrStr)
307
if err != nil {
308
return err
309
}
311
- redirTo := "https://{http.request.host}"
312
- if addr.StartPort != uint(app.httpsPort()) {
313
- redirTo += ":" + strconv.Itoa(int(addr.StartPort))
314
- }
315
- redirTo += "{http.request.uri}"
316
-
317
- // build the route
318
- redirRoute := Route{
319
- MatcherSets: []MatcherSet{matcherSet},
320
- Handlers: []MiddlewareHandler{
321
- StaticResponse{
322
- StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
323
- Headers: http.Header{
324
- "Location": []string{redirTo},
325
- "Connection": []string{"close"},
326
- },
327
- Close: true,
328
- },
329
- },
330
- }
310
+ redirRoute := app.makeRedirRoute(addr.StartPort, matcherSet)
311
312
// use the network/host information from the address,
313
// but change the port to the HTTP port then rebuild
@@ -355,25 +335,7 @@ uniqueDomainsLoop:
335
// it's not something that should be relied on. We can change this
336
// if we want to.
337
appendCatchAll := func(routes []Route) []Route {
358
- redirTo := "https://{http.request.host}"
359
- if app.httpsPort() != DefaultHTTPSPort {
360
- redirTo += ":" + strconv.Itoa(app.httpsPort())
361
- }
362
- redirTo += "{http.request.uri}"
363
- routes = append(routes, Route{
364
- MatcherSets: []MatcherSet{{MatchProtocol("http")}},
365
- Handlers: []MiddlewareHandler{
366
- StaticResponse{
367
- StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
368
- Headers: http.Header{
369
- "Location": []string{redirTo},
370
- "Connection": []string{"close"},
371
- },
372
- Close: true,
373
- },
374
- },
375
- })
376
- return routes
338
+ return append(routes, app.makeRedirRoute(uint(app.httpsPort()), MatcherSet{MatchProtocol("http")}))
339
}
340
341
redirServersLoop:
@@ -422,6 +384,40 @@ redirServersLoop:
384
return nil
385
}
386
387
+func (app *App) makeRedirRoute(redirToPort uint, matcherSet MatcherSet) Route {
388
+ redirTo := "https://{http.request.host}"
389
+
390
+ // since this is an external redirect, we should only append an explicit
391
+ // port if we know it is not the officially standardized HTTPS port, and,
392
+ // notably, also not the port that Caddy thinks is the HTTPS port (the
393
+ // configurable HTTPSPort parameter) - we can't change the standard HTTPS
394
+ // port externally, so that config parameter is for internal use only;
395
+ // we also do not append the port if it happens to be the HTTP port as
396
+ // well, obviously (for example, user defines the HTTP port explicitly
397
+ // in the list of listen addresses for a server)
398
+ if redirToPort != uint(app.httpPort()) &&
399
+ redirToPort != uint(app.httpsPort()) &&
400
+ redirToPort != DefaultHTTPPort &&
401
+ redirToPort != DefaultHTTPSPort {
402
+ redirTo += ":" + strconv.Itoa(int(redirToPort))
403
+ }
404
+
405
+ redirTo += "{http.request.uri}"
406
+ return Route{
407
+ MatcherSets: []MatcherSet{matcherSet},
408
+ Handlers: []MiddlewareHandler{
409
+ StaticResponse{
410
+ StatusCode: WeakString(strconv.Itoa(http.StatusPermanentRedirect)),
411
+ Headers: http.Header{
412
+ "Location": []string{redirTo},
413
+ "Connection": []string{"close"},
414
+ },
415
+ Close: true,
416
+ },
417
+ },
418
+ }
419
+}
420
+
421
// createAutomationPolicy ensures that automated certificates for this
422
// app are managed properly. This adds up to two automation policies:
423
// one for the public names, and one for the internal names. If a catch-all