Test http-range resume download

This commit is contained in:
Steve Streeting 2016-06-07 12:01:14 +01:00
parent b727d95327
commit c9c457c270
2 changed files with 86 additions and 2 deletions

@ -20,6 +20,7 @@ import (
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"sync"
)
@ -44,6 +45,7 @@ var (
"status-batch-403", "status-batch-404", "status-batch-410", "status-batch-422", "status-batch-500",
"status-storage-403", "status-storage-404", "status-storage-410", "status-storage-422", "status-storage-500",
"status-legacy-404", "status-legacy-410", "status-legacy-422", "status-legacy-403", "status-legacy-500",
"status-batch-resume-206",
}
)
@ -284,9 +286,14 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, repo string) {
}
type batchReq struct {
Transfers []string `json:"transfers"`
Operation string `json:"operation"`
Objects []lfsObject `json:"objects"`
}
type batchResp struct {
Transfer string `json:"transfer,omitempty"`
Objects []lfsObject `json:"objects"`
}
buf := &bytes.Buffer{}
tee := io.TeeReader(r.Body, buf)
@ -304,6 +311,7 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, repo string) {
res := []lfsObject{}
testingChunked := testingChunkedTransferEncoding(r)
var transferChoice string
for _, obj := range objs.Objects {
action := objs.Operation
@ -337,6 +345,14 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, repo string) {
o.Err = &lfsError{Code: 422, Message: "welp"}
case "status-batch-500":
o.Err = &lfsError{Code: 500, Message: "welp"}
case "status-batch-resume-206":
for _, t := range objs.Transfers {
if t == "http-range" {
transferChoice = "http-range"
break
}
}
fallthrough
default: // regular 200 response
if addAction {
o.Actions = map[string]lfsLink{
@ -355,7 +371,7 @@ func lfsBatchHandler(w http.ResponseWriter, r *http.Request, repo string) {
res = append(res, o)
}
ores := map[string][]lfsObject{"objects": res}
ores := batchResp{Transfer: transferChoice, Objects: res}
by, err := json.Marshal(ores)
if err != nil {
@ -427,9 +443,32 @@ func storageHandler(w http.ResponseWriter, r *http.Request) {
case "GET":
parts := strings.Split(r.URL.Path, "/")
oid := parts[len(parts)-1]
statusCode := 200
byteLimit := 0
resumeAt := int64(0)
if by, ok := largeObjects.Get(repo, oid); ok {
w.Write(by)
if len(by) == len("status-batch-resume-206") && string(by) == "status-batch-resume-206" {
// Resume if header includes range, otherwise deliberately interrupt
if rangeHdr := r.Header.Get("Range"); rangeHdr != "" {
regex := regexp.MustCompile(`bytes=(\d+)\-.*`)
match := regex.FindStringSubmatch(rangeHdr)
if match != nil && len(match) > 1 {
statusCode = 206
resumeAt, _ = strconv.ParseInt(match[1], 10, 32)
}
} else {
byteLimit = 10
}
}
w.WriteHeader(statusCode)
if byteLimit > 0 {
w.Write(by[0:byteLimit])
} else if resumeAt > 0 {
w.Write(by[resumeAt:])
} else {
w.Write(by)
}
return
}

45
test/test-resume-http-range.sh Executable file

@ -0,0 +1,45 @@
#!/usr/bin/env bash
. "test/testlib.sh"
begin_test "resume-http-range"
(
set -e
reponame="$(basename "$0" ".sh")"
setup_remote_repo "$reponame"
clone_repo "$reponame" $reponame
git lfs track "*.dat" 2>&1 | tee track.log
grep "Tracking \*.dat" track.log
# this string announces to server that we want http-range support and to
# interrupt the transfer when started from 0 to cause resume
contents="status-batch-resume-206"
contents_oid=$(calc_oid "$contents")
printf "$contents" > a.dat
git add a.dat
git add .gitattributes
git commit -m "add a.dat" 2>&1 | tee commit.log
git push origin master
assert_server_object "$reponame" "$contents_oid"
# delete local copy then fetch it back
# server will abort the transfer mid way (so will error) when not resuming
# then we can restart it
rm -rf .git/lfs/objects
git lfs fetch 2>&1 | tee fetchinterrupted.log
refute_local_object "$contents_oid"
# now fetch again, this should try to resume and server should send remainder
# this time (it does not cut short when Range is requested)
GIT_TRACE=1 git lfs fetch 2>&1 | tee fetchresume.log
grep "http-range: server accepted resume" fetchresume.log
assert_local_object "$contents_oid" "${#contents}"
)
end_test