-
Notifications
You must be signed in to change notification settings - Fork 739
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
Implement EID Permissions #1633
Conversation
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.
A couple of comments
exchange/utils.go
Outdated
} | ||
|
||
var eids []openrtb_ext.ExtUserEid | ||
if err := json.Unmarshal(eidsRaw, &eids); err != nil { |
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.
Given that extractBuyerUIDs
unmarshals the User.Ext
into an openrtb_ext.ExtUser
struct that already reads the eids
into an []ExtUserEid
array, maybe we can work with this field and avoid additional unmarshalling inside removeUnpermissionedEids
. Both extractBuyerUIDs
and removeUnpermissionedEids
use the unmarshalled User.Ext
, therefore we could maybe:
174 func getAuctionBidderRequests(req AuctionRequest, requestExt *openrtb_ext.ExtRequest, impsByBidder map[string][]openrtb.I
175
176 bidderRequests := make([]BidderRequest, 0, len(impsByBidder))
177
+ userExt := unmarshalUserExt(req.BidRequest.User)
+
178 - explicitBuyerUIDs, err := extractBuyerUIDs(req.BidRequest.User)
+ explicitBuyerUIDs, err := extractBuyerUIDs(userExt)
179 if err != nil {
180 return nil, []error{err}
181 }
182
183 *-- 11 lines: var sChainsByBidder map[string]*openrtb_ext.ExtRequestPrebidSChainSChain---
194
195 var errs []error
196 for bidder, imps := range impsByBidder {
197 coreBidder := resolveBidder(bidder, aliases)
198
199 *-- 5 lines: reqCopy := *req.BidRequest-------------------------------------------------
204
205 if err := removeUnpermissionedEids(&reqCopy, bidder, requestExt); err != nil {
+ if err := removeUnpermissionedEids(&reqCopy, bidder, requestExt, userExt); err != nil {
206 errs = append(errs, fmt.Errorf("unable to enforce request.ext.prebid.data.eidpermissions because %v", err))
207 continue
208 }
exchange/utils.go
and modify removeUnpermissionedEids
accordingly.
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.
Without a doubt there's room for improvement here. It's complicated though since extractBuyerUIDs
applies for the entire request and removeUnpermissionedEids
applies to a request copy for the bidder. I experimented locally with what you're suggesting.. but object tracking and map cloning became complicated. We'll be addressing duplicate serialization over time in the near future, so let's just tackle it then.
func (deps *endpointDeps) validateEidPermissions(req *openrtb_ext.ExtRequest, aliases map[string]string) error { | ||
if req == nil || req.Prebid.Data == nil { | ||
return nil | ||
} |
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.
According to issue #1621: "If eidPermissions is not an array, ignore it and emit a 400 error with a reasonable description in the body". We do check the array lenght downstream in exchange/utils.go
line 464:
457 func removeUnpermissionedEids(request *openrtb.BidRequest, bidder string, requestExt *openrtb_ext.ExtRequest) error {
458 // ensure request might have eids (as much as we can check before unmarshalling)
459 if request.User == nil || len(request.User.Ext) == 0 {
460 return nil
461 }
462
463 // ensure request has eid permissions to enforce
464 if requestExt == nil || requestExt.Prebid.Data == nil || len(requestExt.Prebid.Data.EidPermissions) == 0 {
465 return nil //empty array check ----^
466 }
Should we error out when empty instead? If so, should we do it here before it gets downstream?
426 func (deps *endpointDeps) validateEidPermissions(req *openrtb_ext.ExtRequest, aliases map[string]string) error {
427 if req == nil || req.Prebid.Data == nil {
428 return nil
429 }
+ if len(requestExt.Prebid.Data.EidPermissions) == 0 {
+ return fmt.Errorf(`eidPermissions is not an array, ignore it and emit a 400 error...`)
+ }
430
431 uniqueSources := make(map[string]struct{}, len(req.Prebid.Data.EidPermissions))
432 for i, eid := range req.Prebid.Data.EidPermissions {
433 if len(eid.Source) == 0 {
434 return fmt.Errorf(`request.ext.prebid.data.eidpermissions[%d] missing required field: "source"`, i)
435 }
endpoints/openrtb2/auction.go
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.
The unmarshaller enforces type correctness. If it's not an array, the core json.Unmarshal method will return an error and we already consider that a fatal error. I don't really see a need to consider an empty array as a validation error. It's silly to pass an empty array.. but is it worth rejecting a request for?
@@ -1440,19 +1440,19 @@ func TestCurrencyTrunc(t *testing.T) { | |||
|
|||
ui := uint64(1) | |||
req := openrtb.BidRequest{ | |||
ID: "someID", | |||
ID: "anyRequestID", |
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.
Unrelated: Cleaned up some of the test ids to make it clear they have no special meaning.
func (deps *endpointDeps) validateEidPermissions(req *openrtb_ext.ExtRequest, aliases map[string]string) error { | ||
if req == nil || req.Prebid.Data == nil { | ||
return nil | ||
} |
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.
The unmarshaller enforces type correctness. If it's not an array, the core json.Unmarshal method will return an error and we already consider that a fatal error. I don't really see a need to consider an empty array as a validation error. It's silly to pass an empty array.. but is it worth rejecting a request for?
expectations: map[string]*bidderRequest{coreBidder: spec.ExpectedRequest}, | ||
mockResponses: map[string]bidderResponse{coreBidder: spec.MockResponse}, | ||
expectations: map[string]*bidderRequest{alias: spec.ExpectedRequest}, | ||
mockResponses: map[string]bidderResponse{alias: spec.MockResponse}, |
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.
Fixes an unrelated test framework bug. We never met the condition before, so it's gone unnoticed.
prepareSource(&reqCopy, bidder, sChainsByBidder) | ||
|
||
bidder := BidderRequest{ | ||
if err := removeUnpermissionedEids(&reqCopy, bidder, requestExt); err != nil { | ||
errs = append(errs, fmt.Errorf("unable to enforce request.ext.prebid.data.eidpermissions because %v", err)) |
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.
The errors are just from marshalling, which shouldn't occur here. Is a continue the correct behavior?
exchange/utils.go
Outdated
} | ||
|
||
var eids []openrtb_ext.ExtUserEid | ||
if err := json.Unmarshal(eidsRaw, &eids); err != nil { |
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.
Without a doubt there's room for improvement here. It's complicated though since extractBuyerUIDs
applies for the entire request and removeUnpermissionedEids
applies to a request copy for the bidder. I experimented locally with what you're suggesting.. but object tracking and map cloning became complicated. We'll be addressing duplicate serialization over time in the near future, so let's just tackle it then.
expectedUserExt: json.RawMessage(`{"eids":[{"source":"source1","id":"anyID"}]}`), | ||
}, | ||
{ | ||
description: "Allowed By Empty Permissions", |
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.
What is the difference between nil permissions and empty permissions?
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.
As of now, nothing. Good catch. This was a copy/paste error. Fixed.
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.
LGTM
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.
LGTM
@@ -419,6 +423,51 @@ func validateSChains(req *openrtb_ext.ExtRequest) error { | |||
return err | |||
} | |||
|
|||
func (deps *endpointDeps) validateEidPermissions(req *openrtb_ext.ExtRequest, aliases map[string]string) error { | |||
if req == nil || req.Prebid.Data == nil { |
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.
The first condition will never be false because validateEidPermissions
only gets called if condition in line 320 of endpoints/openrtb2/auction.go
evaluates to true
320 } else if bidExt != nil {
.
.
.
335 if err := deps.validateEidPermissions(bidExt, aliases); err != nil {
336 return []error{err}
337 }
338 }
endpoints/openrtb2/auction.go
|
||
testCases := []struct { | ||
description string | ||
request *openrtb_ext.ExtRequest |
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.
Just to not get confused with an incoming bid request, can we change the name to requestExt
? Or bidRequestExt
?
{Source: "sourceB", Bidders: []string{"z"}}, | ||
}}}}, | ||
expectedError: errors.New(`request.ext.prebid.data.eidpermissions[1] contains unrecognized bidder "z"`), | ||
}, |
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.
Can we add the test: "Valid, more than one element in the Bidders
array"?
Implements: #1621