-
Notifications
You must be signed in to change notification settings - Fork 758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
limit the size of the uids cookie #1004
Changes from 4 commits
bb3a1c8
ad41f46
6ce9501
be06e84
bf41c0a
68d1a23
a5ce966
348b9f7
2edd18e
74c1744
5cd01f8
357b6fc
048273c
04c85c7
1ffc002
24cf211
89d76b7
b1134cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,15 +27,16 @@ type Configuration struct { | |
EnableGzip bool `mapstructure:"enable_gzip"` | ||
// StatusResponse is the string which will be returned by the /status endpoint when things are OK. | ||
// If empty, it will return a 204 with no content. | ||
StatusResponse string `mapstructure:"status_response"` | ||
AuctionTimeouts AuctionTimeouts `mapstructure:"auction_timeouts_ms"` | ||
CacheURL Cache `mapstructure:"cache"` | ||
RecaptchaSecret string `mapstructure:"recaptcha_secret"` | ||
HostCookie HostCookie `mapstructure:"host_cookie"` | ||
Metrics Metrics `mapstructure:"metrics"` | ||
DataCache DataCache `mapstructure:"datacache"` | ||
StoredRequests StoredRequests `mapstructure:"stored_requests"` | ||
CategoryMapping StoredRequestsSlim `mapstructure:"category_mapping"` | ||
StatusResponse string `mapstructure:"status_response"` | ||
AuctionTimeouts AuctionTimeouts `mapstructure:"auction_timeouts_ms"` | ||
CacheURL Cache `mapstructure:"cache"` | ||
RecaptchaSecret string `mapstructure:"recaptcha_secret"` | ||
HostCookie HostCookie `mapstructure:"host_cookie"` | ||
MaxCookieSizeBytes int `mapstructure:"max_cookie_size_bytes"` | ||
Metrics Metrics `mapstructure:"metrics"` | ||
DataCache DataCache `mapstructure:"datacache"` | ||
StoredRequests StoredRequests `mapstructure:"stored_requests"` | ||
CategoryMapping StoredRequestsSlim `mapstructure:"category_mapping"` | ||
// Note that StoredVideo refers to stored video requests, and has nothing to do with caching video creatives. | ||
StoredVideo StoredRequestsSlim `mapstructure:"stored_video_req"` | ||
|
||
|
@@ -168,12 +169,13 @@ type FileLogs struct { | |
} | ||
|
||
type HostCookie struct { | ||
Domain string `mapstructure:"domain"` | ||
Family string `mapstructure:"family"` | ||
CookieName string `mapstructure:"cookie_name"` | ||
OptOutURL string `mapstructure:"opt_out_url"` | ||
OptInURL string `mapstructure:"opt_in_url"` | ||
OptOutCookie Cookie `mapstructure:"optout_cookie"` | ||
Domain string `mapstructure:"domain"` | ||
Family string `mapstructure:"family"` | ||
CookieName string `mapstructure:"cookie_name"` | ||
OptOutURL string `mapstructure:"opt_out_url"` | ||
OptInURL string `mapstructure:"opt_in_url"` | ||
MaxCookieSizeBytes int `mapstructure:"max_cookie_size_bytes"` | ||
OptOutCookie Cookie `mapstructure:"optout_cookie"` | ||
// Cookie timeout in days | ||
TTL int64 `mapstructure:"ttl_days"` | ||
} | ||
|
@@ -500,6 +502,7 @@ func SetupViper(v *viper.Viper, filename string) { | |
v.SetDefault("host_cookie.optout_cookie.name", "") | ||
v.SetDefault("host_cookie.value", "") | ||
v.SetDefault("host_cookie.ttl_days", 90) | ||
v.SetDefault("host_cookie.max_cookie_size_bytes", 32768) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably want to set the default as unlimited, so it won't change the behavior of running installs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
v.SetDefault("http_client.max_idle_connections", 400) | ||
v.SetDefault("http_client.max_idle_connections_per_host", 10) | ||
v.SetDefault("http_client.idle_connection_timeout_seconds", 60) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"encoding/base64" | ||
"encoding/json" | ||
"errors" | ||
"math" | ||
"net/http" | ||
"time" | ||
|
||
|
@@ -14,6 +15,7 @@ import ( | |
// DEFAULT_TTL is the default amount of time which a cookie is considered valid. | ||
const DEFAULT_TTL = 14 * 24 * time.Hour | ||
const UID_COOKIE_NAME = "uids" | ||
const MAX_COOKIE_SIZE int = 1 << 15 // 32 KB | ||
|
||
// customBidderTTLs stores rules about how long a particular UID sync is valid for each bidder. | ||
// If a bidder does a cookie sync *without* listing a rule here, then the DEFAULT_TTL will be used. | ||
|
@@ -30,9 +32,10 @@ var bidderToFamilyNames = map[openrtb_ext.BidderName]string{ | |
// To get an instance of this from a request, use ParsePBSCookieFromRequest. | ||
// To write an instance onto a response, use SetCookieOnResponse. | ||
type PBSCookie struct { | ||
uids map[string]uidWithExpiry | ||
optOut bool | ||
birthday *time.Time | ||
uids map[string]uidWithExpiry | ||
optOut bool | ||
birthday *time.Time | ||
maxSizeBytes int | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need Spoke with @guscarreon offline about this and he said he will make the suggested change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
} | ||
|
||
// uidWithExpiry bundles the UID with an Expiration date. | ||
|
@@ -49,17 +52,17 @@ func ParsePBSCookieFromRequest(r *http.Request, cookie *config.HostCookie) *PBSC | |
if cookie.OptOutCookie.Name != "" { | ||
optOutCookie, err1 := r.Cookie(cookie.OptOutCookie.Name) | ||
if err1 == nil && optOutCookie.Value == cookie.OptOutCookie.Value { | ||
pc := NewPBSCookie() | ||
pc := NewPBSCookie(cookie.MaxCookieSizeBytes) | ||
pc.SetPreference(false) | ||
return pc | ||
} | ||
} | ||
var parsed *PBSCookie | ||
uidCookie, err2 := r.Cookie(UID_COOKIE_NAME) | ||
if err2 == nil { | ||
parsed = ParsePBSCookie(uidCookie) | ||
parsed = ParsePBSCookie(uidCookie, cookie.MaxCookieSizeBytes) | ||
} else { | ||
parsed = NewPBSCookie() | ||
parsed = NewPBSCookie(cookie.MaxCookieSizeBytes) | ||
} | ||
// Fixes #582 | ||
if uid, _, _ := parsed.GetUID(cookie.Family); uid == "" && cookie.CookieName != "" { | ||
|
@@ -71,8 +74,8 @@ func ParsePBSCookieFromRequest(r *http.Request, cookie *config.HostCookie) *PBSC | |
} | ||
|
||
// ParsePBSCookie parses the UserSync cookie from a raw HTTP cookie. | ||
func ParsePBSCookie(uidCookie *http.Cookie) *PBSCookie { | ||
pc := NewPBSCookie() | ||
func ParsePBSCookie(uidCookie *http.Cookie, MaxSizeBytes int) *PBSCookie { | ||
pc := NewPBSCookie(MaxSizeBytes) | ||
|
||
j, err := base64.URLEncoding.DecodeString(uidCookie.Value) | ||
if err != nil { | ||
|
@@ -87,10 +90,11 @@ func ParsePBSCookie(uidCookie *http.Cookie) *PBSCookie { | |
} | ||
|
||
// NewPBSCookie returns an empty PBSCookie | ||
func NewPBSCookie() *PBSCookie { | ||
func NewPBSCookie(MaxSizeBytes int) *PBSCookie { | ||
return &PBSCookie{ | ||
uids: make(map[string]uidWithExpiry), | ||
birthday: timestamp(), | ||
uids: make(map[string]uidWithExpiry), | ||
birthday: timestamp(), | ||
maxSizeBytes: MaxSizeBytes, | ||
} | ||
} | ||
|
||
|
@@ -162,9 +166,30 @@ func (cookie *PBSCookie) GetId(bidderName openrtb_ext.BidderName) (id string, ex | |
// SetCookieOnResponse is a shortcut for "ToHTTPCookie(); cookie.setDomain(domain); setCookie(w, cookie)" | ||
func (cookie *PBSCookie) SetCookieOnResponse(w http.ResponseWriter, domain string, ttl time.Duration) { | ||
httpCookie := cookie.ToHTTPCookie(ttl) | ||
var now time.Time = time.Now() | ||
|
||
if domain != "" { | ||
httpCookie.Domain = domain | ||
} | ||
|
||
var currSize int = len([]byte(httpCookie.String())) | ||
for cookie.maxSizeBytes > 0 && currSize > cookie.maxSizeBytes { | ||
var oldestElem string = "" | ||
var oldestDate int64 = math.MaxInt64 | ||
for key, value := range cookie.uids { | ||
timeUntilExpiration := value.Expires.Sub(now) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a tip: Time package has an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
if timeUntilExpiration < time.Duration(oldestDate) { | ||
oldestElem = key | ||
oldestDate = int64(timeUntilExpiration) | ||
} | ||
} | ||
delete(cookie.uids, oldestElem) | ||
httpCookie = cookie.ToHTTPCookie(ttl) | ||
if domain != "" { | ||
httpCookie.Domain = domain | ||
} | ||
currSize = len([]byte(httpCookie.String())) | ||
} | ||
http.SetCookie(w, httpCookie) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have a Max Size here as well as in
HostCookie
. I thinkHostCookie
is probably the best place for it out of the two.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, that's a leftover from another approach I was trying. Good call. Removed