Fix public file streaming with async download
- Use io.Pipe for immediate response headers - Start WebDAV download in goroutine to avoid blocking - Stream content as it becomes available - Prevents client timeouts on slow downloads - Maintains CORS and MIME type headers
This commit is contained in:
@@ -3178,14 +3178,20 @@ func publicFileViewHandler(w http.ResponseWriter, r *http.Request, db *database.
|
||||
downloadCtx, cancel := context.WithTimeout(r.Context(), 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// Stream file
|
||||
// Create a pipe for streaming
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
|
||||
// Start download in goroutine
|
||||
go func() {
|
||||
defer pipeWriter.Close()
|
||||
resp, err := client.Download(downloadCtx, file.Path, r.Header.Get("Range"))
|
||||
if err != nil {
|
||||
errors.LogError(r, err, "Failed to download file")
|
||||
errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError)
|
||||
pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
io.Copy(pipeWriter, resp.Body)
|
||||
}()
|
||||
|
||||
// Add CORS headers for public access
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
@@ -3193,24 +3199,16 @@ func publicFileViewHandler(w http.ResponseWriter, r *http.Request, db *database.
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Range")
|
||||
|
||||
// Set status code (200 or 206 for partial)
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
|
||||
// Copy headers from Nextcloud response, but skip Content-Type to ensure correct MIME type
|
||||
for k, v := range resp.Header {
|
||||
if k != "Content-Type" {
|
||||
w.Header()[k] = v
|
||||
}
|
||||
}
|
||||
w.WriteHeader(200) // Assume 200 for now, or check if Range was requested
|
||||
|
||||
// Set correct Content-Type based on file extension
|
||||
w.Header().Set("Content-Type", mimeType)
|
||||
|
||||
// Ensure inline viewing behavior (no Content-Disposition attachment)
|
||||
w.Header().Del("Content-Disposition")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", file.Name))
|
||||
|
||||
// Copy body
|
||||
io.Copy(w, resp.Body)
|
||||
// Copy body from pipe
|
||||
io.Copy(w, pipeReader)
|
||||
}
|
||||
|
||||
func getUserFileShareLinkHandler(w http.ResponseWriter, r *http.Request, db *database.DB) {
|
||||
|
||||
Reference in New Issue
Block a user