Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 20:30 UTC
caddyfile: Prevent bad block opening tokens (#4655)
* caddyfile: Prevent bad block opening tokens * Clarifying comments
Francis Lavoie committed
Mar 23, 2022 at 14:34 UTC
134b8056444d8f417c0eb4163809f9659ffc3317
3 files changed
+77
-2
caddyconfig/caddyfile/dispenser.go
+56
-2
@@ -458,6 +458,60 @@ func (d *Dispenser) isNewLine() bool {
458
if d.cursor > len(d.tokens)-1 {
459
return false
460
}
461
- return d.tokens[d.cursor-1].File != d.tokens[d.cursor].File ||
462
- d.tokens[d.cursor-1].Line+d.numLineBreaks(d.cursor-1) < d.tokens[d.cursor].Line
461
+
462
+ prev := d.tokens[d.cursor-1]
463
+ curr := d.tokens[d.cursor]
464
+
465
+ // If the previous token is from a different file,
466
+ // we can assume it's from a different line
467
+ if prev.File != curr.File {
468
+ return true
469
+ }
470
+
471
+ // The previous token may contain line breaks if
472
+ // it was quoted and spanned multiple lines. e.g:
473
+ //
474
+ // dir "foo
475
+ // bar
476
+ // baz"
477
+ prevLineBreaks := d.numLineBreaks(d.cursor - 1)
478
+
479
+ // If the previous token (incl line breaks) ends
480
+ // on a line earlier than the current token,
481
+ // then the current token is on a new line
482
+ return prev.Line+prevLineBreaks < curr.Line
483
+}
484
+
485
+// isNextOnNewLine determines whether the current token is on a different
486
+// line (higher line number) than the next token. It handles imported
487
+// tokens correctly. If there isn't a next token, it returns true.
488
+func (d *Dispenser) isNextOnNewLine() bool {
489
+ if d.cursor < 0 {
490
+ return false
491
+ }
492
+ if d.cursor >= len(d.tokens)-1 {
493
+ return true
494
+ }
495
+
496
+ curr := d.tokens[d.cursor]
497
+ next := d.tokens[d.cursor+1]
498
+
499
+ // If the next token is from a different file,
500
+ // we can assume it's from a different line
501
+ if curr.File != next.File {
502
+ return true
503
+ }
504
+
505
+ // The current token may contain line breaks if
506
+ // it was quoted and spanned multiple lines. e.g:
507
+ //
508
+ // dir "foo
509
+ // bar
510
+ // baz"
511
+ currLineBreaks := d.numLineBreaks(d.cursor)
512
+
513
+ // If the current token (incl line breaks) ends
514
+ // on a line earlier than the next token,
515
+ // then the next token is on a new line
516
+ return curr.Line+currLineBreaks < next.Line
517
}
caddyconfig/caddyfile/parse.go
+7
@@ -494,6 +494,13 @@ func (p *parser) directive() error {
494
for p.Next() {
495
if p.Val() == "{" {
496
p.nesting++
497
+ if !p.isNextOnNewLine() && p.Token().wasQuoted == 0 {
498
+ return p.Err("Unexpected next token after '{' on same line")
499
+ }
500
+ } else if p.Val() == "{}" {
501
+ if p.isNextOnNewLine() && p.Token().wasQuoted == 0 {
502
+ return p.Err("Unexpected '{}' at end of line")
503
+ }
504
} else if p.isNewLine() && p.nesting == 0 {
505
p.cursor-- // read too far
506
break
caddyconfig/caddyfile/parse_test.go
+14
@@ -191,6 +191,20 @@ func TestParseOneAndImport(t *testing.T) {
191
192
{``, false, []string{}, []int{}},
193
194
+ // Unexpected next token after '{' on same line
195
+ {`localhost
196
+ dir1 { a b }`, true, []string{"localhost"}, []int{}},
197
+ // Workaround with quotes
198
+ {`localhost
199
+ dir1 "{" a b "}"`, false, []string{"localhost"}, []int{5}},
200
+
201
+ // Unexpected '{}' at end of line
202
+ {`localhost
203
+ dir1 {}`, true, []string{"localhost"}, []int{}},
204
+ // Workaround with quotes
205
+ {`localhost
206
+ dir1 "{}"`, false, []string{"localhost"}, []int{2}},
207
+
208
// import with args
209
{`import testdata/import_args0.txt a`, false, []string{"a"}, []int{}},
210
{`import testdata/import_args1.txt a b`, false, []string{"a", "b"}, []int{}},