summaryrefslogtreecommitdiff
path: root/caddyconfig
diff options
context:
space:
mode:
authorFrancis Lavoie <lavofr@gmail.com>2022-03-23 14:34:13 -0400
committerGitHub <noreply@github.com>2022-03-23 12:34:13 -0600
commit134b8056444d8f417c0eb4163809f9659ffc3317 (patch)
tree62bc3fc0af4af24926730f63af56740943e3f36f /caddyconfig
parentc9b5e7f77b8aac7334d81c552c583af81ba1c400 (diff)
caddyfile: Prevent bad block opening tokens (#4655)
* caddyfile: Prevent bad block opening tokens * Clarifying comments
Diffstat (limited to 'caddyconfig')
-rwxr-xr-xcaddyconfig/caddyfile/dispenser.go58
-rwxr-xr-xcaddyconfig/caddyfile/parse.go7
-rwxr-xr-xcaddyconfig/caddyfile/parse_test.go14
3 files changed, 77 insertions, 2 deletions
diff --git a/caddyconfig/caddyfile/dispenser.go b/caddyconfig/caddyfile/dispenser.go
index fbe71ad..8a78f43 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 1e694f9..b463238 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 8d43e1a..c3f6fa6 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{}},