From 629c0d0f65f83bc648d79f390a070bc3f47d8649 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sat, 26 Dec 2020 20:59:45 +0000 Subject: [PATCH] serve http: fix serving files of unknown length Before this change serving files of unknown length were always returned as 0 length files. This change serves them correctly, but does not support Range: requests on them. See: https://forum.rclone.org/t/serve-http-behavior-when-the-size-is-unknown/21319 --- cmd/serve/http/http.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/cmd/serve/http/http.go b/cmd/serve/http/http.go index 84c0a3205..aeef57e78 100644 --- a/cmd/serve/http/http.go +++ b/cmd/serve/http/http.go @@ -1,6 +1,7 @@ package http import ( + "io" "net/http" "os" "path" @@ -172,8 +173,11 @@ func (s *server) serveFile(w http.ResponseWriter, r *http.Request, remote string obj := entry.(fs.Object) file := node.(*vfs.File) - // Set content length since we know how long the object is - w.Header().Set("Content-Length", strconv.FormatInt(node.Size(), 10)) + // Set content length if we know how long the object is + knownSize := obj.Size() >= 0 + if knownSize { + w.Header().Set("Content-Length", strconv.FormatInt(node.Size(), 10)) + } // Set content type mimeType := fs.MimeType(r.Context(), obj) @@ -210,5 +214,19 @@ func (s *server) serveFile(w http.ResponseWriter, r *http.Request, remote string // FIXME in = fs.NewAccount(in, obj).WithBuffer() // account the transfer // Serve the file - http.ServeContent(w, r, remote, node.ModTime(), in) + if knownSize { + http.ServeContent(w, r, remote, node.ModTime(), in) + } else { + // http.ServeContent can't serve unknown length files + if rangeRequest := r.Header.Get("Range"); rangeRequest != "" { + http.Error(w, "Can't use Range: on files of unknown length", http.StatusRequestedRangeNotSatisfiable) + return + } + n, err := io.Copy(w, in) + if err != nil { + fs.Errorf(obj, "Didn't finish writing GET request (wrote %d/unknown bytes): %v", n, err) + return + } + } + }