diff --git a/archive.go b/archive.go index a437e88ae83b69a056a44941298e5eacce8231fe..b615c3c93e10ee4ebd47aaa86e69ecbc8c0f3d30 100644 --- a/archive.go +++ b/archive.go @@ -5,7 +5,6 @@ In this file we handle 'git archive' downloads package main import ( - "errors" "fmt" "io" "io/ioutil" @@ -20,7 +19,8 @@ import ( func handleGetArchive(w http.ResponseWriter, r *gitRequest) { var format string - switch filepath.Base(r.URL.Path) { + urlPath := r.URL.Path + switch filepath.Base(urlPath) { case "archive.zip": format = "zip" case "archive.tar": @@ -30,7 +30,7 @@ func handleGetArchive(w http.ResponseWriter, r *gitRequest) { case "archive.tar.bz2": format = "tar.bz2" default: - fail500(w, "handleGetArchive", errors.New("invalid archive format")) + fail500(w, fmt.Errorf("handleGetArchive: invalid format: %s", urlPath)) } archiveFilename := path.Base(r.ArchivePath) @@ -52,7 +52,7 @@ func handleGetArchive(w http.ResponseWriter, r *gitRequest) { // to finalize the cached archive. tempFile, err := prepareArchiveTempfile(path.Dir(r.ArchivePath), archiveFilename) if err != nil { - fail500(w, "handleGetArchive create tempfile for archive", err) + fail500(w, fmt.Errorf("handleGetArchive: create tempfile: %v", err)) } defer tempFile.Close() defer os.Remove(tempFile.Name()) @@ -62,12 +62,12 @@ func handleGetArchive(w http.ResponseWriter, r *gitRequest) { archiveCmd := gitCommand("", "git", "--git-dir="+r.RepoPath, "archive", "--format="+archiveFormat, "--prefix="+r.ArchivePrefix+"/", r.CommitId) archiveStdout, err := archiveCmd.StdoutPipe() if err != nil { - fail500(w, "handleGetArchive", err) + fail500(w, fmt.Errorf("handleGetArchive: archive stdout: %v", err)) return } defer archiveStdout.Close() if err := archiveCmd.Start(); err != nil { - fail500(w, "handleGetArchive", err) + fail500(w, fmt.Errorf("handleGetArchive: start %v: %v", archiveCmd.Args, err)) return } defer cleanUpProcessGroup(archiveCmd) // Ensure brute force subprocess clean-up @@ -80,13 +80,13 @@ func handleGetArchive(w http.ResponseWriter, r *gitRequest) { stdout, err = compressCmd.StdoutPipe() if err != nil { - fail500(w, "handleGetArchive compressCmd stdout pipe", err) + fail500(w, fmt.Errorf("handleGetArchive: compress stdout: %v", err)) return } defer stdout.Close() if err := compressCmd.Start(); err != nil { - fail500(w, "handleGetArchive start compressCmd process", err) + fail500(w, fmt.Errorf("handleGetArchive: start %v: %v", compressCmd.Args, err)) return } defer compressCmd.Wait() @@ -101,22 +101,22 @@ func handleGetArchive(w http.ResponseWriter, r *gitRequest) { setArchiveHeaders(w, format, archiveFilename) w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just return if _, err := io.Copy(w, archiveReader); err != nil { - logContext("handleGetArchive read from subprocess", err) + log.Printf("handleGetArchive: read: %v", err) return } if err := archiveCmd.Wait(); err != nil { - logContext("handleGetArchive wait for archiveCmd", err) + log.Printf("handleGetArchive: archiveCmd: %v", err) return } if compressCmd != nil { if err := compressCmd.Wait(); err != nil { - logContext("handleGetArchive wait for compressCmd", err) + log.Printf("handleGetArchive: compressCmd: %v", err) return } } if err := finalizeCachedArchive(tempFile, r.ArchivePath); err != nil { - logContext("handleGetArchive finalize cached archive", err) + log.Printf("handleGetArchive: finalize cached archive: %v", err) return } } diff --git a/authorization.go b/authorization.go index 42ef1f3b5898192cbf4bd9843c8bfa22576a0d01..8c8c0df91a08f0052e4e8a9f585591f0e7364edb 100644 --- a/authorization.go +++ b/authorization.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "errors" + "fmt" "io" "net/http" "strings" @@ -12,13 +13,13 @@ func preAuthorizeHandler(handleFunc serviceHandleFunc, suffix string) serviceHan return func(w http.ResponseWriter, r *gitRequest) { authReq, err := r.u.newUpstreamRequest(r.Request, nil, suffix) if err != nil { - fail500(w, "newUpstreamRequest", err) + fail500(w, fmt.Errorf("preAuthorizeHandler: newUpstreamRequest: %v", err)) return } authResponse, err := r.u.httpClient.Do(authReq) if err != nil { - fail500(w, "doAuthRequest", err) + fail500(w, fmt.Errorf("preAuthorizeHandler: do %v: %v", authReq.URL.Path, err)) return } defer authResponse.Body.Close() @@ -46,7 +47,7 @@ func preAuthorizeHandler(handleFunc serviceHandleFunc, suffix string) serviceHan // request metadata. We must extract this information from the auth // response body. if err := json.NewDecoder(authResponse.Body).Decode(&r.authorizationResponse); err != nil { - fail500(w, "decode authorization response", err) + 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 @@ -68,7 +69,7 @@ func preAuthorizeHandler(handleFunc serviceHandleFunc, suffix string) serviceHan func repoPreAuthorizeHandler(handleFunc serviceHandleFunc) serviceHandleFunc { return preAuthorizeHandler(func(w http.ResponseWriter, r *gitRequest) { if r.RepoPath == "" { - fail500(w, "repoPreAuthorizeHandler", errors.New("missing authorization response")) + fail500(w, errors.New("repoPreAuthorizeHandler: RepoPath empty")) return } diff --git a/git-http.go b/git-http.go index ebe631c330e42dd58933b30e4120a31a984f5bcf..99542073aa01d6b217529e42af66282d58ef410f 100644 --- a/git-http.go +++ b/git-http.go @@ -7,6 +7,7 @@ package main import ( "fmt" "io" + "log" "net/http" "path/filepath" "strings" @@ -24,12 +25,12 @@ func handleGetInfoRefs(w http.ResponseWriter, r *gitRequest) { cmd := gitCommand(r.GL_ID, "git", subCommand(rpc), "--stateless-rpc", "--advertise-refs", r.RepoPath) stdout, err := cmd.StdoutPipe() if err != nil { - fail500(w, "handleGetInfoRefs", err) + fail500(w, fmt.Errorf("handleGetInfoRefs: stdout: %v", err)) return } defer stdout.Close() if err := cmd.Start(); err != nil { - fail500(w, "handleGetInfoRefs", err) + fail500(w, fmt.Errorf("handleGetInfoRefs: start %v: %v", cmd.Args, err)) return } defer cleanUpProcessGroup(cmd) // Ensure brute force subprocess clean-up @@ -39,19 +40,19 @@ func handleGetInfoRefs(w http.ResponseWriter, r *gitRequest) { w.Header().Add("Cache-Control", "no-cache") w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just return if err := pktLine(w, fmt.Sprintf("# service=%s\n", rpc)); err != nil { - logContext("handleGetInfoRefs response", err) + log.Printf("handleGetInfoRefs: pktLine: %v", err) return } if err := pktFlush(w); err != nil { - logContext("handleGetInfoRefs response", err) + log.Printf("handleGetInfoRefs: pktFlush: %v", err) return } if _, err := io.Copy(w, stdout); err != nil { - logContext("handleGetInfoRefs read from subprocess", err) + log.Printf("handleGetInfoRefs: read from %v: %v", cmd.Args, err) return } if err := cmd.Wait(); err != nil { - logContext("handleGetInfoRefs wait for subprocess", err) + log.Printf("handleGetInfoRefs: wait for %v: %v", cmd.Args, err) return } } @@ -63,7 +64,7 @@ func handlePostRPC(w http.ResponseWriter, r *gitRequest) { 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, "handlePostRPC", err) + fail500(w, fmt.Errorf("handlePostRPC: unsupported action: %s", r.URL.Path)) return } @@ -71,25 +72,25 @@ func handlePostRPC(w http.ResponseWriter, r *gitRequest) { cmd := gitCommand(r.GL_ID, "git", subCommand(action), "--stateless-rpc", r.RepoPath) stdout, err := cmd.StdoutPipe() if err != nil { - fail500(w, "handlePostRPC", err) + fail500(w, fmt.Errorf("handlePostRPC: stdout: %v", err)) return } defer stdout.Close() stdin, err := cmd.StdinPipe() if err != nil { - fail500(w, "handlePostRPC", err) + fail500(w, fmt.Errorf("handlePostRPC: stdin: %v", err)) return } defer stdin.Close() if err := cmd.Start(); err != nil { - fail500(w, "handlePostRPC", err) + 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, "handlePostRPC write to subprocess", err) + fail500(w, fmt.Errorf("handlePostRPC write to %v: %v", cmd.Args, err)) return } // Signal to the Git subprocess that no more data is coming @@ -106,11 +107,11 @@ func handlePostRPC(w http.ResponseWriter, r *gitRequest) { // This io.Copy may take a long time, both for Git push and pull. if _, err := io.Copy(w, stdout); err != nil { - logContext("handlePostRPC read from subprocess", err) + log.Printf("handlePostRPC read from %v:%v", cmd.Args, err) return } if err := cmd.Wait(); err != nil { - logContext("handlePostRPC wait for subprocess", err) + log.Printf("handlePostRPC wait for %v: %v", err) return } } diff --git a/handlers.go b/handlers.go index f64309db5505beb1c780f933f87be4a24e3308c5..8e008800a398328b57e452719e7de82e6c8b9ed4 100644 --- a/handlers.go +++ b/handlers.go @@ -19,15 +19,15 @@ func contentEncodingHandler(handleFunc serviceHandleFunc) serviceHandleFunc { body = r.Body case "gzip": body, err = gzip.NewReader(r.Body) + defer body.Close() default: err = fmt.Errorf("unsupported content encoding: %s", contentEncoding) } if err != nil { - fail500(w, "contentEncodingHandler", err) + fail500(w, fmt.Errorf("contentEncodingHandler: %v", err)) return } - defer body.Close() r.Body = body r.Header.Del("Content-Encoding") diff --git a/helpers.go b/helpers.go index cbeab079e65293a02d30be76802882c2217ba492..52ff5bd7ebe54db1b808ff12706f192704fcd2a1 100644 --- a/helpers.go +++ b/helpers.go @@ -17,18 +17,14 @@ import ( "syscall" ) -func fail400(w http.ResponseWriter, context string, err error) { +func fail400(w http.ResponseWriter, err error) { http.Error(w, "Bad request", 400) - logContext(context, err) + log.Print(err) } -func fail500(w http.ResponseWriter, context string, err error) { +func fail500(w http.ResponseWriter, err error) { http.Error(w, "Internal server error", 500) - logContext(context, err) -} - -func logContext(context string, err error) { - log.Printf("%s: %v", context, err) + log.Print(err) } // Git subprocess helpers diff --git a/lfs.go b/lfs.go index 025dfff54ac0c56356c182fa72880f49b05a5edb..44638b21185bd49a8a39d8f8dc014ee8ed112e3c 100644 --- a/lfs.go +++ b/lfs.go @@ -8,6 +8,7 @@ import ( "crypto/sha256" "encoding/hex" "errors" + "fmt" "io" "io/ioutil" "net/http" @@ -15,31 +16,21 @@ import ( "path/filepath" ) -var ( - errHashMismatch = errors.New("Content hash does not match OID") - errSizeMismatch = errors.New("Content size does not match") -) - func lfsAuthorizeHandler(handleFunc serviceHandleFunc) serviceHandleFunc { return preAuthorizeHandler(func(w http.ResponseWriter, r *gitRequest) { if r.StoreLFSPath == "" { - fail500(w, "lfsAuthorizeHandler", errors.New("Don't know where to store object, no store path specified.")) + fail500(w, errors.New("lfsAuthorizeHandler: StoreLFSPath empty")) return } if r.LfsOid == "" { - fail500(w, "lfsAuthorizeHandler", errors.New("Lfs object oid not specified.")) - return - } - - if r.LfsSize == 0 { - fail500(w, "lfsAuthorizeHandler", errors.New("Lfs object size not specified.")) + fail500(w, errors.New("lfsAuthorizeHandler: LfsOid empty")) return } if err := os.MkdirAll(r.StoreLFSPath, 0700); err != nil { - fail500(w, "Couldn't create directory for storing LFS tmp objects.", err) + fail500(w, fmt.Errorf("lfsAuthorizeHandler: mkdir StoreLFSPath: %v", err)) return } @@ -50,7 +41,7 @@ func lfsAuthorizeHandler(handleFunc serviceHandleFunc) serviceHandleFunc { func handleStoreLfsObject(w http.ResponseWriter, r *gitRequest) { file, err := ioutil.TempFile(r.StoreLFSPath, r.LfsOid) if err != nil { - fail500(w, "Couldn't open tmp file for writing.", err) + fail500(w, fmt.Errorf("handleStoreLfsObject: create tempfile: %v", err)) return } defer os.Remove(file.Name()) @@ -61,32 +52,32 @@ func handleStoreLfsObject(w http.ResponseWriter, r *gitRequest) { written, err := io.Copy(hw, r.Body) if err != nil { - fail500(w, "Failed to save received LFS object.", err) + fail500(w, fmt.Errorf("handleStoreLfsObject: write tempfile: %v", err)) return } file.Close() if written != r.LfsSize { - fail500(w, "Inconsistent size: ", errSizeMismatch) + fail500(w, fmt.Errorf("handleStoreLfsObject: expected size %d, wrote %d", r.LfsSize, written)) return } shaStr := hex.EncodeToString(hash.Sum(nil)) if shaStr != r.LfsOid { - fail500(w, "Inconsistent size: ", errSizeMismatch) + fail500(w, fmt.Errorf("handleStoreLfsObject: expected sha256 %s, got %s", r.LfsOid, shaStr)) return } r.Header.Set("X-GitLab-Lfs-Tmp", filepath.Base(file.Name())) storeReq, err := r.u.newUpstreamRequest(r.Request, nil, "") if err != nil { - fail500(w, "newUpstreamRequestLfsStoreCallback", err) + fail500(w, fmt.Errorf("handleStoreLfsObject: newUpstreamRequest: %v", err)) return } storeResponse, err := r.u.httpClient.Do(storeReq) if err != nil { - fail500(w, "doRequestLfsStoreCallback", err) + fail500(w, fmt.Errorf("handleStoreLfsObject: do %v: %v", storeReq.URL.Path, err)) return } defer storeResponse.Body.Close() diff --git a/proxy.go b/proxy.go index 36079de0984a9cb77ec7fecff24326958e09d986..4605b827b01f95cb44f71fd0da715c80f8851d73 100644 --- a/proxy.go +++ b/proxy.go @@ -1,19 +1,20 @@ package main import ( + "fmt" "net/http" ) func proxyRequest(w http.ResponseWriter, r *gitRequest) { upRequest, err := r.u.newUpstreamRequest(r.Request, r.Body, "") if err != nil { - fail500(w, "newUpstreamRequest", err) + fail500(w, fmt.Errorf("proxyRequest: newUpstreamRequest: %v", err)) return } upResponse, err := r.u.httpClient.Do(upRequest) if err != nil { - fail500(w, "do upstream request", err) + fail500(w, fmt.Errorf("proxyRequest: do %v: %v", upRequest.URL.Path, err)) return } defer upResponse.Body.Close() diff --git a/uploads.go b/uploads.go index 81cfb1ee624d51484bdc7be74a332950e4ae8fb2..37c1fd90b6337660e7b4998c9a220e5da43c6e35 100644 --- a/uploads.go +++ b/uploads.go @@ -3,6 +3,7 @@ package main import ( "bytes" "errors" + "fmt" "io" "io/ioutil" "mime/multipart" @@ -84,7 +85,7 @@ func rewriteFormFilesFromMultipart(r *gitRequest, writer *multipart.Writer) (cle func handleFileUploads(w http.ResponseWriter, r *gitRequest) { if r.TempPath == "" { - fail500(w, "handleUploadFile", errors.New("missing temporary path")) + fail500(w, errors.New("handleFileUploads: TempPath empty")) return } @@ -98,7 +99,7 @@ func handleFileUploads(w http.ResponseWriter, r *gitRequest) { if err == http.ErrNotMultipart { proxyRequest(w, r) } else { - fail500(w, "Couldn't handle upload request.", err) + fail500(w, fmt.Errorf("handleFileUploads: extract files from multipart: %v", err)) } return } @@ -113,7 +114,7 @@ func handleFileUploads(w http.ResponseWriter, r *gitRequest) { // Create request upstreamRequest, err := r.u.newUpstreamRequest(r.Request, nil, "") if err != nil { - fail500(w, "Couldn't handle artifacts upload request.", err) + fail500(w, fmt.Errorf("handleFileUploads: newUpstreamRequest: %v", err)) return } @@ -125,7 +126,7 @@ func handleFileUploads(w http.ResponseWriter, r *gitRequest) { // Forward request to backend upstreamResponse, err := r.u.httpClient.Do(upstreamRequest) if err != nil { - fail500(w, "do upstream request", err) + fail500(w, fmt.Errorf("handleFileUploads: do request %v", upstreamRequest.URL.Path, err)) return } defer upstreamResponse.Body.Close() diff --git a/xsendfile.go b/xsendfile.go index 88e3e51dcb39a5dc386335db7d160cc455cd1eb9..6f72a6b43620420c86829281c72adbb4847c8ea2 100644 --- a/xsendfile.go +++ b/xsendfile.go @@ -7,6 +7,7 @@ via the X-Sendfile mechanism. All that is needed in the Rails code is the package main import ( + "fmt" "io" "log" "net/http" @@ -16,7 +17,7 @@ import ( func handleSendFile(w http.ResponseWriter, r *gitRequest) { upRequest, err := r.u.newUpstreamRequest(r.Request, r.Body, "") if err != nil { - fail500(w, "newUpstreamRequest", err) + fail500(w, fmt.Errorf("handleSendFile: newUpstreamRequest: %v", err)) return } @@ -24,7 +25,7 @@ func handleSendFile(w http.ResponseWriter, r *gitRequest) { upResponse, err := r.u.httpClient.Do(upRequest) r.Body.Close() if err != nil { - fail500(w, "do upstream request", err) + fail500(w, fmt.Errorf("handleSendfile:do upstream request: %v", err)) return } @@ -45,7 +46,7 @@ func handleSendFile(w http.ResponseWriter, r *gitRequest) { // Copy body from Rails upResponse if _, err := io.Copy(w, upResponse.Body); err != nil { - fail500(w, "Couldn't finalize X-File download request.", err) + fail500(w, fmt.Errorf("handleSendFile: copy upstream response: %v", err)) } return } @@ -54,14 +55,14 @@ func handleSendFile(w http.ResponseWriter, r *gitRequest) { upResponse.Body.Close() content, err := os.Open(sendfile) if err != nil { - fail500(w, "open sendfile", err) + fail500(w, fmt.Errorf("handleSendile: open sendfile: %v", err)) return } defer content.Close() fi, err := content.Stat() if err != nil { - fail500(w, "xSendFile get mtime", err) + fail500(w, fmt.Errorf("handleSendfile: get mtime: %v", err)) return } http.ServeContent(w, r.Request, "", fi.ModTime(), content)