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

httpcaddyfile: 'handle_errors' directive

Not sure I love the name of the directive; might change it later.

Matthew Holt committed Feb 16, 2020 at 22:24 UTC 23cc26d585bfbbe06ae8d2f46fa64956e368baac
3 files changed +85 -41
caddyconfig/httpcaddyfile/builtins.go
+15 -29
@@ -35,7 +35,8 @@ func init() {
35 RegisterHandlerDirective("redir", parseRedir)
36 RegisterHandlerDirective("respond", parseRespond)
37 RegisterHandlerDirective("route", parseRoute)
38 - RegisterHandlerDirective("handle", parseHandle)
38 + RegisterHandlerDirective("handle", parseSegmentAsSubroute)
39 + RegisterDirective("handle_errors", parseHandleErrors)
40 }
41
42 // parseBind parses the bind directive. Syntax:
@@ -235,7 +236,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
236 return nil, h.Errf("getting DNS provider module named '%s': %v", provName, err)
237 }
238 mgr.Challenges.DNSRaw = caddyconfig.JSONModuleObject(dnsProvModule.New(), "provider", provName, h.warnings)
238 -
239 +
240 case "ca_root":
241 arg := h.RemainingArgs()
242 if len(arg) != 1 {
@@ -387,36 +388,21 @@ func parseRoute(h Helper) (caddyhttp.MiddlewareHandler, error) {
388 return sr, nil
389 }
390
390 -// parseHandle parses the route directive.
391 func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
392 - var allResults []ConfigValue
393 -
394 - for h.Next() {
395 - for nesting := h.Nesting(); h.NextBlock(nesting); {
396 - dir := h.Val()
397 -
398 - dirFunc, ok := registeredDirectives[dir]
399 - if !ok {
400 - return nil, h.Errf("unrecognized directive: %s", dir)
401 - }
402 -
403 - subHelper := h
404 - subHelper.Dispenser = h.NewFromNextSegment()
405 -
406 - results, err := dirFunc(subHelper)
407 - if err != nil {
408 - return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err)
409 - }
410 - for _, result := range results {
411 - result.directive = dir
412 - allResults = append(allResults, result)
413 - }
414 - }
392 + return parseSegmentAsSubroute(h)
393 +}
394
416 - return buildSubroute(allResults, h.groupCounter)
395 +func parseHandleErrors(h Helper) ([]ConfigValue, error) {
396 + subroute, err := parseSegmentAsSubroute(h)
397 + if err != nil {
398 + return nil, err
399 }
418 -
419 - return nil, nil
400 + return []ConfigValue{
401 + {
402 + Class: "error_route",
403 + Value: subroute,
404 + },
405 + }, nil
406 }
407
408 var tagCounter = 0
caddyconfig/httpcaddyfile/directives.go
+33
@@ -37,6 +37,7 @@ var directiveOrder = []string{
37 "uri_replace",
38 "try_files",
39
40 + // middleware handlers that typically wrap responses
41 "basicauth",
42 "header",
43 "request_header",
@@ -46,6 +47,7 @@ var directiveOrder = []string{
47 "handle",
48 "route",
49
50 + // handlers that typically respond to requests
51 "respond",
52 "reverse_proxy",
53 "php_fastcgi",
@@ -291,6 +293,37 @@ func sortRoutes(routes []ConfigValue) {
293 })
294 }
295
296 +// parseSegmentAsSubroute parses the segment such that its subdirectives
297 +// are themselves treated as directives, from which a subroute is built
298 +// and returned.
299 +func parseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) {
300 + var allResults []ConfigValue
301 + for h.Next() {
302 + for nesting := h.Nesting(); h.NextBlock(nesting); {
303 + dir := h.Val()
304 +
305 + dirFunc, ok := registeredDirectives[dir]
306 + if !ok {
307 + return nil, h.Errf("unrecognized directive: %s", dir)
308 + }
309 +
310 + subHelper := h
311 + subHelper.Dispenser = h.NewFromNextSegment()
312 +
313 + results, err := dirFunc(subHelper)
314 + if err != nil {
315 + return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err)
316 + }
317 + for _, result := range results {
318 + result.directive = dir
319 + allResults = append(allResults, result)
320 + }
321 + }
322 + return buildSubroute(allResults, h.groupCounter) // TODO: should we move this outside the loop?
323 + }
324 + return nil, nil
325 +}
326 +
327 // serverBlock pairs a Caddyfile server block
328 // with a "pile" of config values, keyed by class
329 // name.
caddyconfig/httpcaddyfile/httptype.go
+37 -12
@@ -474,18 +474,18 @@ func (st *ServerType) serversFromPairings(
474 return nil, err
475 }
476
477 - if len(matcherSetsEnc) == 0 && len(p.serverBlocks) == 1 {
478 - // no need to wrap the handlers in a subroute if this is
479 - // the only server block and there is no matcher for it
480 - srv.Routes = append(srv.Routes, siteSubroute.Routes...)
481 - } else {
482 - srv.Routes = append(srv.Routes, caddyhttp.Route{
483 - MatcherSetsRaw: matcherSetsEnc,
484 - HandlersRaw: []json.RawMessage{
485 - caddyconfig.JSONModuleObject(siteSubroute, "handler", "subroute", warnings),
486 - },
487 - Terminal: true, // only first matching site block should be evaluated
488 - })
477 + // add the site block's route(s) to the server
478 + srv.Routes = appendSubrouteToRouteList(srv.Routes, siteSubroute, matcherSetsEnc, p, warnings)
479 +
480 + // if error routes are defined, add those too
481 + if errorSubrouteVals, ok := sblock.pile["error_route"]; ok {
482 + if srv.Errors == nil {
483 + srv.Errors = new(caddyhttp.HTTPErrorConfig)
484 + }
485 + for _, val := range errorSubrouteVals {
486 + sr := val.Value.(*caddyhttp.Subroute)
487 + srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, matcherSetsEnc, p, warnings)
488 + }
489 }
490 }
491
@@ -497,6 +497,31 @@ func (st *ServerType) serversFromPairings(
497 return servers, nil
498 }
499
500 +// appendSubrouteToRouteList appends the routes in subroute
501 +// to the routeList, optionally qualified by matchers.
502 +func appendSubrouteToRouteList(routeList caddyhttp.RouteList,
503 + subroute *caddyhttp.Subroute,
504 + matcherSetsEnc []caddy.ModuleMap,
505 + p sbAddrAssociation,
506 + warnings *[]caddyconfig.Warning) caddyhttp.RouteList {
507 + if len(matcherSetsEnc) == 0 && len(p.serverBlocks) == 1 {
508 + // no need to wrap the handlers in a subroute if this is
509 + // the only server block and there is no matcher for it
510 + routeList = append(routeList, subroute.Routes...)
511 + } else {
512 + routeList = append(routeList, caddyhttp.Route{
513 + MatcherSetsRaw: matcherSetsEnc,
514 + HandlersRaw: []json.RawMessage{
515 + caddyconfig.JSONModuleObject(subroute, "handler", "subroute", warnings),
516 + },
517 + Terminal: true, // only first matching site block should be evaluated
518 + })
519 + }
520 + return routeList
521 +}
522 +
523 +// buildSubroute turns the config values, which are expected to be routes
524 +// into a clean and orderly subroute that has all the routes within it.
525 func buildSubroute(routes []ConfigValue, groupCounter counter) (*caddyhttp.Subroute, error) {
526 for _, val := range routes {
527 if !directiveIsOrdered(val.directive) {