Fix issues with headers
This commit is contained in:
@@ -107,7 +107,7 @@
|
||||
<div class="navbar-end">
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Theme Toggle -->
|
||||
<div class="tooltip tooltip-left" data-tip="Toggle Theme">
|
||||
<div class="tooltip tooltip-left">
|
||||
<label class="swap swap-rotate btn btn-ghost btn-circle hover:bg-base-300 transition-colors">
|
||||
<input type="checkbox" id="themeToggle" class="theme-controller" />
|
||||
<!-- Sun icon for light mode -->
|
||||
|
||||
@@ -108,7 +108,7 @@ func (f *File) getDownloadByteRange() (*[2]int64, error) {
|
||||
|
||||
// setVideoStreamingHeaders sets the necessary headers for video streaming
|
||||
// It returns error and a boolean indicating if the request is a range request
|
||||
func (f *File) servePreloadedContent(w http.ResponseWriter, r *http.Request) (error, bool) {
|
||||
func (f *File) servePreloadedContent(w http.ResponseWriter, r *http.Request) error {
|
||||
content := f.content
|
||||
size := int64(len(content))
|
||||
|
||||
@@ -117,7 +117,7 @@ func (f *File) servePreloadedContent(w http.ResponseWriter, r *http.Request) (er
|
||||
ranges, err := parseRange(rangeHeader, size)
|
||||
if err != nil || len(ranges) != 1 {
|
||||
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
|
||||
return &streamError{Err: fmt.Errorf("invalid range"), StatusCode: http.StatusRequestedRangeNotSatisfiable}, false
|
||||
return &streamError{Err: fmt.Errorf("invalid range"), StatusCode: http.StatusRequestedRangeNotSatisfiable}
|
||||
}
|
||||
|
||||
start, end := ranges[0].start, ranges[0].end
|
||||
@@ -126,7 +126,7 @@ func (f *File) servePreloadedContent(w http.ResponseWriter, r *http.Request) (er
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
|
||||
_, err = w.Write(content[start : end+1])
|
||||
return err, true
|
||||
return err
|
||||
}
|
||||
|
||||
// Full content
|
||||
@@ -134,10 +134,10 @@ func (f *File) servePreloadedContent(w http.ResponseWriter, r *http.Request) (er
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
|
||||
_, err := w.Write(content)
|
||||
return err, false
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *File) StreamResponse(w http.ResponseWriter, r *http.Request) (error, bool) {
|
||||
func (f *File) StreamResponse(w http.ResponseWriter, r *http.Request) error {
|
||||
// Handle preloaded content files
|
||||
if f.content != nil {
|
||||
return f.servePreloadedContent(w, r)
|
||||
@@ -147,24 +147,24 @@ func (f *File) StreamResponse(w http.ResponseWriter, r *http.Request) (error, bo
|
||||
return f.streamWithRetry(w, r, 0)
|
||||
}
|
||||
|
||||
func (f *File) streamWithRetry(w http.ResponseWriter, r *http.Request, retryCount int) (error, bool) {
|
||||
func (f *File) streamWithRetry(w http.ResponseWriter, r *http.Request, retryCount int) error {
|
||||
const maxRetries = 3
|
||||
_log := f.cache.Logger()
|
||||
|
||||
// Get download link (with caching optimization)
|
||||
downloadLink, err := f.getDownloadLink()
|
||||
if err != nil {
|
||||
return &streamError{Err: err, StatusCode: http.StatusPreconditionFailed}, false
|
||||
return &streamError{Err: err, StatusCode: http.StatusPreconditionFailed}
|
||||
}
|
||||
|
||||
if downloadLink == "" {
|
||||
return &streamError{Err: fmt.Errorf("empty download link"), StatusCode: http.StatusNotFound}, false
|
||||
return &streamError{Err: fmt.Errorf("empty download link"), StatusCode: http.StatusNotFound}
|
||||
}
|
||||
|
||||
// Create upstream request with streaming optimizations
|
||||
upstreamReq, err := http.NewRequest("GET", downloadLink, nil)
|
||||
if err != nil {
|
||||
return &streamError{Err: err, StatusCode: http.StatusInternalServerError}, false
|
||||
return &streamError{Err: err, StatusCode: http.StatusInternalServerError}
|
||||
}
|
||||
|
||||
setVideoStreamingHeaders(upstreamReq)
|
||||
@@ -172,12 +172,12 @@ func (f *File) streamWithRetry(w http.ResponseWriter, r *http.Request, retryCoun
|
||||
// Handle range requests (critical for video seeking)
|
||||
isRangeRequest := f.handleRangeRequest(upstreamReq, r, w)
|
||||
if isRangeRequest == -1 {
|
||||
return &streamError{Err: fmt.Errorf("invalid range"), StatusCode: http.StatusRequestedRangeNotSatisfiable}, false
|
||||
return &streamError{Err: fmt.Errorf("invalid range"), StatusCode: http.StatusRequestedRangeNotSatisfiable}
|
||||
}
|
||||
|
||||
resp, err := sharedClient.Do(upstreamReq)
|
||||
if err != nil {
|
||||
return &streamError{Err: err, StatusCode: http.StatusServiceUnavailable}, false
|
||||
return &streamError{Err: err, StatusCode: http.StatusServiceUnavailable}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -192,11 +192,11 @@ func (f *File) streamWithRetry(w http.ResponseWriter, r *http.Request, retryCoun
|
||||
return f.streamWithRetry(w, r, retryCount+1)
|
||||
}
|
||||
if retryErr != nil {
|
||||
return retryErr, false
|
||||
return retryErr
|
||||
}
|
||||
|
||||
if err := f.streamBuffer(w, resp.Body); err != nil {
|
||||
return err, false
|
||||
return err
|
||||
}
|
||||
if contentLength := resp.Header.Get("Content-Length"); contentLength != "" {
|
||||
w.Header().Set("Content-Length", contentLength)
|
||||
@@ -205,7 +205,7 @@ func (f *File) streamWithRetry(w http.ResponseWriter, r *http.Request, retryCoun
|
||||
if contentRange := resp.Header.Get("Content-Range"); contentRange != "" && isRangeRequest == 1 {
|
||||
w.Header().Set("Content-Range", contentRange)
|
||||
}
|
||||
return nil, isRangeRequest == 1
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) streamBuffer(w http.ResponseWriter, src io.Reader) error {
|
||||
|
||||
@@ -463,31 +463,30 @@ func (h *Handler) handleGet(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err, ranged := file.StreamResponse(w, r)
|
||||
// Check if this will be a range request before streaming
|
||||
isRangeRequest := r.Header.Get("Range") != ""
|
||||
|
||||
if err != nil {
|
||||
// Write status headers before streaming starts
|
||||
if isRangeRequest {
|
||||
w.WriteHeader(http.StatusPartialContent)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
if err := file.StreamResponse(w, r); err != nil {
|
||||
var streamErr *streamError
|
||||
if errors.As(err, &streamErr) {
|
||||
// Handle client disconnections silently (just debug log)
|
||||
if errors.Is(streamErr.Err, context.Canceled) || errors.Is(streamErr.Err, context.DeadlineExceeded) || streamErr.IsClientDisconnection {
|
||||
return
|
||||
}
|
||||
|
||||
if streamErr.StatusCode > 0 {
|
||||
http.Error(w, streamErr.Error(), streamErr.StatusCode)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Generic error
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
// For other errors, we can't send HTTP error response since headers are already written
|
||||
h.logger.Error().Err(streamErr.Err).Str("file", file.name).Msg("Stream error after headers written")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if ranged {
|
||||
// If the file was served as a ranged request, return a 206 status code
|
||||
w.WriteHeader(http.StatusPartialContent)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// Generic error - can't send HTTP error response since headers are already written
|
||||
h.logger.Error().Err(err).Str("file", file.name).Msg("Generic stream error after headers written")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user