Explorar o código

refactor(mediaproxy): remove dependency on gorilla/mux

Frédéric Guillot hai 3 semanas
pai
achega
b1713dc626

+ 1 - 1
internal/api/enclosure.go

@@ -34,7 +34,7 @@ func (h *handler) getEnclosureByID(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	enclosure.ProxifyEnclosureURL(h.router, config.Opts.MediaProxyMode(), config.Opts.MediaProxyResourceTypes())
+	enclosure.ProxifyEnclosureURL(config.Opts.MediaProxyMode(), config.Opts.MediaProxyResourceTypes())
 
 	response.JSON(w, r, enclosure)
 }

+ 4 - 4
internal/api/entry.go

@@ -36,8 +36,8 @@ func (h *handler) getEntryFromBuilder(w http.ResponseWriter, r *http.Request, b
 		return
 	}
 
-	entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entry.Content)
-	entry.Enclosures.ProxifyEnclosureURL(h.router, config.Opts.MediaProxyMode(), config.Opts.MediaProxyResourceTypes())
+	entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(entry.Content)
+	entry.Enclosures.ProxifyEnclosureURL(config.Opts.MediaProxyMode(), config.Opts.MediaProxyResourceTypes())
 
 	response.JSON(w, r, entry)
 }
@@ -166,7 +166,7 @@ func (h *handler) findEntries(w http.ResponseWriter, r *http.Request, feedID int
 	}
 
 	for i := range entries {
-		entries[i].Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entries[i].Content)
+		entries[i].Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(entries[i].Content)
 	}
 
 	response.JSON(w, r, &entriesResponse{Total: count, Entries: entries})
@@ -454,7 +454,7 @@ func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	response.JSON(w, r, entryContentResponse{Content: mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, entry.Content), ReadingTime: entry.ReadingTime})
+	response.JSON(w, r, entryContentResponse{Content: mediaproxy.RewriteDocumentWithAbsoluteProxyURL(entry.Content), ReadingTime: entry.ReadingTime})
 }
 
 func (h *handler) flushHistory(w http.ResponseWriter, r *http.Request) {

+ 5 - 5
internal/fever/handler.go

@@ -13,19 +13,19 @@ import (
 	"miniflux.app/v2/internal/http/request"
 	"miniflux.app/v2/internal/http/response"
 	"miniflux.app/v2/internal/integration"
+	"miniflux.app/v2/internal/mediaproxy"
 	"miniflux.app/v2/internal/model"
 	"miniflux.app/v2/internal/storage"
 )
 
 // NewHandler returns an http.Handler for Fever API calls.
-func NewHandler(store *storage.Storage, proxyRewriter func(string) string) http.Handler {
-	h := &feverHandler{store: store, proxyRewriter: proxyRewriter}
+func NewHandler(store *storage.Storage) http.Handler {
+	h := &feverHandler{store: store}
 	return http.HandlerFunc(h.serve)
 }
 
 type feverHandler struct {
-	store         *storage.Storage
-	proxyRewriter func(string) string
+	store *storage.Storage
 }
 
 func (h *feverHandler) serve(w http.ResponseWriter, r *http.Request) {
@@ -318,7 +318,7 @@ func (h *feverHandler) handleItems(w http.ResponseWriter, r *http.Request) {
 			FeedID:    entry.FeedID,
 			Title:     entry.Title,
 			Author:    entry.Author,
-			HTML:      h.proxyRewriter(entry.Content),
+			HTML:      mediaproxy.RewriteDocumentWithAbsoluteProxyURL(entry.Content),
 			URL:       entry.URL,
 			IsSaved:   isSaved,
 			IsRead:    isRead,

+ 6 - 9
internal/googlereader/handler.go

@@ -15,6 +15,7 @@ import (
 	"miniflux.app/v2/internal/http/request"
 	"miniflux.app/v2/internal/http/response"
 	"miniflux.app/v2/internal/integration"
+	"miniflux.app/v2/internal/mediaproxy"
 	"miniflux.app/v2/internal/model"
 	"miniflux.app/v2/internal/proxyrotator"
 	"miniflux.app/v2/internal/reader/fetcher"
@@ -34,11 +35,9 @@ var (
 
 // NewHandler returns an http.Handler that handles Google Reader API calls.
 // The returned handler expects the base path to be stripped from the request URL.
-func NewHandler(store *storage.Storage, rewriteContent func(string) string, proxifyEnclosures func(model.EnclosureList)) http.Handler {
+func NewHandler(store *storage.Storage) http.Handler {
 	h := &greaderHandler{
-		store:             store,
-		rewriteContent:    rewriteContent,
-		proxifyEnclosures: proxifyEnclosures,
+		store: store,
 	}
 
 	authMiddleware := newAuthMiddleware(store)
@@ -67,9 +66,7 @@ func NewHandler(store *storage.Storage, rewriteContent func(string) string, prox
 }
 
 type greaderHandler struct {
-	store             *storage.Storage
-	rewriteContent    func(string) string
-	proxifyEnclosures func(model.EnclosureList)
+	store *storage.Storage
 }
 
 func (h *greaderHandler) clientLoginHandler(w http.ResponseWriter, r *http.Request) {
@@ -696,8 +693,8 @@ func (h *greaderHandler) streamItemContentsHandler(w http.ResponseWriter, r *htt
 			categories = append(categories, userStarred)
 		}
 
-		entry.Content = h.rewriteContent(entry.Content)
-		h.proxifyEnclosures(entry.Enclosures)
+		entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(entry.Content)
+		entry.Enclosures.ProxifyEnclosureURL(config.Opts.MediaProxyMode(), config.Opts.MediaProxyResourceTypes())
 
 		result.Items[i] = contentItem{
 			ID:            convertEntryIDToLongFormItemID(entry.ID),

+ 2 - 14
internal/http/server/httpd.go

@@ -18,8 +18,6 @@ import (
 	"miniflux.app/v2/internal/fever"
 	"miniflux.app/v2/internal/googlereader"
 	"miniflux.app/v2/internal/http/request"
-	"miniflux.app/v2/internal/mediaproxy"
-	"miniflux.app/v2/internal/model"
 	"miniflux.app/v2/internal/storage"
 	"miniflux.app/v2/internal/ui"
 	"miniflux.app/v2/internal/worker"
@@ -244,20 +242,10 @@ func setupHandler(store *storage.Storage, pool *worker.Pool) *mux.Router {
 	// Fever API routing
 	feverSubrouter := subrouter.PathPrefix("/fever").Subrouter()
 	feverSubrouter.Use(fever.Middleware(store))
-	feverSubrouter.Handle("/", fever.NewHandler(store, func(content string) string {
-		return mediaproxy.RewriteDocumentWithAbsoluteProxyURL(subrouter, content)
-	})).Name("feverEndpoint")
+	feverSubrouter.Handle("/", fever.NewHandler(store)).Name("feverEndpoint")
 
 	// Google Reader API routing
-	googleReaderHandler := http.StripPrefix(config.Opts.BasePath(), googlereader.NewHandler(
-		store,
-		func(content string) string {
-			return mediaproxy.RewriteDocumentWithAbsoluteProxyURL(subrouter, content)
-		},
-		func(el model.EnclosureList) {
-			el.ProxifyEnclosureURL(subrouter, config.Opts.MediaProxyMode(), config.Opts.MediaProxyResourceTypes())
-		},
-	))
+	googleReaderHandler := http.StripPrefix(config.Opts.BasePath(), googlereader.NewHandler(store))
 	subrouter.HandleFunc("/accounts/ClientLogin", googleReaderHandler.ServeHTTP).Methods(http.MethodPost).Name("ClientLogin")
 	subrouter.PathPrefix("/reader/api/0").Handler(googleReaderHandler)
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 566 - 149
internal/mediaproxy/media_proxy_test.go


+ 14 - 19
internal/mediaproxy/rewriter.go

@@ -12,20 +12,19 @@ import (
 	"miniflux.app/v2/internal/reader/sanitizer"
 
 	"github.com/PuerkitoBio/goquery"
-	"github.com/gorilla/mux"
 )
 
-type urlProxyRewriter func(router *mux.Router, url string) string
+type urlProxyRewriter func(url string) string
 
-func RewriteDocumentWithRelativeProxyURL(router *mux.Router, htmlDocument string) string {
-	return genericProxyRewriter(router, ProxifyRelativeURL, htmlDocument)
+func RewriteDocumentWithRelativeProxyURL(htmlDocument string) string {
+	return genericProxyRewriter(ProxifyRelativeURL, htmlDocument)
 }
 
-func RewriteDocumentWithAbsoluteProxyURL(router *mux.Router, htmlDocument string) string {
-	return genericProxyRewriter(router, ProxifyAbsoluteURL, htmlDocument)
+func RewriteDocumentWithAbsoluteProxyURL(htmlDocument string) string {
+	return genericProxyRewriter(ProxifyAbsoluteURL, htmlDocument)
 }
 
-func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter, htmlDocument string) string {
+func genericProxyRewriter(proxifyFunction urlProxyRewriter, htmlDocument string) string {
 	proxyOption := config.Opts.MediaProxyMode()
 	if proxyOption == "none" {
 		return htmlDocument
@@ -42,12 +41,12 @@ func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter,
 			doc.Find("img, picture source").Each(func(i int, img *goquery.Selection) {
 				if srcAttrValue, ok := img.Attr("src"); ok {
 					if shouldProxifyURL(srcAttrValue, proxyOption) {
-						img.SetAttr("src", proxifyFunction(router, srcAttrValue))
+						img.SetAttr("src", proxifyFunction(srcAttrValue))
 					}
 				}
 
 				if srcsetAttrValue, ok := img.Attr("srcset"); ok {
-					proxifySourceSet(img, router, proxifyFunction, proxyOption, srcsetAttrValue)
+					proxifySourceSet(img, proxifyFunction, proxyOption, srcsetAttrValue)
 				}
 			})
 
@@ -55,7 +54,7 @@ func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter,
 				doc.Find("video").Each(func(i int, video *goquery.Selection) {
 					if posterAttrValue, ok := video.Attr("poster"); ok {
 						if shouldProxifyURL(posterAttrValue, proxyOption) {
-							video.SetAttr("poster", proxifyFunction(router, posterAttrValue))
+							video.SetAttr("poster", proxifyFunction(posterAttrValue))
 						}
 					}
 				})
@@ -65,7 +64,7 @@ func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter,
 			doc.Find("audio, audio source").Each(func(i int, audio *goquery.Selection) {
 				if srcAttrValue, ok := audio.Attr("src"); ok {
 					if shouldProxifyURL(srcAttrValue, proxyOption) {
-						audio.SetAttr("src", proxifyFunction(router, srcAttrValue))
+						audio.SetAttr("src", proxifyFunction(srcAttrValue))
 					}
 				}
 			})
@@ -74,13 +73,13 @@ func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter,
 			doc.Find("video, video source").Each(func(i int, video *goquery.Selection) {
 				if srcAttrValue, ok := video.Attr("src"); ok {
 					if shouldProxifyURL(srcAttrValue, proxyOption) {
-						video.SetAttr("src", proxifyFunction(router, srcAttrValue))
+						video.SetAttr("src", proxifyFunction(srcAttrValue))
 					}
 				}
 
 				if posterAttrValue, ok := video.Attr("poster"); ok {
 					if shouldProxifyURL(posterAttrValue, proxyOption) {
-						video.SetAttr("poster", proxifyFunction(router, posterAttrValue))
+						video.SetAttr("poster", proxifyFunction(posterAttrValue))
 					}
 				}
 			})
@@ -95,12 +94,12 @@ func genericProxyRewriter(router *mux.Router, proxifyFunction urlProxyRewriter,
 	return output
 }
 
-func proxifySourceSet(element *goquery.Selection, router *mux.Router, proxifyFunction urlProxyRewriter, proxyOption, srcsetAttrValue string) {
+func proxifySourceSet(element *goquery.Selection, proxifyFunction urlProxyRewriter, proxyOption, srcsetAttrValue string) {
 	imageCandidates := sanitizer.ParseSrcSetAttribute(srcsetAttrValue)
 
 	for _, imageCandidate := range imageCandidates {
 		if shouldProxifyURL(imageCandidate.ImageURL, proxyOption) {
-			imageCandidate.ImageURL = proxifyFunction(router, imageCandidate.ImageURL)
+			imageCandidate.ImageURL = proxifyFunction(imageCandidate.ImageURL)
 		}
 	}
 
@@ -115,10 +114,6 @@ func shouldProxifyURL(mediaURL, mediaProxyOption string) bool {
 	}
 
 	switch {
-	case mediaURL == "":
-		return false
-	case strings.HasPrefix(mediaURL, "data:"):
-		return false
 	case mediaProxyOption == "all" && (strings.EqualFold(parsedURL.Scheme, "http") || strings.EqualFold(parsedURL.Scheme, "https")):
 		return true
 	case mediaProxyOption != "none" && strings.EqualFold(parsedURL.Scheme, "http"):

+ 7 - 7
internal/mediaproxy/url.go

@@ -7,15 +7,13 @@ import (
 	"crypto/hmac"
 	"crypto/sha256"
 	"encoding/base64"
+	"fmt"
 	"net/url"
 
-	"github.com/gorilla/mux"
-
 	"miniflux.app/v2/internal/config"
-	"miniflux.app/v2/internal/http/route"
 )
 
-func ProxifyRelativeURL(router *mux.Router, mediaURL string) string {
+func ProxifyRelativeURL(mediaURL string) string {
 	if mediaURL == "" {
 		return ""
 	}
@@ -29,10 +27,12 @@ func ProxifyRelativeURL(router *mux.Router, mediaURL string) string {
 	mac := hmac.New(sha256.New, config.Opts.MediaProxyPrivateKey())
 	mac.Write(mediaURLBytes)
 	digest := mac.Sum(nil)
-	return route.Path(router, "proxy", "encodedDigest", base64.URLEncoding.EncodeToString(digest), "encodedURL", base64.URLEncoding.EncodeToString(mediaURLBytes))
+
+	// Preserve the configured base path so proxied URLs still work when Miniflux is served from a subfolder.
+	return fmt.Sprintf("%s/proxy/%s/%s", config.Opts.BasePath(), base64.URLEncoding.EncodeToString(digest), base64.URLEncoding.EncodeToString(mediaURLBytes))
 }
 
-func ProxifyAbsoluteURL(router *mux.Router, mediaURL string) string {
+func ProxifyAbsoluteURL(mediaURL string) string {
 	if mediaURL == "" {
 		return ""
 	}
@@ -42,7 +42,7 @@ func ProxifyAbsoluteURL(router *mux.Router, mediaURL string) string {
 	}
 
 	// Note that the proxyified URL is relative to the root URL.
-	proxifiedUrl := ProxifyRelativeURL(router, mediaURL)
+	proxifiedUrl := ProxifyRelativeURL(mediaURL)
 	absoluteURL, err := url.JoinPath(config.Opts.RootURL(), proxifiedUrl)
 	if err != nil {
 		return mediaURL

+ 4 - 6
internal/model/enclosure.go

@@ -6,8 +6,6 @@ package model // import "miniflux.app/v2/internal/model"
 import (
 	"strings"
 
-	"github.com/gorilla/mux"
-
 	"miniflux.app/v2/internal/mediaproxy"
 )
 
@@ -52,9 +50,9 @@ func (e *Enclosure) IsImage() bool {
 }
 
 // ProxifyEnclosureURL modifies the enclosure URL to use the media proxy if necessary.
-func (e *Enclosure) ProxifyEnclosureURL(router *mux.Router, mediaProxyOption string, mediaProxyResourceTypes []string) {
+func (e *Enclosure) ProxifyEnclosureURL(mediaProxyOption string, mediaProxyResourceTypes []string) {
 	if mediaproxy.ShouldProxifyURLWithMimeType(e.URL, e.MimeType, mediaProxyOption, mediaProxyResourceTypes) {
-		e.URL = mediaproxy.ProxifyAbsoluteURL(router, e.URL)
+		e.URL = mediaproxy.ProxifyAbsoluteURL(e.URL)
 	}
 }
 
@@ -83,8 +81,8 @@ func (el EnclosureList) ContainsAudioOrVideo() bool {
 	return false
 }
 
-func (el EnclosureList) ProxifyEnclosureURL(router *mux.Router, mediaProxyOption string, mediaProxyResourceTypes []string) {
+func (el EnclosureList) ProxifyEnclosureURL(mediaProxyOption string, mediaProxyResourceTypes []string) {
 	for _, enclosure := range el {
-		enclosure.ProxifyEnclosureURL(router, mediaProxyOption, mediaProxyResourceTypes)
+		enclosure.ProxifyEnclosureURL(mediaProxyOption, mediaProxyResourceTypes)
 	}
 }

+ 5 - 15
internal/model/enclosure_test.go

@@ -4,11 +4,9 @@
 package model
 
 import (
-	"net/http"
 	"os"
 	"testing"
 
-	"github.com/gorilla/mux"
 	"miniflux.app/v2/internal/config"
 )
 
@@ -296,9 +294,6 @@ func TestEnclosure_ProxifyEnclosureURL(t *testing.T) {
 		t.Fatalf(`Config parsing failure: %v`, err)
 	}
 
-	router := mux.NewRouter()
-	router.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
-
 	testCases := []struct {
 		name                    string
 		url                     string
@@ -391,7 +386,7 @@ func TestEnclosure_ProxifyEnclosureURL(t *testing.T) {
 			originalURL := enclosure.URL
 
 			// Call the method
-			enclosure.ProxifyEnclosureURL(router, tc.mediaProxyOption, tc.mediaProxyResourceTypes)
+			enclosure.ProxifyEnclosureURL(tc.mediaProxyOption, tc.mediaProxyResourceTypes)
 
 			// Check if URL changed as expected
 			urlChanged := enclosure.URL != originalURL
@@ -426,9 +421,6 @@ func TestEnclosureList_ProxifyEnclosureURL(t *testing.T) {
 		t.Fatalf(`Config parsing failure: %v`, err)
 	}
 
-	router := mux.NewRouter()
-	router.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
-
 	testCases := []struct {
 		name                    string
 		enclosures              EnclosureList
@@ -507,7 +499,7 @@ func TestEnclosureList_ProxifyEnclosureURL(t *testing.T) {
 			}
 
 			// Call the method
-			tc.enclosures.ProxifyEnclosureURL(router, tc.mediaProxyOption, tc.mediaProxyResourceTypes)
+			tc.enclosures.ProxifyEnclosureURL(tc.mediaProxyOption, tc.mediaProxyResourceTypes)
 
 			// Count how many URLs actually changed
 			changedCount := 0
@@ -541,8 +533,6 @@ func TestEnclosure_ProxifyEnclosureURL_EdgeCases(t *testing.T) {
 		t.Fatalf(`Config parsing failure: %v`, err)
 	}
 
-	router := mux.NewRouter()
-	router.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
 	t.Run("Empty resource types slice", func(t *testing.T) {
 		enclosure := &Enclosure{
 			URL:      "http://example.com/audio.mp3",
@@ -550,7 +540,7 @@ func TestEnclosure_ProxifyEnclosureURL_EdgeCases(t *testing.T) {
 		}
 
 		originalURL := enclosure.URL
-		enclosure.ProxifyEnclosureURL(router, "all", []string{})
+		enclosure.ProxifyEnclosureURL("all", []string{})
 
 		// With empty resource types, URL should not change
 		if enclosure.URL != originalURL {
@@ -565,7 +555,7 @@ func TestEnclosure_ProxifyEnclosureURL_EdgeCases(t *testing.T) {
 		}
 
 		originalURL := enclosure.URL
-		enclosure.ProxifyEnclosureURL(router, "all", nil)
+		enclosure.ProxifyEnclosureURL("all", nil)
 
 		// With nil resource types, URL should not change
 		if enclosure.URL != originalURL {
@@ -579,7 +569,7 @@ func TestEnclosure_ProxifyEnclosureURL_EdgeCases(t *testing.T) {
 		}
 
 		originalURL := enclosure.URL
-		enclosure.ProxifyEnclosureURL(router, "invalid-mode", []string{"audio"})
+		enclosure.ProxifyEnclosureURL("invalid-mode", []string{"audio"})
 
 		// With invalid proxy mode, the function still proxifies non-HTTPS URLs
 		// because shouldProxifyURL defaults to checking URL scheme

+ 2 - 4
internal/template/functions.go

@@ -67,14 +67,12 @@ func (f *funcMap) Map() template.FuncMap {
 		"safeHTML": func(str string) template.HTML {
 			return template.HTML(str)
 		},
-		"proxyFilter": func(data string) string {
-			return mediaproxy.RewriteDocumentWithRelativeProxyURL(f.router, data)
-		},
+		"proxyFilter": mediaproxy.RewriteDocumentWithRelativeProxyURL,
 		"proxyURL": func(link string) string {
 			mediaProxyMode := config.Opts.MediaProxyMode()
 
 			if mediaProxyMode == "all" || (mediaProxyMode != "none" && !urllib.IsHTTPS(link)) {
-				return mediaproxy.ProxifyRelativeURL(f.router, link)
+				return mediaproxy.ProxifyRelativeURL(link)
 			}
 
 			return link

+ 1 - 1
internal/ui/entry_scraper.go

@@ -65,5 +65,5 @@ func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) {
 
 	readingTime := locale.NewPrinter(user.Language).Plural("entry.estimated_reading_time", entry.ReadingTime, entry.ReadingTime)
 
-	response.JSON(w, r, map[string]string{"content": mediaproxy.RewriteDocumentWithRelativeProxyURL(h.router, entry.Content), "reading_time": readingTime})
+	response.JSON(w, r, map[string]string{"content": mediaproxy.RewriteDocumentWithRelativeProxyURL(entry.Content), "reading_time": readingTime})
 }

+ 3 - 1
internal/ui/ui.go

@@ -104,9 +104,11 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
 	uiRouter.HandleFunc("/entry/save/{entryID}", handler.saveEntry).Name("saveEntry").Methods(http.MethodPost)
 	uiRouter.HandleFunc("/entry/enclosure/{enclosureID}/save-progression", handler.saveEnclosureProgression).Name("saveEnclosureProgression").Methods(http.MethodPost)
 	uiRouter.HandleFunc("/entry/download/{entryID}", handler.fetchContent).Name("fetchContent").Methods(http.MethodPost)
-	uiRouter.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", handler.mediaProxy).Name("proxy").Methods(http.MethodGet)
 	uiRouter.HandleFunc("/entry/star/{entryID}", handler.toggleStarred).Name("toggleStarred").Methods(http.MethodPost)
 
+	// Media proxy.
+	uiRouter.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", handler.mediaProxy).Name("proxy").Methods(http.MethodGet)
+
 	// Share pages.
 	uiRouter.HandleFunc("/entry/share/{entryID}", handler.createSharedEntry).Name("shareEntry").Methods(http.MethodPost)
 	uiRouter.HandleFunc("/entry/unshare/{entryID}", handler.unshareEntry).Name("unshareEntry").Methods(http.MethodPost)

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio