Fix issues with repair, move to a different streaming option

This commit is contained in:
Mukhtar Akere
2025-06-18 10:42:44 +01:00
parent 5661b05ec1
commit b2e99585f7
6 changed files with 507 additions and 275 deletions

View File

@@ -1,6 +1,7 @@
package webdav
import (
"fmt"
"github.com/stanNthe5/stringbuf"
"net/http"
"net/url"
@@ -132,3 +133,122 @@ func writeXml(w http.ResponseWriter, status int, buf stringbuf.StringBuf) {
w.WriteHeader(status)
_, _ = w.Write(buf.Bytes())
}
func hasHeadersWritten(w http.ResponseWriter) bool {
// Most ResponseWriter implementations support this
if hw, ok := w.(interface{ Written() bool }); ok {
return hw.Written()
}
return false
}
func isClientDisconnection(err error) bool {
if err == nil {
return false
}
errStr := err.Error()
// Common client disconnection error patterns
return strings.Contains(errStr, "broken pipe") ||
strings.Contains(errStr, "connection reset by peer") ||
strings.Contains(errStr, "write: connection reset") ||
strings.Contains(errStr, "read: connection reset") ||
strings.Contains(errStr, "context canceled") ||
strings.Contains(errStr, "context deadline exceeded") ||
strings.Contains(errStr, "client disconnected") ||
strings.Contains(errStr, "EOF")
}
type httpRange struct{ start, end int64 }
func parseRange(s string, size int64) ([]httpRange, error) {
if s == "" {
return nil, nil
}
const b = "bytes="
if !strings.HasPrefix(s, b) {
return nil, fmt.Errorf("invalid range")
}
var ranges []httpRange
for _, ra := range strings.Split(s[len(b):], ",") {
ra = strings.TrimSpace(ra)
if ra == "" {
continue
}
i := strings.Index(ra, "-")
if i < 0 {
return nil, fmt.Errorf("invalid range")
}
start, end := strings.TrimSpace(ra[:i]), strings.TrimSpace(ra[i+1:])
var r httpRange
if start == "" {
i, err := strconv.ParseInt(end, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid range")
}
if i > size {
i = size
}
r.start = size - i
r.end = size - 1
} else {
i, err := strconv.ParseInt(start, 10, 64)
if err != nil || i < 0 {
return nil, fmt.Errorf("invalid range")
}
r.start = i
if end == "" {
r.end = size - 1
} else {
i, err := strconv.ParseInt(end, 10, 64)
if err != nil || r.start > i {
return nil, fmt.Errorf("invalid range")
}
if i >= size {
i = size - 1
}
r.end = i
}
}
if r.start > size-1 {
continue
}
ranges = append(ranges, r)
}
return ranges, nil
}
func setVideoStreamingHeaders(req *http.Request) {
// Request optimizations for faster response
req.Header.Set("Accept", "*/*")
req.Header.Set("Accept-Encoding", "identity")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("User-Agent", "VideoStream/1.0")
req.Header.Set("Priority", "u=1")
}
func setVideoResponseHeaders(w http.ResponseWriter, resp *http.Response, isRange bool) {
// Copy essential headers from upstream
if contentLength := resp.Header.Get("Content-Length"); contentLength != "" {
w.Header().Set("Content-Length", contentLength)
}
if contentRange := resp.Header.Get("Content-Range"); contentRange != "" && isRange {
w.Header().Set("Content-Range", contentRange)
}
// Video streaming optimizations
w.Header().Set("Accept-Ranges", "bytes") // Enable seeking
w.Header().Set("Connection", "keep-alive") // Keep connection open
// Prevent buffering in proxies/CDNs
w.Header().Set("X-Accel-Buffering", "no") // Nginx
w.Header().Set("Proxy-Buffering", "off") // General proxy
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Range")
w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Range")
w.WriteHeader(resp.StatusCode)
}