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
}