Commit b61e1bf5 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 1cc37d3f
...@@ -34,11 +34,11 @@ type AuthReply struct { ...@@ -34,11 +34,11 @@ type AuthReply struct {
// Entry in authorization reply cache // Entry in authorization reply cache
type AuthCacheEntry struct { type AuthCacheEntry struct {
// FIXME we need to lock the entry only to "correctly" update Nhit on // FIXME we need to lock the entry only to "correctly" update Nhit on
// read side but we can tolerate some looses in Nhit and update it // read side, but we can tolerate some looses in Nhit and update it
// without mutex or atomic. Only -race complains... // without mutex or atomic. Only -race complains...
// (we could use atomic.Value for atomic cache entry updates from // ( we could use atomic.Value for atomic whole cache entry updates from
// refresher withot need for locks on readers side, but the need to do // refresher withot need for locks on readers side, but the need to do
// .Nhit++ on readers side ruins that) // .Nhit++ on readers side ruins that )
sync.Mutex sync.Mutex
AuthReply AuthReply
...@@ -54,8 +54,8 @@ type AuthCacheEntry struct { ...@@ -54,8 +54,8 @@ type AuthCacheEntry struct {
// //
// XXX should be not only project (privateToken etc...) // XXX should be not only project (privateToken etc...)
type AuthCache struct { type AuthCache struct {
mu sync.RWMutex // guards .cached mu sync.RWMutex // guards .cached
cached map[string]*AuthCacheEntry cached map[string]*AuthCacheEntry
} }
var authCache = AuthCache{cached: make(map[string]*AuthCacheEntry)} var authCache = AuthCache{cached: make(map[string]*AuthCacheEntry)}
...@@ -98,7 +98,7 @@ have_entry: ...@@ -98,7 +98,7 @@ have_entry:
goto have_entry goto have_entry
} }
// new non-ready entry // new not-yet-ready entry
auth = &AuthCacheEntry{ready: make(chan struct{})} auth = &AuthCacheEntry{ready: make(chan struct{})}
c.cached[project] = auth c.cached[project] = auth
c.mu.Unlock() c.mu.Unlock()
...@@ -135,9 +135,9 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri ...@@ -135,9 +135,9 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri
auth.Unlock() auth.Unlock()
// clear cache entry if it is not used // clear cache entry if it is not used
log.Printf("AUTH refresh - %v #hit: %v", project, nhit) //log.Printf("AUTH refresh - %v #hit: %v", project, nhit)
if nhit == 0 { // not used - we can remove and stop refreshing if nhit == 0 { // not used - we can remove and stop refreshing
log.Printf("AUTH - removing %v", project) //log.Printf("AUTH - removing %v", project)
// NOTE it is ok even if someone gets this auth in this time window // NOTE it is ok even if someone gets this auth in this time window
// and use it for some time // and use it for some time
c.mu.Lock() c.mu.Lock()
...@@ -146,8 +146,7 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri ...@@ -146,8 +146,7 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri
break break
} }
log.Printf("AUTH - refreshing %v", project) //log.Printf("AUTH - refreshing %v", project)
// XXX what if it stucks?
authReply := askAuthBackend(u, project) authReply := askAuthBackend(u, project)
auth.Lock() auth.Lock()
...@@ -160,7 +159,7 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri ...@@ -160,7 +159,7 @@ func (c *AuthCache) refreshEntry(auth *AuthCacheEntry, u *upstream, project stri
// Ask auth backend about whether download is ok for a project. // Ask auth backend about whether download is ok for a project.
// Authorization is approved if AuthReply.RepoPath != "" on return // Authorization is approved if AuthReply.RepoPath != "" on return
// In case of errors, diagnostic is emitted to AuthReply.RawReply XXX not only diagnostic // Raw auth backend response is emitted to AuthReply.RawReply
func askAuthBackend(u *upstream, project string) AuthReply { func askAuthBackend(u *upstream, project string) AuthReply {
authReply := AuthReply{ authReply := AuthReply{
RawReply: httptest.NewRecorder(), RawReply: httptest.NewRecorder(),
...@@ -169,15 +168,14 @@ func askAuthBackend(u *upstream, project string) AuthReply { ...@@ -169,15 +168,14 @@ func askAuthBackend(u *upstream, project string) AuthReply {
// Request to auth backend to verify whether download is possible via // Request to auth backend to verify whether download is possible via
// asking as `git fetch` would do. // asking as `git fetch` would do.
// XXX privateToken not propagated, etc ... // XXX privateToken not propagated, etc ...
reqDownloadAccess, err := http.NewRequest("GET", reqDownloadAccess, err := http.NewRequest("GET", project+".git/info/refs?service=git-upload-pack", nil)
project+".git/info/refs?service=git-upload-pack", nil)
if err != nil { if err != nil {
fail500(authReply.RawReply, "GET git-upload-pack", err) fail500(authReply.RawReply, "GET git-upload-pack", err)
return authReply return authReply
} }
// prepare everything and go through preAuthorizeHandler() that will send // Prepare everything and go through preAuthorizeHandler() that will send
// request to auth backend and analyze/parse the reply into r.authorizationResponse // request to auth backend and analyze/parse the reply into r.authorizationResponse.
// it also logs/emits output in case of errors - we do not have to do it here // it also logs/emits output in case of errors - we do not have to do it here
r := &gitRequest{ r := &gitRequest{
Request: reqDownloadAccess, Request: reqDownloadAccess,
...@@ -235,7 +233,6 @@ func handleGetBlobRaw(w http.ResponseWriter, r *gitRequest) { ...@@ -235,7 +233,6 @@ func handleGetBlobRaw(w http.ResponseWriter, r *gitRequest) {
emitBlob(w, authReply.RepoPath, refpath) emitBlob(w, authReply.RepoPath, refpath)
} }
// Emit content of blob located at <ref>/path (jointly denoted as 'refpath') to output // Emit content of blob located at <ref>/path (jointly denoted as 'refpath') to output
func emitBlob(w http.ResponseWriter, repopath string, refpath string) { func emitBlob(w http.ResponseWriter, repopath string, refpath string) {
// Communicate with `git cat-file --batch` trying refs from longest // Communicate with `git cat-file --batch` trying refs from longest
...@@ -275,7 +272,6 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) { ...@@ -275,7 +272,6 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) {
for i := len(refpathv); i > 0; i-- { for i := len(refpathv); i > 0; i-- {
ref := strings.Join(refpathv[:i], "/") ref := strings.Join(refpathv[:i], "/")
path := strings.Join(refpathv[i:], "/") path := strings.Join(refpathv[i:], "/")
//log.Printf("Trying %v %v", ref, path)
_, err := fmt.Fprintf(queryStdin, "%s:%s\n", ref, path) _, err := fmt.Fprintf(queryStdin, "%s:%s\n", ref, path)
if err != nil { if err != nil {
fail500(w, "git cat-file --batch; write", err) fail500(w, "git cat-file --batch; write", err)
...@@ -288,8 +284,6 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) { ...@@ -288,8 +284,6 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) {
return return
} }
//log.Printf("<- %s", reply)
// <object> SP missing LF // <object> SP missing LF
if strings.HasSuffix(reply, " missing\n") { if strings.HasSuffix(reply, " missing\n") {
continue continue
...@@ -304,10 +298,10 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) { ...@@ -304,10 +298,10 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) {
if type_ != "blob" { if type_ != "blob" {
log.Printf("git cat-file --batch-check; %v is not blob (is %v)", sha1, type_) log.Printf("git cat-file --batch-check; %v is not blob (is %v)", sha1, type_)
sha1 = "" // so it will return 404 sha1 = "" // so it will return 404
} }
// so we found this blob object // git object found
break break
} }
...@@ -322,7 +316,7 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) { ...@@ -322,7 +316,7 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string) {
w.Header().Set("Content-Transfer-Encoding", "binary") w.Header().Set("Content-Transfer-Encoding", "binary")
w.Header().Set("Content-Length", fmt.Sprintf("%d", size)) w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Content-Type-Options", "nosniff")
// net/http sniffs stream and and automatically detects and sets // net/http sniffs stream and automatically detects and sets
// Content-Type header. We do not have to do it ourselves. // Content-Type header. We do not have to do it ourselves.
w.Header().Set("Cache-Control", "private") // Rails sets this for IE compatibility w.Header().Set("Cache-Control", "private") // Rails sets this for IE compatibility
......
...@@ -66,7 +66,6 @@ type gitRequest struct { ...@@ -66,7 +66,6 @@ type gitRequest struct {
// Routing table // Routing table
var gitServices = [...]gitService{ var gitServices = [...]gitService{
gitService{"GET", regexp.MustCompile(`/raw/.+\z`), handleGetBlobRaw},
gitService{"GET", regexp.MustCompile(`/info/refs\z`), repoPreAuthorizeHandler(handleGetInfoRefs)}, gitService{"GET", regexp.MustCompile(`/info/refs\z`), repoPreAuthorizeHandler(handleGetInfoRefs)},
gitService{"POST", regexp.MustCompile(`/git-upload-pack\z`), repoPreAuthorizeHandler(contentEncodingHandler(handlePostRPC))}, gitService{"POST", regexp.MustCompile(`/git-upload-pack\z`), repoPreAuthorizeHandler(contentEncodingHandler(handlePostRPC))},
gitService{"POST", regexp.MustCompile(`/git-receive-pack\z`), repoPreAuthorizeHandler(contentEncodingHandler(handlePostRPC))}, gitService{"POST", regexp.MustCompile(`/git-receive-pack\z`), repoPreAuthorizeHandler(contentEncodingHandler(handlePostRPC))},
...@@ -76,6 +75,7 @@ var gitServices = [...]gitService{ ...@@ -76,6 +75,7 @@ var gitServices = [...]gitService{
gitService{"GET", regexp.MustCompile(`/repository/archive.tar.gz\z`), repoPreAuthorizeHandler(handleGetArchive)}, gitService{"GET", regexp.MustCompile(`/repository/archive.tar.gz\z`), repoPreAuthorizeHandler(handleGetArchive)},
gitService{"GET", regexp.MustCompile(`/repository/archive.tar.bz2\z`), repoPreAuthorizeHandler(handleGetArchive)}, gitService{"GET", regexp.MustCompile(`/repository/archive.tar.bz2\z`), repoPreAuthorizeHandler(handleGetArchive)},
gitService{"GET", regexp.MustCompile(`/uploads/`), handleSendFile}, gitService{"GET", regexp.MustCompile(`/uploads/`), handleSendFile},
gitService{"GET", regexp.MustCompile(`/raw/.+\z`), handleGetBlobRaw},
// Git LFS // Git LFS
gitService{"PUT", regexp.MustCompile(`/gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`), lfsAuthorizeHandler(handleStoreLfsObject)}, gitService{"PUT", regexp.MustCompile(`/gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`), lfsAuthorizeHandler(handleStoreLfsObject)},
......
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