mirror of https://github.com/perkeep/perkeep.git
untested Range support
This commit is contained in:
parent
e360dbee7c
commit
47de79266d
|
@ -29,8 +29,34 @@ func handleGet(conn *http.Conn, req *http.Request) {
|
|||
serverError(conn, err)
|
||||
return
|
||||
}
|
||||
|
||||
reqRange := getRequestedRange(req)
|
||||
if reqRange.SkipBytes != 0 {
|
||||
_, err = file.Seek(reqRange.SkipBytes, 0)
|
||||
if err != nil {
|
||||
serverError(conn, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var input io.Reader = file
|
||||
if reqRange.LimitBytes != -1 {
|
||||
input = io.LimitReader(file, reqRange.LimitBytes)
|
||||
}
|
||||
|
||||
conn.SetHeader("Content-Type", "application/octet-stream")
|
||||
bytesCopied, err := io.Copy(conn, file)
|
||||
if !reqRange.IsWholeFile() {
|
||||
remainBytes := stat.Size - reqRange.SkipBytes
|
||||
if reqRange.LimitBytes != -1 &&
|
||||
reqRange.LimitBytes < remainBytes {
|
||||
remainBytes = reqRange.LimitBytes
|
||||
}
|
||||
conn.SetHeader("Content-Range",
|
||||
fmt.Sprintf("%d-%d/%d", reqRange.SkipBytes,
|
||||
reqRange.SkipBytes + remainBytes,
|
||||
stat.Size))
|
||||
}
|
||||
bytesCopied, err := io.Copy(conn, input)
|
||||
|
||||
// If there's an error at this point, it's too late to tell the client,
|
||||
// as they've already been receiving bytes. But they should be smart enough
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Default is {0, -1} to read all of a file.
|
||||
type requestedRange struct {
|
||||
SkipBytes int64
|
||||
LimitBytes int64 // or -1 to read all
|
||||
}
|
||||
|
||||
func (rr *requestedRange) IsWholeFile() bool {
|
||||
return rr.SkipBytes == 0 && rr.LimitBytes == -1;
|
||||
}
|
||||
|
||||
var wholeRange = &requestedRange{0, -1}
|
||||
|
||||
var rangePattern = regexp.MustCompile(`bytes=([0-9]+)-([0-9]*)`)
|
||||
|
||||
func getRequestedRange(req *http.Request) *requestedRange {
|
||||
rrange, ok := req.Header["Range"]
|
||||
if !ok {
|
||||
return wholeRange
|
||||
}
|
||||
return getRequestedRangeFromString(rrange)
|
||||
}
|
||||
|
||||
func getRequestedRangeFromString(rrange string) *requestedRange {
|
||||
matches := rangePattern.MatchStrings(rrange)
|
||||
if len(matches) == 0 {
|
||||
return wholeRange;
|
||||
}
|
||||
limitBytes := int64(-1)
|
||||
if len(matches[2]) > 0 {
|
||||
limitBytes, _ = strconv.Atoi64(matches[2])
|
||||
}
|
||||
skipBytes, _ := strconv.Atoi64(matches[1])
|
||||
limitBytes -= skipBytes
|
||||
return &requestedRange{skipBytes, limitBytes}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func testRange(t *t.Testing) {
|
||||
|
||||
}
|
Loading…
Reference in New Issue