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
caddyfile: Add args on imports (#3423)
* caddyfile: Add support for args on imports * caddyfile: Add more import args tests
Francis Lavoie committed
Jun 1, 2020 at 12:43 UTC
fdf2a77feb53cb9dd6de772f811e96a5f6b2d2c4
7 files changed
+168
-8
caddyconfig/caddyfile/parse.go
+27
-6
@@ -20,7 +20,10 @@ import (
20
"log"
21
"os"
22
"path/filepath"
23
+ "strconv"
24
"strings"
25
+
26
+ "github.com/caddyserver/caddy/v2"
27
)
28
29
// Parse parses the input just enough to group tokens, in
@@ -292,11 +295,19 @@ func (p *parser) doImport() error {
295
if importPattern == "" {
296
return p.Err("Import requires a non-empty filepath")
297
}
295
- if p.NextArg() {
296
- return p.Err("Import takes only one argument (glob pattern or file)")
298
+
299
+ // grab remaining args as placeholder replacements
300
+ args := p.RemainingArgs()
301
+
302
+ // add args to the replacer
303
+ repl := caddy.NewReplacer()
304
+ for index, arg := range args {
305
+ repl.Set("args."+strconv.Itoa(index), arg)
306
}
298
- // splice out the import directive and its argument (2 tokens total)
299
- tokensBefore := p.tokens[:p.cursor-1]
307
+
308
+ // splice out the import directive and its arguments
309
+ // (2 tokens, plus the length of args)
310
+ tokensBefore := p.tokens[:p.cursor-1-len(args)]
311
tokensAfter := p.tokens[p.cursor+1:]
312
var importedTokens []Token
313
@@ -348,10 +359,20 @@ func (p *parser) doImport() error {
359
}
360
}
361
362
+ // copy the tokens so we don't overwrite p.definedSnippets
363
+ tokensCopy := make([]Token, len(importedTokens))
364
+ copy(tokensCopy, importedTokens)
365
+
366
+ // run the argument replacer on the tokens
367
+ for index, token := range tokensCopy {
368
+ token.Text = repl.ReplaceKnown(token.Text, "")
369
+ tokensCopy[index] = token
370
+ }
371
+
372
// splice the imported tokens in the place of the import statement
373
// and rewind cursor so Next() will land on first imported token
353
- p.tokens = append(tokensBefore, append(importedTokens, tokensAfter...)...)
354
- p.cursor--
374
+ p.tokens = append(tokensBefore, append(tokensCopy, tokensAfter...)...)
375
+ p.cursor -= len(args) + 1
376
377
return nil
378
}
caddyconfig/caddyfile/parse_test.go
+6
-2
@@ -182,14 +182,17 @@ func TestParseOneAndImport(t *testing.T) {
182
"host1",
183
}, []int{1, 2}},
184
185
- {`import testdata/import_test1.txt testdata/import_test2.txt`, true, []string{}, []int{}},
186
-
185
{`import testdata/not_found.txt`, true, []string{}, []int{}},
186
187
{`""`, false, []string{}, []int{}},
188
189
{``, false, []string{}, []int{}},
190
191
+ // import with args
192
+ {`import testdata/import_args0.txt a`, false, []string{"a"}, []int{}},
193
+ {`import testdata/import_args1.txt a b`, false, []string{"a", "b"}, []int{}},
194
+ {`import testdata/import_args*.txt a b`, false, []string{"a"}, []int{2}},
195
+
196
// test cases found by fuzzing!
197
{`import }{$"`, true, []string{}, []int{}},
198
{`import /*/*.txt`, true, []string{}, []int{}},
@@ -210,6 +213,7 @@ func TestParseOneAndImport(t *testing.T) {
213
t.Errorf("Test %d: Expected no error, but got: %v", i, err)
214
}
215
216
+ // t.Logf("%+v\n", result)
217
if len(result.Keys) != len(test.keys) {
218
t.Errorf("Test %d: Expected %d keys, got %d",
219
i, len(test.keys), len(result.Keys))
caddyconfig/caddyfile/testdata/import_args0.txt
new
+1
@@ -0,0 +1 @@
1
+{args.0}
\ No newline at end of file
caddyconfig/caddyfile/testdata/import_args1.txt
new
+1
@@ -0,0 +1 @@
1
+{args.0} {args.1}
\ No newline at end of file
caddytest/integration/caddyfile_adapt/import_args_file.txt
new
+49
@@ -0,0 +1,49 @@
1
+example.com
2
+
3
+import testdata/import_respond.txt Groot Rocket
4
+import testdata/import_respond.txt you "the confused man"
5
+----------
6
+{
7
+ "apps": {
8
+ "http": {
9
+ "servers": {
10
+ "srv0": {
11
+ "listen": [
12
+ ":443"
13
+ ],
14
+ "routes": [
15
+ {
16
+ "match": [
17
+ {
18
+ "host": [
19
+ "example.com"
20
+ ]
21
+ }
22
+ ],
23
+ "handle": [
24
+ {
25
+ "handler": "subroute",
26
+ "routes": [
27
+ {
28
+ "handle": [
29
+ {
30
+ "body": "'I am Groot', hears Rocket",
31
+ "handler": "static_response"
32
+ },
33
+ {
34
+ "body": "'I am you', hears the confused man",
35
+ "handler": "static_response"
36
+ }
37
+ ]
38
+ }
39
+ ]
40
+ }
41
+ ],
42
+ "terminal": true
43
+ }
44
+ ]
45
+ }
46
+ }
47
+ }
48
+ }
49
+}
\ No newline at end of file
caddytest/integration/caddyfile_adapt/import_args_snippet.txt
new
+83
@@ -0,0 +1,83 @@
1
+(logging) {
2
+ log {
3
+ output file /var/log/caddy/{args.0}.access.log
4
+ }
5
+}
6
+
7
+a.example.com {
8
+ import logging a.example.com
9
+}
10
+
11
+b.example.com {
12
+ import logging b.example.com
13
+}
14
+----------
15
+{
16
+ "logging": {
17
+ "logs": {
18
+ "default": {
19
+ "exclude": [
20
+ "http.log.access.log0",
21
+ "http.log.access.log1"
22
+ ]
23
+ },
24
+ "log0": {
25
+ "writer": {
26
+ "filename": "/var/log/caddy/a.example.com.access.log",
27
+ "output": "file"
28
+ },
29
+ "include": [
30
+ "http.log.access.log0"
31
+ ]
32
+ },
33
+ "log1": {
34
+ "writer": {
35
+ "filename": "/var/log/caddy/b.example.com.access.log",
36
+ "output": "file"
37
+ },
38
+ "include": [
39
+ "http.log.access.log1"
40
+ ]
41
+ }
42
+ }
43
+ },
44
+ "apps": {
45
+ "http": {
46
+ "servers": {
47
+ "srv0": {
48
+ "listen": [
49
+ ":443"
50
+ ],
51
+ "routes": [
52
+ {
53
+ "match": [
54
+ {
55
+ "host": [
56
+ "a.example.com"
57
+ ]
58
+ }
59
+ ],
60
+ "terminal": true
61
+ },
62
+ {
63
+ "match": [
64
+ {
65
+ "host": [
66
+ "b.example.com"
67
+ ]
68
+ }
69
+ ],
70
+ "terminal": true
71
+ }
72
+ ],
73
+ "logs": {
74
+ "logger_names": {
75
+ "a.example.com": "log0",
76
+ "b.example.com": "log1"
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+}
\ No newline at end of file
caddytest/integration/testdata/import_respond.txt
new
+1
@@ -0,0 +1 @@
1
+respond "'I am {args.0}', hears {args.1}"
\ No newline at end of file