diff options
author | Francis Lavoie <[email protected]> | 2022-03-23 14:34:13 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2022-03-23 12:34:13 -0600 |
commit | 134b8056444d8f417c0eb4163809f9659ffc3317 (patch) | |
tree | 62bc3fc0af4af24926730f63af56740943e3f36f /caddyconfig/caddyfile | |
parent | c9b5e7f77b8aac7334d81c552c583af81ba1c400 (diff) | |
download | caddy-134b8056444d8f417c0eb4163809f9659ffc3317.tar.gz caddy-134b8056444d8f417c0eb4163809f9659ffc3317.zip |
caddyfile: Prevent bad block opening tokens (#4655)
* caddyfile: Prevent bad block opening tokens
* Clarifying comments
Diffstat (limited to 'caddyconfig/caddyfile')
-rwxr-xr-x | caddyconfig/caddyfile/dispenser.go | 58 | ||||
-rwxr-xr-x | caddyconfig/caddyfile/parse.go | 7 | ||||
-rwxr-xr-x | caddyconfig/caddyfile/parse_test.go | 14 |
3 files changed, 77 insertions, 2 deletions
diff --git a/caddyconfig/caddyfile/dispenser.go b/caddyconfig/caddyfile/dispenser.go index fbe71ad02..8a78f4337 100755 --- a/caddyconfig/caddyfile/dispenser.go +++ b/caddyconfig/caddyfile/dispenser.go @@ -458,6 +458,60 @@ func (d *Dispenser) isNewLine() bool { if d.cursor > len(d.tokens)-1 { return false } - return d.tokens[d.cursor-1].File != d.tokens[d.cursor].File || - d.tokens[d.cursor-1].Line+d.numLineBreaks(d.cursor-1) < d.tokens[d.cursor].Line + + prev := d.tokens[d.cursor-1] + curr := d.tokens[d.cursor] + + // If the previous token is from a different file, + // we can assume it's from a different line + if prev.File != curr.File { + return true + } + + // The previous token may contain line breaks if + // it was quoted and spanned multiple lines. e.g: + // + // dir "foo + // bar + // baz" + prevLineBreaks := d.numLineBreaks(d.cursor - 1) + + // If the previous token (incl line breaks) ends + // on a line earlier than the current token, + // then the current token is on a new line + return prev.Line+prevLineBreaks < curr.Line +} + +// isNextOnNewLine determines whether the current token is on a different +// line (higher line number) than the next token. It handles imported +// tokens correctly. If there isn't a next token, it returns true. +func (d *Dispenser) isNextOnNewLine() bool { + if d.cursor < 0 { + return false + } + if d.cursor >= len(d.tokens)-1 { + return true + } + + curr := d.tokens[d.cursor] + next := d.tokens[d.cursor+1] + + // If the next token is from a different file, + // we can assume it's from a different line + if curr.File != next.File { + return true + } + + // The current token may contain line breaks if + // it was quoted and spanned multiple lines. e.g: + // + // dir "foo + // bar + // baz" + currLineBreaks := d.numLineBreaks(d.cursor) + + // If the current token (incl line breaks) ends + // on a line earlier than the next token, + // then the next token is on a new line + return curr.Line+currLineBreaks < next.Line } diff --git a/caddyconfig/caddyfile/parse.go b/caddyconfig/caddyfile/parse.go index 1e694f9f5..b46323848 100755 --- a/caddyconfig/caddyfile/parse.go +++ b/caddyconfig/caddyfile/parse.go @@ -494,6 +494,13 @@ func (p *parser) directive() error { for p.Next() { if p.Val() == "{" { p.nesting++ + if !p.isNextOnNewLine() && p.Token().wasQuoted == 0 { + return p.Err("Unexpected next token after '{' on same line") + } + } else if p.Val() == "{}" { + if p.isNextOnNewLine() && p.Token().wasQuoted == 0 { + return p.Err("Unexpected '{}' at end of line") + } } else if p.isNewLine() && p.nesting == 0 { p.cursor-- // read too far break diff --git a/caddyconfig/caddyfile/parse_test.go b/caddyconfig/caddyfile/parse_test.go index 8d43e1aa5..c3f6fa644 100755 --- a/caddyconfig/caddyfile/parse_test.go +++ b/caddyconfig/caddyfile/parse_test.go @@ -191,6 +191,20 @@ func TestParseOneAndImport(t *testing.T) { {``, false, []string{}, []int{}}, + // Unexpected next token after '{' on same line + {`localhost + dir1 { a b }`, true, []string{"localhost"}, []int{}}, + // Workaround with quotes + {`localhost + dir1 "{" a b "}"`, false, []string{"localhost"}, []int{5}}, + + // Unexpected '{}' at end of line + {`localhost + dir1 {}`, true, []string{"localhost"}, []int{}}, + // Workaround with quotes + {`localhost + dir1 "{}"`, false, []string{"localhost"}, []int{2}}, + // import with args {`import testdata/import_args0.txt a`, false, []string{"a"}, []int{}}, {`import testdata/import_args1.txt a b`, false, []string{"a", "b"}, []int{}}, |