caddyfile: Do not replace import tokens if they are part of a snippet (#5539)

* fix variadic placeholder in imported file which also imports

* fix tests.

* skip replacing args when imported token may be part of a snippet
This commit is contained in:
WeidiDeng 2023-05-23 05:36:55 +08:00 committed by GitHub
parent 5bd9c49042
commit cee4441cb1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 99 additions and 5 deletions

View file

@ -214,7 +214,7 @@ func (p *parser) addresses() error {
// special case: import directive replaces tokens during parse-time // special case: import directive replaces tokens during parse-time
if tkn == "import" && p.isNewLine() { if tkn == "import" && p.isNewLine() {
err := p.doImport() err := p.doImport(0)
if err != nil { if err != nil {
return err return err
} }
@ -314,7 +314,7 @@ func (p *parser) directives() error {
// special case: import directive replaces tokens during parse-time // special case: import directive replaces tokens during parse-time
if p.Val() == "import" { if p.Val() == "import" {
err := p.doImport() err := p.doImport(1)
if err != nil { if err != nil {
return err return err
} }
@ -340,7 +340,7 @@ func (p *parser) directives() error {
// is on the token before where the import directive was. In // is on the token before where the import directive was. In
// other words, call Next() to access the first token that was // other words, call Next() to access the first token that was
// imported. // imported.
func (p *parser) doImport() error { func (p *parser) doImport(nesting int) error {
// syntax checks // syntax checks
if !p.NextArg() { if !p.NextArg() {
return p.ArgErr() return p.ArgErr()
@ -443,10 +443,16 @@ func (p *parser) doImport() error {
// copy the tokens so we don't overwrite p.definedSnippets // copy the tokens so we don't overwrite p.definedSnippets
tokensCopy := make([]Token, 0, len(importedTokens)) tokensCopy := make([]Token, 0, len(importedTokens))
var (
maybeSnippet bool
maybeSnippetId bool
index int
)
// run the argument replacer on the tokens // run the argument replacer on the tokens
// golang for range slice return a copy of value // golang for range slice return a copy of value
// similarly, append also copy value // similarly, append also copy value
for _, token := range importedTokens { for i, token := range importedTokens {
// set the token's file to refer to import directive line number and snippet name // set the token's file to refer to import directive line number and snippet name
if token.snippetName != "" { if token.snippetName != "" {
token.updateFile(fmt.Sprintf("%s:%d (import %s)", token.File, p.Line(), token.snippetName)) token.updateFile(fmt.Sprintf("%s:%d (import %s)", token.File, p.Line(), token.snippetName))
@ -454,6 +460,40 @@ func (p *parser) doImport() error {
token.updateFile(fmt.Sprintf("%s:%d (import)", token.File, p.Line())) token.updateFile(fmt.Sprintf("%s:%d (import)", token.File, p.Line()))
} }
// naive way of determine snippets, as snippets definition can only follow name + block
// format, won't check for nesting correctness or any other error, that's what parser does.
if !maybeSnippet && nesting == 0 {
// first of the line
if i == 0 || importedTokens[i-1].originalFile() != token.originalFile() || importedTokens[i-1].Line+importedTokens[i-1].NumLineBreaks() < token.Line {
index = 0
} else {
index++
}
if index == 0 && len(token.Text) >= 3 && strings.HasPrefix(token.Text, "(") && strings.HasSuffix(token.Text, ")") {
maybeSnippetId = true
}
}
switch token.Text {
case "{":
nesting++
if index == 1 && maybeSnippetId && nesting == 1 {
maybeSnippet = true
maybeSnippetId = false
}
case "}":
nesting--
if nesting == 0 && maybeSnippet {
maybeSnippet = false
}
}
if maybeSnippet {
tokensCopy = append(tokensCopy, token)
continue
}
foundVariadic, startIndex, endIndex := parseVariadic(token, len(args)) foundVariadic, startIndex, endIndex := parseVariadic(token, len(args))
if foundVariadic { if foundVariadic {
for _, arg := range args[startIndex:endIndex] { for _, arg := range args[startIndex:endIndex] {
@ -553,7 +593,7 @@ func (p *parser) directive() error {
} else if p.Val() == "}" && p.nesting == 0 { } else if p.Val() == "}" && p.nesting == 0 {
return p.Err("Unexpected '}' because no matching opening brace") return p.Err("Unexpected '}' because no matching opening brace")
} else if p.Val() == "import" && p.isNewLine() { } else if p.Val() == "import" && p.isNewLine() {
if err := p.doImport(); err != nil { if err := p.doImport(1); err != nil {
return err return err
} }
p.cursor-- // cursor is advanced when we continue, so roll back one more p.cursor-- // cursor is advanced when we continue, so roll back one more

View file

@ -243,6 +243,27 @@ func TestImportErrorLine(t *testing.T) {
return err != nil && strings.Contains(err.Error(), "Caddyfile:5 (import t1):2") return err != nil && strings.Contains(err.Error(), "Caddyfile:5 (import t1):2")
}, },
}, },
{
input: `
import testdata/import_variadic_snippet.txt
:8080 {
import t1 true
}`,
errorFunc: func(err error) bool {
return err == nil
},
},
{
input: `
import testdata/import_variadic_with_import.txt
:8080 {
import t1 true
import t2 true
}`,
errorFunc: func(err error) bool {
return err == nil
},
},
} { } {
adapter := caddyfile.Adapter{ adapter := caddyfile.Adapter{
ServerType: ServerType{}, ServerType: ServerType{},

View file

@ -0,0 +1,9 @@
(t2) {
respond 200 {
body {args[:]}
}
}
:8082 {
import t2 false
}

View file

@ -0,0 +1,9 @@
(t1) {
respond 200 {
body {args[:]}
}
}
:8081 {
import t1 false
}

View file

@ -0,0 +1,15 @@
(t1) {
respond 200 {
body {args[:]}
}
}
:8081 {
import t1 false
}
import import_variadic.txt
:8083 {
import t2 true
}