summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorY.Horie <u5.horie@gmail.com>2023-02-07 03:29:03 +0900
committerGitHub <noreply@github.com>2023-02-06 18:29:03 +0000
commit8d3a1b8bcbc36930ca3ad0a6b38604ceaa697ecb (patch)
tree667145696d028e6893dc3d88a56a778a27e3366a /modules
parentac83b7e218e3c3eb4ef26922196759434b130786 (diff)
caddyauth: Use singleflight for basic auth (#5344)
* caddyauth: Add singleflight for basic auth * Fixes #5338 * it occurred the thunder herd problem like this https://medium.com/@mhrlife/avoid-duplicate-requests-while-filling-cache-98c687879f59 * Update modules/caddyhttp/caddyauth/basicauth.go Fix comment Co-authored-by: Francis Lavoie <lavofr@gmail.com> --------- Co-authored-by: Francis Lavoie <lavofr@gmail.com> Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
Diffstat (limited to 'modules')
-rw-r--r--modules/caddyhttp/caddyauth/basicauth.go13
1 files changed, 11 insertions, 2 deletions
diff --git a/modules/caddyhttp/caddyauth/basicauth.go b/modules/caddyhttp/caddyauth/basicauth.go
index eb6fd59..f515a72 100644
--- a/modules/caddyhttp/caddyauth/basicauth.go
+++ b/modules/caddyhttp/caddyauth/basicauth.go
@@ -26,6 +26,7 @@ import (
"time"
"github.com/caddyserver/caddy/v2"
+ "golang.org/x/sync/singleflight"
)
func init() {
@@ -142,6 +143,7 @@ func (hba *HTTPBasicAuth) Provision(ctx caddy.Context) error {
if hba.HashCache != nil {
hba.HashCache.cache = make(map[string]bool)
hba.HashCache.mu = new(sync.RWMutex)
+ hba.HashCache.g = new(singleflight.Group)
}
return nil
@@ -190,12 +192,18 @@ func (hba HTTPBasicAuth) correctPassword(account Account, plaintextPassword []by
if ok {
return same, nil
}
-
// slow track: do the expensive op, then add it to the cache
- same, err := compare()
+ // but perform it in a singleflight group so that multiple
+ // parallel requests using the same password don't cause a
+ // thundering herd problem by all performing the same hashing
+ // operation before the first one finishes and caches it.
+ v, err, _ := hba.HashCache.g.Do(cacheKey, func() (any, error) {
+ return compare()
+ })
if err != nil {
return false, err
}
+ same = v.(bool)
hba.HashCache.mu.Lock()
if len(hba.HashCache.cache) >= 1000 {
hba.HashCache.makeRoom() // keep cache size under control
@@ -223,6 +231,7 @@ func (hba HTTPBasicAuth) promptForCredentials(w http.ResponseWriter, err error)
// compute on every HTTP request.
type Cache struct {
mu *sync.RWMutex
+ g *singleflight.Group
// map of concatenated hashed password + plaintext password + salt, to result
cache map[string]bool