Commit 86971fa6 authored by Jacob Vosmaer's avatar Jacob Vosmaer

First steps for downloading uploads

parent ed976a2f
PREFIX=/usr/local
VERSION=$(shell git describe)-$(shell date -u +%Y%m%d.%H%M%S)
gitlab-workhorse: main.go githandler.go archive.go git-http.go helpers.go
gitlab-workhorse: main.go githandler.go archive.go git-http.go helpers.go upload.go
go build -ldflags "-X main.Version ${VERSION}" -o gitlab-workhorse
install: gitlab-workhorse
......
......@@ -17,6 +17,11 @@ import (
)
func handleGetArchive(w http.ResponseWriter, r *gitRequest, format string) {
if !looksLikeRepo(r.RepoPath) {
http.Error(w, "Not Found", 404)
return
}
archiveFilename := path.Base(r.ArchivePath)
if cachedArchive, err := os.Open(r.ArchivePath); err == nil {
......
......@@ -13,6 +13,11 @@ import (
)
func handleGetInfoRefs(w http.ResponseWriter, r *gitRequest, _ string) {
if !looksLikeRepo(r.RepoPath) {
http.Error(w, "Not Found", 404)
return
}
rpc := r.URL.Query().Get("service")
if !(rpc == "git-upload-pack" || rpc == "git-receive-pack") {
// The 'dumb' Git HTTP protocol is not supported
......@@ -57,6 +62,11 @@ func handleGetInfoRefs(w http.ResponseWriter, r *gitRequest, _ string) {
}
func handlePostRPC(w http.ResponseWriter, r *gitRequest, rpc string) {
if !looksLikeRepo(r.RepoPath) {
http.Error(w, "Not Found", 404)
return
}
var body io.ReadCloser
var err error
......
......@@ -11,8 +11,6 @@ import (
"io"
"log"
"net/http"
"os"
"path"
"regexp"
"strings"
)
......@@ -48,6 +46,10 @@ type gitRequest struct {
// 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
// ContentPath is a file on disk we can serve to the client
ContentPath string
// ContentDisposition is used to set the Content-Disposition header
ContentDisposition string
}
// Routing table
......@@ -60,6 +62,7 @@ var gitServices = [...]gitService{
gitService{"GET", regexp.MustCompile(`/repository/archive.tar\z`), handleGetArchive, "tar"},
gitService{"GET", regexp.MustCompile(`/repository/archive.tar.gz\z`), handleGetArchive, "tar.gz"},
gitService{"GET", regexp.MustCompile(`/repository/archive.tar.bz2\z`), handleGetArchive, "tar.bz2"},
gitService{"GET", regexp.MustCompile(`/uploads/`), handleGetUpload, ""},
}
func newGitHandler(authBackend string, authTransport http.RoundTripper) *gitHandler {
......@@ -95,7 +98,7 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
defer authResponse.Body.Close()
if authResponse.StatusCode != 200 {
if authResponse.StatusCode != 200 || authResponse.Header.Get("GitLab-Workhorse") == "reject" {
// 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
......@@ -134,24 +137,9 @@ func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
if !looksLikeRepo(gitReq.RepoPath) {
http.Error(w, "Not Found", 404)
return
}
g.handleFunc(w, gitReq, g.rpc)
}
func looksLikeRepo(p string) bool {
// If /path/to/foo.git/objects exists then let's assume it is a valid Git
// repository.
if _, err := os.Stat(path.Join(p, "objects")); err != nil {
log.Print(err)
return false
}
return true
}
func (h *gitHandler) doAuthRequest(r *http.Request) (result *http.Response, err error) {
url := h.authBackend + r.URL.RequestURI()
authReq, err := http.NewRequest(r.Method, url, nil)
......
......@@ -10,9 +10,20 @@ import (
"net/http"
"os"
"os/exec"
"path"
"syscall"
)
func looksLikeRepo(p string) bool {
// If /path/to/foo.git/objects exists then let's assume it is a valid Git
// repository.
if _, err := os.Stat(path.Join(p, "objects")); err != nil {
log.Print(err)
return false
}
return true
}
func fail500(w http.ResponseWriter, context string, err error) {
http.Error(w, "Internal server error", 500)
logContext(context, err)
......
package main
import (
"fmt"
"net/http"
"os"
"path"
)
func handleGetUpload(w http.ResponseWriter, r *gitRequest, _ string) {
if r.ContentDisposition == "attachment" {
w.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, path.Base(r.ContentPath)))
} else {
w.Header().Add("Content-Disposition", r.ContentDisposition)
}
f, err := os.Open(r.ContentPath)
if err != nil {
logContext("handleGetUpload open file", err)
http.Error(w, "Not Found", 404)
return
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
fail500(w, "handleGetUpload get mtime", err)
return
}
http.ServeContent(w, r.Request, "", fi.ModTime(), f)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment