Skip to content
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

Merged
merged 18 commits into from
Sep 10, 2019
Merged

limit the size of the uids cookie #1004

merged 18 commits into from
Sep 10, 2019

Conversation

guscarreon
Copy link
Contributor

We hit an issue where the header (containing the uids cookie) overran the limit that Ingress could handle. This pull request checks the size of the PBSCookie and, if found bigger than 32 KB in its http form, traverses the PBSCookie.uids field deleting the entries closest to expiration date.

usersync/cookie.go Outdated Show resolved Hide resolved
@@ -162,9 +215,31 @@ 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 MAX_COOKIE_SIZE int = 1 << 15 // 32 KB
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will want this as a config parameter rather than hardcoded. Also a check for a 0 "size" to disable enforcement of a maximum size may not be bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean get it from the configmap.yaml file itself? Bring it all the way here straight from the Configuration struct found in config/config.go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean check for a 0 size? A 0 size httpCookie.String()?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, bring the config struct, or the relevant value, all the way down to here. It is the configured value for MAX_COOKIE_SIZE you should check for a 0 value, as a method of turning off this feature. If a host limits the number of bidders they support, they can limit the size the cookie can grow to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

var oldestElem string = ""
var oldestDate int64 = math.MaxInt64
for key, value := range cookie.uids {
var timeSince time.Duration = now.Sub(value.Expires)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to specify time.Duration as that is already defined as the return type of now.Sub()

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, since you are taking the current time, and subtracting the expirery time, this will result in a negative number. The most negative number will be the expires time that is furthest from now, so in the end we will remove the entry that has the longest time before it expires.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gosh, I got the Sub() function backwards, corrected

config/config.go Outdated
CacheURL Cache `mapstructure:"cache"`
RecaptchaSecret string `mapstructure:"recaptcha_secret"`
HostCookie HostCookie `mapstructure:"host_cookie"`
MaxCookieSizeBytes int `mapstructure:"max_cookie_size_bytes"`
Copy link
Collaborator

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 think HostCookie is probably the best place for it out of the two.

Copy link
Contributor Author

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

config/config.go Outdated
@@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

hhhjort
hhhjort previously approved these changes Aug 28, 2019
Copy link
Collaborator

@hhhjort hhhjort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hhhjort hhhjort assigned mansinahar and unassigned hhhjort Aug 28, 2019
var oldestElem string = ""
var oldestDate int64 = math.MaxInt64
for key, value := range cookie.uids {
timeUntilExpiration := value.Expires.Sub(now)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a tip: Time package has an until function that will do exactly this for you. So you can potentially replace this with time.Until(value.Expires)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

uids map[string]uidWithExpiry
optOut bool
birthday *time.Time
maxSizeBytes int
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need maxSizeBytes as part of the PBSCookie struct. We can just access the MaxCookieSizeBytes in the HostCookie struct and pass it on in the call to SetCookieOnResponse. This should make the code a little simpler.

Spoke with @guscarreon offline about this and he said he will make the suggested change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

hhhjort
hhhjort previously approved these changes Sep 5, 2019
config/config.go Outdated
// If a non-zero-less-than-500-byte "host_cookie.max_cookie_size_bytes" value was specified in the
// environment configuration of prebid-server, default to 500 bytes
if maxCookieSize != 0 && maxCookieSize < MIN_COOKIE_SIZE_BYTES {
return errors.New("Configured cookie size is less than allowed minimum size")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to incorporate the MIN_COOKIE_SIZE_BYTES value in the error message so that the user knows what it is from the error message itself rather than having to dig into the code to find it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes perfect sense, done

}

func newBigCookie() (*PBSCookie, int) {
var bigCookie *PBSCookie = &PBSCookie{
Copy link
Contributor

@mansinahar mansinahar Sep 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about creating a test folder and adding these different cookies there in .json files and then using those in the tests rather than populating this test file with a giant map?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spoke with @guscarreon about this and we probably don't need this particular test case to start with and so he's gonna evaluate and remove this if not needed.

assert.Equal(t, cookieToSendLen, len(processedCookie.uids), "[Test %d] MaxCookieSizeBytes equal to zero or bigger than %d bytes should be snough to set and remain cookie unchanged \n", i+1, len(processedCookie.uids))
_, oldestFound := processedCookie.uids["key7"]
assert.Equal(t, cookieToSendLen, len(processedCookie.uids), "[Test %d] MaxCookieSizeBytes equal to zero or bigger than %d bytes should be enough to set and remain cookie unchanged \n", i+1, len(processedCookie.uids))
_, oldestFound := processedCookie.uids[closestToExpirationDate]
assert.Equal(t, oldestFound, true, "[Test %d] Oldest entry in cookie should not have been eliminated", i+1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just do assert.Contains here on the map and skip the previous line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

assert.Equal(t, oldestFound, true, "[Test %d] Oldest entry in cookie should not have been eliminated", i+1)
case "trim":
assert.Equal(t, cookieToSendLen > len(processedCookie.uids), true, "[Test %d] MaxCookieSizeBytes of %d is smaller than %d bytes and cookie entries should have been removed\n", i+1, testCases[i].maxCookieSize, cookieToSendLen)
_, oldestFound := processedCookie.uids["key7"]
_, oldestFound := processedCookie.uids[closestToExpirationDate]
assert.Equal(t, oldestFound, false, "[Test %d] Oldest entry in cookie was not eliminated", i+1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@hhhjort hhhjort merged commit ddf172c into prebid:master Sep 10, 2019
mansinahar pushed a commit to mansinahar/prebid-server that referenced this pull request Nov 1, 2019
* some research

* Modifications and test cases in place

* Hans' corrections and random expiration date to cookies in test case

* Cookie size gets defined in configmap.yaml now

* removed MaxCookieSizeBytes duplicate

* removed unnecessary constant declaration

* Set unlimited size as default, added unlimited size test case

* corrected test case

* symplified solution by pulling size from Configuration struct itself

* substituted time.Sub() for time.Until() and tuned adapter test cases

* removed vim .swp files

* MIN_COOKIE_SIZE_BYTES implemented in config.go

* correct SetCookieOnResponse() return value

* Printed MIN_COOKIE_SIZE_BYTES in error message, added one more test case in usersync/cookie_test.go

* Resolved conflict in config/config.go

* Resolved another conflict
katsuo5 pushed a commit to flux-dev-team/prebid-server-1 that referenced this pull request Dec 1, 2020
* some research

* Modifications and test cases in place

* Hans' corrections and random expiration date to cookies in test case

* Cookie size gets defined in configmap.yaml now

* removed MaxCookieSizeBytes duplicate

* removed unnecessary constant declaration

* Set unlimited size as default, added unlimited size test case

* corrected test case

* symplified solution by pulling size from Configuration struct itself

* substituted time.Sub() for time.Until() and tuned adapter test cases

* removed vim .swp files

* MIN_COOKIE_SIZE_BYTES implemented in config.go

* correct SetCookieOnResponse() return value

* Printed MIN_COOKIE_SIZE_BYTES in error message, added one more test case in usersync/cookie_test.go

* Resolved conflict in config/config.go

* Resolved another conflict
katsuo5 pushed a commit to flux-dev-team/prebid-server-1 that referenced this pull request Dec 2, 2020
* some research

* Modifications and test cases in place

* Hans' corrections and random expiration date to cookies in test case

* Cookie size gets defined in configmap.yaml now

* removed MaxCookieSizeBytes duplicate

* removed unnecessary constant declaration

* Set unlimited size as default, added unlimited size test case

* corrected test case

* symplified solution by pulling size from Configuration struct itself

* substituted time.Sub() for time.Until() and tuned adapter test cases

* removed vim .swp files

* MIN_COOKIE_SIZE_BYTES implemented in config.go

* correct SetCookieOnResponse() return value

* Printed MIN_COOKIE_SIZE_BYTES in error message, added one more test case in usersync/cookie_test.go

* Resolved conflict in config/config.go

* Resolved another conflict
katsuo5 pushed a commit to flux-dev-team/prebid-server-1 that referenced this pull request Dec 4, 2020
* some research

* Modifications and test cases in place

* Hans' corrections and random expiration date to cookies in test case

* Cookie size gets defined in configmap.yaml now

* removed MaxCookieSizeBytes duplicate

* removed unnecessary constant declaration

* Set unlimited size as default, added unlimited size test case

* corrected test case

* symplified solution by pulling size from Configuration struct itself

* substituted time.Sub() for time.Until() and tuned adapter test cases

* removed vim .swp files

* MIN_COOKIE_SIZE_BYTES implemented in config.go

* correct SetCookieOnResponse() return value

* Printed MIN_COOKIE_SIZE_BYTES in error message, added one more test case in usersync/cookie_test.go

* Resolved conflict in config/config.go

* Resolved another conflict
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants