From 7c5d6cf35f46be7c295788a7a10cbccada15a8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Guillot?= Date: Wed, 30 Oct 2024 20:11:11 -0700 Subject: [PATCH] feat(mediaproxy): pass original filename in Content-Disposition header When you download/save proxified media, the original filename is lost. That information could be retained by passing a header `Content-Disposition: inline; filename="ORIGNAL_FILENAME.EXT"` when serving the media file. The requested URL would still be obfuscated, but if the client downloads the file it'll use that original filename. --- internal/ui/proxy.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/ui/proxy.go b/internal/ui/proxy.go index a1984375ed8..8c0f0f618ac 100644 --- a/internal/ui/proxy.go +++ b/internal/ui/proxy.go @@ -12,6 +12,7 @@ import ( "log/slog" "net/http" "net/url" + "path" "time" "miniflux.app/v2/internal/config" @@ -57,23 +58,23 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) { return } - u, err := url.Parse(string(decodedURL)) + parsedMediaURL, err := url.Parse(string(decodedURL)) if err != nil { html.BadRequest(w, r, errors.New("invalid URL provided")) return } - if u.Scheme != "http" && u.Scheme != "https" { + if parsedMediaURL.Scheme != "http" && parsedMediaURL.Scheme != "https" { html.BadRequest(w, r, errors.New("invalid URL provided")) return } - if u.Host == "" { + if parsedMediaURL.Host == "" { html.BadRequest(w, r, errors.New("invalid URL provided")) return } - if !u.IsAbs() { + if !parsedMediaURL.IsAbs() { html.BadRequest(w, r, errors.New("invalid URL provided")) return } @@ -145,6 +146,11 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) { b.WithStatus(resp.StatusCode) b.WithHeader("Content-Security-Policy", `default-src 'self'`) b.WithHeader("Content-Type", resp.Header.Get("Content-Type")) + + if filename := path.Base(parsedMediaURL.Path); filename != "" { + b.WithHeader("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, filename)) + } + forwardedResponseHeader := []string{"Content-Encoding", "Content-Type", "Content-Length", "Accept-Ranges", "Content-Range"} for _, responseHeaderName := range forwardedResponseHeader { if resp.Header.Get(responseHeaderName) != "" {