@marcel91200 / caddy Mirror · read-only / commits / 134b8056
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 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{}},