X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/45f10d80d1b584808a6e375214b5be6bc7d2a730..e67d0f5d43c56f78694ea4a5f93acec5c93cd0fb:/services/arv-git-httpd/auth_handler.go diff --git a/services/arv-git-httpd/auth_handler.go b/services/arv-git-httpd/auth_handler.go index fccb0c9576..b7373b5c1e 100644 --- a/services/arv-git-httpd/auth_handler.go +++ b/services/arv-git-httpd/auth_handler.go @@ -1,3 +1,7 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + package main import ( @@ -5,6 +9,7 @@ import ( "net/http" "os" "strings" + "sync" "time" "git.curoverse.com/arvados.git/sdk/go/arvadosclient" @@ -12,13 +17,24 @@ import ( "git.curoverse.com/arvados.git/sdk/go/httpserver" ) -var clientPool = arvadosclient.MakeClientPool() - type authHandler struct { - handler http.Handler + handler http.Handler + clientPool *arvadosclient.ClientPool + setupOnce sync.Once +} + +func (h *authHandler) setup() { + ac, err := arvadosclient.New(&theConfig.Client) + if err != nil { + log.Fatal(err) + } + h.clientPool = &arvadosclient.ClientPool{Prototype: ac} + log.Printf("%+v", h.clientPool.Prototype) } func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) { + h.setupOnce.Do(h.setup) + var statusCode int var statusText string var apiToken string @@ -27,6 +43,29 @@ func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) { w := httpserver.WrapResponseWriter(wOrig) + if r.Method == "OPTIONS" { + method := r.Header.Get("Access-Control-Request-Method") + if method != "GET" && method != "POST" { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST") + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Max-Age", "86400") + w.WriteHeader(http.StatusOK) + return + } + + if r.Header.Get("Origin") != "" { + // Allow simple cross-origin requests without user + // credentials ("user credentials" as defined by CORS, + // i.e., cookies, HTTP authentication, and client-side + // SSL certificates. See + // http://www.w3.org/TR/cors/#user-credentials). + w.Header().Set("Access-Control-Allow-Origin", "*") + } + defer func() { if w.WroteStatus() == 0 { // Nobody has called WriteHeader yet: that @@ -62,18 +101,18 @@ func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) { // "foo/bar". pathParts := strings.SplitN(r.URL.Path[1:], ".git/", 2) if len(pathParts) != 2 { - statusCode, statusText = http.StatusBadRequest, "bad request" + statusCode, statusText = http.StatusNotFound, "not found" return } repoName = pathParts[0] repoName = strings.TrimRight(repoName, "/") - arv := clientPool.Get() + arv := h.clientPool.Get() if arv == nil { - statusCode, statusText = http.StatusInternalServerError, "connection pool failed: "+clientPool.Err().Error() + statusCode, statusText = http.StatusInternalServerError, "connection pool failed: "+h.clientPool.Err().Error() return } - defer clientPool.Put(arv) + defer h.clientPool.Put(arv) // Ask API server whether the repository is readable using // this token (by trying to read it!) @@ -129,7 +168,7 @@ func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) { "/" + repoName + "/.git", } for _, dir := range tryDirs { - if fileInfo, err := os.Stat(theConfig.Root + dir); err != nil { + if fileInfo, err := os.Stat(theConfig.RepoRoot + dir); err != nil { if !os.IsNotExist(err) { statusCode, statusText = http.StatusInternalServerError, err.Error() return @@ -141,7 +180,7 @@ func (h *authHandler) ServeHTTP(wOrig http.ResponseWriter, r *http.Request) { } if rewrittenPath == "" { log.Println("WARNING:", repoUUID, - "git directory not found in", theConfig.Root, tryDirs) + "git directory not found in", theConfig.RepoRoot, tryDirs) // We say "content not found" to disambiguate from the // earlier "API says that repo does not exist" error. statusCode, statusText = http.StatusNotFound, "content not found"