|  | @ -39,7 +39,7 @@ type Server struct { | 
			
		
	
		
		
			
				
					|  |  | 	Errors            *HTTPErrorConfig            `json:"errors,omitempty"` |  |  | 	Errors            *HTTPErrorConfig            `json:"errors,omitempty"` | 
			
		
	
		
		
			
				
					|  |  | 	TLSConnPolicies   caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"` |  |  | 	TLSConnPolicies   caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"` | 
			
		
	
		
		
			
				
					|  |  | 	AutoHTTPS         *AutoHTTPSConfig            `json:"automatic_https,omitempty"` |  |  | 	AutoHTTPS         *AutoHTTPSConfig            `json:"automatic_https,omitempty"` | 
			
		
	
		
		
			
				
					
					|  |  | 	MaxRehandles      int                         `json:"max_rehandles,omitempty"` |  |  | 	MaxRehandles      *int                        `json:"max_rehandles,omitempty"` | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  | 	StrictSNIHost     bool                        `json:"strict_sni_host,omitempty"` // TODO: see if we can turn this on by default when clientauth is configured
 |  |  | 	StrictSNIHost     bool                        `json:"strict_sni_host,omitempty"` // TODO: see if we can turn this on by default when clientauth is configured
 | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 	tlsApp *caddytls.TLS |  |  | 	tlsApp *caddytls.TLS | 
			
		
	
	
		
		
			
				
					|  | @ -65,9 +65,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
			
		
	
		
		
			
				
					|  |  | 	addHTTPVarsToReplacer(repl, r, w) |  |  | 	addHTTPVarsToReplacer(repl, r, w) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 	// build and execute the main handler chain
 |  |  | 	// build and execute the main handler chain
 | 
			
		
	
		
		
			
				
					
					|  |  | 	stack := s.Routes.BuildCompositeRoute(r) |  |  | 	err := s.executeCompositeRoute(w, r, s.Routes) | 
			
				
				
			
		
	
		
		
			
				
					|  |  | 	stack = s.wrapPrimaryRoute(stack) |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 	err := s.executeCompositeRoute(w, r, stack) |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					|  |  | 	if err != nil { |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					|  |  | 		// add the raw error value to the request context
 |  |  | 		// add the raw error value to the request context
 | 
			
		
	
		
		
			
				
					|  |  | 		// so it can be accessed by error handlers
 |  |  | 		// so it can be accessed by error handlers
 | 
			
		
	
	
		
		
			
				
					|  | @ -85,8 +83,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
			
		
	
		
		
			
				
					|  |  | 		} |  |  | 		} | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | 		if s.Errors != nil && len(s.Errors.Routes) > 0 { |  |  | 		if s.Errors != nil && len(s.Errors.Routes) > 0 { | 
			
		
	
		
		
			
				
					
					|  |  | 			errStack := s.Errors.Routes.BuildCompositeRoute(r) |  |  | 			err := s.executeCompositeRoute(w, r, s.Errors.Routes) | 
			
				
				
			
		
	
		
		
			
				
					|  |  | 			err := s.executeCompositeRoute(w, r, errStack) |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					|  |  | 			if err != nil { |  |  | 			if err != nil { | 
			
		
	
		
		
			
				
					|  |  | 				// TODO: what should we do if the error handler has an error?
 |  |  | 				// TODO: what should we do if the error handler has an error?
 | 
			
		
	
		
		
			
				
					|  |  | 				log.Printf("[ERROR] [%s %s] handling error: %v", r.Method, r.RequestURI, err) |  |  | 				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) { | 
			
		
	
		
		
			
				
					|  |  | 	} |  |  | 	} | 
			
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  | // executeCompositeRoute executes stack with w and r. This function handles
 |  |  | // executeCompositeRoute compiles a composite route from routeList and executes
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | // the special ErrRehandle error value, which reprocesses requests through
 |  |  | // it using w and r. This function handles the sentinel ErrRehandle error value,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | // the stack again. Any error value returned from this function would be an
 |  |  | // which reprocesses requests through the stack again. Any error value returned
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | // actual error that needs to be handled.
 |  |  | // from this function would be an actual error that needs to be handled.
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | func (s *Server) executeCompositeRoute(w http.ResponseWriter, r *http.Request, stack Handler) error { |  |  | func (s *Server) executeCompositeRoute(w http.ResponseWriter, r *http.Request, routeList RouteList) error { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  | 	maxRehandles := 0 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	if s.MaxRehandles != nil { | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		maxRehandles = *s.MaxRehandles | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					|  |  | 	var err error |  |  | 	var err error | 
			
		
	
		
		
			
				
					
					|  |  | 	for i := -1; i <= s.MaxRehandles; i++ { |  |  | 	for i := -1; i <= maxRehandles; i++ { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  | 		// we started the counter at -1 because we
 |  |  | 		// we started the counter at -1 because we
 | 
			
		
	
		
		
			
				
					|  |  | 		// always want to run this at least once
 |  |  | 		// always want to run this at least once
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// the purpose of rehandling is often to give
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// matchers a chance to re-evaluate on the
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// changed version of the request, so compile
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// the handler stack anew in each iteration
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		stack := routeList.BuildCompositeRoute(r) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		stack = s.wrapPrimaryRoute(stack) | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 		// only loop if rehandling is required
 | 
			
		
	
		
		
			
				
					|  |  | 		err = stack.ServeHTTP(w, r) |  |  | 		err = stack.ServeHTTP(w, r) | 
			
		
	
		
		
			
				
					|  |  | 		if err != ErrRehandle { |  |  | 		if err != ErrRehandle { | 
			
		
	
		
		
			
				
					|  |  | 			break |  |  | 			break | 
			
		
	
		
		
			
				
					|  |  | 		} |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  | 		if i >= s.MaxRehandles-1 { |  |  | 		if i >= maxRehandles-1 { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  | 			return fmt.Errorf("too many rehandles") |  |  | 			return fmt.Errorf("too many rehandles") | 
			
		
	
		
		
			
				
					|  |  | 		} |  |  | 		} | 
			
		
	
		
		
			
				
					|  |  | 	} |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  | 
 |