@marcel91200 / caddy Mirror · read-only / commits / d789596b
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: Implement better logic for inserting the HTTP->HTTPS redirs (#4033)

* caddyhttp: Implement better logic for inserting the HTTP->HTTPS redirs * caddyhttp: Add integration test

Francis Lavoie committed Apr 19, 2021 at 21:54 UTC d789596bc0b014c99d75c00fe8e55c40ee3d58e3
3 files changed +69 -14
caddytest/integration/autohttps_test.go
+23
@@ -80,3 +80,26 @@ func TestAutoHTTPRedirectsWithHTTPListenerFirstInAddresses(t *testing.T) {
80 `, "json")
81 tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
82 }
83 +
84 +func TestAutoHTTPRedirectsInsertedBeforeUserDefinedCatchAll(t *testing.T) {
85 + tester := caddytest.NewTester(t)
86 + tester.InitServer(`
87 + {
88 + http_port 9080
89 + https_port 9443
90 + local_certs
91 + }
92 + http://:9080 {
93 + respond "Foo"
94 + }
95 + http://baz.localhost:9080 {
96 + respond "Baz"
97 + }
98 + bar.localhost {
99 + respond "Bar"
100 + }
101 + `, "caddyfile")
102 + tester.AssertRedirect("http://bar.localhost:9080/", "https://bar.localhost/", http.StatusPermanentRedirect)
103 + tester.AssertGetResponse("http://foo.localhost:9080/", 200, "Foo")
104 + tester.AssertGetResponse("http://baz.localhost:9080/", 200, "Baz")
105 +}
modules/caddyhttp/autohttps.go
+15 -14
@@ -342,21 +342,22 @@ redirServersLoop:
342 for redirServerAddr, routes := range redirServers {
343 // for each redirect listener, see if there's already a
344 // server configured to listen on that exact address; if so,
345 - // simply add the redirect route to the end of its route
346 - // list; otherwise, we'll create a new server for all the
347 - // listener addresses that are unused and serve the
348 - // remaining redirects from it
349 - for srvName, srv := range app.Servers {
345 + // insert the redirect route to the end of its route list
346 + // after any other routes with host matchers; otherwise,
347 + // we'll create a new server for all the listener addresses
348 + // that are unused and serve the remaining redirects from it
349 + for _, srv := range app.Servers {
350 if srv.hasListenerAddress(redirServerAddr) {
351 - // user has configured a server for the same address
352 - // that the redirect runs from; simply append our
353 - // redirect route to the existing routes, with a
354 - // caveat that their config might override ours
355 - app.logger.Warn("user server is listening on same interface as automatic HTTP->HTTPS redirects; user-configured routes might override these redirects",
356 - zap.String("server_name", srvName),
357 - zap.String("interface", redirServerAddr),
358 - )
359 - srv.Routes = append(srv.Routes, appendCatchAll(routes)...)
351 + // find the index of the route after the last route with a host
352 + // matcher, then insert the redirects there, but before any
353 + // user-defined catch-all routes
354 + // see https://github.com/caddyserver/caddy/issues/3212
355 + insertIndex := srv.findLastRouteWithHostMatcher()
356 + srv.Routes = append(srv.Routes[:insertIndex], append(routes, srv.Routes[insertIndex:]...)...)
357 +
358 + // append our catch-all route in case the user didn't define their own
359 + srv.Routes = appendCatchAll(srv.Routes)
360 +
361 continue redirServersLoop
362 }
363 }
modules/caddyhttp/server.go
+31
@@ -373,6 +373,37 @@ func (s *Server) hasTLSClientAuth() bool {
373 return false
374 }
375
376 +// findLastRouteWithHostMatcher returns the index of the last route
377 +// in the server which has a host matcher. Used during Automatic HTTPS
378 +// to determine where to insert the HTTP->HTTPS redirect route, such
379 +// that it is after any other host matcher but before any "catch-all"
380 +// route without a host matcher.
381 +func (s *Server) findLastRouteWithHostMatcher() int {
382 + lastIndex := len(s.Routes)
383 + for i, route := range s.Routes {
384 + // since we want to break out of an inner loop, use a closure
385 + // to allow us to use 'return' when we found a host matcher
386 + found := (func() bool {
387 + for _, sets := range route.MatcherSets {
388 + for _, matcher := range sets {
389 + switch matcher.(type) {
390 + case *MatchHost:
391 + return true
392 + }
393 + }
394 + }
395 + return false
396 + })()
397 +
398 + // if we found the host matcher, change the lastIndex to
399 + // just after the current route
400 + if found {
401 + lastIndex = i + 1
402 + }
403 + }
404 + return lastIndex
405 +}
406 +
407 // HTTPErrorConfig determines how to handle errors
408 // from the HTTP handlers.
409 type HTTPErrorConfig struct {