Skip to content

Commit

Permalink
caddyfile: Prevent bad block opening tokens (#4655)
Browse files Browse the repository at this point in the history
* caddyfile: Prevent bad block opening tokens

* Clarifying comments
  • Loading branch information
francislavoie authored Mar 23, 2022
1 parent c9b5e7f commit 134b805
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
58 changes: 56 additions & 2 deletions caddyconfig/caddyfile/dispenser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
7 changes: 7 additions & 0 deletions caddyconfig/caddyfile/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions caddyconfig/caddyfile/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}},
Expand Down

0 comments on commit 134b805

Please sign in to comment.