Commit 2960ec22 authored by Kirill Smelkov's avatar Kirill Smelkov

X AuthCache is now per upstream. Tests pass

parent 4b3b9a15
......@@ -53,17 +53,20 @@ type AuthCacheEntry struct {
//
// XXX should be not only project (private_token etc...)
type AuthCache struct {
u *upstream // for which upstream we cache auth
mu sync.RWMutex // guards .cached
cached map[string]*AuthCacheEntry
}
var authCache = AuthCache{cached: make(map[string]*AuthCacheEntry)}
func NewAuthCache(u *upstream) *AuthCache {
return &AuthCache{u: u, cached: make(map[string]*AuthCacheEntry)}
}
// Verify that download access is ok or not.
// first we try to use the cache; if information is not there -> ask auth backend
// download is ok if AuthReply.RepoPath != ""
// XXX u should not be in args?
func (c *AuthCache) VerifyDownloadAccess(u *upstream, project string) AuthReply {
func (c *AuthCache) VerifyDownloadAccess(project string) AuthReply {
var authReply AuthReply
// first try to read from cache in parallel with other readers
......@@ -104,7 +107,7 @@ have_entry:
c.mu.Unlock()
// this goroutine becomes responsible for quering auth backend
auth.AuthReply = askAuthBackend(u, project)
auth.AuthReply = askAuthBackend(c.u, project)
auth.Tauth = time.Now().Unix()
auth.Nhit = 0
......@@ -114,7 +117,7 @@ have_entry:
close(auth.ready)
// launch entry refresher
go c.refreshEntry(auth, u, project)
go c.refreshEntry(auth, project)
}
return authReply
......@@ -125,7 +128,7 @@ const authCacheRefresh = 30 * time.Second
// Goroutine to refresh auth cache entry periodically while it is used.
// if the entry is detected to be not used - remove it from cache and stop refreshing.
func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project string) {
func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, project string) {
for {
time.Sleep(authCacheRefresh)
......@@ -146,7 +149,7 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri
}
//log.Printf("AUTH - refreshing %v", project)
authReply := askAuthBackend(u, project)
authReply := askAuthBackend(c.u, project)
auth.Lock()
auth.AuthReply = authReply
......@@ -193,7 +196,7 @@ func askAuthBackend(u *upstream, project string) AuthReply {
}
func verifyDownloadAccess(u *upstream, project string) AuthReply {
return authCache.VerifyDownloadAccess(u, project)
return u.authCache.VerifyDownloadAccess(project)
}
// HTTP handler for `.../raw/<ref>/path`
......@@ -220,9 +223,8 @@ func handleGetBlobRaw(w http.ResponseWriter, r *gitRequest) {
w.Header()[k] = v
}
w.WriteHeader(authReply.RawReply.Code)
// NOTE do not consume authReply.RawReply.Body with io.Copy -
// this way it will be read one time only and next reads will
// be empty.
// NOTE do not consume authReply.RawReply.Body with io.Copy() -
// this way it will be read one time only and next reads will be empty.
_, err := w.Write(authReply.RawReply.Body.Bytes())
if err != nil {
logContext("writing authReply.RawReply.Body", err)
......
......@@ -20,6 +20,7 @@ type serviceHandleFunc func(w http.ResponseWriter, r *gitRequest)
type upstream struct {
httpClient *http.Client
authBackend string
authCache *AuthCache
}
type gitService struct {
......@@ -89,8 +90,10 @@ var gitServices = [...]gitService{
}
func newUpstream(authBackend string, authTransport http.RoundTripper) *upstream {
return &upstream{&http.Client{Transport: authTransport}, authBackend}
u := &upstream{&http.Client{Transport: authTransport}, authBackend, nil}
u.authCache = NewAuthCache(u)
// XXX Timeout: ... ?
return u
}
func (u *upstream) ServeHTTP(w http.ResponseWriter, r *http.Request) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment