@marcel91200 / caddy Mirror · read-only / commits / 40e05e5a
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

http: Improve auto HTTP->HTTPS redirects, fix edge cases

See https://caddy.community/t/v2-issues-with-multiple-server-blocks-in-caddyfile-style-config/6206/13?u=matt Also print pid when using `caddy start`

Matthew Holt committed Sep 18, 2019 at 18:01 UTC 40e05e5a01d50b381fa7a7a472ea38f44518f02c
3 files changed +86 -74
cmd/commands.go
+1 -1
@@ -130,7 +130,7 @@ func cmdStart() (int, error) {
130 // when one of the goroutines unblocks, we're done and can exit
131 select {
132 case <-success:
133 - fmt.Println("Successfully started Caddy")
133 + fmt.Printf("Successfully started Caddy (pid=%d)\n", cmd.Process.Pid)
134 case err := <-exit:
135 return caddy.ExitCodeFailedStartup,
136 fmt.Errorf("caddy process exited with error: %v", err)
modules/caddyhttp/caddyhttp.go
+66 -63
@@ -183,12 +183,8 @@ func (app *App) Start() error {
183 }
184
185 // enable TLS
186 - httpPort := app.HTTPPort
187 - if httpPort == 0 {
188 - httpPort = DefaultHTTPPort
189 - }
186 _, port, _ := net.SplitHostPort(addr)
191 - if len(srv.TLSConnPolicies) > 0 && port != strconv.Itoa(httpPort) {
187 + if len(srv.TLSConnPolicies) > 0 && port != strconv.Itoa(app.httpPort()) {
188 tlsCfg, err := srv.TLSConnPolicies.TLSConfig(app.ctx)
189 if err != nil {
190 return fmt.Errorf("%s/%s: making TLS configuration: %v", network, addr, err)
@@ -273,8 +269,9 @@ func (app *App) automaticHTTPS() error {
269 }
270 tlsApp := tlsAppIface.(*caddytls.TLS)
271
276 - lnAddrMap := make(map[string]struct{})
277 - var redirRoutes RouteList
272 + // this map will store associations of HTTP listener
273 + // addresses to the routes that do HTTP->HTTPS redirects
274 + lnAddrRedirRoutes := make(map[string]Route)
275
276 for srvName, srv := range app.Servers {
277 srv.tlsApp = tlsApp
@@ -284,9 +281,9 @@ func (app *App) automaticHTTPS() error {
281 }
282
283 // skip if all listeners use the HTTP port
287 - if !srv.listenersUseAnyPortOtherThan(app.HTTPPort) {
288 - log.Printf("[INFO] Server %v is only listening on the HTTP port %d, so no automatic HTTPS will be applied to this server",
289 - srv.Listen, app.HTTPPort)
284 + if !srv.listenersUseAnyPortOtherThan(app.httpPort()) {
285 + log.Printf("[INFO] Server %s is only listening on the HTTP port %d, so no automatic HTTPS will be applied to this server",
286 + srvName, app.httpPort())
287 continue
288 }
289
@@ -334,10 +331,10 @@ func (app *App) automaticHTTPS() error {
331 acmeManager := &caddytls.ACMEManagerMaker{
332 Challenges: caddytls.ChallengesConfig{
333 HTTP: caddytls.HTTPChallengeConfig{
337 - AlternatePort: app.HTTPPort,
334 + AlternatePort: app.HTTPPort, // we specifically want the user-configured port, if any
335 },
336 TLSALPN: caddytls.TLSALPNChallengeConfig{
340 - AlternatePort: app.HTTPSPort,
337 + AlternatePort: app.HTTPSPort, // we specifically want the user-configured port, if any
338 },
339 },
340 }
@@ -367,12 +364,6 @@ func (app *App) automaticHTTPS() error {
364
365 log.Printf("[INFO] Enabling automatic HTTP->HTTPS redirects for %v", domains)
366
370 - // notify user if their config might override the HTTP->HTTPS redirects
371 - if srv.listenersIncludePort(app.HTTPPort) {
372 - log.Printf("[WARNING] Server %v is listening on HTTP port %d, so automatic HTTP->HTTPS redirects may be overridden by your own configuration",
373 - srv.Listen, app.HTTPPort)
374 - }
375 -
367 // create HTTP->HTTPS redirects
368 for _, addr := range srv.Listen {
369 netw, host, port, err := caddy.SplitNetworkAddress(addr)
@@ -380,28 +371,22 @@ func (app *App) automaticHTTPS() error {
371 return fmt.Errorf("%s: invalid listener address: %v", srvName, addr)
372 }
373
383 - httpPort := app.HTTPPort
384 - if httpPort == 0 {
385 - httpPort = DefaultHTTPPort
386 - }
387 - httpRedirLnAddr := caddy.JoinNetworkAddress(netw, host, strconv.Itoa(httpPort))
388 - lnAddrMap[httpRedirLnAddr] = struct{}{}
389 -
374 if parts := strings.SplitN(port, "-", 2); len(parts) == 2 {
375 port = parts[0]
376 }
377 redirTo := "https://{http.request.host}"
378
395 - httpsPort := app.HTTPSPort
396 - if httpsPort == 0 {
397 - httpsPort = DefaultHTTPSPort
398 - }
399 - if port != strconv.Itoa(httpsPort) {
379 + if port != strconv.Itoa(app.httpsPort()) {
380 redirTo += ":" + port
381 }
382 redirTo += "{http.request.uri}"
383
404 - redirRoutes = append(redirRoutes, Route{
384 + // build the plaintext HTTP variant of this address
385 + httpRedirLnAddr := caddy.JoinNetworkAddress(netw, host, strconv.Itoa(app.httpPort()))
386 +
387 + // create the route that does the redirect and associate
388 + // it with the listener address it will be served from
389 + lnAddrRedirRoutes[httpRedirLnAddr] = Route{
390 MatcherSets: []MatcherSet{
391 {
392 MatchProtocol("http"),
@@ -418,52 +403,70 @@ func (app *App) automaticHTTPS() error {
403 Close: true,
404 },
405 },
421 - })
406 + }
407 +
408 }
409 }
410 }
411
426 - if len(lnAddrMap) > 0 {
427 - var lnAddrs []string
428 - mapLoop:
429 - for addr := range lnAddrMap {
430 - netw, addrs, err := caddy.ParseNetworkAddress(addr)
431 - if err != nil {
432 - continue
433 - }
434 - for _, a := range addrs {
435 - if app.listenerTaken(netw, a) {
436 - continue mapLoop
412 + // if there are HTTP->HTTPS redirects to add, do so now
413 + if len(lnAddrRedirRoutes) > 0 {
414 + var redirServerAddrs []string
415 + var redirRoutes []Route
416 +
417 + // for each redirect listener, see if there's already a
418 + // server configured to listen on that exact address; if
419 + // so, simply the redirect route to the end of its route
420 + // list; otherwise, we'll create a new server for all the
421 + // listener addresses that are unused and serve the
422 + // remaining redirects from it
423 + redirRoutesLoop:
424 + for addr, redirRoute := range lnAddrRedirRoutes {
425 + for srvName, srv := range app.Servers {
426 + if srv.hasListenerAddress(addr) {
427 + // user has configured a server for the same address
428 + // that the redirect runs from; simply append our
429 + // redirect route to the existing routes, with a
430 + // caveat that their config might override ours
431 + log.Printf("[WARNING] Server %s is listening on %s, so automatic HTTP->HTTPS redirects might be overridden by your own configuration",
432 + srvName, addr)
433 + srv.Routes = append(srv.Routes, redirRoute)
434 + continue redirRoutesLoop
435 }
436 }
439 - lnAddrs = append(lnAddrs, addr)
437 + // no server with this listener address exists;
438 + // save this address and route for custom server
439 + redirServerAddrs = append(redirServerAddrs, addr)
440 + redirRoutes = append(redirRoutes, redirRoute)
441 }
441 - app.Servers["auto_https_redirects"] = &Server{
442 - Listen: lnAddrs,
443 - Routes: redirRoutes,
444 - AutoHTTPS: &AutoHTTPSConfig{Disabled: true},
445 - tlsApp: tlsApp, // required to solve HTTP challenge
442 +
443 + // if there are routes remaining which do not belong
444 + // in any existing server, make our own to serve the
445 + // rest of the redirects
446 + if len(redirServerAddrs) > 0 {
447 + app.Servers["remaining_auto_https_redirects"] = &Server{
448 + Listen: redirServerAddrs,
449 + Routes: redirRoutes,
450 + tlsApp: tlsApp, // required to solve HTTP challenge
451 + }
452 }
453 }
454
455 return nil
456 }
457
452 -func (app *App) listenerTaken(network, address string) bool {
453 - for _, srv := range app.Servers {
454 - for _, addr := range srv.Listen {
455 - netw, addrs, err := caddy.ParseNetworkAddress(addr)
456 - if err != nil || netw != network {
457 - continue
458 - }
459 - for _, a := range addrs {
460 - if a == address {
461 - return true
462 - }
463 - }
464 - }
458 +func (app *App) httpPort() int {
459 + if app.HTTPPort == 0 {
460 + return DefaultHTTPPort
461 }
466 - return false
462 + return app.HTTPPort
463 +}
464 +
465 +func (app *App) httpsPort() int {
466 + if app.HTTPSPort == 0 {
467 + return DefaultHTTPSPort
468 + }
469 + return app.HTTPSPort
470 }
471
472 var defaultALPN = []string{"h2", "http/1.1"}
modules/caddyhttp/server.go
+19 -10
@@ -196,17 +196,26 @@ func (s *Server) listenersUseAnyPortOtherThan(otherPort int) bool {
196 return false
197 }
198
199 -// listenersIncludePort returns true if there are any
200 -// listeners in s that use otherPort.
201 -func (s *Server) listenersIncludePort(otherPort int) bool {
199 +func (s *Server) hasListenerAddress(fullAddr string) bool {
200 + netw, addrs, err := caddy.ParseNetworkAddress(fullAddr)
201 + if err != nil {
202 + return false
203 + }
204 + if len(addrs) != 1 {
205 + return false
206 + }
207 + addr := addrs[0]
208 for _, lnAddr := range s.Listen {
203 - _, addrs, err := caddy.ParseNetworkAddress(lnAddr)
204 - if err == nil {
205 - for _, a := range addrs {
206 - _, port, err := net.SplitHostPort(a)
207 - if err == nil && port == strconv.Itoa(otherPort) {
208 - return true
209 - }
209 + thisNetw, thisAddrs, err := caddy.ParseNetworkAddress(lnAddr)
210 + if err != nil {
211 + continue
212 + }
213 + if thisNetw != netw {
214 + continue
215 + }
216 + for _, a := range thisAddrs {
217 + if a == addr {
218 + return true
219 }
220 }
221 }