mirror of
https://github.com/gohugoio/hugo.git
synced 2025-03-19 16:43:03 +00:00
tpl: Fix race condition in regexp cache
Protect regular expression cache with a mutex. Fixes #1973
This commit is contained in:
parent
f6c3ca8b2a
commit
aedb13b219
1 changed files with 41 additions and 10 deletions
|
@ -33,6 +33,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
@ -1244,7 +1245,42 @@ func replace(a, b, c interface{}) (string, error) {
|
||||||
return strings.Replace(aStr, bStr, cStr, -1), nil
|
return strings.Replace(aStr, bStr, cStr, -1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var regexpCache = make(map[string]*regexp.Regexp)
|
// regexpCache represents a cache of regexp objects protected by a mutex.
|
||||||
|
type regexpCache struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
re map[string]*regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a regexp object from the cache based upon the pattern.
|
||||||
|
// If the pattern is not found in the cache, create one
|
||||||
|
func (rc *regexpCache) Get(pattern string) (re *regexp.Regexp, err error) {
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
if re, ok = rc.get(pattern); !ok {
|
||||||
|
re, err = regexp.Compile(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rc.set(pattern, re)
|
||||||
|
}
|
||||||
|
|
||||||
|
return re, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
|
||||||
|
rc.mu.RLock()
|
||||||
|
re, ok = rc.re[key]
|
||||||
|
rc.mu.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *regexpCache) set(key string, re *regexp.Regexp) {
|
||||||
|
rc.mu.Lock()
|
||||||
|
rc.re[key] = re
|
||||||
|
rc.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
|
||||||
|
|
||||||
// replaceRE exposes a regular expression replacement function to the templates.
|
// replaceRE exposes a regular expression replacement function to the templates.
|
||||||
func replaceRE(pattern, repl, src interface{}) (_ string, err error) {
|
func replaceRE(pattern, repl, src interface{}) (_ string, err error) {
|
||||||
|
@ -1263,16 +1299,11 @@ func replaceRE(pattern, repl, src interface{}) (_ string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := regexpCache[patternStr]; !ok {
|
re, err := reCache.Get(patternStr)
|
||||||
re, err2 := regexp.Compile(patternStr)
|
if err != nil {
|
||||||
if err2 != nil {
|
return "", err
|
||||||
return "", err2
|
|
||||||
}
|
}
|
||||||
|
return re.ReplaceAllString(srcStr, replStr), nil
|
||||||
regexpCache[patternStr] = re
|
|
||||||
}
|
|
||||||
|
|
||||||
return regexpCache[patternStr].ReplaceAllString(srcStr, replStr), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dateFormat converts the textual representation of the datetime string into
|
// dateFormat converts the textual representation of the datetime string into
|
||||||
|
|
Loading…
Reference in a new issue