Skip to content

Commit 3d30d3c

Browse files
committed
fix: Fix concurrent map read/write for route pattern cache
Fix #23
1 parent 45e5f67 commit 3d30d3c

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

routes/auth/handler.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import (
1212
"github.com/sharat87/httpbun/util"
1313
)
1414

15-
var BasicAuthRoute = util.RoutePat("/basic-auth/(?P<user>[^/]+)/(?P<pass>[^/]+)/?")
15+
var BasicAuthRoute = "/basic-auth/(?P<user>[^/]+)/(?P<pass>[^/]+)/?"
1616

17-
var BearerAuthRoute = util.RoutePat(`/bearer(/(?P<tok>[^/]+))?/?`)
17+
var BearerAuthRoute = `/bearer(/(?P<tok>[^/]+))?/?`
1818

19-
var DigestAuthRoute = util.RoutePat(`/digest-auth(/((?P<qop>[^/]+)/)?(?P<user>[^/]+)/(?P<pass>[^/]+))?/?`)
19+
var DigestAuthRoute = `/digest-auth(/((?P<qop>[^/]+)/)?(?P<user>[^/]+)/(?P<pass>[^/]+))?/?`
2020

2121
var Routes = map[string]exchange.HandlerFn{
2222
BasicAuthRoute: handleAuthBasic,

util/routing.go

+20-10
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,14 @@ package util
33
import (
44
"net/url"
55
"regexp"
6+
"sync"
67
)
78

8-
var PatCache = map[string]regexp.Regexp{}
9-
10-
func RoutePat(pat string) string {
11-
return "(?s)^" + pat + "$"
12-
}
9+
var patCache = map[string]regexp.Regexp{}
10+
var cacheLock = sync.RWMutex{}
1311

1412
func MatchRoutePat(pat string, path string) (map[string]string, bool) {
15-
re, isCacheHit := PatCache[pat]
16-
if !isCacheHit {
17-
re = *regexp.MustCompile(pat)
18-
PatCache[pat] = re
19-
}
13+
re := getPattern("^" + pat + "$")
2014

2115
match := re.FindStringSubmatch(path)
2216
if match == nil {
@@ -38,3 +32,19 @@ func MatchRoutePat(pat string, path string) (map[string]string, bool) {
3832

3933
return result, true
4034
}
35+
36+
func getPattern(pat string) regexp.Regexp {
37+
// this implementation is fine since we don't ever delete items from cache.
38+
cacheLock.RLock()
39+
re, isCacheHit := patCache[pat]
40+
cacheLock.RUnlock()
41+
42+
if !isCacheHit {
43+
cacheLock.Lock()
44+
defer cacheLock.Unlock()
45+
re = *regexp.MustCompile(pat)
46+
patCache[pat] = re
47+
}
48+
49+
return re
50+
}

0 commit comments

Comments
 (0)