Commit d7116ae4 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Serve cached files from disk

parent 103750f1
...@@ -18,6 +18,7 @@ import ( ...@@ -18,6 +18,7 @@ import (
"path" "path"
"strings" "strings"
"syscall" "syscall"
"time"
) )
type gitHandler struct { type gitHandler struct {
...@@ -205,6 +206,23 @@ func handleGetInfoRefs(env gitEnv, _ string, repoPath string, w http.ResponseWri ...@@ -205,6 +206,23 @@ func handleGetInfoRefs(env gitEnv, _ string, repoPath string, w http.ResponseWri
} }
func handleGetArchive(env gitEnv, format string, repoPath string, w http.ResponseWriter, r *http.Request) { func handleGetArchive(env gitEnv, format string, repoPath string, w http.ResponseWriter, r *http.Request) {
archiveFilename := path.Base(env.ArchivePath)
w.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, archiveFilename))
if format == "zip" {
w.Header().Add("Content-Type", "application/zip")
} else {
w.Header().Add("Content-Type", "application/octet-stream")
}
w.Header().Add("Content-Transfer-Encoding", "binary")
w.Header().Add("Cache-Control", "private")
if f, err := os.Open(env.ArchivePath); err == nil {
defer f.Close()
log.Printf("Serving cached file %q", env.ArchivePath)
http.ServeContent(w, r, archiveFilename, time.Unix(0, 0), f)
return
}
var compressCmd *exec.Cmd var compressCmd *exec.Cmd
var archiveFormat string var archiveFormat string
switch format { switch format {
...@@ -222,8 +240,6 @@ func handleGetArchive(env gitEnv, format string, repoPath string, w http.Respons ...@@ -222,8 +240,6 @@ func handleGetArchive(env gitEnv, format string, repoPath string, w http.Respons
compressCmd = nil compressCmd = nil
} }
archiveFilename := path.Base(env.ArchivePath)
archiveCmd := gitCommand(env, "git", "--git-dir="+repoPath, "archive", "--format="+archiveFormat, "--prefix="+env.ArchivePrefix+"/", env.CommitId) archiveCmd := gitCommand(env, "git", "--git-dir="+repoPath, "archive", "--format="+archiveFormat, "--prefix="+env.ArchivePrefix+"/", env.CommitId)
archiveStdout, err := archiveCmd.StdoutPipe() archiveStdout, err := archiveCmd.StdoutPipe()
if err != nil { if err != nil {
...@@ -260,14 +276,6 @@ func handleGetArchive(env gitEnv, format string, repoPath string, w http.Respons ...@@ -260,14 +276,6 @@ func handleGetArchive(env gitEnv, format string, repoPath string, w http.Respons
} }
// Start writing the response // Start writing the response
if format == "zip" {
w.Header().Add("Content-Type", "application/zip")
} else {
w.Header().Add("Content-Type", "application/octet-stream")
}
w.Header().Add("Content-Transfer-Encoding", "binary")
w.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, archiveFilename))
w.Header().Add("Cache-Control", "private")
w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just return w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just return
if _, err := io.Copy(w, stdout); err != nil { if _, err := io.Copy(w, stdout); err != nil {
logContext("handleGetArchive read from subprocess", err) logContext("handleGetArchive read from subprocess", err)
......
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
...@@ -23,6 +25,7 @@ const testProject = "test" ...@@ -23,6 +25,7 @@ const testProject = "test"
var remote = fmt.Sprintf("http://%s/%s", servAddr, testRepo) var remote = fmt.Sprintf("http://%s/%s", servAddr, testRepo)
var checkoutDir = path.Join(scratchDir, "test") var checkoutDir = path.Join(scratchDir, "test")
var cacheDir = path.Join(scratchDir, "cache")
func TestAllowedClone(t *testing.T) { func TestAllowedClone(t *testing.T) {
// Prepare clone directory // Prepare clone directory
...@@ -187,6 +190,36 @@ func TestAllowedApiDownloadZip(t *testing.T) { ...@@ -187,6 +190,36 @@ func TestAllowedApiDownloadZip(t *testing.T) {
runOrFail(t, extractCmd) runOrFail(t, extractCmd)
} }
func TestDownloadCacheHit(t *testing.T) {
prepareDownloadDir(t)
// Prepare test server and backend
archiveName := "foobar.zip"
ts := testAuthServer(200, archiveOkBody(t, archiveName))
defer ts.Close()
defer cleanUpProcessGroup(startServerOrFail(t, ts))
if err := os.MkdirAll(cacheDir, 0755); err != nil {
t.Fatal(err)
}
cachedContent := []byte{'c', 'a', 'c', 'h', 'e', 'd'}
if err := ioutil.WriteFile(path.Join(cacheDir, archiveName), cachedContent, 0644); err != nil {
t.Fatal(err)
}
downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("http://%s/api/v3/projects/123/repository/archive.zip", servAddr))
downloadCmd.Dir = scratchDir
runOrFail(t, downloadCmd)
actual, err := ioutil.ReadFile(path.Join(scratchDir, archiveName))
if err != nil {
t.Fatal(err)
}
if bytes.Compare(actual, cachedContent) != 0 {
t.Fatal("Unexpected file contents in download")
}
}
func prepareDownloadDir(t *testing.T) { func prepareDownloadDir(t *testing.T) {
if err := os.RemoveAll(scratchDir); err != nil { if err := os.RemoveAll(scratchDir); err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -264,10 +297,10 @@ func archiveOkBody(t *testing.T, archiveName string) string { ...@@ -264,10 +297,10 @@ func archiveOkBody(t *testing.T, archiveName string) string {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
archivePath := path.Join(cwd, scratchDir, "cache", archiveName) archivePath := path.Join(cwd, cacheDir, archiveName)
jsonString := `{ jsonString := `{
"RepoPath":"%s", "RepoPath":"%s",
"ArchivePath":"/tmp/%s", "ArchivePath":"%s",
"CommitId":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", "CommitId":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd",
"ArchivePrefix":"foobar123" "ArchivePrefix":"foobar123"
}` }`
......
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