@marcel91200 / caddy Mirror · read-only / commits / 21643a00
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: 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.

Matthew Holt committed Jan 16, 2020 at 12:09 UTC 21643a007a2d2d90e1636ecd6b49f82560f4c939
3 files changed +85 -39
caddyconfig/httpcaddyfile/directives.go
+11 -4
@@ -25,9 +25,9 @@ import (
25 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
26 )
27
28 -// defaultDirectiveOrder specifies the order
28 +// directiveOrder specifies the order
29 // to apply directives in HTTP routes.
30 -var defaultDirectiveOrder = []string{
30 +var directiveOrder = []string{
31 "rewrite",
32 "strip_prefix",
33 "strip_suffix",
@@ -168,6 +168,8 @@ func (h Helper) NewRoute(matcherSet caddy.ModuleMap,
168 }
169 }
170
171 +// GroupRoutes adds the routes (caddyhttp.Route type) in vals to the
172 +// same group, if there is more than one route in vals.
173 func (h Helper) GroupRoutes(vals []ConfigValue) {
174 // ensure there's at least two routes; group of one is pointless
175 var count int
@@ -185,7 +187,7 @@ func (h Helper) GroupRoutes(vals []ConfigValue) {
187
188 // now that we know the group will have some effect, do it
189 groupNum := *h.groupCounter
188 - for i := 0; i < len(vals); i++ {
190 + for i := range vals {
191 if route, ok := vals[i].Value.(caddyhttp.Route); ok {
192 route.Group = fmt.Sprintf("group%d", groupNum)
193 vals[i].Value = route
@@ -226,7 +228,12 @@ type ConfigValue struct {
228 directive string
229 }
230
229 -func sortRoutes(handlers []ConfigValue, dirPositions map[string]int) {
231 +func sortRoutes(handlers []ConfigValue) {
232 + dirPositions := make(map[string]int)
233 + for i, dir := range directiveOrder {
234 + dirPositions[dir] = i
235 + }
236 +
237 // while we are sorting, we will need to decode a route's path matcher
238 // in order to sub-sort by path length; we can amortize this operation
239 // for efficiency by storing the decoded matchers in a slice
caddyconfig/httpcaddyfile/httptype.go
+4 -18
@@ -65,8 +65,8 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
65 val, err = parseOptHTTPPort(disp)
66 case "https_port":
67 val, err = parseOptHTTPSPort(disp)
68 - case "handler_order":
69 - val, err = parseOptHandlerOrder(disp)
68 + case "order":
69 + val, err = parseOptOrder(disp)
70 case "experimental_http3":
71 val, err = parseOptExperimentalHTTP3(disp)
72 case "storage":
@@ -397,23 +397,9 @@ func (st *ServerType) serversFromPairings(
397 siteSubroute.Routes = append(siteSubroute.Routes, cfgVal.Value.(caddyhttp.Route))
398 }
399
400 - // set up each handler directive - the order of the handlers
401 - // as they are added to the routes depends on user preference
400 + // set up each handler directive, making sure to honor directive order
401 dirRoutes := sblock.pile["route"]
403 - handlerOrder, ok := options["handler_order"].([]string)
404 - if !ok {
405 - handlerOrder = defaultDirectiveOrder
406 - }
407 - if len(handlerOrder) == 1 && handlerOrder[0] == "appearance" {
408 - handlerOrder = nil
409 - }
410 - if handlerOrder != nil {
411 - dirPositions := make(map[string]int)
412 - for i, dir := range handlerOrder {
413 - dirPositions[dir] = i
414 - }
415 - sortRoutes(dirRoutes, dirPositions)
416 - }
402 + sortRoutes(dirRoutes)
403
404 // add all the routes piled in from directives
405 for _, r := range dirRoutes {
caddyconfig/httpcaddyfile/options.go
+70 -17
@@ -58,27 +58,80 @@ func parseOptExperimentalHTTP3(d *caddyfile.Dispenser) (bool, error) {
58 return true, nil
59 }
60
61 -func parseOptHandlerOrder(d *caddyfile.Dispenser) ([]string, error) {
62 - if !d.Next() {
63 - return nil, d.ArgErr()
64 - }
65 - order := d.RemainingArgs()
66 - if len(order) == 1 && order[0] == "appearance" {
67 - return []string{"appearance"}, nil
68 - }
69 - if len(order) > 0 && d.NextBlock(0) {
70 - return nil, d.Err("cannot open block if there are arguments")
71 - }
72 - for d.NextBlock(0) {
73 - order = append(order, d.Val())
61 +func parseOptOrder(d *caddyfile.Dispenser) ([]string, error) {
62 + newOrder := directiveOrder
63 +
64 + for d.Next() {
65 + // get directive name
66 + if !d.Next() {
67 + return nil, d.ArgErr()
68 + }
69 + dirName := d.Val()
70 + if _, ok := registeredDirectives[dirName]; !ok {
71 + return nil, fmt.Errorf("%s is not a registered directive", dirName)
72 + }
73 +
74 + // get positional token
75 + if !d.Next() {
76 + return nil, d.ArgErr()
77 + }
78 + pos := d.Val()
79 +
80 + // if directive exists, first remove it
81 + for i, d := range newOrder {
82 + if d == dirName {
83 + newOrder = append(newOrder[:i], newOrder[i+1:]...)
84 + break
85 + }
86 + }
87 +
88 + // act on the positional
89 + switch pos {
90 + case "first":
91 + newOrder = append([]string{dirName}, newOrder...)
92 + if d.NextArg() {
93 + return nil, d.ArgErr()
94 + }
95 + directiveOrder = newOrder
96 + return newOrder, nil
97 + case "last":
98 + newOrder = append(newOrder, dirName)
99 + if d.NextArg() {
100 + return nil, d.ArgErr()
101 + }
102 + directiveOrder = newOrder
103 + return newOrder, nil
104 + case "before":
105 + case "after":
106 + default:
107 + return nil, fmt.Errorf("unknown positional '%s'", pos)
108 + }
109 +
110 + // get name of other directive
111 + if !d.NextArg() {
112 + return nil, d.ArgErr()
113 + }
114 + otherDir := d.Val()
115 if d.NextArg() {
116 return nil, d.ArgErr()
117 }
118 +
119 + // insert directive into proper position
120 + for i, d := range newOrder {
121 + if d == otherDir {
122 + if pos == "before" {
123 + newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...)
124 + } else if pos == "after" {
125 + newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...)
126 + }
127 + break
128 + }
129 + }
130 }
78 - if len(order) == 0 {
79 - return nil, d.ArgErr()
80 - }
81 - return order, nil
131 +
132 + directiveOrder = newOrder
133 +
134 + return newOrder, nil
135 }
136
137 func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {