summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddyhttp/server.go')
-rw-r--r--modules/caddyhttp/server.go78
1 files changed, 23 insertions, 55 deletions
diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go
index c333991..ce61b13 100644
--- a/modules/caddyhttp/server.go
+++ b/modules/caddyhttp/server.go
@@ -61,10 +61,12 @@ type Server struct {
MaxHeaderBytes int `json:"max_header_bytes,omitempty"`
// Routes describes how this server will handle requests.
- // When a request comes in, each route's matchers will
- // be evaluated against the request, and matching routes
- // will be compiled into a middleware chain in the order
- // in which they appear in the list.
+ // Routes are executed sequentially. First a route's matchers
+ // are evaluated, then its grouping. If it matches and has
+ // not been mutually-excluded by its grouping, then its
+ // handlers are executed sequentially. The sequence of invoked
+ // handlers comprises a compiled middleware chain that flows
+ // from each matching route and its handlers to the next.
Routes RouteList `json:"routes,omitempty"`
// Errors is how this server will handle errors returned from any
@@ -86,11 +88,6 @@ type Server struct {
// only on the HTTPS port.
AutoHTTPS *AutoHTTPSConfig `json:"automatic_https,omitempty"`
- // MaxRehandles is the maximum number of times to allow a
- // request to be rehandled, to prevent accidental infinite
- // loops. Default: 1.
- MaxRehandles *int `json:"max_rehandles,omitempty"`
-
// If true, will require that a request's Host header match
// the value of the ServerName sent by the client's TLS
// ClientHello; often a necessary safeguard when using TLS
@@ -105,6 +102,9 @@ type Server struct {
// This field is not subject to compatibility promises.
ExperimentalHTTP3 bool `json:"experimental_http3,omitempty"`
+ primaryHandlerChain Handler
+ errorHandlerChain Handler
+
tlsApp *caddytls.TLS
logger *zap.Logger
accessLogger *zap.Logger
@@ -129,6 +129,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, repl)
ctx = context.WithValue(ctx, ServerCtxKey, s)
ctx = context.WithValue(ctx, VarsCtxKey, make(map[string]interface{}))
+ ctx = context.WithValue(ctx, routeGroupCtxKey, make(map[string]struct{}))
var url2 url.URL // avoid letting this escape to the heap
ctx = context.WithValue(ctx, OriginalRequestCtxKey, originalRequest(r, &url2))
r = r.WithContext(ctx)
@@ -137,22 +138,22 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// anymore, finish setting up the replacer
addHTTPVarsToReplacer(repl, r, w)
- loggableReq := LoggableHTTPRequest{r}
+ // encode the request for logging purposes before
+ // it enters any handler chain; this is necessary
+ // to capture the original request in case it gets
+ // modified during handling
+ loggableReq := zap.Object("request", LoggableHTTPRequest{r})
errLog := s.errorLogger.With(
- // encode the request for logging purposes before
- // it enters any handler chain; this is necessary
- // to capture the original request in case it gets
- // modified during handling
- zap.Object("request", loggableReq),
+ loggableReq,
)
if s.accessLogger != nil {
wrec := NewResponseRecorder(w, nil, nil)
w = wrec
- accLog := s.accessLogger.With(
- // capture the original version of the request
- zap.Object("request", loggableReq),
- )
+
+ // capture the original version of the request
+ accLog := s.accessLogger.With(loggableReq)
+
start := time.Now()
defer func() {
latency := time.Since(start)
@@ -187,8 +188,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
- // build and execute the primary handler chain
- err := s.executeCompositeRoute(w, r, s.Routes)
+ // execute the primary handler chain
+ err := s.primaryHandlerChain.ServeHTTP(w, r)
if err != nil {
// prepare the error log
logger := errLog
@@ -204,7 +205,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if s.Errors != nil && len(s.Errors.Routes) > 0 {
// execute user-defined error handling route
- err2 := s.executeCompositeRoute(w, r, s.Errors.Routes)
+ err2 := s.errorHandlerChain.ServeHTTP(w, r)
if err2 == nil {
// user's error route handled the error response
// successfully, so now just log the error
@@ -229,39 +230,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
-// executeCompositeRoute compiles a composite route from routeList and executes
-// it using w and r. This function handles the sentinel ErrRehandle error value,
-// which reprocesses requests through the stack again. Any error value returned
-// from this function would be an actual error that needs to be handled.
-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
- for i := -1; i <= maxRehandles; i++ {
- // we started the counter at -1 because we
- // 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)
- if err != ErrRehandle {
- break
- }
- if i >= maxRehandles-1 {
- return fmt.Errorf("too many rehandles")
- }
- }
- return err
-}
-
// wrapPrimaryRoute wraps stack (a compiled middleware handler chain)
// in s.enforcementHandler which performs crucial security checks, etc.
func (s *Server) wrapPrimaryRoute(stack Handler) Handler {