projects
/
arvados.git
/ blobdiff
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Avoid http client race in test case.
[arvados.git]
/
services
/
ws
/
permission.go
diff --git
a/services/ws/permission.go
b/services/ws/permission.go
index 1dc06b852260e1e6b54b20870491ad363f57699f..a39a959312aed582957d8845dddfc70394b649a4 100644
(file)
--- a/
services/ws/permission.go
+++ b/
services/ws/permission.go
@@
-1,3
+1,7
@@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
package main
import (
package main
import (
@@
-18,7
+22,7
@@
type permChecker interface {
Check(uuid string) (bool, error)
}
Check(uuid string) (bool, error)
}
-func
N
ewPermChecker(ac arvados.Client) permChecker {
+func
n
ewPermChecker(ac arvados.Client) permChecker {
ac.AuthToken = ""
return &cachingPermChecker{
Client: &ac,
ac.AuthToken = ""
return &cachingPermChecker{
Client: &ac,
@@
-36,42
+40,67
@@
type cachingPermChecker struct {
*arvados.Client
cache map[string]cacheEnt
maxCurrent int
*arvados.Client
cache map[string]cacheEnt
maxCurrent int
+
+ nChecks uint64
+ nMisses uint64
+ nInvalid uint64
}
func (pc *cachingPermChecker) SetToken(token string) {
}
func (pc *cachingPermChecker) SetToken(token string) {
+ if pc.Client.AuthToken == token {
+ return
+ }
pc.Client.AuthToken = token
pc.Client.AuthToken = token
+ pc.cache = make(map[string]cacheEnt)
}
func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
}
func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
+ pc.nChecks++
+ logger := logger(nil).
+ WithField("token", pc.Client.AuthToken).
+ WithField("uuid", uuid)
pc.tidy()
now := time.Now()
if perm, ok := pc.cache[uuid]; ok && now.Sub(perm.Time) < maxPermCacheAge {
pc.tidy()
now := time.Now()
if perm, ok := pc.cache[uuid]; ok && now.Sub(perm.Time) < maxPermCacheAge {
-
debugLogf("perm (cached): %+q %+q ...%v", pc.Client.AuthToken, uuid, perm.allowed
)
+
logger.WithField("allowed", perm.allowed).Debug("cache hit"
)
return perm.allowed, nil
}
var buf map[string]interface{}
path, err := pc.PathForUUID("get", uuid)
if err != nil {
return perm.allowed, nil
}
var buf map[string]interface{}
path, err := pc.PathForUUID("get", uuid)
if err != nil {
+ pc.nInvalid++
return false, err
}
return false, err
}
+
+ pc.nMisses++
err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
- "select": {`["uuid"]`},
+ "include_trash": {"true"},
+ "select": {`["uuid"]`},
})
var allowed bool
if err == nil {
allowed = true
})
var allowed bool
if err == nil {
allowed = true
- } else if txErr, ok := err.(
arvados.TransactionError); ok && txErr.StatusCode == http.StatusNotFound
{
+ } else if txErr, ok := err.(
*arvados.TransactionError); ok && pc.isNotAllowed(txErr.StatusCode)
{
allowed = false
} else {
allowed = false
} else {
-
errorLogf("perm err: %+q %+q: %T %s", pc.Client.AuthToken, uuid, err, err
)
+
logger.WithError(err).Error("lookup error"
)
return false, err
}
return false, err
}
-
debugLogf("perm: %+q %+q ...%v", pc.Client.AuthToken, uuid, allowed
)
+
logger.WithField("allowed", allowed).Debug("cache miss"
)
pc.cache[uuid] = cacheEnt{Time: now, allowed: allowed}
return allowed, nil
}
pc.cache[uuid] = cacheEnt{Time: now, allowed: allowed}
return allowed, nil
}
+func (pc *cachingPermChecker) isNotAllowed(status int) bool {
+ switch status {
+ case http.StatusForbidden, http.StatusUnauthorized, http.StatusNotFound:
+ return true
+ default:
+ return false
+ }
+}
+
func (pc *cachingPermChecker) tidy() {
if len(pc.cache) <= pc.maxCurrent*2 {
return
func (pc *cachingPermChecker) tidy() {
if len(pc.cache) <= pc.maxCurrent*2 {
return