Skip to content

Commit

Permalink
optimize placeholder scan in case of many unclosed braces
Browse files Browse the repository at this point in the history
  • Loading branch information
JensErat committed Jan 4, 2023
1 parent 06a9e09 commit 6a0a9bf
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 4 deletions.
23 changes: 19 additions & 4 deletions replacer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package caddy

import (
"fmt"
"math"
"os"
"path/filepath"
"regexp"
Expand Down Expand Up @@ -140,9 +141,14 @@ func (r *Replacer) replace(input, empty string, treatUnknownAsEmpty, errOnEmpty,

// iterate the input to find each placeholder
var lastWriteCursor int
skipOpeningBraces := 0
for placeholderStart := 0; placeholderStart < len(input); placeholderStart++ {
switch input[placeholderStart] {
case phOpen:
if skipOpeningBraces > 0 {
skipOpeningBraces--
continue
}
// process possible placeholder in remaining loop (do not drop into default)
case phEscape:
// escape character at the end of the input or next character not a brace or escape character
Expand All @@ -164,16 +170,21 @@ func (r *Replacer) replace(input, empty string, treatUnknownAsEmpty, errOnEmpty,

// our iterator is now on an unescaped open brace (start of placeholder), find matching closing brace
var placeholderEnd int
bracesLevel := 0
skipOpeningBraces = math.MaxInt
unclosedBraces := 0
placeHolderEndFound := false
placeholderEndScanner:
for placeholderEnd = placeholderStart + 1; placeholderEnd < len(input); placeholderEnd++ {
switch input[placeholderEnd] {
case phOpen:
bracesLevel++
unclosedBraces++
case phClose:
if bracesLevel > 0 {
bracesLevel--
// remember the minimum level of unclosed braces, we can skip that many opening braces later
if unclosedBraces < skipOpeningBraces {
skipOpeningBraces = unclosedBraces - 1
}
if unclosedBraces > 0 {
unclosedBraces--
continue
}
placeHolderEndFound = true
Expand All @@ -186,6 +197,10 @@ func (r *Replacer) replace(input, empty string, treatUnknownAsEmpty, errOnEmpty,
}
// no matching closing brace found, this is not a complete placeholder, continue search
if !placeHolderEndFound {
// remember the minimum level of unclosed braces, we can skip that many opening braces later
if unclosedBraces < skipOpeningBraces {
skipOpeningBraces = unclosedBraces - 1
}
continue
}

Expand Down
4 changes: 4 additions & 0 deletions replacer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ func BenchmarkReplacer(b *testing.B) {
name: "escaped placeholder",
input: `\{"json": \{"nested": "{bar}"\}\}`,
},
{
name: "many unclosed braces",
input: `{{{{{{{{{{{{{{{{{{{{{{{{{`,
},
} {
b.Run(bm.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
Expand Down

0 comments on commit 6a0a9bf

Please sign in to comment.