Skip to content

Commit ccc5e7a

Browse files
committed
fileserver: support simple Range headers
This is sufficient to allow efficient media streaming. Specifically, these two header forms are supported for content that does not have an injector: Range: bytes N- Range: bytes N-M Partial fix for cortesi#42
1 parent 98a1cca commit ccc5e7a

File tree

1 file changed

+23
-0
lines changed

1 file changed

+23
-0
lines changed

fileserver/fileserver.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os"
1414
"path"
1515
"path/filepath"
16+
"regexp"
1617
"sort"
1718
"strconv"
1819
"strings"
@@ -27,6 +28,8 @@ import (
2728

2829
const sniffLen = 512
2930

31+
var simpleRangeRegexp = regexp.MustCompile(`^bytes=(\d+)-(\d*)$`)
32+
3033
func rawHeaderGet(h http.Header, key string) string {
3134
if v := h[key]; len(v) > 0 {
3235
return v[0]
@@ -148,6 +151,26 @@ func serveContent(ci inject.CopyInject, w http.ResponseWriter, r *http.Request,
148151
}
149152
}
150153

154+
rangeopt := r.Header.Get("Range")
155+
if rangeopt != "" && !injector.Found() && r.Method == "GET" {
156+
m := simpleRangeRegexp.FindStringSubmatch(rangeopt)
157+
if m != nil {
158+
start, err1 := strconv.ParseInt(m[1], 10, 64)
159+
end, err2 := strconv.ParseInt(m[2], 10, 64)
160+
if err2 != nil {
161+
end = size - 1
162+
}
163+
164+
if err1 == nil && start <= end && end < size {
165+
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, size))
166+
w.WriteHeader(206)
167+
content.Seek(start, io.SeekStart)
168+
_, err = io.CopyN(w, content, end-start+1)
169+
return err
170+
}
171+
}
172+
}
173+
151174
w.WriteHeader(code)
152175
if r.Method != "HEAD" {
153176
_, err := injector.Copy(w)

0 commit comments

Comments
 (0)