mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 14:13:48 +03:00
httpcaddyfile: Replace 'handler_order' option with 'order'
This allows individual directives to be ordered relative to others, where order matters (for example HTTP handlers). Will primarily be useful when developing new directives, so you don't have to modify the Caddy source code. Can also be useful if you prefer that redir comes before rewrite, for example. Note that these are global options. The route directive can be used to give a specific order to a specific group of HTTP handler directives.
This commit is contained in:
parent
2466ed1484
commit
21643a007a
3 changed files with 85 additions and 39 deletions
|
@ -25,9 +25,9 @@ import (
|
|||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
// defaultDirectiveOrder specifies the order
|
||||
// directiveOrder specifies the order
|
||||
// to apply directives in HTTP routes.
|
||||
var defaultDirectiveOrder = []string{
|
||||
var directiveOrder = []string{
|
||||
"rewrite",
|
||||
"strip_prefix",
|
||||
"strip_suffix",
|
||||
|
@ -168,6 +168,8 @@ func (h Helper) NewRoute(matcherSet caddy.ModuleMap,
|
|||
}
|
||||
}
|
||||
|
||||
// GroupRoutes adds the routes (caddyhttp.Route type) in vals to the
|
||||
// same group, if there is more than one route in vals.
|
||||
func (h Helper) GroupRoutes(vals []ConfigValue) {
|
||||
// ensure there's at least two routes; group of one is pointless
|
||||
var count int
|
||||
|
@ -185,7 +187,7 @@ func (h Helper) GroupRoutes(vals []ConfigValue) {
|
|||
|
||||
// now that we know the group will have some effect, do it
|
||||
groupNum := *h.groupCounter
|
||||
for i := 0; i < len(vals); i++ {
|
||||
for i := range vals {
|
||||
if route, ok := vals[i].Value.(caddyhttp.Route); ok {
|
||||
route.Group = fmt.Sprintf("group%d", groupNum)
|
||||
vals[i].Value = route
|
||||
|
@ -226,7 +228,12 @@ type ConfigValue struct {
|
|||
directive string
|
||||
}
|
||||
|
||||
func sortRoutes(handlers []ConfigValue, dirPositions map[string]int) {
|
||||
func sortRoutes(handlers []ConfigValue) {
|
||||
dirPositions := make(map[string]int)
|
||||
for i, dir := range directiveOrder {
|
||||
dirPositions[dir] = i
|
||||
}
|
||||
|
||||
// while we are sorting, we will need to decode a route's path matcher
|
||||
// in order to sub-sort by path length; we can amortize this operation
|
||||
// for efficiency by storing the decoded matchers in a slice
|
||||
|
|
|
@ -65,8 +65,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
|
|||
val, err = parseOptHTTPPort(disp)
|
||||
case "https_port":
|
||||
val, err = parseOptHTTPSPort(disp)
|
||||
case "handler_order":
|
||||
val, err = parseOptHandlerOrder(disp)
|
||||
case "order":
|
||||
val, err = parseOptOrder(disp)
|
||||
case "experimental_http3":
|
||||
val, err = parseOptExperimentalHTTP3(disp)
|
||||
case "storage":
|
||||
|
@ -397,23 +397,9 @@ func (st *ServerType) serversFromPairings(
|
|||
siteSubroute.Routes = append(siteSubroute.Routes, cfgVal.Value.(caddyhttp.Route))
|
||||
}
|
||||
|
||||
// set up each handler directive - the order of the handlers
|
||||
// as they are added to the routes depends on user preference
|
||||
// set up each handler directive, making sure to honor directive order
|
||||
dirRoutes := sblock.pile["route"]
|
||||
handlerOrder, ok := options["handler_order"].([]string)
|
||||
if !ok {
|
||||
handlerOrder = defaultDirectiveOrder
|
||||
}
|
||||
if len(handlerOrder) == 1 && handlerOrder[0] == "appearance" {
|
||||
handlerOrder = nil
|
||||
}
|
||||
if handlerOrder != nil {
|
||||
dirPositions := make(map[string]int)
|
||||
for i, dir := range handlerOrder {
|
||||
dirPositions[dir] = i
|
||||
}
|
||||
sortRoutes(dirRoutes, dirPositions)
|
||||
}
|
||||
sortRoutes(dirRoutes)
|
||||
|
||||
// add all the routes piled in from directives
|
||||
for _, r := range dirRoutes {
|
||||
|
|
|
@ -58,27 +58,80 @@ func parseOptExperimentalHTTP3(d *caddyfile.Dispenser) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func parseOptHandlerOrder(d *caddyfile.Dispenser) ([]string, error) {
|
||||
if !d.Next() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
order := d.RemainingArgs()
|
||||
if len(order) == 1 && order[0] == "appearance" {
|
||||
return []string{"appearance"}, nil
|
||||
}
|
||||
if len(order) > 0 && d.NextBlock(0) {
|
||||
return nil, d.Err("cannot open block if there are arguments")
|
||||
}
|
||||
for d.NextBlock(0) {
|
||||
order = append(order, d.Val())
|
||||
func parseOptOrder(d *caddyfile.Dispenser) ([]string, error) {
|
||||
newOrder := directiveOrder
|
||||
|
||||
for d.Next() {
|
||||
// get directive name
|
||||
if !d.Next() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
dirName := d.Val()
|
||||
if _, ok := registeredDirectives[dirName]; !ok {
|
||||
return nil, fmt.Errorf("%s is not a registered directive", dirName)
|
||||
}
|
||||
|
||||
// get positional token
|
||||
if !d.Next() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
pos := d.Val()
|
||||
|
||||
// if directive exists, first remove it
|
||||
for i, d := range newOrder {
|
||||
if d == dirName {
|
||||
newOrder = append(newOrder[:i], newOrder[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// act on the positional
|
||||
switch pos {
|
||||
case "first":
|
||||
newOrder = append([]string{dirName}, newOrder...)
|
||||
if d.NextArg() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
directiveOrder = newOrder
|
||||
return newOrder, nil
|
||||
case "last":
|
||||
newOrder = append(newOrder, dirName)
|
||||
if d.NextArg() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
directiveOrder = newOrder
|
||||
return newOrder, nil
|
||||
case "before":
|
||||
case "after":
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown positional '%s'", pos)
|
||||
}
|
||||
|
||||
// get name of other directive
|
||||
if !d.NextArg() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
otherDir := d.Val()
|
||||
if d.NextArg() {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
|
||||
// insert directive into proper position
|
||||
for i, d := range newOrder {
|
||||
if d == otherDir {
|
||||
if pos == "before" {
|
||||
newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...)
|
||||
} else if pos == "after" {
|
||||
newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(order) == 0 {
|
||||
return nil, d.ArgErr()
|
||||
}
|
||||
return order, nil
|
||||
|
||||
directiveOrder = newOrder
|
||||
|
||||
return newOrder, nil
|
||||
}
|
||||
|
||||
func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
|
||||
|
|
Loading…
Reference in a new issue