@@ -27,18 +27,25 @@ import (
27
27
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
28
28
)
29
29
30
- // directiveOrder specifies the order
31
- // to apply directives in HTTP routes.
30
+ // defaultDirectiveOrder specifies the default order
31
+ // to apply directives in HTTP routes. This must only
32
+ // consist of directives that are included in Caddy's
33
+ // standard distribution.
32
34
//
33
- // The root directive goes first in case rewrites or
34
- // redirects depend on existence of files, i.e. the
35
- // file matcher, which must know the root first.
35
+ // e.g. The 'root' directive goes near the start in
36
+ // case rewrites or redirects depend on existence of
37
+ // files, i.e. the file matcher, which must know the
38
+ // root first.
36
39
//
37
- // The header directive goes second so that headers
38
- // can be manipulated before doing redirects.
39
- var directiveOrder = []string {
40
+ // e.g. The 'header' directive goes before 'redir' so
41
+ // that headers can be manipulated before doing redirects.
42
+ //
43
+ // e.g. The 'respond' directive is near the end because it
44
+ // writes a response and terminates the middleware chain.
45
+ var defaultDirectiveOrder = []string {
40
46
"tracing" ,
41
47
48
+ // set variables that may be used by other directives
42
49
"map" ,
43
50
"vars" ,
44
51
"fs" ,
@@ -85,6 +92,11 @@ var directiveOrder = []string{
85
92
"acme_server" ,
86
93
}
87
94
95
+ // directiveOrder specifies the order to apply directives
96
+ // in HTTP routes, after being modified by either the
97
+ // plugins or by the user via the "order" global option.
98
+ var directiveOrder = defaultDirectiveOrder
99
+
88
100
// directiveIsOrdered returns true if dir is
89
101
// a known, ordered (sorted) directive.
90
102
func directiveIsOrdered (dir string ) bool {
@@ -131,6 +143,58 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
131
143
})
132
144
}
133
145
146
+ // RegisterDirectiveOrder registers the default order for a
147
+ // directive from a plugin.
148
+ //
149
+ // This is useful when a plugin has a well-understood place
150
+ // it should run in the middleware pipeline, and it allows
151
+ // users to avoid having to define the order themselves.
152
+ //
153
+ // The directive dir may be placed in the position relative
154
+ // to ('before' or 'after') a directive included in Caddy's
155
+ // standard distribution. It cannot be relative to another
156
+ // plugin's directive.
157
+ //
158
+ // EXPERIMENTAL: This API may change or be removed.
159
+ func RegisterDirectiveOrder (dir string , position Positional , standardDir string ) {
160
+ // check if directive was already ordered
161
+ if directiveIsOrdered (dir ) {
162
+ panic ("directive '" + dir + "' already ordered" )
163
+ }
164
+
165
+ if position != Before && position != After {
166
+ panic ("the 2nd argument must be either 'before' or 'after', got '" + position + "'" )
167
+ }
168
+
169
+ // check if directive exists in standard distribution, since
170
+ // we can't allow plugins to depend on one another; we can't
171
+ // guarantee the order that plugins are loaded in.
172
+ foundStandardDir := false
173
+ for _ , d := range defaultDirectiveOrder {
174
+ if d == standardDir {
175
+ foundStandardDir = true
176
+ }
177
+ }
178
+ if ! foundStandardDir {
179
+ panic ("the 3rd argument '" + standardDir + "' must be a directive that exists in the standard distribution of Caddy" )
180
+ }
181
+
182
+ // insert directive into proper position
183
+ newOrder := directiveOrder
184
+ for i , d := range newOrder {
185
+ if d != standardDir {
186
+ continue
187
+ }
188
+ if position == Before {
189
+ newOrder = append (newOrder [:i ], append ([]string {dir }, newOrder [i :]... )... )
190
+ } else if position == After {
191
+ newOrder = append (newOrder [:i + 1 ], append ([]string {dir }, newOrder [i + 1 :]... )... )
192
+ }
193
+ break
194
+ }
195
+ directiveOrder = newOrder
196
+ }
197
+
134
198
// RegisterGlobalOption registers a unique global option opt with
135
199
// an associated unmarshaling (setup) function. When the global
136
200
// option opt is encountered in a Caddyfile, setupFunc will be
@@ -555,6 +619,16 @@ func (sb serverBlock) isAllHTTP() bool {
555
619
return true
556
620
}
557
621
622
+ // Positional are the supported modes for ordering directives.
623
+ type Positional string
624
+
625
+ const (
626
+ Before Positional = "before"
627
+ After Positional = "after"
628
+ First Positional = "first"
629
+ Last Positional = "last"
630
+ )
631
+
558
632
type (
559
633
// UnmarshalFunc is a function which can unmarshal Caddyfile
560
634
// tokens into zero or more config values using a Helper type.
0 commit comments