mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 14:13:48 +03:00
httpcaddyfile: 'handle_errors' directive
Not sure I love the name of the directive; might change it later.
This commit is contained in:
parent
bc2e406572
commit
23cc26d585
3 changed files with 85 additions and 41 deletions
|
@ -35,7 +35,8 @@ func init() {
|
|||
RegisterHandlerDirective("redir", parseRedir)
|
||||
RegisterHandlerDirective("respond", parseRespond)
|
||||
RegisterHandlerDirective("route", parseRoute)
|
||||
RegisterHandlerDirective("handle", parseHandle)
|
||||
RegisterHandlerDirective("handle", parseSegmentAsSubroute)
|
||||
RegisterDirective("handle_errors", parseHandleErrors)
|
||||
}
|
||||
|
||||
// parseBind parses the bind directive. Syntax:
|
||||
|
@ -387,36 +388,21 @@ func parseRoute(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
|||
return sr, nil
|
||||
}
|
||||
|
||||
// parseHandle parses the route directive.
|
||||
func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||
var allResults []ConfigValue
|
||||
|
||||
for h.Next() {
|
||||
for nesting := h.Nesting(); h.NextBlock(nesting); {
|
||||
dir := h.Val()
|
||||
|
||||
dirFunc, ok := registeredDirectives[dir]
|
||||
if !ok {
|
||||
return nil, h.Errf("unrecognized directive: %s", dir)
|
||||
return parseSegmentAsSubroute(h)
|
||||
}
|
||||
|
||||
subHelper := h
|
||||
subHelper.Dispenser = h.NewFromNextSegment()
|
||||
|
||||
results, err := dirFunc(subHelper)
|
||||
func parseHandleErrors(h Helper) ([]ConfigValue, error) {
|
||||
subroute, err := parseSegmentAsSubroute(h)
|
||||
if err != nil {
|
||||
return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err)
|
||||
return nil, err
|
||||
}
|
||||
for _, result := range results {
|
||||
result.directive = dir
|
||||
allResults = append(allResults, result)
|
||||
}
|
||||
}
|
||||
|
||||
return buildSubroute(allResults, h.groupCounter)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return []ConfigValue{
|
||||
{
|
||||
Class: "error_route",
|
||||
Value: subroute,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var tagCounter = 0
|
||||
|
|
|
@ -37,6 +37,7 @@ var directiveOrder = []string{
|
|||
"uri_replace",
|
||||
"try_files",
|
||||
|
||||
// middleware handlers that typically wrap responses
|
||||
"basicauth",
|
||||
"header",
|
||||
"request_header",
|
||||
|
@ -46,6 +47,7 @@ var directiveOrder = []string{
|
|||
"handle",
|
||||
"route",
|
||||
|
||||
// handlers that typically respond to requests
|
||||
"respond",
|
||||
"reverse_proxy",
|
||||
"php_fastcgi",
|
||||
|
@ -291,6 +293,37 @@ func sortRoutes(routes []ConfigValue) {
|
|||
})
|
||||
}
|
||||
|
||||
// parseSegmentAsSubroute parses the segment such that its subdirectives
|
||||
// are themselves treated as directives, from which a subroute is built
|
||||
// and returned.
|
||||
func parseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||
var allResults []ConfigValue
|
||||
for h.Next() {
|
||||
for nesting := h.Nesting(); h.NextBlock(nesting); {
|
||||
dir := h.Val()
|
||||
|
||||
dirFunc, ok := registeredDirectives[dir]
|
||||
if !ok {
|
||||
return nil, h.Errf("unrecognized directive: %s", dir)
|
||||
}
|
||||
|
||||
subHelper := h
|
||||
subHelper.Dispenser = h.NewFromNextSegment()
|
||||
|
||||
results, err := dirFunc(subHelper)
|
||||
if err != nil {
|
||||
return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err)
|
||||
}
|
||||
for _, result := range results {
|
||||
result.directive = dir
|
||||
allResults = append(allResults, result)
|
||||
}
|
||||
}
|
||||
return buildSubroute(allResults, h.groupCounter) // TODO: should we move this outside the loop?
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// serverBlock pairs a Caddyfile server block
|
||||
// with a "pile" of config values, keyed by class
|
||||
// name.
|
||||
|
|
|
@ -474,18 +474,18 @@ func (st *ServerType) serversFromPairings(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if len(matcherSetsEnc) == 0 && len(p.serverBlocks) == 1 {
|
||||
// no need to wrap the handlers in a subroute if this is
|
||||
// the only server block and there is no matcher for it
|
||||
srv.Routes = append(srv.Routes, siteSubroute.Routes...)
|
||||
} else {
|
||||
srv.Routes = append(srv.Routes, caddyhttp.Route{
|
||||
MatcherSetsRaw: matcherSetsEnc,
|
||||
HandlersRaw: []json.RawMessage{
|
||||
caddyconfig.JSONModuleObject(siteSubroute, "handler", "subroute", warnings),
|
||||
},
|
||||
Terminal: true, // only first matching site block should be evaluated
|
||||
})
|
||||
// add the site block's route(s) to the server
|
||||
srv.Routes = appendSubrouteToRouteList(srv.Routes, siteSubroute, matcherSetsEnc, p, warnings)
|
||||
|
||||
// if error routes are defined, add those too
|
||||
if errorSubrouteVals, ok := sblock.pile["error_route"]; ok {
|
||||
if srv.Errors == nil {
|
||||
srv.Errors = new(caddyhttp.HTTPErrorConfig)
|
||||
}
|
||||
for _, val := range errorSubrouteVals {
|
||||
sr := val.Value.(*caddyhttp.Subroute)
|
||||
srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, matcherSetsEnc, p, warnings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,6 +497,31 @@ func (st *ServerType) serversFromPairings(
|
|||
return servers, nil
|
||||
}
|
||||
|
||||
// appendSubrouteToRouteList appends the routes in subroute
|
||||
// to the routeList, optionally qualified by matchers.
|
||||
func appendSubrouteToRouteList(routeList caddyhttp.RouteList,
|
||||
subroute *caddyhttp.Subroute,
|
||||
matcherSetsEnc []caddy.ModuleMap,
|
||||
p sbAddrAssociation,
|
||||
warnings *[]caddyconfig.Warning) caddyhttp.RouteList {
|
||||
if len(matcherSetsEnc) == 0 && len(p.serverBlocks) == 1 {
|
||||
// no need to wrap the handlers in a subroute if this is
|
||||
// the only server block and there is no matcher for it
|
||||
routeList = append(routeList, subroute.Routes...)
|
||||
} else {
|
||||
routeList = append(routeList, caddyhttp.Route{
|
||||
MatcherSetsRaw: matcherSetsEnc,
|
||||
HandlersRaw: []json.RawMessage{
|
||||
caddyconfig.JSONModuleObject(subroute, "handler", "subroute", warnings),
|
||||
},
|
||||
Terminal: true, // only first matching site block should be evaluated
|
||||
})
|
||||
}
|
||||
return routeList
|
||||
}
|
||||
|
||||
// buildSubroute turns the config values, which are expected to be routes
|
||||
// into a clean and orderly subroute that has all the routes within it.
|
||||
func buildSubroute(routes []ConfigValue, groupCounter counter) (*caddyhttp.Subroute, error) {
|
||||
for _, val := range routes {
|
||||
if !directiveIsOrdered(val.directive) {
|
||||
|
|
Loading…
Reference in a new issue