MCPcopy
hub / github.com/caddyserver/caddy / wrapRoute

Function wrapRoute

modules/caddyhttp/routes.go:256–326  ·  view source on GitHub ↗

wrapRoute wraps route with a middleware and handler so that it can be chained in and defer evaluation of its matchers to request-time. Like wrapMiddleware, it is vital that this wrapping takes place in its own stack frame so as to not overwrite the reference to the intended route by looping and chan

(route Route)

Source from the content-addressed store, hash-verified

254// its own stack frame so as to not overwrite the reference to the
255// intended route by looping and changing the reference each time.
256func wrapRoute(route Route) Middleware {
257 return func(next Handler) Handler {
258 return HandlerFunc(func(rw http.ResponseWriter, req *http.Request) error {
259 // TODO: Update this comment, it seems we've moved the copy into the handler?
260 // copy the next handler (it's an interface, so it's just
261 // a very lightweight copy of a pointer); this is important
262 // because this is a closure to the func below, which
263 // re-assigns the value as it compiles the middleware stack;
264 // if we don't make this copy, we'd affect the underlying
265 // pointer for all future request (yikes); we could
266 // alternatively solve this by moving the func below out of
267 // this closure and into a standalone package-level func,
268 // but I just thought this made more sense
269 nextCopy := next
270
271 // route must match at least one of the matcher sets
272 matches, err := route.MatcherSets.AnyMatchWithError(req)
273 if err != nil {
274 // allow matchers the opportunity to short circuit
275 // the request and trigger the error handling chain
276 return err
277 }
278 if !matches {
279 // call the next handler, and skip this one,
280 // since the matcher didn't match
281 return nextCopy.ServeHTTP(rw, req)
282 }
283
284 // if route is part of a group, ensure only the
285 // first matching route in the group is applied
286 if route.Group != "" {
287 groups := req.Context().Value(routeGroupCtxKey).(map[string]struct{})
288
289 if _, ok := groups[route.Group]; ok {
290 // this group has already been
291 // satisfied by a matching route
292 return nextCopy.ServeHTTP(rw, req)
293 }
294
295 // this matching route satisfies the group
296 groups[route.Group] = struct{}{}
297 }
298
299 // make terminal routes terminate
300 if route.Terminal {
301 if _, ok := req.Context().Value(ErrorCtxKey).(error); ok {
302 nextCopy = errorEmptyHandler
303 } else {
304 nextCopy = emptyHandler
305 }
306 }
307
308 // compile this route's handler stack
309 for _, middleware := range slices.Backward(route.middleware) {
310 nextCopy = middleware(nextCopy)
311 }
312
313 // Apply metrics instrumentation once for the entire route,

Callers 2

CompileMethod · 0.85
CompileMethod · 0.85

Calls 5

HandlerFuncFuncType · 0.85
AnyMatchWithErrorMethod · 0.80
ServeHTTPMethod · 0.65
ValueMethod · 0.45

Tested by

no test coverage detected