mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-28 06:33:47 +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("redir", parseRedir)
|
||||||
RegisterHandlerDirective("respond", parseRespond)
|
RegisterHandlerDirective("respond", parseRespond)
|
||||||
RegisterHandlerDirective("route", parseRoute)
|
RegisterHandlerDirective("route", parseRoute)
|
||||||
RegisterHandlerDirective("handle", parseHandle)
|
RegisterHandlerDirective("handle", parseSegmentAsSubroute)
|
||||||
|
RegisterDirective("handle_errors", parseHandleErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseBind parses the bind directive. Syntax:
|
// parseBind parses the bind directive. Syntax:
|
||||||
|
@ -387,36 +388,21 @@ func parseRoute(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||||
return sr, nil
|
return sr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseHandle parses the route directive.
|
|
||||||
func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||||
var allResults []ConfigValue
|
return parseSegmentAsSubroute(h)
|
||||||
|
|
||||||
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
|
func parseHandleErrors(h Helper) ([]ConfigValue, error) {
|
||||||
subHelper.Dispenser = h.NewFromNextSegment()
|
subroute, err := parseSegmentAsSubroute(h)
|
||||||
|
|
||||||
results, err := dirFunc(subHelper)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, result := range results {
|
return []ConfigValue{
|
||||||
result.directive = dir
|
{
|
||||||
allResults = append(allResults, result)
|
Class: "error_route",
|
||||||
}
|
Value: subroute,
|
||||||
}
|
},
|
||||||
|
}, nil
|
||||||
return buildSubroute(allResults, h.groupCounter)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagCounter = 0
|
var tagCounter = 0
|
||||||
|
|
|
@ -37,6 +37,7 @@ var directiveOrder = []string{
|
||||||
"uri_replace",
|
"uri_replace",
|
||||||
"try_files",
|
"try_files",
|
||||||
|
|
||||||
|
// middleware handlers that typically wrap responses
|
||||||
"basicauth",
|
"basicauth",
|
||||||
"header",
|
"header",
|
||||||
"request_header",
|
"request_header",
|
||||||
|
@ -46,6 +47,7 @@ var directiveOrder = []string{
|
||||||
"handle",
|
"handle",
|
||||||
"route",
|
"route",
|
||||||
|
|
||||||
|
// handlers that typically respond to requests
|
||||||
"respond",
|
"respond",
|
||||||
"reverse_proxy",
|
"reverse_proxy",
|
||||||
"php_fastcgi",
|
"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
|
// serverBlock pairs a Caddyfile server block
|
||||||
// with a "pile" of config values, keyed by class
|
// with a "pile" of config values, keyed by class
|
||||||
// name.
|
// name.
|
||||||
|
|
|
@ -474,18 +474,18 @@ func (st *ServerType) serversFromPairings(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matcherSetsEnc) == 0 && len(p.serverBlocks) == 1 {
|
// add the site block's route(s) to the server
|
||||||
// no need to wrap the handlers in a subroute if this is
|
srv.Routes = appendSubrouteToRouteList(srv.Routes, siteSubroute, matcherSetsEnc, p, warnings)
|
||||||
// the only server block and there is no matcher for it
|
|
||||||
srv.Routes = append(srv.Routes, siteSubroute.Routes...)
|
// if error routes are defined, add those too
|
||||||
} else {
|
if errorSubrouteVals, ok := sblock.pile["error_route"]; ok {
|
||||||
srv.Routes = append(srv.Routes, caddyhttp.Route{
|
if srv.Errors == nil {
|
||||||
MatcherSetsRaw: matcherSetsEnc,
|
srv.Errors = new(caddyhttp.HTTPErrorConfig)
|
||||||
HandlersRaw: []json.RawMessage{
|
}
|
||||||
caddyconfig.JSONModuleObject(siteSubroute, "handler", "subroute", warnings),
|
for _, val := range errorSubrouteVals {
|
||||||
},
|
sr := val.Value.(*caddyhttp.Subroute)
|
||||||
Terminal: true, // only first matching site block should be evaluated
|
srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, matcherSetsEnc, p, warnings)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,6 +497,31 @@ func (st *ServerType) serversFromPairings(
|
||||||
return servers, nil
|
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) {
|
func buildSubroute(routes []ConfigValue, groupCounter counter) (*caddyhttp.Subroute, error) {
|
||||||
for _, val := range routes {
|
for _, val := range routes {
|
||||||
if !directiveIsOrdered(val.directive) {
|
if !directiveIsOrdered(val.directive) {
|
||||||
|
|
Loading…
Reference in a new issue