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

Fix rehandling bug

Matthew Holt committed Jul 11, 2019 at 22:02 UTC 9722dbe18a568b8229e07bafb6189a08fa3859e2
2 files changed +33 -15
modules/caddyhttp/caddyhttp.go
+10 -2
@@ -85,6 +85,10 @@ func (app *App) Provision(ctx caddy.Context) error {
85 return fmt.Errorf("setting up server error handling routes: %v", err)
86 }
87 }
88 +
89 + if srv.MaxRehandles == nil {
90 + srv.MaxRehandles = &DefaultMaxRehandles
91 + }
92 }
93
94 return nil
@@ -111,8 +115,8 @@ func (app *App) Validate() error {
115
116 // each server's max rehandle value must be valid
117 for srvName, srv := range app.Servers {
114 - if srv.MaxRehandles < 0 {
115 - return fmt.Errorf("%s: invalid max_rehandles value: %d", srvName, srv.MaxRehandles)
118 + if srv.MaxRehandles != nil && *srv.MaxRehandles < 0 {
119 + return fmt.Errorf("%s: invalid max_rehandles value: %d", srvName, *srv.MaxRehandles)
120 }
121 }
122
@@ -435,6 +439,10 @@ const (
439 DefaultHTTPSPort = 443
440 )
441
442 +// DefaultMaxRehandles is the maximum number of rehandles to
443 +// allow, if not specified explicitly.
444 +var DefaultMaxRehandles = 3
445 +
446 // Interface guards
447 var (
448 _ caddy.App = (*App)(nil)
modules/caddyhttp/server.go
+23 -13
@@ -39,7 +39,7 @@ type Server struct {
39 Errors *HTTPErrorConfig `json:"errors,omitempty"`
40 TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"`
41 AutoHTTPS *AutoHTTPSConfig `json:"automatic_https,omitempty"`
42 - MaxRehandles int `json:"max_rehandles,omitempty"`
42 + MaxRehandles *int `json:"max_rehandles,omitempty"`
43 StrictSNIHost bool `json:"strict_sni_host,omitempty"` // TODO: see if we can turn this on by default when clientauth is configured
44
45 tlsApp *caddytls.TLS
@@ -65,9 +65,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
65 addHTTPVarsToReplacer(repl, r, w)
66
67 // build and execute the main handler chain
68 - stack := s.Routes.BuildCompositeRoute(r)
69 - stack = s.wrapPrimaryRoute(stack)
70 - err := s.executeCompositeRoute(w, r, stack)
68 + err := s.executeCompositeRoute(w, r, s.Routes)
69 if err != nil {
70 // add the raw error value to the request context
71 // so it can be accessed by error handlers
@@ -85,8 +83,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
83 }
84
85 if s.Errors != nil && len(s.Errors.Routes) > 0 {
88 - errStack := s.Errors.Routes.BuildCompositeRoute(r)
89 - err := s.executeCompositeRoute(w, r, errStack)
86 + err := s.executeCompositeRoute(w, r, s.Errors.Routes)
87 if err != nil {
88 // TODO: what should we do if the error handler has an error?
89 log.Printf("[ERROR] [%s %s] handling error: %v", r.Method, r.RequestURI, err)
@@ -103,20 +100,33 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
100 }
101 }
102
106 -// executeCompositeRoute executes stack with w and r. This function handles
107 -// the special ErrRehandle error value, which reprocesses requests through
108 -// the stack again. Any error value returned from this function would be an
109 -// actual error that needs to be handled.
110 -func (s *Server) executeCompositeRoute(w http.ResponseWriter, r *http.Request, stack Handler) error {
103 +// executeCompositeRoute compiles a composite route from routeList and executes
104 +// it using w and r. This function handles the sentinel ErrRehandle error value,
105 +// which reprocesses requests through the stack again. Any error value returned
106 +// from this function would be an actual error that needs to be handled.
107 +func (s *Server) executeCompositeRoute(w http.ResponseWriter, r *http.Request, routeList RouteList) error {
108 + maxRehandles := 0
109 + if s.MaxRehandles != nil {
110 + maxRehandles = *s.MaxRehandles
111 + }
112 var err error
112 - for i := -1; i <= s.MaxRehandles; i++ {
113 + for i := -1; i <= maxRehandles; i++ {
114 // we started the counter at -1 because we
115 // always want to run this at least once
116 +
117 + // the purpose of rehandling is often to give
118 + // matchers a chance to re-evaluate on the
119 + // changed version of the request, so compile
120 + // the handler stack anew in each iteration
121 + stack := routeList.BuildCompositeRoute(r)
122 + stack = s.wrapPrimaryRoute(stack)
123 +
124 + // only loop if rehandling is required
125 err = stack.ServeHTTP(w, r)
126 if err != ErrRehandle {
127 break
128 }
119 - if i >= s.MaxRehandles-1 {
129 + if i >= maxRehandles-1 {
130 return fmt.Errorf("too many rehandles")
131 }
132 }