diff --git a/archive.go b/archive.go index 76a78f7000e419c9d877d0cbda373dabe6754919..a91b2b7a1dea291e834c58ccbf051753e1d6a124 100644 --- a/archive.go +++ b/archive.go @@ -5,6 +5,7 @@ In this file we handle 'git archive' downloads package main import ( + "./internal/api" "./internal/helper" "fmt" "io" @@ -18,7 +19,7 @@ import ( "time" ) -func handleGetArchive(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func handleGetArchive(w http.ResponseWriter, r *http.Request, a *api.Response) { var format string urlPath := r.URL.Path switch filepath.Base(urlPath) { @@ -31,7 +32,7 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *apiResponse) { case "archive.tar.bz2": format = "tar.bz2" default: - fail500(w, fmt.Errorf("handleGetArchive: invalid format: %s", urlPath)) + helper.Fail500(w, fmt.Errorf("handleGetArchive: invalid format: %s", urlPath)) return } @@ -54,7 +55,7 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *apiResponse) { // to finalize the cached archive. tempFile, err := prepareArchiveTempfile(path.Dir(a.ArchivePath), archiveFilename) if err != nil { - fail500(w, fmt.Errorf("handleGetArchive: create tempfile: %v", err)) + helper.Fail500(w, fmt.Errorf("handleGetArchive: create tempfile: %v", err)) return } defer tempFile.Close() @@ -65,12 +66,12 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *apiResponse) { archiveCmd := gitCommand("", "git", "--git-dir="+a.RepoPath, "archive", "--format="+archiveFormat, "--prefix="+a.ArchivePrefix+"/", a.CommitId) archiveStdout, err := archiveCmd.StdoutPipe() if err != nil { - fail500(w, fmt.Errorf("handleGetArchive: archive stdout: %v", err)) + helper.Fail500(w, fmt.Errorf("handleGetArchive: archive stdout: %v", err)) return } defer archiveStdout.Close() if err := archiveCmd.Start(); err != nil { - fail500(w, fmt.Errorf("handleGetArchive: start %v: %v", archiveCmd.Args, err)) + helper.Fail500(w, fmt.Errorf("handleGetArchive: start %v: %v", archiveCmd.Args, err)) return } defer cleanUpProcessGroup(archiveCmd) // Ensure brute force subprocess clean-up @@ -83,13 +84,13 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *apiResponse) { stdout, err = compressCmd.StdoutPipe() if err != nil { - fail500(w, fmt.Errorf("handleGetArchive: compress stdout: %v", err)) + helper.Fail500(w, fmt.Errorf("handleGetArchive: compress stdout: %v", err)) return } defer stdout.Close() if err := compressCmd.Start(); err != nil { - fail500(w, fmt.Errorf("handleGetArchive: start %v: %v", compressCmd.Args, err)) + helper.Fail500(w, fmt.Errorf("handleGetArchive: start %v: %v", compressCmd.Args, err)) return } defer compressCmd.Wait() diff --git a/artifacts.go b/artifacts.go index e1d2dd45b3b6c6a823721b9045db420c959b9010..0a2cfdf4569e76bb426568eb3277552e466e0260 100644 --- a/artifacts.go +++ b/artifacts.go @@ -1,11 +1,12 @@ package main import ( + "./internal/api" "net/http" ) -func artifactsAuthorizeHandler(api *API, h httpHandleFunc) httpHandleFunc { - return api.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func artifactsAuthorizeHandler(myAPI *api.API, h http.HandlerFunc) http.HandlerFunc { + return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) { r.Header.Set(tempPathHeader, a.TempPath) h(w, r) }, "/authorize") diff --git a/authorization.go b/authorization.go deleted file mode 100644 index 8fd7de1f441fb067413365909e516a97fcbdfa3b..0000000000000000000000000000000000000000 --- a/authorization.go +++ /dev/null @@ -1,112 +0,0 @@ -package main - -import ( - "./internal/proxy" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "strings" -) - -func (api *API) newUpstreamRequest(r *http.Request, body io.Reader, suffix string) (*http.Request, error) { - url := *api.URL - url.Path = r.URL.RequestURI() + suffix - authReq := &http.Request{ - Method: r.Method, - URL: &url, - Header: proxy.HeaderClone(r.Header), - } - if body != nil { - authReq.Body = ioutil.NopCloser(body) - } - - // Clean some headers when issuing a new request without body - if body == nil { - authReq.Header.Del("Content-Type") - authReq.Header.Del("Content-Encoding") - authReq.Header.Del("Content-Length") - authReq.Header.Del("Content-Disposition") - authReq.Header.Del("Accept-Encoding") - - // Hop-by-hop headers. These are removed when sent to the backend. - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html - authReq.Header.Del("Transfer-Encoding") - authReq.Header.Del("Connection") - authReq.Header.Del("Keep-Alive") - authReq.Header.Del("Proxy-Authenticate") - authReq.Header.Del("Proxy-Authorization") - authReq.Header.Del("Te") - authReq.Header.Del("Trailers") - authReq.Header.Del("Upgrade") - } - - // Also forward the Host header, which is excluded from the Header map by the http libary. - // This allows the Host header received by the backend to be consistent with other - // requests not going through gitlab-workhorse. - authReq.Host = r.Host - // Set a custom header for the request. This can be used in some - // configurations (Passenger) to solve auth request routing problems. - authReq.Header.Set("Gitlab-Workhorse", Version) - - return authReq, nil -} - -func (api *API) preAuthorizeHandler(h serviceHandleFunc, suffix string) httpHandleFunc { - return func(w http.ResponseWriter, r *http.Request) { - authReq, err := api.newUpstreamRequest(r, nil, suffix) - if err != nil { - fail500(w, fmt.Errorf("preAuthorizeHandler: newUpstreamRequest: %v", err)) - return - } - - authResponse, err := api.Do(authReq) - if err != nil { - fail500(w, fmt.Errorf("preAuthorizeHandler: do %v: %v", authReq.URL.Path, err)) - return - } - defer authResponse.Body.Close() - - if authResponse.StatusCode != 200 { - // The Git request is not allowed by the backend. Maybe the - // client needs to send HTTP Basic credentials. Forward the - // response from the auth backend to our client. This includes - // the 'WWW-Authenticate' header that acts as a hint that - // Basic auth credentials are needed. - for k, v := range authResponse.Header { - // Accomodate broken clients that do case-sensitive header lookup - if k == "Www-Authenticate" { - w.Header()["WWW-Authenticate"] = v - } else { - w.Header()[k] = v - } - } - w.WriteHeader(authResponse.StatusCode) - io.Copy(w, authResponse.Body) - return - } - - a := &apiResponse{} - // The auth backend validated the client request and told us additional - // request metadata. We must extract this information from the auth - // response body. - if err := json.NewDecoder(authResponse.Body).Decode(a); err != nil { - fail500(w, fmt.Errorf("preAuthorizeHandler: decode authorization response: %v", err)) - return - } - // Don't hog a TCP connection in CLOSE_WAIT, we can already close it now - authResponse.Body.Close() - - // Negotiate authentication (Kerberos) may need to return a WWW-Authenticate - // header to the client even in case of success as per RFC4559. - for k, v := range authResponse.Header { - // Case-insensitive comparison as per RFC7230 - if strings.EqualFold(k, "WWW-Authenticate") { - w.Header()[k] = v - } - } - - h(w, r, a) - } -} diff --git a/authorization_test.go b/authorization_test.go index a85e3a13986b70b45d6beba4b1d4226844f55229..c2edbb83a8258e0a346eab49fc0f8db26694aec9 100644 --- a/authorization_test.go +++ b/authorization_test.go @@ -1,6 +1,7 @@ package main import ( + "./internal/api" "fmt" "net/http" "net/http/httptest" @@ -8,7 +9,7 @@ import ( "testing" ) -func okHandler(w http.ResponseWriter, _ *http.Request, _ *apiResponse) { +func okHandler(w http.ResponseWriter, _ *http.Request, _ *api.Response) { w.WriteHeader(201) fmt.Fprint(w, "{\"status\":\"ok\"}") } @@ -26,7 +27,7 @@ func runPreAuthorizeHandler(t *testing.T, suffix string, url *regexp.Regexp, api api := newUpstream(ts.URL, "").API response := httptest.NewRecorder() - api.preAuthorizeHandler(okHandler, suffix)(response, httpRequest) + api.PreAuthorizeHandler(okHandler, suffix)(response, httpRequest) assertResponseCode(t, response, expectedCode) return response } @@ -35,7 +36,7 @@ func TestPreAuthorizeHappyPath(t *testing.T) { runPreAuthorizeHandler( t, "/authorize", regexp.MustCompile(`/authorize\z`), - &apiResponse{}, + &api.Response{}, 200, 201) } @@ -43,7 +44,7 @@ func TestPreAuthorizeSuffix(t *testing.T) { runPreAuthorizeHandler( t, "/different-authorize", regexp.MustCompile(`/authorize\z`), - &apiResponse{}, + &api.Response{}, 200, 404) } diff --git a/deploy_page.go b/deploy_page.go index 4db63c6ebb49c512c14b0357eaf043a28cd3a9d6..a1ce2109a2ee3399fd8f74d24b4d97a83c8393c5 100644 --- a/deploy_page.go +++ b/deploy_page.go @@ -6,7 +6,7 @@ import ( "path/filepath" ) -func handleDeployPage(documentRoot *string, handler httpHandleFunc) httpHandleFunc { +func handleDeployPage(documentRoot *string, handler http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { deployPage := filepath.Join(*documentRoot, "index.html") data, err := ioutil.ReadFile(deployPage) diff --git a/development.go b/development.go index 17ba95aefda5bb553c58008be655be2ff4cce9bb..eb5f6fdb31ea310ba05dd11bf6b21e13ddad1e7b 100644 --- a/development.go +++ b/development.go @@ -2,7 +2,7 @@ package main import "net/http" -func handleDevelopmentMode(developmentMode *bool, handler httpHandleFunc) httpHandleFunc { +func handleDevelopmentMode(developmentMode *bool, handler http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !*developmentMode { http.NotFound(w, r) diff --git a/error_pages.go b/error_pages.go index aa365dd84bf107e7d5932851a00970e3d822d7a5..bd858050fdab20ba9e5d13debbd033a30c34ab43 100644 --- a/error_pages.go +++ b/error_pages.go @@ -59,7 +59,7 @@ func (s *errorPageResponseWriter) Flush() { s.WriteHeader(http.StatusOK) } -func handleRailsError(documentRoot *string, handler http.Handler) httpHandleFunc { +func handleRailsError(documentRoot *string, handler http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { rw := errorPageResponseWriter{ rw: w, diff --git a/error_pages_test.go b/error_pages_test.go index 44463525578621bdc7351cefe4a359fc66830542..8b78ea3d1d8797aabbd012d8b2a8065861247afb 100644 --- a/error_pages_test.go +++ b/error_pages_test.go @@ -21,7 +21,7 @@ func TestIfErrorPageIsPresented(t *testing.T) { ioutil.WriteFile(filepath.Join(dir, "404.html"), []byte(errorPage), 0600) w := httptest.NewRecorder() - h := httpHandleFunc(func(w http.ResponseWriter, _ *http.Request) { + h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(404) fmt.Fprint(w, "Not Found") }) @@ -41,7 +41,7 @@ func TestIfErrorPassedIfNoErrorPageIsFound(t *testing.T) { w := httptest.NewRecorder() errorResponse := "ERROR" - h := httpHandleFunc(func(w http.ResponseWriter, _ *http.Request) { + h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(404) fmt.Fprint(w, errorResponse) }) diff --git a/git-http.go b/git-http.go index 48dfe81a528034950325d7ad55fb0793d45d9e45..2364d02ecbb110c84ac85dc6176dc29dc4a0b840 100644 --- a/git-http.go +++ b/git-http.go @@ -5,6 +5,7 @@ In this file we handle the Git 'smart HTTP' protocol package main import ( + "./internal/api" "./internal/helper" "errors" "fmt" @@ -27,10 +28,10 @@ func looksLikeRepo(p string) bool { return true } -func repoPreAuthorizeHandler(api *API, handleFunc serviceHandleFunc) httpHandleFunc { - return api.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func repoPreAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.HandlerFunc { + return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) { if a.RepoPath == "" { - fail500(w, errors.New("repoPreAuthorizeHandler: RepoPath empty")) + helper.Fail500(w, errors.New("repoPreAuthorizeHandler: RepoPath empty")) return } @@ -43,7 +44,7 @@ func repoPreAuthorizeHandler(api *API, handleFunc serviceHandleFunc) httpHandleF }, "") } -func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *api.Response) { rpc := r.URL.Query().Get("service") if !(rpc == "git-upload-pack" || rpc == "git-receive-pack") { // The 'dumb' Git HTTP protocol is not supported @@ -55,12 +56,12 @@ func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *apiResponse) { cmd := gitCommand(a.GL_ID, "git", subCommand(rpc), "--stateless-rpc", "--advertise-refs", a.RepoPath) stdout, err := cmd.StdoutPipe() if err != nil { - fail500(w, fmt.Errorf("handleGetInfoRefs: stdout: %v", err)) + helper.Fail500(w, fmt.Errorf("handleGetInfoRefs: stdout: %v", err)) return } defer stdout.Close() if err := cmd.Start(); err != nil { - fail500(w, fmt.Errorf("handleGetInfoRefs: start %v: %v", cmd.Args, err)) + helper.Fail500(w, fmt.Errorf("handleGetInfoRefs: start %v: %v", cmd.Args, err)) return } defer cleanUpProcessGroup(cmd) // Ensure brute force subprocess clean-up @@ -87,14 +88,14 @@ func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *apiResponse) { } } -func handlePostRPC(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func handlePostRPC(w http.ResponseWriter, r *http.Request, a *api.Response) { var err error // Get Git action from URL action := filepath.Base(r.URL.Path) if !(action == "git-upload-pack" || action == "git-receive-pack") { // The 'dumb' Git HTTP protocol is not supported - fail500(w, fmt.Errorf("handlePostRPC: unsupported action: %s", r.URL.Path)) + helper.Fail500(w, fmt.Errorf("handlePostRPC: unsupported action: %s", r.URL.Path)) return } @@ -102,25 +103,25 @@ func handlePostRPC(w http.ResponseWriter, r *http.Request, a *apiResponse) { cmd := gitCommand(a.GL_ID, "git", subCommand(action), "--stateless-rpc", a.RepoPath) stdout, err := cmd.StdoutPipe() if err != nil { - fail500(w, fmt.Errorf("handlePostRPC: stdout: %v", err)) + helper.Fail500(w, fmt.Errorf("handlePostRPC: stdout: %v", err)) return } defer stdout.Close() stdin, err := cmd.StdinPipe() if err != nil { - fail500(w, fmt.Errorf("handlePostRPC: stdin: %v", err)) + helper.Fail500(w, fmt.Errorf("handlePostRPC: stdin: %v", err)) return } defer stdin.Close() if err := cmd.Start(); err != nil { - fail500(w, fmt.Errorf("handlePostRPC: start %v: %v", cmd.Args, err)) + helper.Fail500(w, fmt.Errorf("handlePostRPC: start %v: %v", cmd.Args, err)) return } defer cleanUpProcessGroup(cmd) // Ensure brute force subprocess clean-up // Write the client request body to Git's standard input if _, err := io.Copy(stdin, r.Body); err != nil { - fail500(w, fmt.Errorf("handlePostRPC write to %v: %v", cmd.Args, err)) + helper.Fail500(w, fmt.Errorf("handlePostRPC write to %v: %v", cmd.Args, err)) return } // Signal to the Git subprocess that no more data is coming diff --git a/handlers.go b/handlers.go index 441e68ae6742ac09adbfa8b076df86fc26f4eee7..ec94c3d23bbc3f4ce8628a36a373df0c7352e34f 100644 --- a/handlers.go +++ b/handlers.go @@ -1,13 +1,14 @@ package main import ( + "./internal/helper" "compress/gzip" "fmt" "io" "net/http" ) -func contentEncodingHandler(h httpHandleFunc) httpHandleFunc { +func contentEncodingHandler(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var body io.ReadCloser var err error @@ -24,7 +25,7 @@ func contentEncodingHandler(h httpHandleFunc) httpHandleFunc { } if err != nil { - fail500(w, fmt.Errorf("contentEncodingHandler: %v", err)) + helper.Fail500(w, fmt.Errorf("contentEncodingHandler: %v", err)) return } defer body.Close() diff --git a/helpers.go b/helpers.go index c9c75dd8f6f32bef2e0a991dc5d82151f55f9893..5aa9929199ea4a000543042db84481fbb7dca650 100644 --- a/helpers.go +++ b/helpers.go @@ -5,7 +5,6 @@ Miscellaneous helpers: logging, errors, subprocesses package main import ( - "./internal/helper" "fmt" "net/http" "os" @@ -14,11 +13,6 @@ import ( "syscall" ) -func fail500(w http.ResponseWriter, err error) { - http.Error(w, "Internal server error", 500) - helper.LogError(err) -} - func httpError(w http.ResponseWriter, r *http.Request, error string, code int) { if r.ProtoAtLeast(1, 1) { // Force client to disconnect if we render request error diff --git a/internal/helper/helpers.go b/internal/helper/helpers.go index 9cf2519577aa9d4f321d0af4da045c717d28cc32..bf2f8a7eed457d1a77202b4d94b70d30f5c1af67 100644 --- a/internal/helper/helpers.go +++ b/internal/helper/helpers.go @@ -3,9 +3,15 @@ package helper import ( "errors" "log" + "net/http" "os" ) +func Fail500(w http.ResponseWriter, err error) { + http.Error(w, "Internal server error", 500) + LogError(err) +} + func LogError(err error) { log.Printf("error: %v", err) } diff --git a/lfs.go b/lfs.go index 63d01e0cff5da121f99b8771b613351a69493d6c..5aa81e466b7962afaa6a4f5e39c5debf66a98b54 100644 --- a/lfs.go +++ b/lfs.go @@ -5,6 +5,8 @@ In this file we handle git lfs objects downloads and uploads package main import ( + "./internal/api" + "./internal/helper" "bytes" "crypto/sha256" "encoding/hex" @@ -17,21 +19,21 @@ import ( "path/filepath" ) -func lfsAuthorizeHandler(api *API, handleFunc serviceHandleFunc) httpHandleFunc { - return api.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func lfsAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.HandlerFunc { + return myAPI.PreAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *api.Response) { if a.StoreLFSPath == "" { - fail500(w, errors.New("lfsAuthorizeHandler: StoreLFSPath empty")) + helper.Fail500(w, errors.New("lfsAuthorizeHandler: StoreLFSPath empty")) return } if a.LfsOid == "" { - fail500(w, errors.New("lfsAuthorizeHandler: LfsOid empty")) + helper.Fail500(w, errors.New("lfsAuthorizeHandler: LfsOid empty")) return } if err := os.MkdirAll(a.StoreLFSPath, 0700); err != nil { - fail500(w, fmt.Errorf("lfsAuthorizeHandler: mkdia StoreLFSPath: %v", err)) + helper.Fail500(w, fmt.Errorf("lfsAuthorizeHandler: mkdia StoreLFSPath: %v", err)) return } @@ -39,11 +41,11 @@ func lfsAuthorizeHandler(api *API, handleFunc serviceHandleFunc) httpHandleFunc }, "/authorize") } -func handleStoreLfsObject(h http.Handler) serviceHandleFunc { - return func(w http.ResponseWriter, r *http.Request, a *apiResponse) { +func handleStoreLfsObject(h http.Handler) api.HandleFunc { + return func(w http.ResponseWriter, r *http.Request, a *api.Response) { file, err := ioutil.TempFile(a.StoreLFSPath, a.LfsOid) if err != nil { - fail500(w, fmt.Errorf("handleStoreLfsObject: create tempfile: %v", err)) + helper.Fail500(w, fmt.Errorf("handleStoreLfsObject: create tempfile: %v", err)) return } defer os.Remove(file.Name()) @@ -54,19 +56,19 @@ func handleStoreLfsObject(h http.Handler) serviceHandleFunc { written, err := io.Copy(hw, r.Body) if err != nil { - fail500(w, fmt.Errorf("handleStoreLfsObject: write tempfile: %v", err)) + helper.Fail500(w, fmt.Errorf("handleStoreLfsObject: write tempfile: %v", err)) return } file.Close() if written != a.LfsSize { - fail500(w, fmt.Errorf("handleStoreLfsObject: expected size %d, wrote %d", a.LfsSize, written)) + helper.Fail500(w, fmt.Errorf("handleStoreLfsObject: expected size %d, wrote %d", a.LfsSize, written)) return } shaStr := hex.EncodeToString(hash.Sum(nil)) if shaStr != a.LfsOid { - fail500(w, fmt.Errorf("handleStoreLfsObject: expected sha256 %s, got %s", a.LfsOid, shaStr)) + helper.Fail500(w, fmt.Errorf("handleStoreLfsObject: expected sha256 %s, got %s", a.LfsOid, shaStr)) return } diff --git a/main.go b/main.go index b4bda1a27efa8a8ce8ae0d2c688a3b6607ab6a66..a29612125306e75ab8371b9ac3458a82e3d3a7e6 100644 --- a/main.go +++ b/main.go @@ -46,12 +46,6 @@ type httpRoute struct { handler http.Handler } -type httpHandleFunc func(http.ResponseWriter, *http.Request) - -func (h httpHandleFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h(w, r) -} - const projectPattern = `^/[^/]+/[^/]+/` const gitProjectPattern = `^/[^/]+/[^/]+\.git/` diff --git a/main_test.go b/main_test.go index b6808d65fc51d4960b8a236a462a1d4421b1ac8a..890db645a7ddad3df001fbcbd8bdedd8dddfebf9 100644 --- a/main_test.go +++ b/main_test.go @@ -1,6 +1,7 @@ package main import ( + "./internal/api" "bytes" "encoding/json" "fmt" @@ -340,7 +341,7 @@ func runOrFail(t *testing.T, cmd *exec.Cmd) { } func gitOkBody(t *testing.T) interface{} { - return &apiResponse{ + return &api.Response{ GL_ID: "user-123", RepoPath: repoPath(t), } @@ -353,7 +354,7 @@ func archiveOkBody(t *testing.T, archiveName string) interface{} { } archivePath := path.Join(cwd, cacheDir, archiveName) - return &apiResponse{ + return &api.Response{ RepoPath: repoPath(t), ArchivePath: archivePath, CommitId: "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", diff --git a/servefile.go b/servefile.go index 7779dd6af1f544b824e21c9ef4337cba0cbbb929..a51428c47890f53354657d77e98f9ca20c253573 100644 --- a/servefile.go +++ b/servefile.go @@ -17,13 +17,13 @@ const ( CacheExpireMax ) -func (u *upstream) handleServeFile(documentRoot *string, cache CacheMode, notFoundHandler httpHandleFunc) httpHandleFunc { +func (u *upstream) handleServeFile(documentRoot *string, cache CacheMode, notFoundHandler http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { file := filepath.Join(*documentRoot, u.relativeURIPath(cleanURIPath(r.URL.Path))) // The filepath.Join does Clean traversing directories up if !strings.HasPrefix(file, *documentRoot) { - fail500(w, &os.PathError{ + helper.Fail500(w, &os.PathError{ Op: "open", Path: file, Err: os.ErrInvalid, diff --git a/uploads.go b/uploads.go index 28d5c084f275b1230a3fb4aae8eabc9f7adb665c..dea7e35b80fe3b3d91e1d1ff4219bc77131de631 100644 --- a/uploads.go +++ b/uploads.go @@ -1,6 +1,7 @@ package main import ( + "./internal/helper" "bytes" "errors" "fmt" @@ -85,11 +86,11 @@ func rewriteFormFilesFromMultipart(r *http.Request, writer *multipart.Writer, te return cleanup, nil } -func handleFileUploads(h http.Handler) httpHandleFunc { +func handleFileUploads(h http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { tempPath := r.Header.Get(tempPathHeader) if tempPath == "" { - fail500(w, errors.New("handleFileUploads: TempPath empty")) + helper.Fail500(w, errors.New("handleFileUploads: TempPath empty")) return } r.Header.Del(tempPathHeader) @@ -104,7 +105,7 @@ func handleFileUploads(h http.Handler) httpHandleFunc { if err == http.ErrNotMultipart { h.ServeHTTP(w, r) } else { - fail500(w, fmt.Errorf("handleFileUploads: extract files from multipart: %v", err)) + helper.Fail500(w, fmt.Errorf("handleFileUploads: extract files from multipart: %v", err)) } return } diff --git a/upstream.go b/upstream.go index 4a557a0f984b5c3f8b96cce043381adedf71fea7..c95b33dd423c246139727e394d3e3cceef4f5603 100644 --- a/upstream.go +++ b/upstream.go @@ -7,6 +7,7 @@ In this file we handle request routing and interaction with the authBackend. package main import ( + "./internal/api" "./internal/proxy" "fmt" "log" @@ -17,48 +18,13 @@ import ( "time" ) -type serviceHandleFunc func(http.ResponseWriter, *http.Request, *apiResponse) - -type API struct { - *http.Client - *url.URL -} - type upstream struct { - API *API + API *api.API Proxy *proxy.Proxy authBackend string relativeURLRoot string } -type apiResponse struct { - // GL_ID is an environment variable used by gitlab-shell hooks during 'git - // push' and 'git pull' - GL_ID string - // RepoPath is the full path on disk to the Git repository the request is - // about - RepoPath string - // ArchivePath is the full path where we should find/create a cached copy - // of a requested archive - ArchivePath string - // ArchivePrefix is used to put extracted archive contents in a - // subdirectory - ArchivePrefix string - // CommitId is used do prevent race conditions between the 'time of check' - // in the GitLab Rails app and the 'time of use' in gitlab-workhorse. - CommitId string - // StoreLFSPath is provided by the GitLab Rails application - // to mark where the tmp file should be placed - StoreLFSPath string - // LFS object id - LfsOid string - // LFS object size - LfsSize int64 - // TmpPath is the path where we should store temporary files - // This is set by authorization middleware - TempPath string -} - func newUpstream(authBackend string, authSocket string) *upstream { parsedURL, err := url.Parse(authBackend) if err != nil { @@ -88,8 +54,12 @@ func newUpstream(authBackend string, authSocket string) *upstream { proxyTransport := proxy.NewRoundTripper(authTransport) up := &upstream{ - authBackend: authBackend, - API: &API{Client: &http.Client{Transport: proxyTransport}, URL: parsedURL}, + authBackend: authBackend, + API: &api.API{ + Client: &http.Client{Transport: proxyTransport}, + URL: parsedURL, + Version: Version, + }, Proxy: proxy.NewProxy(parsedURL, proxyTransport, Version), relativeURLRoot: relativeURLRoot, }