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) {