image_proxy.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright 2020 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package proxy // import "miniflux.app/proxy"
  5. import (
  6. "strings"
  7. "miniflux.app/config"
  8. "miniflux.app/reader/sanitizer"
  9. "miniflux.app/url"
  10. "github.com/PuerkitoBio/goquery"
  11. "github.com/gorilla/mux"
  12. )
  13. // ImageProxyRewriter replaces image URLs with internal proxy URLs.
  14. func ImageProxyRewriter(router *mux.Router, data string) string {
  15. proxyImages := config.Opts.ProxyImages()
  16. if proxyImages == "none" {
  17. return data
  18. }
  19. doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
  20. if err != nil {
  21. return data
  22. }
  23. doc.Find("img").Each(func(i int, img *goquery.Selection) {
  24. if srcAttrValue, ok := img.Attr("src"); ok {
  25. if !isDataURL(srcAttrValue) && (proxyImages == "all" || !url.IsHTTPS(srcAttrValue)) {
  26. img.SetAttr("src", ProxifyURL(router, srcAttrValue))
  27. }
  28. }
  29. if srcsetAttrValue, ok := img.Attr("srcset"); ok {
  30. proxifySourceSet(img, router, proxyImages, srcsetAttrValue)
  31. }
  32. })
  33. doc.Find("picture source").Each(func(i int, sourceElement *goquery.Selection) {
  34. if srcsetAttrValue, ok := sourceElement.Attr("srcset"); ok {
  35. proxifySourceSet(sourceElement, router, proxyImages, srcsetAttrValue)
  36. }
  37. })
  38. output, err := doc.Find("body").First().Html()
  39. if err != nil {
  40. return data
  41. }
  42. return output
  43. }
  44. func proxifySourceSet(element *goquery.Selection, router *mux.Router, proxyImages, srcsetAttrValue string) {
  45. imageCandidates := sanitizer.ParseSrcSetAttribute(srcsetAttrValue)
  46. for _, imageCandidate := range imageCandidates {
  47. if !isDataURL(imageCandidate.ImageURL) && (proxyImages == "all" || !url.IsHTTPS(imageCandidate.ImageURL)) {
  48. imageCandidate.ImageURL = ProxifyURL(router, imageCandidate.ImageURL)
  49. }
  50. }
  51. element.SetAttr("srcset", imageCandidates.String())
  52. }
  53. func isDataURL(s string) bool {
  54. return strings.HasPrefix(s, "data:")
  55. }