[DRE-commits] [gitlab-workhorse] 02/03: Imported Upstream version 0.7.2
Dmitry Smirnov
onlyjob at moszumanska.debian.org
Mon Jul 18 06:37:38 UTC 2016
This is an automated email from the git hooks/post-receive script.
onlyjob pushed a commit to branch master
in repository gitlab-workhorse.
commit 94bbbda
Author: Dmitry Smirnov <onlyjob at member.fsf.org>
Date: Mon Jul 18 06:37:02 2016
Imported Upstream version 0.7.2
---
.gitignore | 1 +
CHANGELOG | 23 +++++++++
Makefile | 36 +++++++++----
README.md | 39 ++++----------
VERSION | 2 +-
authorization_test.go | 7 +--
cmd/gitlab-zip-cat/main.go | 5 +-
cmd/gitlab-zip-metadata/main.go | 3 +-
internal/api/api.go | 14 ++---
internal/artifacts/artifact_download.go | 7 +--
internal/artifacts/artifact_download_test.go | 7 +--
internal/artifacts/artifacts_upload.go | 9 ++--
internal/artifacts/artifacts_upload_test.go | 11 ++--
internal/badgateway/roundtripper.go | 3 +-
internal/delay/responsewriter.go | 76 ++++++++++++++++++++++++++++
internal/delay/responsewriter_test.go | 53 +++++++++++++++++++
internal/git/archive.go | 36 +++++++++----
internal/git/blob.go | 42 +++++++--------
internal/git/git-http.go | 30 ++++++-----
internal/lfs/lfs.go | 10 ++--
internal/proxy/proxy.go | 10 ++--
internal/senddata/injecter.go | 32 ++++++++++++
internal/senddata/senddata.go | 75 +++++++++++++++++++++++++++
internal/senddata/senddata_test.go | 20 ++++++++
internal/{senddata => sendfile}/sendfile.go | 37 ++++++--------
internal/staticpages/deploy_page.go | 3 +-
internal/staticpages/deploy_page_test.go | 3 +-
internal/staticpages/error_pages.go | 3 +-
internal/staticpages/error_pages_test.go | 3 +-
internal/staticpages/servefile.go | 5 +-
internal/staticpages/servefile_test.go | 3 +-
internal/upload/uploads.go | 3 +-
internal/upload/uploads_test.go | 7 +--
internal/upstream/development_test.go | 3 +-
internal/upstream/handlers.go | 3 +-
internal/upstream/handlers_test.go | 3 +-
internal/upstream/routes.go | 41 +++++++--------
internal/upstream/upstream.go | 7 +--
main.go | 5 +-
main_test.go | 68 ++++++++++++++-----------
proxy_test.go | 9 ++--
41 files changed, 526 insertions(+), 231 deletions(-)
diff --git a/.gitignore b/.gitignore
index acb538e..9bde789 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ testdata/scratch
testdata/public
gitlab-zip-cat
gitlab-zip-metadata
+_build
diff --git a/CHANGELOG b/CHANGELOG
index 6a8c7f4..fcf30f4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,29 @@
Formerly known as 'gitlab-git-http-server'.
+v0.7.2
+
+Integrate with GOPATH during development (remove relative imports
+etc.). Buffer Git HTTP responses so that we may return an error if the
+local command fails early.
+
+v0.7.1
+
+Set Content-Length (retrieved from Git) on raw blob data responses.
+
+v0.7.0
+
+Start using a 'v' prefix on the version string.
+
+0.6.5
+
+Inject 'git archive' data the same way as Git blob data.
+
+0.6.4
+
+Increase default ProxyHeadersTimeout to 5 minutes. Fix injecting raw
+blobs for /api/v3 requetsts.
+
0.6.3
Add support for sending Git raw git blobs via gitlab-workhorse.
diff --git a/Makefile b/Makefile
index 197ca4b..9b3146d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,26 +1,33 @@
PREFIX=/usr/local
VERSION=$(shell git describe)-$(shell date -u +%Y%m%d.%H%M%S)
+export GOPATH=$(shell pwd)/_build
GOBUILD=go build -ldflags "-X main.Version=${VERSION}"
+PKG=gitlab.com/gitlab-org/gitlab-workhorse
-all: gitlab-zip-cat gitlab-zip-metadata gitlab-workhorse
+all: clean-build gitlab-zip-cat gitlab-zip-metadata gitlab-workhorse
-gitlab-zip-cat: $(shell find cmd/gitlab-zip-cat/ -name '*.go')
- ${GOBUILD} -o $@ ./cmd/$@
+gitlab-zip-cat: _build $(shell find cmd/gitlab-zip-cat/ -name '*.go')
+ ${GOBUILD} -o $@ ${PKG}/cmd/$@
-gitlab-zip-metadata: $(shell find cmd/gitlab-zip-metadata/ -name '*.go')
- ${GOBUILD} -o $@ ./cmd/$@
+gitlab-zip-metadata: _build $(shell find cmd/gitlab-zip-metadata/ -name '*.go')
+ ${GOBUILD} -o $@ ${PKG}/cmd/$@
-gitlab-workhorse: $(shell find . -name '*.go')
- ${GOBUILD} -o $@
+gitlab-workhorse: _build $(shell find . -name '*.go' | grep -v '^\./_')
+ ${GOBUILD} -o $@ ${PKG}
install: gitlab-workhorse gitlab-zip-cat gitlab-zip-metadata
mkdir -p $(DESTDIR)${PREFIX}/bin/
install gitlab-workhorse gitlab-zip-cat gitlab-zip-metadata ${DESTDIR}${PREFIX}/bin/
+_build:
+ mkdir -p $@/src/${PKG}
+ tar -cf - --exclude $@ --exclude .git . | (cd $@/src/${PKG} && tar -xf -)
+ touch $@
+
.PHONY: test
-test: testdata/data/group/test.git clean-workhorse all
- go fmt ./... | awk '{ print } END { if (NR > 0) { print "Please run go fmt"; exit 1 } }'
- support/path go test ./...
+test: testdata/data/group/test.git clean-build clean-workhorse all
+ go fmt ${PKG}/... | awk '{ print } END { if (NR > 0) { print "Please run go fmt"; exit 1 } }'
+ support/path go test ${PKG}/...
@echo SUCCESS
coverage: testdata/data/group/test.git
@@ -28,6 +35,9 @@ coverage: testdata/data/group/test.git
go tool cover -html=test.coverage -o coverage.html
rm -f test.coverage
+fmt:
+ go fmt ./...
+
testdata/data/group/test.git: testdata/data
git clone --bare https://gitlab.com/gitlab-org/gitlab-test.git $@
@@ -35,9 +45,13 @@ testdata/data:
mkdir -p $@
.PHONY: clean
-clean: clean-workhorse
+clean: clean-workhorse clean-build
rm -rf testdata/data testdata/scratch
.PHONY: clean-workhorse
clean-workhorse:
rm -f gitlab-workhorse gitlab-zip-cat gitlab-zip-metadata
+
+.PHONY: clean-build
+clean-build:
+ rm -rf _build
diff --git a/README.md b/README.md
index a6a674c..e228cc5 100644
--- a/README.md
+++ b/README.md
@@ -70,42 +70,21 @@ make install PREFIX=/foo
## Tests
-```
-make clean test
-```
-
-## Try it out
-
-You can try out the Git server without authentication as follows:
+Run the tests with:
```
-# Start a fake auth backend that allows everything/everybody
-make test/data/test.git
-go run support/fake-auth-backend.go ~+/test/data/test.git &
-# Start gitlab-workhorse
-make
-./gitlab-workhorse
+make clean test
```
-Now you can try things like:
+### Coverage / what to test
-```
-git clone http://localhost:8181/test.git
-curl -JO http://localhost:8181/test/repository/archive.zip
-```
+Each feature in gitlab-workhorse should have an integration test that
+verifies that the feature 'kicks in' on the right requests and leaves
+other requests unaffected. It is better to also have package-level tests
+for specific behavior but the high-level integration tests should have
+the first priority during development.
-## Example request flow
-
-- start POST repo.git/git-receive-pack to NGINX
-- ..start POST repo.git/git-receive-pack to gitlab-workhorse
-- ....start POST repo.git/git-receive-pack to Unicorn for auth
-- ....end POST to Unicorn for auth
-- ....start git-receive-pack process from gitlab-workhorse
-- ......start POST /api/v3/internal/allowed to Unicorn from Git hook (check protected branches)
-- ......end POST to Unicorn from Git hook
-- ....end git-receive-pack process
-- ..end POST to gitlab-workhorse
-- end POST to NGINX
+It is OK if a feature is only covered by integration tests.
## License
diff --git a/VERSION b/VERSION
index 844f6a9..7486fdb 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.6.3
+0.7.2
diff --git a/authorization_test.go b/authorization_test.go
index 7b12e05..6f67f23 100644
--- a/authorization_test.go
+++ b/authorization_test.go
@@ -1,14 +1,15 @@
package main
import (
- "./internal/api"
- "./internal/helper"
- "./internal/testhelper"
"fmt"
"net/http"
"net/http/httptest"
"regexp"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func okHandler(w http.ResponseWriter, _ *http.Request, _ *api.Response) {
diff --git a/cmd/gitlab-zip-cat/main.go b/cmd/gitlab-zip-cat/main.go
index e86edfd..29d233e 100644
--- a/cmd/gitlab-zip-cat/main.go
+++ b/cmd/gitlab-zip-cat/main.go
@@ -1,12 +1,13 @@
package main
import (
- "../../internal/zipartifacts"
"archive/zip"
"flag"
"fmt"
"io"
"os"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/zipartifacts"
)
const progName = "gitlab-zip-cat"
@@ -25,7 +26,7 @@ func main() {
}
if len(os.Args) != 3 {
- fmt.Fprintf(os.Stderr, "Usage: %s FILE.ZIP ENTRY", progName)
+ fmt.Fprintf(os.Stderr, "Usage: %s FILE.ZIP ENTRY\n", progName)
os.Exit(1)
}
diff --git a/cmd/gitlab-zip-metadata/main.go b/cmd/gitlab-zip-metadata/main.go
index b399275..1487701 100644
--- a/cmd/gitlab-zip-metadata/main.go
+++ b/cmd/gitlab-zip-metadata/main.go
@@ -1,10 +1,11 @@
package main
import (
- "../../internal/zipartifacts"
"flag"
"fmt"
"os"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/zipartifacts"
)
const progName = "gitlab-zip-metadata"
diff --git a/internal/api/api.go b/internal/api/api.go
index b23ea7e..51c1ff2 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -1,8 +1,6 @@
package api
import (
- "../badgateway"
- "../helper"
"encoding/json"
"fmt"
"io"
@@ -10,6 +8,9 @@ import (
"net/http"
"net/url"
"strings"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
type API struct {
@@ -38,15 +39,6 @@ type Response struct {
// 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
diff --git a/internal/artifacts/artifact_download.go b/internal/artifacts/artifact_download.go
index 71dd322..4c296bf 100644
--- a/internal/artifacts/artifact_download.go
+++ b/internal/artifacts/artifact_download.go
@@ -1,9 +1,6 @@
package artifacts
import (
- "../api"
- "../helper"
- "../zipartifacts"
"bufio"
"errors"
"fmt"
@@ -15,6 +12,10 @@ import (
"path/filepath"
"strings"
"syscall"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/zipartifacts"
)
func detectFileContentType(fileName string) string {
diff --git a/internal/artifacts/artifact_download_test.go b/internal/artifacts/artifact_download_test.go
index c7a6cab..381affa 100644
--- a/internal/artifacts/artifact_download_test.go
+++ b/internal/artifacts/artifact_download_test.go
@@ -1,9 +1,6 @@
package artifacts
import (
- "../api"
- "../helper"
- "../testhelper"
"archive/zip"
"encoding/base64"
"encoding/json"
@@ -13,6 +10,10 @@ import (
"net/http/httptest"
"os"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func testArtifactDownloadServer(t *testing.T, archive string, entry string) *httptest.Server {
diff --git a/internal/artifacts/artifacts_upload.go b/internal/artifacts/artifacts_upload.go
index f060ec9..6bff536 100644
--- a/internal/artifacts/artifacts_upload.go
+++ b/internal/artifacts/artifacts_upload.go
@@ -1,10 +1,6 @@
package artifacts
import (
- "../api"
- "../helper"
- "../upload"
- "../zipartifacts"
"errors"
"fmt"
"io/ioutil"
@@ -13,6 +9,11 @@ import (
"os"
"os/exec"
"syscall"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/upload"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/zipartifacts"
)
type artifactsUploadProcessor struct {
diff --git a/internal/artifacts/artifacts_upload_test.go b/internal/artifacts/artifacts_upload_test.go
index 63ab83f..c47b867 100644
--- a/internal/artifacts/artifacts_upload_test.go
+++ b/internal/artifacts/artifacts_upload_test.go
@@ -1,11 +1,6 @@
package artifacts
import (
- "../api"
- "../helper"
- "../proxy"
- "../testhelper"
- "../zipartifacts"
"archive/zip"
"bytes"
"compress/gzip"
@@ -18,6 +13,12 @@ import (
"net/http/httptest"
"os"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/zipartifacts"
)
func testArtifactsUploadServer(t *testing.T, tempPath string) *httptest.Server {
diff --git a/internal/badgateway/roundtripper.go b/internal/badgateway/roundtripper.go
index b6c153c..5b7d855 100644
--- a/internal/badgateway/roundtripper.go
+++ b/internal/badgateway/roundtripper.go
@@ -1,13 +1,14 @@
package badgateway
import (
- "../helper"
"bytes"
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
// Values from http.DefaultTransport
diff --git a/internal/delay/responsewriter.go b/internal/delay/responsewriter.go
new file mode 100644
index 0000000..3493a5a
--- /dev/null
+++ b/internal/delay/responsewriter.go
@@ -0,0 +1,76 @@
+// Package delay exports delay.ResponseWriter. This type implements
+// http.ResponseWriter with the ability to delay setting the HTTP
+// response code (with WriteHeader()) until writing the first bufferSize
+// bytes. This makes it possible, up to a point, to 'change your mind'
+// about the HTTP status code. The caller must call
+// ResponseWriter.Flush() before returning from the handler (e.g. using
+// 'defer').
+
+package delay
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+)
+
+const bufferSize = 8192
+
+type ResponseWriter struct {
+ writer http.ResponseWriter
+ status int
+ bufWritten int
+ cap int
+ flushed bool
+ buffer *bytes.Buffer
+}
+
+func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
+ return &ResponseWriter{
+ writer: w,
+ buffer: bytes.NewBuffer(make([]byte, 0, bufferSize)),
+ cap: bufferSize,
+ }
+}
+
+func (rw *ResponseWriter) Write(buf []byte) (int, error) {
+ if !rw.flushed && len(buf)+rw.bufWritten <= rw.cap {
+ n, err := rw.buffer.Write(buf)
+ rw.bufWritten += n
+ return n, err
+ }
+
+ if err := rw.Flush(); err != nil {
+ return 0, err
+ }
+
+ return rw.writer.Write(buf)
+}
+
+func (rw *ResponseWriter) Header() http.Header {
+ return rw.writer.Header()
+}
+
+func (rw *ResponseWriter) WriteHeader(code int) {
+ if rw.status != 0 {
+ return
+ }
+ rw.status = code
+}
+
+func (rw *ResponseWriter) Flush() error {
+ if rw.flushed {
+ return nil
+ }
+ rw.flushed = true
+
+ if rw.status == 0 {
+ rw.writer.WriteHeader(http.StatusOK)
+ } else {
+ rw.writer.WriteHeader(rw.status)
+ }
+
+ _, err := io.Copy(rw.writer, rw.buffer)
+ rw.buffer = nil // "Release" the buffer for GC
+ return err
+}
diff --git a/internal/delay/responsewriter_test.go b/internal/delay/responsewriter_test.go
new file mode 100644
index 0000000..5717a2b
--- /dev/null
+++ b/internal/delay/responsewriter_test.go
@@ -0,0 +1,53 @@
+package delay
+
+import (
+ "fmt"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestSanity(t *testing.T) {
+ first, second := 200, 500
+ w := httptest.NewRecorder()
+ w.WriteHeader(first)
+ w.WriteHeader(second)
+ if code := w.Code; code != first {
+ t.Fatalf("Expected HTTP code %d, got %d", first, code)
+ }
+}
+
+func TestSmallResponse(t *testing.T) {
+ code := 500
+ body := "hello"
+ w := httptest.NewRecorder()
+ rw := NewResponseWriter(w)
+ fmt.Fprint(rw, body)
+ rw.WriteHeader(code)
+ rw.Flush()
+
+ if actualCode := w.Code; actualCode != code {
+ t.Fatalf("Expected code %d, got %d", code, actualCode)
+ }
+ if actualBody := w.Body.String(); actualBody != body {
+ t.Fatalf("Expected body %q, got %q", body, actualBody)
+ }
+}
+
+func TestLargeResponse(t *testing.T) {
+ code := 200
+ body := strings.Repeat("0123456789", bufferSize/5) // must exceed the buffer size
+ w := httptest.NewRecorder()
+ rw := NewResponseWriter(w)
+ fmt.Fprint(rw, body)
+ // Because the 'body' was too long this 500 should be ignored
+ rw.WriteHeader(500)
+ rw.Flush()
+
+ if actualCode := w.Code; actualCode != code {
+ t.Fatalf("Expected code %d, got %d", code, actualCode)
+ }
+ if actualBody := w.Body.String(); actualBody != body {
+ t.Fatalf("Expected body %q, got %q", body, actualBody)
+ }
+}
diff --git a/internal/git/archive.go b/internal/git/archive.go
index 854c887..cffc12c 100644
--- a/internal/git/archive.go
+++ b/internal/git/archive.go
@@ -5,8 +5,6 @@ In this file we handle 'git archive' downloads
package git
import (
- "../api"
- "../helper"
"fmt"
"io"
"io/ioutil"
@@ -18,13 +16,28 @@ import (
"path/filepath"
"syscall"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/senddata"
)
-func GetArchive(a *api.API) http.Handler {
- return repoPreAuthorizeHandler(a, handleGetArchive)
+type archive struct{ senddata.Prefix }
+type archiveParams struct {
+ RepoPath string
+ ArchivePath string
+ ArchivePrefix string
+ CommitId string
}
-func handleGetArchive(w http.ResponseWriter, r *http.Request, a *api.Response) {
+var SendArchive = &archive{"git-archive:"}
+
+func (a *archive) Inject(w http.ResponseWriter, r *http.Request, sendData string) {
+ var params archiveParams
+ if err := a.Unpack(¶ms, sendData); err != nil {
+ helper.Fail500(w, fmt.Errorf("SendArchive: unpack sendData: %v", err))
+ return
+ }
+
var format string
urlPath := r.URL.Path
switch filepath.Base(urlPath) {
@@ -41,11 +54,11 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *api.Response) {
return
}
- archiveFilename := path.Base(a.ArchivePath)
+ archiveFilename := path.Base(params.ArchivePath)
- if cachedArchive, err := os.Open(a.ArchivePath); err == nil {
+ if cachedArchive, err := os.Open(params.ArchivePath); err == nil {
defer cachedArchive.Close()
- log.Printf("Serving cached file %q", a.ArchivePath)
+ log.Printf("Serving cached file %q", params.ArchivePath)
setArchiveHeaders(w, format, archiveFilename)
// Even if somebody deleted the cachedArchive from disk since we opened
// the file, Unix file semantics guarantee we can still read from the
@@ -58,7 +71,7 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *api.Response) {
// safe. We create the tempfile in the same directory as the final cached
// archive we want to create so that we can use an atomic link(2) operation
// to finalize the cached archive.
- tempFile, err := prepareArchiveTempfile(path.Dir(a.ArchivePath), archiveFilename)
+ tempFile, err := prepareArchiveTempfile(path.Dir(params.ArchivePath), archiveFilename)
if err != nil {
helper.Fail500(w, fmt.Errorf("handleGetArchive: create tempfile: %v", err))
return
@@ -68,7 +81,7 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *api.Response) {
compressCmd, archiveFormat := parseArchiveFormat(format)
- archiveCmd := gitCommand("", "git", "--git-dir="+a.RepoPath, "archive", "--format="+archiveFormat, "--prefix="+a.ArchivePrefix+"/", a.CommitId)
+ archiveCmd := gitCommand("", "git", "--git-dir="+params.RepoPath, "archive", "--format="+archiveFormat, "--prefix="+params.ArchivePrefix+"/", params.CommitId)
archiveStdout, err := archiveCmd.StdoutPipe()
if err != nil {
helper.Fail500(w, fmt.Errorf("handleGetArchive: archive stdout: %v", err))
@@ -125,13 +138,14 @@ func handleGetArchive(w http.ResponseWriter, r *http.Request, a *api.Response) {
}
}
- if err := finalizeCachedArchive(tempFile, a.ArchivePath); err != nil {
+ if err := finalizeCachedArchive(tempFile, params.ArchivePath); err != nil {
helper.LogError(fmt.Errorf("handleGetArchive: finalize cached archive: %v", err))
return
}
}
func setArchiveHeaders(w http.ResponseWriter, format string, archiveFilename string) {
+ w.Header().Del("Content-Length")
w.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, archiveFilename))
if format == "zip" {
w.Header().Add("Content-Type", "application/zip")
diff --git a/internal/git/blob.go b/internal/git/blob.go
index aa1b7d6..9f4634d 100644
--- a/internal/git/blob.go
+++ b/internal/git/blob.go
@@ -1,35 +1,40 @@
package git
import (
- "../helper"
- "encoding/base64"
- "encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/senddata"
)
-type blobParams struct {
- RepoPath string
- BlobId string
-}
+type blob struct{ senddata.Prefix }
+type blobParams struct{ RepoPath, BlobId string }
-const SendBlobPrefix = "git-blob:"
+var SendBlob = &blob{"git-blob:"}
-func SendBlob(w http.ResponseWriter, r *http.Request, sendData string) {
- params, err := unpackSendData(sendData)
- if err != nil {
+func (b *blob) Inject(w http.ResponseWriter, r *http.Request, sendData string) {
+ var params blobParams
+ if err := b.Unpack(¶ms, sendData); err != nil {
helper.Fail500(w, fmt.Errorf("SendBlob: unpack sendData: %v", err))
return
}
+
log.Printf("SendBlob: sending %q for %q", params.BlobId, r.URL.Path)
+ sizeOutput, err := gitCommand("", "git", "--git-dir="+params.RepoPath, "cat-file", "-s", params.BlobId).Output()
+ if err != nil {
+ helper.Fail500(w, fmt.Errorf("SendBlob: get blob size: %v", err))
+ return
+ }
+
gitShowCmd := gitCommand("", "git", "--git-dir="+params.RepoPath, "cat-file", "blob", params.BlobId)
stdout, err := gitShowCmd.StdoutPipe()
if err != nil {
- helper.Fail500(w, fmt.Errorf("SendBlob: git stdout: %v", err))
+ helper.Fail500(w, fmt.Errorf("SendBlob: git cat-file stdout: %v", err))
return
}
if err := gitShowCmd.Start(); err != nil {
@@ -38,6 +43,7 @@ func SendBlob(w http.ResponseWriter, r *http.Request, sendData string) {
}
defer helper.CleanUpProcessGroup(gitShowCmd)
+ w.Header().Set("Content-Length", strings.TrimSpace(string(sizeOutput)))
if _, err := io.Copy(w, stdout); err != nil {
helper.LogError(fmt.Errorf("SendBlob: copy git cat-file stdout: %v", err))
return
@@ -47,15 +53,3 @@ func SendBlob(w http.ResponseWriter, r *http.Request, sendData string) {
return
}
}
-
-func unpackSendData(sendData string) (*blobParams, error) {
- jsonBytes, err := base64.URLEncoding.DecodeString(strings.TrimPrefix(sendData, SendBlobPrefix))
- if err != nil {
- return nil, err
- }
- result := &blobParams{}
- if err := json.Unmarshal([]byte(jsonBytes), result); err != nil {
- return nil, err
- }
- return result, nil
-}
diff --git a/internal/git/git-http.go b/internal/git/git-http.go
index d0c41b8..4b75e04 100644
--- a/internal/git/git-http.go
+++ b/internal/git/git-http.go
@@ -5,8 +5,6 @@ In this file we handle the Git 'smart HTTP' protocol
package git
import (
- "../api"
- "../helper"
"errors"
"fmt"
"io"
@@ -16,6 +14,10 @@ import (
"path"
"path/filepath"
"strings"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/delay"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
func GetInfoRefs(a *api.API) http.Handler {
@@ -52,7 +54,10 @@ func repoPreAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.Han
}, "")
}
-func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *api.Response) {
+func handleGetInfoRefs(_w http.ResponseWriter, r *http.Request, a *api.Response) {
+ w := delay.NewResponseWriter(_w)
+ defer w.Flush()
+
rpc := r.URL.Query().Get("service")
if !(rpc == "git-upload-pack" || rpc == "git-receive-pack") {
// The 'dumb' Git HTTP protocol is not supported
@@ -77,26 +82,28 @@ func handleGetInfoRefs(w http.ResponseWriter, r *http.Request, a *api.Response)
// Start writing the response
w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-advertisement", rpc))
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 {
- helper.LogError(fmt.Errorf("handleGetInfoRefs: pktLine: %v", err))
+ helper.Fail500(w, fmt.Errorf("handleGetInfoRefs: pktLine: %v", err))
return
}
if err := pktFlush(w); err != nil {
- helper.LogError(fmt.Errorf("handleGetInfoRefs: pktFlush: %v", err))
+ helper.Fail500(w, fmt.Errorf("handleGetInfoRefs: pktFlush: %v", err))
return
}
if _, err := io.Copy(w, stdout); err != nil {
- helper.LogError(fmt.Errorf("handleGetInfoRefs: copy output of %v: %v", cmd.Args, err))
+ helper.Fail500(w, fmt.Errorf("handleGetInfoRefs: copy output of %v: %v", cmd.Args, err))
return
}
if err := cmd.Wait(); err != nil {
- helper.LogError(fmt.Errorf("handleGetInfoRefs: wait for %v: %v", cmd.Args, err))
+ helper.Fail500(w, fmt.Errorf("handleGetInfoRefs: wait for %v: %v", cmd.Args, err))
return
}
}
-func handlePostRPC(w http.ResponseWriter, r *http.Request, a *api.Response) {
+func handlePostRPC(_w http.ResponseWriter, r *http.Request, a *api.Response) {
+ w := delay.NewResponseWriter(_w)
+ defer w.Flush()
+
var err error
// Get Git action from URL
@@ -142,15 +149,14 @@ func handlePostRPC(w http.ResponseWriter, r *http.Request, a *api.Response) {
// Start writing the response
w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-result", action))
w.Header().Add("Cache-Control", "no-cache")
- w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just return
// This io.Copy may take a long time, both for Git push and pull.
if _, err := io.Copy(w, stdout); err != nil {
- helper.LogError(fmt.Errorf("handlePostRPC copy output of %v: %v", cmd.Args, err))
+ helper.Fail500(w, fmt.Errorf("handlePostRPC copy output of %v: %v", cmd.Args, err))
return
}
if err := cmd.Wait(); err != nil {
- helper.LogError(fmt.Errorf("handlePostRPC wait for %v: %v", cmd.Args, err))
+ helper.Fail500(w, fmt.Errorf("handlePostRPC wait for %v: %v", cmd.Args, err))
return
}
}
diff --git a/internal/lfs/lfs.go b/internal/lfs/lfs.go
index 6d78cb6..c65256b 100644
--- a/internal/lfs/lfs.go
+++ b/internal/lfs/lfs.go
@@ -5,9 +5,6 @@ In this file we handle git lfs objects downloads and uploads
package lfs
import (
- "../api"
- "../helper"
- "../proxy"
"bytes"
"crypto/sha256"
"encoding/hex"
@@ -18,10 +15,13 @@ import (
"net/http"
"os"
"path/filepath"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
-func PutStore(a *api.API, p *proxy.Proxy) http.Handler {
- return lfsAuthorizeHandler(a, handleStoreLfsObject(p))
+func PutStore(a *api.API, h http.Handler) http.Handler {
+ return lfsAuthorizeHandler(a, handleStoreLfsObject(h))
}
func lfsAuthorizeHandler(myAPI *api.API, handleFunc api.HandleFunc) http.Handler {
diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go
index 39422f9..f83d41d 100644
--- a/internal/proxy/proxy.go
+++ b/internal/proxy/proxy.go
@@ -1,12 +1,12 @@
package proxy
import (
- "../badgateway"
- "../helper"
- "../senddata"
"net/http"
"net/http/httputil"
"net/url"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
type Proxy struct {
@@ -34,8 +34,6 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Set Workhorse version
req.Header.Set("Gitlab-Workhorse", p.Version)
- rw := senddata.NewSendFileResponseWriter(w, &req)
- defer rw.Flush()
- p.reverseProxy.ServeHTTP(&rw, &req)
+ p.reverseProxy.ServeHTTP(w, &req)
}
diff --git a/internal/senddata/injecter.go b/internal/senddata/injecter.go
new file mode 100644
index 0000000..72d8039
--- /dev/null
+++ b/internal/senddata/injecter.go
@@ -0,0 +1,32 @@
+package senddata
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "net/http"
+ "strings"
+)
+
+type Injecter interface {
+ Match(string) bool
+ Inject(http.ResponseWriter, *http.Request, string)
+}
+
+type Prefix string
+
+const HeaderKey = "Gitlab-Workhorse-Send-Data"
+
+func (p Prefix) Match(s string) bool {
+ return strings.HasPrefix(s, string(p))
+}
+
+func (p Prefix) Unpack(result interface{}, sendData string) error {
+ jsonBytes, err := base64.URLEncoding.DecodeString(strings.TrimPrefix(sendData, string(p)))
+ if err != nil {
+ return err
+ }
+ if err := json.Unmarshal([]byte(jsonBytes), result); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/internal/senddata/senddata.go b/internal/senddata/senddata.go
new file mode 100644
index 0000000..cc163c9
--- /dev/null
+++ b/internal/senddata/senddata.go
@@ -0,0 +1,75 @@
+package senddata
+
+import (
+ "net/http"
+)
+
+type sendDataResponseWriter struct {
+ rw http.ResponseWriter
+ status int
+ hijacked bool
+ req *http.Request
+ injecters []Injecter
+}
+
+func SendData(h http.Handler, injecters ...Injecter) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ s := sendDataResponseWriter{
+ rw: w,
+ req: r,
+ injecters: injecters,
+ }
+ defer s.Flush()
+ h.ServeHTTP(&s, r)
+ })
+}
+
+func (s *sendDataResponseWriter) Header() http.Header {
+ return s.rw.Header()
+}
+
+func (s *sendDataResponseWriter) Write(data []byte) (n int, err error) {
+ if s.status == 0 {
+ s.WriteHeader(http.StatusOK)
+ }
+ if s.hijacked {
+ return
+ }
+ return s.rw.Write(data)
+}
+
+func (s *sendDataResponseWriter) WriteHeader(status int) {
+ if s.status != 0 {
+ return
+ }
+ s.status = status
+
+ if s.status == http.StatusOK && s.tryInject() {
+ return
+ }
+
+ s.Header().Del(HeaderKey)
+ s.rw.WriteHeader(s.status)
+}
+
+func (s *sendDataResponseWriter) tryInject() bool {
+ header := s.Header().Get(HeaderKey)
+ s.Header().Del(HeaderKey)
+ if header == "" {
+ return false
+ }
+
+ for _, injecter := range s.injecters {
+ if injecter.Match(header) {
+ s.hijacked = true
+ injecter.Inject(s.rw, s.req, header)
+ return true
+ }
+ }
+
+ return false
+}
+
+func (s *sendDataResponseWriter) Flush() {
+ s.WriteHeader(http.StatusOK)
+}
diff --git a/internal/senddata/senddata_test.go b/internal/senddata/senddata_test.go
new file mode 100644
index 0000000..f28f3f4
--- /dev/null
+++ b/internal/senddata/senddata_test.go
@@ -0,0 +1,20 @@
+package senddata
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestHeaderDelete(t *testing.T) {
+ for _, code := range []int{200, 400} {
+ recorder := httptest.NewRecorder()
+ rw := &sendDataResponseWriter{rw: recorder, req: &http.Request{}}
+ rw.Header().Set(HeaderKey, "foobar")
+ rw.WriteHeader(code)
+
+ if header := recorder.Header().Get(HeaderKey); header != "" {
+ t.Fatalf("HTTP %d response: expected header to be empty, found %q", code, header)
+ }
+ }
+}
diff --git a/internal/senddata/sendfile.go b/internal/sendfile/sendfile.go
similarity index 69%
rename from internal/senddata/sendfile.go
rename to internal/sendfile/sendfile.go
index 7d851d6..cd28e45 100644
--- a/internal/senddata/sendfile.go
+++ b/internal/sendfile/sendfile.go
@@ -4,21 +4,17 @@ via the X-Sendfile mechanism. All that is needed in the Rails code is the
'send_file' method.
*/
-package senddata
+package sendfile
import (
- "../git"
- "../helper"
"log"
"net/http"
- "strings"
-)
-const (
- sendDataResponseHeader = "Gitlab-Workhorse-Send-Data"
- sendFileResponseHeader = "X-Sendfile"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
+const sendFileResponseHeader = "X-Sendfile"
+
type sendFileResponseWriter struct {
rw http.ResponseWriter
status int
@@ -26,14 +22,17 @@ type sendFileResponseWriter struct {
req *http.Request
}
-func NewSendFileResponseWriter(rw http.ResponseWriter, req *http.Request) sendFileResponseWriter {
- s := sendFileResponseWriter{
- rw: rw,
- req: req,
- }
- // Advertise to upstream (Rails) that we support X-Sendfile
- req.Header.Set("X-Sendfile-Type", "X-Sendfile")
- return s
+func SendFile(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ s := &sendFileResponseWriter{
+ rw: rw,
+ req: req,
+ }
+ // Advertise to upstream (Rails) that we support X-Sendfile
+ req.Header.Set("X-Sendfile-Type", "X-Sendfile")
+ defer s.Flush()
+ h.ServeHTTP(s, req)
+ })
}
func (s *sendFileResponseWriter) Header() http.Header {
@@ -70,12 +69,6 @@ func (s *sendFileResponseWriter) WriteHeader(status int) {
sendFileFromDisk(s.rw, s.req, file)
return
}
- if sendData := s.Header().Get(sendDataResponseHeader); strings.HasPrefix(sendData, git.SendBlobPrefix) {
- s.Header().Del(sendDataResponseHeader)
- s.hijacked = true
- git.SendBlob(s.rw, s.req, sendData)
- return
- }
s.rw.WriteHeader(s.status)
return
diff --git a/internal/staticpages/deploy_page.go b/internal/staticpages/deploy_page.go
index b777fbc..d08ed44 100644
--- a/internal/staticpages/deploy_page.go
+++ b/internal/staticpages/deploy_page.go
@@ -1,10 +1,11 @@
package staticpages
import (
- "../helper"
"io/ioutil"
"net/http"
"path/filepath"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
func (s *Static) DeployPage(handler http.Handler) http.Handler {
diff --git a/internal/staticpages/deploy_page_test.go b/internal/staticpages/deploy_page_test.go
index 2e4be67..fd02de4 100644
--- a/internal/staticpages/deploy_page_test.go
+++ b/internal/staticpages/deploy_page_test.go
@@ -1,13 +1,14 @@
package staticpages
import (
- "../testhelper"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func TestIfNoDeployPageExist(t *testing.T) {
diff --git a/internal/staticpages/error_pages.go b/internal/staticpages/error_pages.go
index 958c32e..1f57636 100644
--- a/internal/staticpages/error_pages.go
+++ b/internal/staticpages/error_pages.go
@@ -1,12 +1,13 @@
package staticpages
import (
- "../helper"
"fmt"
"io/ioutil"
"log"
"net/http"
"path/filepath"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
type errorPageResponseWriter struct {
diff --git a/internal/staticpages/error_pages_test.go b/internal/staticpages/error_pages_test.go
index 72d259d..c391c3b 100644
--- a/internal/staticpages/error_pages_test.go
+++ b/internal/staticpages/error_pages_test.go
@@ -1,7 +1,6 @@
package staticpages
import (
- "../testhelper"
"fmt"
"io/ioutil"
"net/http"
@@ -9,6 +8,8 @@ import (
"os"
"path/filepath"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func TestIfErrorPageIsPresented(t *testing.T) {
diff --git a/internal/staticpages/servefile.go b/internal/staticpages/servefile.go
index 5349935..82e8d1d 100644
--- a/internal/staticpages/servefile.go
+++ b/internal/staticpages/servefile.go
@@ -1,14 +1,15 @@
package staticpages
import (
- "../helper"
- "../urlprefix"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/urlprefix"
)
type CacheMode int
diff --git a/internal/staticpages/servefile_test.go b/internal/staticpages/servefile_test.go
index 860d0a8..652573d 100644
--- a/internal/staticpages/servefile_test.go
+++ b/internal/staticpages/servefile_test.go
@@ -1,7 +1,6 @@
package staticpages
import (
- "../testhelper"
"bytes"
"compress/gzip"
"io/ioutil"
@@ -10,6 +9,8 @@ import (
"os"
"path/filepath"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func TestServingNonExistingFile(t *testing.T) {
diff --git a/internal/upload/uploads.go b/internal/upload/uploads.go
index 55dab71..2318b9e 100644
--- a/internal/upload/uploads.go
+++ b/internal/upload/uploads.go
@@ -1,7 +1,6 @@
package upload
import (
- "../helper"
"bytes"
"fmt"
"io"
@@ -9,6 +8,8 @@ import (
"mime/multipart"
"net/http"
"os"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
type MultipartFormProcessor interface {
diff --git a/internal/upload/uploads_test.go b/internal/upload/uploads_test.go
index f779b50..0f8272f 100644
--- a/internal/upload/uploads_test.go
+++ b/internal/upload/uploads_test.go
@@ -1,9 +1,6 @@
package upload
import (
- "../helper"
- "../proxy"
- "../testhelper"
"bytes"
"errors"
"fmt"
@@ -16,6 +13,10 @@ import (
"regexp"
"strings"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
var nilHandler = http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
diff --git a/internal/upstream/development_test.go b/internal/upstream/development_test.go
index d83fd35..bfe6a4a 100644
--- a/internal/upstream/development_test.go
+++ b/internal/upstream/development_test.go
@@ -1,10 +1,11 @@
package upstream
import (
- "../testhelper"
"net/http"
"net/http/httptest"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func TestDevelopmentModeEnabled(t *testing.T) {
diff --git a/internal/upstream/handlers.go b/internal/upstream/handlers.go
index d1a96ce..7a7628c 100644
--- a/internal/upstream/handlers.go
+++ b/internal/upstream/handlers.go
@@ -1,11 +1,12 @@
package upstream
import (
- "../helper"
"compress/gzip"
"fmt"
"io"
"net/http"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
)
func contentEncodingHandler(h http.Handler) http.Handler {
diff --git a/internal/upstream/handlers_test.go b/internal/upstream/handlers_test.go
index b5357ad..3c53621 100644
--- a/internal/upstream/handlers_test.go
+++ b/internal/upstream/handlers_test.go
@@ -1,7 +1,6 @@
package upstream
import (
- "../testhelper"
"bytes"
"compress/gzip"
"fmt"
@@ -10,6 +9,8 @@ import (
"net/http/httptest"
"reflect"
"testing"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func TestGzipEncoding(t *testing.T) {
diff --git a/internal/upstream/routes.go b/internal/upstream/routes.go
index 0fe09d4..d73fccc 100644
--- a/internal/upstream/routes.go
+++ b/internal/upstream/routes.go
@@ -1,14 +1,17 @@
package upstream
import (
- apipkg "../api"
- "../artifacts"
- "../git"
- "../lfs"
- proxypkg "../proxy"
- "../staticpages"
"net/http"
"regexp"
+
+ apipkg "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/artifacts"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/git"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/lfs"
+ proxypkg "gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/senddata"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/sendfile"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/staticpages"
)
type route struct {
@@ -37,10 +40,14 @@ func (u *Upstream) configureRoutes() {
u.RoundTripper,
)
static := &staticpages.Static{u.DocumentRoot}
- proxy := proxypkg.NewProxy(
- u.Backend,
- u.Version,
- u.RoundTripper,
+ proxy := senddata.SendData(
+ sendfile.SendFile(proxypkg.NewProxy(
+ u.Backend,
+ u.Version,
+ u.RoundTripper,
+ )),
+ git.SendArchive,
+ git.SendBlob,
)
u.Routes = []route{
@@ -50,20 +57,6 @@ func (u *Upstream) configureRoutes() {
route{"POST", regexp.MustCompile(gitProjectPattern + `git-receive-pack\z`), contentEncodingHandler(git.PostRPC(api))},
route{"PUT", regexp.MustCompile(gitProjectPattern + `gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`), lfs.PutStore(api, proxy)},
- // Repository Archive
- route{"GET", regexp.MustCompile(projectPattern + `repository/archive\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectPattern + `repository/archive.zip\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar.gz\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar.bz2\z`), git.GetArchive(api)},
-
- // Repository Archive API
- route{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.zip\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar.gz\z`), git.GetArchive(api)},
- route{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar.bz2\z`), git.GetArchive(api)},
-
// CI Artifacts
route{"GET", regexp.MustCompile(projectPattern + `builds/[0-9]+/artifacts/file/`), contentEncodingHandler(artifacts.DownloadArtifact(api))},
route{"POST", regexp.MustCompile(ciAPIPattern + `v1/builds/[0-9]+/artifacts\z`), contentEncodingHandler(artifacts.UploadArtifacts(api, proxy))},
diff --git a/internal/upstream/upstream.go b/internal/upstream/upstream.go
index 19dda8d..465fd6f 100644
--- a/internal/upstream/upstream.go
+++ b/internal/upstream/upstream.go
@@ -7,14 +7,15 @@ In this file we handle request routing and interaction with the authBackend.
package upstream
import (
- "../badgateway"
- "../helper"
- "../urlprefix"
"fmt"
"net/http"
"net/url"
"strings"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/urlprefix"
)
var DefaultBackend = helper.URLMustParse("http://localhost:8080")
diff --git a/main.go b/main.go
index 91312ae..16650e5 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,6 @@ In this file we start the web server and hand off to the upstream type.
package main
import (
- "./internal/upstream"
"flag"
"fmt"
"log"
@@ -24,6 +23,8 @@ import (
"os"
"syscall"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/upstream"
)
// Current version of GitLab Workhorse
@@ -37,7 +38,7 @@ var authBackend = URLFlag("authBackend", upstream.DefaultBackend, "Authenticatio
var authSocket = flag.String("authSocket", "", "Optional: Unix domain socket to dial authBackend at")
var pprofListenAddr = flag.String("pprofListenAddr", "", "pprof listening address, e.g. 'localhost:6060'")
var documentRoot = flag.String("documentRoot", "public", "Path to static files content")
-var proxyHeadersTimeout = flag.Duration("proxyHeadersTimeout", time.Minute, "How long to wait for response headers when proxying the request")
+var proxyHeadersTimeout = flag.Duration("proxyHeadersTimeout", 5*time.Minute, "How long to wait for response headers when proxying the request")
var developmentMode = flag.Bool("developmentMode", false, "Allow to serve assets from Rails app")
func main() {
diff --git a/main_test.go b/main_test.go
index a4fed1c..9ce37f7 100644
--- a/main_test.go
+++ b/main_test.go
@@ -1,10 +1,6 @@
package main
import (
- "./internal/api"
- "./internal/helper"
- "./internal/testhelper"
- "./internal/upstream"
"bytes"
"encoding/base64"
"encoding/json"
@@ -22,6 +18,11 @@ import (
"strings"
"testing"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/upstream"
)
const scratchDir = "testdata/scratch"
@@ -115,7 +116,7 @@ func TestAllowedDownloadZip(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.zip"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -134,7 +135,7 @@ func TestAllowedDownloadTar(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.tar"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -153,7 +154,7 @@ func TestAllowedDownloadTarGz(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.tar.gz"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -172,7 +173,7 @@ func TestAllowedDownloadTarBz2(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.tar.bz2"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -191,7 +192,7 @@ func TestAllowedApiDownloadZip(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.zip"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -210,7 +211,7 @@ func TestAllowedApiDownloadZipWithSlash(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.zip"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -233,7 +234,7 @@ func TestDownloadCacheHit(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.zip"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -264,7 +265,7 @@ func TestDownloadCacheCreate(t *testing.T) {
// Prepare test server and backend
archiveName := "foobar.zip"
- ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+ ts := archiveOKServer(t, archiveName)
defer ts.Close()
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
@@ -563,8 +564,6 @@ func TestGetGitBlob(t *testing.T) {
responseJSON := fmt.Sprintf(`{"RepoPath":"%s","BlobId":"%s"}`, path.Join(testRepoRoot, testRepo), blobId)
encodedJSON := base64.StdEncoding.EncodeToString([]byte(responseJSON))
w.Header().Set(headerKey, "git-blob:"+encodedJSON)
- // Prevent the Go HTTP server from setting the Content-Length to 0.
- w.Header().Set("Transfer-Encoding", "chunked")
if _, err := fmt.Fprintf(w, "GNU General Public License"); err != nil {
t.Fatal(err)
}
@@ -592,6 +591,9 @@ func TestGetGitBlob(t *testing.T) {
if len(body) != blobLength {
t.Fatalf("Expected body of %d bytes, got %d", blobLength, len(body))
}
+ if cl := resp.Header.Get("Content-Length"); cl != fmt.Sprintf("%d", blobLength) {
+ t.Fatalf("Expected Content-Length %v, got %q", blobLength, cl)
+ }
if !strings.HasPrefix(string(body), "The MIT License (MIT)") {
t.Fatalf("Expected MIT license, got %q", body)
}
@@ -659,6 +661,29 @@ func testAuthServer(url *regexp.Regexp, code int, body interface{}) *httptest.Se
})
}
+func archiveOKServer(t *testing.T, archiveName string) *httptest.Server {
+ return testhelper.TestServerWithHandler(regexp.MustCompile("."), func(w http.ResponseWriter, r *http.Request) {
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ archivePath := path.Join(cwd, cacheDir, archiveName)
+
+ params := struct{ RepoPath, ArchivePath, CommitId, ArchivePrefix string }{
+ repoPath(t),
+ archivePath,
+ "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd",
+ "foobar123",
+ }
+ jsonData, err := json.Marshal(params)
+ if err != nil {
+ t.Fatal(err)
+ }
+ encodedJSON := base64.StdEncoding.EncodeToString(jsonData)
+ w.Header().Set("Gitlab-Workhorse-Send-Data", "git-archive:"+encodedJSON)
+ })
+}
+
func startWorkhorseServer(authBackend string) *httptest.Server {
u := upstream.NewUpstream(
helper.URLMustParse(authBackend),
@@ -686,21 +711,6 @@ func gitOkBody(t *testing.T) interface{} {
}
}
-func archiveOkBody(t *testing.T, archiveName string) interface{} {
- cwd, err := os.Getwd()
- if err != nil {
- t.Fatal(err)
- }
- archivePath := path.Join(cwd, cacheDir, archiveName)
-
- return &api.Response{
- RepoPath: repoPath(t),
- ArchivePath: archivePath,
- CommitId: "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd",
- ArchivePrefix: "foobar123",
- }
-}
-
func repoPath(t *testing.T) string {
cwd, err := os.Getwd()
if err != nil {
diff --git a/proxy_test.go b/proxy_test.go
index 079e7ee..917571e 100644
--- a/proxy_test.go
+++ b/proxy_test.go
@@ -1,10 +1,6 @@
package main
import (
- "./internal/badgateway"
- "./internal/helper"
- "./internal/proxy"
- "./internal/testhelper"
"bytes"
"fmt"
"io"
@@ -14,6 +10,11 @@ import (
"regexp"
"testing"
"time"
+
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/badgateway"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/proxy"
+ "gitlab.com/gitlab-org/gitlab-workhorse/internal/testhelper"
)
func newProxy(url string, rt *badgateway.RoundTripper) *proxy.Proxy {
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/gitlab-workhorse.git
More information about the Pkg-ruby-extras-commits
mailing list