@marcel91200 / caddy Mirror · read-only / commits / 63bda6a0
Fork 0

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