123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- package cookies
- import (
- "fmt"
- "net/http"
- "net/http/cookiejar"
- "net/url"
- "slices"
- "sync"
- "golang.org/x/net/publicsuffix"
- "github.com/imgproxy/imgproxy/v3/httpheaders"
- "github.com/imgproxy/imgproxy/v3/ierrors"
- )
- // Cookies represents a cookies manager
- type Cookies struct {
- config *Config
- }
- // cookieJar is a cookie jar that stores all cookies in memory
- // and doesn't care about domains and paths
- type cookieJar struct {
- entries []*http.Cookie
- mu sync.RWMutex
- }
- // New creates a new Cookies instance
- func New(config *Config) (*Cookies, error) {
- if err := config.Validate(); err != nil {
- return nil, err
- }
- cookies := &Cookies{config: config}
- return cookies, nil
- }
- // SetCookies stores the cookies in the jar. For each source cookie it creates
- // a new cookie with only Name, Value and Quoted fields set.
- func (j *cookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
- j.mu.Lock()
- defer j.mu.Unlock()
- // Remove all unimportant cookie params
- for _, c := range cookies {
- j.entries = append(j.entries, &http.Cookie{
- Name: c.Name,
- Value: c.Value,
- Quoted: c.Quoted,
- })
- }
- }
- // Cookies returns all stored cookies
- func (j *cookieJar) Cookies(u *url.URL) []*http.Cookie {
- j.mu.RLock()
- defer j.mu.RUnlock()
- // NOTE: do we need to clone, or we could just return a ref?
- return slices.Clone(j.entries)
- }
- // JarFromRequest creates a cookie jar from the given HTTP request
- func (c *Cookies) JarFromRequest(r *http.Request) (jar http.CookieJar, err error) {
- // If cookie passthrough is disabled, return nil jar
- if !c.config.CookiePassthrough {
- return nil, nil
- }
- if c.config.CookiePassthroughAll {
- jar = &cookieJar{}
- } else {
- jar, err = cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
- if err != nil {
- return nil, err
- }
- }
- if r == nil {
- return jar, nil
- }
- var cookieBase *url.URL
- if !c.config.CookiePassthroughAll {
- if len(c.config.CookieBaseURL) > 0 {
- if cookieBase, err = url.Parse(c.config.CookieBaseURL); err != nil {
- return nil, ierrors.Wrap(cookieError(fmt.Sprintf("can't parse cookie base URL: %s", err)), 0)
- }
- }
- if cookieBase == nil {
- scheme := r.Header.Get(httpheaders.XForwardedProto)
- if len(scheme) == 0 {
- scheme = "http"
- }
- host := r.Header.Get(httpheaders.XForwardedHost)
- if len(host) == 0 {
- host = r.Header.Get(httpheaders.Host)
- }
- if len(host) == 0 {
- host = r.Host
- }
- if len(host) == 0 {
- return jar, nil
- }
- port := r.Header.Get(httpheaders.XForwardedPort)
- if len(port) > 0 {
- host = host + ":" + port
- }
- cookieBase = &url.URL{
- Scheme: scheme,
- Host: host,
- }
- }
- }
- jar.SetCookies(cookieBase, r.Cookies())
- return jar, nil
- }
|