Przeglądaj źródła

Add IMGPROXY_COOKIE_PASSTHROUGH_ALL config

DarthSim 2 miesięcy temu
rodzic
commit
204cfa3648
5 zmienionych plików z 90 dodań i 36 usunięć
  1. 1 0
      CHANGELOG.md
  2. 5 2
      config/config.go
  3. 81 30
      cookies/cookies.go
  4. 2 2
      imagedata/download.go
  5. 1 2
      stream.go

+ 1 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@
 ## [Unreleased]
 ### Added
 - Add [IMGPROXY_BASE64_URL_INCLUDES_FILENAME](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_BASE64_URL_INCLUDES_FILENAME) config.
+- Add [IMGPROXY_COOKIE_PASSTHROUGH_ALL](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_COOKIE_PASSTHROUGH_ALL) config.
 - (pro) Add PNG EXIF and XMP data to the `/info` endpoint response.
 
 ### Changed

+ 5 - 2
config/config.go

@@ -102,8 +102,9 @@ var (
 	SanitizeSvg        bool
 	AlwaysRasterizeSvg bool
 
-	CookiePassthrough bool
-	CookieBaseURL     string
+	CookiePassthrough    bool
+	CookieBaseURL        string
+	CookiePassthroughAll bool
 
 	SourceURLQuerySeparator string
 
@@ -317,6 +318,7 @@ func Reset() {
 
 	CookiePassthrough = false
 	CookieBaseURL = ""
+	CookiePassthroughAll = false
 
 	SourceURLQuerySeparator = "?"
 	LocalFileSystemRoot = ""
@@ -562,6 +564,7 @@ func Configure() error {
 
 	configurators.Bool(&CookiePassthrough, "IMGPROXY_COOKIE_PASSTHROUGH")
 	configurators.String(&CookieBaseURL, "IMGPROXY_COOKIE_BASE_URL")
+	configurators.Bool(&CookiePassthroughAll, "IMGPROXY_COOKIE_PASSTHROUGH_ALL")
 
 	// Can't rely on configurators.String here because it ignores empty values
 	if s, ok := os.LookupEnv("IMGPROXY_SOURCE_URL_QUERY_SEPARATOR"); ok {

+ 81 - 30
cookies/cookies.go

@@ -5,16 +5,65 @@ import (
 	"net/http"
 	"net/http/cookiejar"
 	"net/url"
+	"sync"
 
 	"golang.org/x/net/publicsuffix"
 
 	"github.com/imgproxy/imgproxy/v3/config"
 )
 
-func JarFromRequest(r *http.Request) (*cookiejar.Jar, error) {
-	jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
-	if err != nil {
-		return nil, err
+type anyCookieJarEntry struct {
+	Name   string
+	Value  string
+	Quoted bool
+}
+
+// anyCookieJar is a cookie jar that stores all cookies in memory
+// and doesn't care about domains and paths
+type anyCookieJar struct {
+	entries []anyCookieJarEntry
+	mu      sync.RWMutex
+}
+
+func (j *anyCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
+	j.mu.Lock()
+	defer j.mu.Unlock()
+
+	for _, c := range cookies {
+		entry := anyCookieJarEntry{
+			Name:   c.Name,
+			Value:  c.Value,
+			Quoted: c.Quoted,
+		}
+		j.entries = append(j.entries, entry)
+	}
+}
+
+func (j *anyCookieJar) Cookies(u *url.URL) []*http.Cookie {
+	j.mu.RLock()
+	defer j.mu.RUnlock()
+
+	cookies := make([]*http.Cookie, 0, len(j.entries))
+	for _, e := range j.entries {
+		c := http.Cookie{
+			Name:   e.Name,
+			Value:  e.Value,
+			Quoted: e.Quoted,
+		}
+		cookies = append(cookies, &c)
+	}
+
+	return cookies
+}
+
+func JarFromRequest(r *http.Request) (jar http.CookieJar, err error) {
+	if config.CookiePassthroughAll {
+		jar = &anyCookieJar{}
+	} else {
+		jar, err = cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	if r == nil {
@@ -23,38 +72,40 @@ func JarFromRequest(r *http.Request) (*cookiejar.Jar, error) {
 
 	var cookieBase *url.URL
 
-	if len(config.CookieBaseURL) > 0 {
-		if cookieBase, err = url.Parse(config.CookieBaseURL); err != nil {
-			return nil, fmt.Errorf("can't parse cookie base URL: %s", err)
+	if !config.CookiePassthroughAll {
+		if len(config.CookieBaseURL) > 0 {
+			if cookieBase, err = url.Parse(config.CookieBaseURL); err != nil {
+				return nil, fmt.Errorf("can't parse cookie base URL: %s", err)
+			}
 		}
-	}
 
-	if cookieBase == nil {
-		scheme := r.Header.Get("X-Forwarded-Proto")
-		if len(scheme) == 0 {
-			scheme = "http"
-		}
+		if cookieBase == nil {
+			scheme := r.Header.Get("X-Forwarded-Proto")
+			if len(scheme) == 0 {
+				scheme = "http"
+			}
 
-		host := r.Header.Get("X-Forwarded-Host")
-		if len(host) == 0 {
-			host = r.Header.Get("Host")
-		}
-		if len(host) == 0 {
-			host = r.Host
-		}
+			host := r.Header.Get("X-Forwarded-Host")
+			if len(host) == 0 {
+				host = r.Header.Get("Host")
+			}
+			if len(host) == 0 {
+				host = r.Host
+			}
 
-		if len(host) == 0 {
-			return jar, nil
-		}
+			if len(host) == 0 {
+				return jar, nil
+			}
 
-		port := r.Header.Get("X-Forwarded-Port")
-		if len(port) > 0 {
-			host = host + ":" + port
-		}
+			port := r.Header.Get("X-Forwarded-Port")
+			if len(port) > 0 {
+				host = host + ":" + port
+			}
 
-		cookieBase = &url.URL{
-			Scheme: scheme,
-			Host:   host,
+			cookieBase = &url.URL{
+				Scheme: scheme,
+				Host:   host,
+			}
 		}
 	}
 

+ 2 - 2
imagedata/download.go

@@ -50,7 +50,7 @@ const msgSourceImageIsUnreachable = "Source image is unreachable"
 
 type DownloadOptions struct {
 	Header    http.Header
-	CookieJar *cookiejar.Jar
+	CookieJar http.CookieJar
 }
 
 type ErrorNotModified struct {
@@ -135,7 +135,7 @@ func headersToStore(res *http.Response) map[string]string {
 	return m
 }
 
-func BuildImageRequest(ctx context.Context, imageURL string, header http.Header, jar *cookiejar.Jar) (*http.Request, context.CancelFunc, error) {
+func BuildImageRequest(ctx context.Context, imageURL string, header http.Header, jar http.CookieJar) (*http.Request, context.CancelFunc, error) {
 	reqCtx, reqCancel := context.WithTimeout(ctx, time.Duration(config.DownloadTimeout)*time.Second)
 
 	imageURL = transportCommon.EscapeURL(imageURL)

+ 1 - 2
stream.go

@@ -5,7 +5,6 @@ import (
 	"io"
 	"mime"
 	"net/http"
-	"net/http/cookiejar"
 	"path/filepath"
 	"strconv"
 	"sync"
@@ -53,7 +52,7 @@ func streamOriginImage(ctx context.Context, reqID string, r *http.Request, rw ht
 	defer metrics.StartStreamingSegment(ctx)()
 
 	var (
-		cookieJar *cookiejar.Jar
+		cookieJar http.CookieJar
 		err       error
 	)