From d048d59d399009200efccdb2c31ded1f7a518085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Guillot?= Date: Mon, 29 Jul 2024 14:46:56 -0700 Subject: [PATCH] fix: use BASE_URL instead of `r.Host` to generate absolute media proxy URL --- internal/api/entry.go | 6 +++--- internal/config/config_test.go | 23 +++++++++++++++++++++++ internal/fever/handler.go | 2 +- internal/googlereader/handler.go | 4 ++-- internal/mediaproxy/media_proxy_test.go | 24 +++++++++++++----------- internal/mediaproxy/rewriter.go | 7 ++----- internal/mediaproxy/url.go | 20 +++++++++----------- 7 files changed, 53 insertions(+), 33 deletions(-) diff --git a/internal/api/entry.go b/internal/api/entry.go index 6a299a01..d8fc01f6 100644 --- a/internal/api/entry.go +++ b/internal/api/entry.go @@ -36,14 +36,14 @@ func (h *handler) getEntryFromBuilder(w http.ResponseWriter, r *http.Request, b return } - entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entry.Content) + entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entry.Content) proxyOption := config.Opts.MediaProxyMode() for i := range entry.Enclosures { if proxyOption == "all" || proxyOption != "none" && !urllib.IsHTTPS(entry.Enclosures[i].URL) { for _, mediaType := range config.Opts.MediaProxyResourceTypes() { if strings.HasPrefix(entry.Enclosures[i].MimeType, mediaType+"/") { - entry.Enclosures[i].URL = mediaproxy.ProxifyAbsoluteURL(h.router, r.Host, entry.Enclosures[i].URL) + entry.Enclosures[i].URL = mediaproxy.ProxifyAbsoluteURL(h.router, entry.Enclosures[i].URL) break } } @@ -164,7 +164,7 @@ func (h *handler) findEntries(w http.ResponseWriter, r *http.Request, feedID int } for i := range entries { - entries[i].Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entries[i].Content) + entries[i].Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entries[i].Content) } json.OK(w, r, &entriesResponse{Total: count, Entries: entries}) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index bc1db2b5..3b979c5d 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -259,6 +259,29 @@ func TestCustomBaseURLWithTrailingSlash(t *testing.T) { } } +func TestCustomBaseURLWithCustomPort(t *testing.T) { + os.Clearenv() + os.Setenv("BASE_URL", "http://example.org:88/folder/") + + parser := NewParser() + opts, err := parser.ParseEnvironmentVariables() + if err != nil { + t.Fatalf(`Parsing failure: %v`, err) + } + + if opts.BaseURL() != "http://example.org:88/folder" { + t.Fatalf(`Unexpected base URL, got "%s"`, opts.BaseURL()) + } + + if opts.RootURL() != "http://example.org:88" { + t.Fatalf(`Unexpected root URL, got "%s"`, opts.RootURL()) + } + + if opts.BasePath() != "/folder" { + t.Fatalf(`Unexpected base path, got "%s"`, opts.BasePath()) + } +} + func TestBaseURLWithoutScheme(t *testing.T) { os.Clearenv() os.Setenv("BASE_URL", "example.org/folder/") diff --git a/internal/fever/handler.go b/internal/fever/handler.go index 831cbe98..45455cf4 100644 --- a/internal/fever/handler.go +++ b/internal/fever/handler.go @@ -324,7 +324,7 @@ func (h *handler) handleItems(w http.ResponseWriter, r *http.Request) { FeedID: entry.FeedID, Title: entry.Title, Author: entry.Author, - HTML: mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entry.Content), + HTML: mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entry.Content), URL: entry.URL, IsSaved: isSaved, IsRead: isRead, diff --git a/internal/googlereader/handler.go b/internal/googlereader/handler.go index f5fa546d..7cce675c 100644 --- a/internal/googlereader/handler.go +++ b/internal/googlereader/handler.go @@ -1003,14 +1003,14 @@ func (h *handler) streamItemContentsHandler(w http.ResponseWriter, r *http.Reque categories = append(categories, userStarred) } - entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entry.Content) + entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entry.Content) proxyOption := config.Opts.MediaProxyMode() for i := range entry.Enclosures { if proxyOption == "all" || proxyOption != "none" && !urllib.IsHTTPS(entry.Enclosures[i].URL) { for _, mediaType := range config.Opts.MediaProxyResourceTypes() { if strings.HasPrefix(entry.Enclosures[i].MimeType, mediaType+"/") { - entry.Enclosures[i].URL = mediaproxy.ProxifyAbsoluteURL(h.router, r.Host, entry.Enclosures[i].URL) + entry.Enclosures[i].URL = mediaproxy.ProxifyAbsoluteURL(h.router, entry.Enclosures[i].URL) break } } diff --git a/internal/mediaproxy/media_proxy_test.go b/internal/mediaproxy/media_proxy_test.go index c142e578..8c544af6 100644 --- a/internal/mediaproxy/media_proxy_test.go +++ b/internal/mediaproxy/media_proxy_test.go @@ -174,7 +174,7 @@ func TestAbsoluteProxyFilterWithHttpsAlways(t *testing.T) { r.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") input := `

Test

` - output := RewriteDocumentWithAbsoluteProxyURL(r, "localhost", input) + output := RewriteDocumentWithAbsoluteProxyURL(r, input) expected := `

Test

` if expected != output { @@ -182,12 +182,10 @@ func TestAbsoluteProxyFilterWithHttpsAlways(t *testing.T) { } } -func TestAbsoluteProxyFilterWithHttpsScheme(t *testing.T) { +func TestAbsoluteProxyFilterWithCustomPortInBaseURL(t *testing.T) { os.Clearenv() - os.Setenv("PROXY_OPTION", "all") - os.Setenv("PROXY_MEDIA_TYPES", "image") - os.Setenv("PROXY_PRIVATE_KEY", "test") - os.Setenv("HTTPS", "1") + os.Setenv("BASE_URL", "http://example.org:88/folder/") + os.Setenv("MEDIA_PROXY_PRIVATE_KEY", "test") var err error parser := config.NewParser() @@ -196,12 +194,16 @@ func TestAbsoluteProxyFilterWithHttpsScheme(t *testing.T) { t.Fatalf(`Parsing failure: %v`, err) } + if config.Opts.BaseURL() != "http://example.org:88/folder" { + t.Fatalf(`Unexpected base URL, got "%s"`, config.Opts.BaseURL()) + } + r := mux.NewRouter() r.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") - input := `

Test

` - output := RewriteDocumentWithAbsoluteProxyURL(r, "localhost", input) - expected := `

Test

` + input := `

Test

` + output := RewriteDocumentWithAbsoluteProxyURL(r, input) + expected := `

Test

` if expected != output { t.Errorf(`Not expected output: got %q instead of %q`, output, expected) @@ -225,7 +227,7 @@ func TestAbsoluteProxyFilterWithHttpsAlwaysAndAudioTag(t *testing.T) { r.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") input := `` - output := RewriteDocumentWithAbsoluteProxyURL(r, "localhost", input) + output := RewriteDocumentWithAbsoluteProxyURL(r, input) expected := `` if expected != output { @@ -300,7 +302,7 @@ func TestAbsoluteProxyFilterWithHttpsAlwaysAndCustomProxyServer(t *testing.T) { r.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") input := `

Test

` - output := RewriteDocumentWithAbsoluteProxyURL(r, "localhost", input) + output := RewriteDocumentWithAbsoluteProxyURL(r, input) expected := `

Test

` if expected != output { diff --git a/internal/mediaproxy/rewriter.go b/internal/mediaproxy/rewriter.go index 72db9848..bb5c2b78 100644 --- a/internal/mediaproxy/rewriter.go +++ b/internal/mediaproxy/rewriter.go @@ -21,11 +21,8 @@ func RewriteDocumentWithRelativeProxyURL(router *mux.Router, htmlDocument string return genericProxyRewriter(router, ProxifyRelativeURL, htmlDocument) } -func RewriteDocumentWithAbsoluteProxyURL(router *mux.Router, host, htmlDocument string) string { - proxifyFunction := func(router *mux.Router, url string) string { - return ProxifyAbsoluteURL(router, host, url) - } - return genericProxyRewriter(router, proxifyFunction, htmlDocument) +func RewriteDocumentWithAbsoluteProxyURL(router *mux.Router, htmlDocument string) string { + return genericProxyRewriter(router, ProxifyAbsoluteURL, htmlDocument) } func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter, htmlDocument string) string { diff --git a/internal/mediaproxy/url.go b/internal/mediaproxy/url.go index c3a9a953..6eb17989 100644 --- a/internal/mediaproxy/url.go +++ b/internal/mediaproxy/url.go @@ -9,13 +9,11 @@ import ( "encoding/base64" "log/slog" "net/url" - "path" - - "miniflux.app/v2/internal/http/route" "github.com/gorilla/mux" "miniflux.app/v2/internal/config" + "miniflux.app/v2/internal/http/route" ) func ProxifyRelativeURL(router *mux.Router, mediaURL string) string { @@ -33,7 +31,7 @@ func ProxifyRelativeURL(router *mux.Router, mediaURL string) string { return route.Path(router, "proxy", "encodedDigest", base64.URLEncoding.EncodeToString(digest), "encodedURL", base64.URLEncoding.EncodeToString([]byte(mediaURL))) } -func ProxifyAbsoluteURL(router *mux.Router, host, mediaURL string) string { +func ProxifyAbsoluteURL(router *mux.Router, mediaURL string) string { if mediaURL == "" { return "" } @@ -43,12 +41,13 @@ func ProxifyAbsoluteURL(router *mux.Router, host, mediaURL string) string { } proxifiedUrl := ProxifyRelativeURL(router, mediaURL) - scheme := "http" - if config.Opts.HTTPS { - scheme = "https" + + absoluteURL, err := url.JoinPath(config.Opts.BaseURL(), proxifiedUrl) + if err != nil { + return mediaURL } - return scheme + "://" + host + proxifiedUrl + return absoluteURL } func proxifyURLWithCustomProxy(mediaURL, customProxyURL string) string { @@ -56,7 +55,7 @@ func proxifyURLWithCustomProxy(mediaURL, customProxyURL string) string { return mediaURL } - proxyUrl, err := url.Parse(customProxyURL) + absoluteURL, err := url.JoinPath(customProxyURL, base64.URLEncoding.EncodeToString([]byte(mediaURL))) if err != nil { slog.Error("Incorrect custom media proxy URL", slog.String("custom_proxy_url", customProxyURL), @@ -65,6 +64,5 @@ func proxifyURLWithCustomProxy(mediaURL, customProxyURL string) string { return mediaURL } - proxyUrl.Path = path.Join(proxyUrl.Path, base64.URLEncoding.EncodeToString([]byte(mediaURL))) - return proxyUrl.String() + return absoluteURL }