diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go index 3c0feb4f7ab..4315ec7926f 100644 --- a/endpoints/openrtb2/amp_auction_test.go +++ b/endpoints/openrtb2/amp_auction_test.go @@ -50,6 +50,9 @@ func TestGoodAmpRequests(t *testing.T) { "imp-with-stored-resp.json", "gdpr-no-consentstring.json", "gdpr.json", + "buyeruids-case-insensitive.json", + "buyeruids-camel-case.json", + "aliased-buyeruids-case-insensitive.json", }, }, { diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 3a929c43abe..fdb135497d0 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -1817,7 +1817,9 @@ func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases return append(errL, errors.New(`request.user.ext.prebid requires a "buyeruids" property with at least one ID defined. If none exist, then request.user.ext.prebid should not be defined.`)) } for bidderName := range prebid.BuyerUIDs { - if _, ok := deps.bidderMap[bidderName]; !ok { + normalizedCoreBidder, _ := deps.normalizeBidderName(bidderName) + coreBidder := normalizedCoreBidder.String() + if _, ok := deps.bidderMap[coreBidder]; !ok { if _, ok := aliases[bidderName]; !ok { return append(errL, fmt.Errorf("request.user.ext.%s is neither a known bidder name nor an alias in request.ext.prebid.aliases", bidderName)) } diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json new file mode 100644 index 00000000000..1d2462c98b8 --- /dev/null +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/aliased-buyeruids-case-insensitive.json @@ -0,0 +1,84 @@ +{ + "description": "Amp request where root.user.ext.prebid.buyeruids field makes use of alias defined in root.ext.prebid.aliases and request makes use of case sensitive bidder name", + "query": "tag_id=101", + "config": { + "mockBidders": [ + { + "bidderName": "appnexus", + "currency": "USD", + "price": 2 + } + ] + }, + "mockBidRequest": { + "id": "request-with-user-ext-obj", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "prebid": { + "bidder": { + "Appnexus": { + "placementId": 12883451 + } + } + } + } + } + ], + "user": { + "ext": { + "prebid": { + "buyeruids": { + "unknown": "123" + } + } + } + }, + "ext": { + "prebid": { + "aliases": { + "unknown": "Appnexus" + } + } + } + }, + "expectedAmpResponse": { + "targeting": { + "hb_bidder": "Appnexus", + "hb_bidder_Appnexus": "Appnexus", + "hb_cache_host": "www.pbcserver.com", + "hb_cache_host_Appnex": "www.pbcserver.com", + "hb_cache_id": "0", + "hb_cache_id_Appnexus": "0", + "hb_cache_path": "/pbcache/endpoint", + "hb_cache_path_Appnex": "/pbcache/endpoint", + "hb_pb": "2.00", + "hb_pb_Appnexus": "2.00" + }, + "ortb2": { + "ext": { + "warnings": { + "general": [ + { + "code": 10002, + "message": "debug turned off for account" + } + ] + } + } + } + }, + "expectedReturnCode": 200 +} \ No newline at end of file diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json new file mode 100644 index 00000000000..4597fe7786a --- /dev/null +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-camel-case.json @@ -0,0 +1,77 @@ +{ + "description": "Amp request where root.user.ext.prebid.buyeruids field has camel case bidder name", + "query": "tag_id=101", + "config": { + "mockBidders": [ + { + "bidderName": "yahooAds", + "currency": "USD", + "price": 2 + } + ] + }, + "mockBidRequest": { + "id": "request-with-user-ext-obj", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "prebid": { + "bidder": { + "YahooAds": { + "placementId": 12883451 + } + } + } + } + } + ], + "user": { + "ext": { + "prebid": { + "buyeruids": { + "YahooAds": "123" + } + } + } + } + }, + "expectedAmpResponse": { + "targeting": { + "hb_bidder": "YahooAds", + "hb_bidder_YahooAds": "YahooAds", + "hb_cache_host": "www.pbcserver.com", + "hb_cache_host_YahooA": "www.pbcserver.com", + "hb_cache_id": "0", + "hb_cache_id_YahooAds": "0", + "hb_cache_path": "/pbcache/endpoint", + "hb_cache_path_YahooA": "/pbcache/endpoint", + "hb_pb": "2.00", + "hb_pb_YahooAds": "2.00" + }, + "ortb2": { + "ext": { + "warnings": { + "general": [ + { + "code": 10002, + "message": "debug turned off for account" + } + ] + } + } + } + }, + "expectedReturnCode": 200 +} \ No newline at end of file diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json new file mode 100644 index 00000000000..976fcb3cf7f --- /dev/null +++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/buyeruids-case-insensitive.json @@ -0,0 +1,77 @@ +{ + "description": "Amp request where root.user.ext.prebid.buyeruids field has case insensitive bidder name", + "query": "tag_id=101", + "config": { + "mockBidders": [ + { + "bidderName": "appnexus", + "currency": "USD", + "price": 2 + } + ] + }, + "mockBidRequest": { + "id": "request-with-user-ext-obj", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "prebid": { + "bidder": { + "Appnexus": { + "placementId": 12883451 + } + } + } + } + } + ], + "user": { + "ext": { + "prebid": { + "buyeruids": { + "Appnexus": "123" + } + } + } + } + }, + "expectedAmpResponse": { + "targeting": { + "hb_bidder": "Appnexus", + "hb_bidder_Appnexus": "Appnexus", + "hb_cache_host": "www.pbcserver.com", + "hb_cache_host_Appnex": "www.pbcserver.com", + "hb_cache_id": "0", + "hb_cache_id_Appnexus": "0", + "hb_cache_path": "/pbcache/endpoint", + "hb_cache_path_Appnex": "/pbcache/endpoint", + "hb_pb": "2.00", + "hb_pb_Appnexus": "2.00" + }, + "ortb2": { + "ext": { + "warnings": { + "general": [ + { + "code": 10002, + "message": "debug turned off for account" + } + ] + } + } + } + }, + "expectedReturnCode": 200 +} \ No newline at end of file diff --git a/exchange/exchangetest/buyeruid_case_insensitive.json b/exchange/exchangetest/buyeruid_case_insensitive.json new file mode 100644 index 00000000000..6999e8c9515 --- /dev/null +++ b/exchange/exchangetest/buyeruid_case_insensitive.json @@ -0,0 +1,144 @@ +{ + "incomingRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "user": { + "id": "userId", + "ext": { + "prebid": { + "buyeruids": { + "APPnexUS": "12345" + } + } + } + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "prebid": { + "bidder": { + "APPnexus": { + "placementId": 1 + }, + "appNEXUS": { + "placementId": 2 + }, + "amx": {} + } + } + } + } + ], + "ext": { + "prebid": { + "aliases": { + "APPnexus": "appnexus", + "appNEXUS": "appnexus" + } + } + } + } + }, + "outgoingRequests": { + "APPnexus": { + "expectRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "user": { + "id": "userId", + "buyeruid": "12345" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "placementId": 1 + } + } + } + ] + } + } + }, + "appNEXUS": { + "expectRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "user": { + "id": "userId", + "buyeruid": "12345" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "placementId": 2 + } + } + } + ] + } + } + }, + "amx": { + "expectRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "user": { + "id": "userId" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + } + } + } + ] + } + } + } + }, + "response": { + "bids": { + "id": "some-request-id", + "ext": {} + } + } +} diff --git a/exchange/utils.go b/exchange/utils.go index 0d9c90cda99..7d5beb64fb0 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -327,6 +327,12 @@ func getAuctionBidderRequests(auctionRequest AuctionRequest, return nil, []error{err} } + lowerCaseExplicitBuyerUIDs := make(map[string]string) + for bidder, uid := range explicitBuyerUIDs { + lowerKey := strings.ToLower(bidder) + lowerCaseExplicitBuyerUIDs[lowerKey] = uid + } + var errs []error for bidder, imps := range impsByBidder { coreBidder := resolveBidder(bidder, aliases) @@ -361,7 +367,7 @@ func getAuctionBidderRequests(auctionRequest AuctionRequest, } syncerKey := bidderToSyncerKey[string(coreBidder)] - if hadSync := prepareUser(&reqCopy, bidder, syncerKey, explicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil { + if hadSync := prepareUser(&reqCopy, bidder, syncerKey, lowerCaseExplicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil { bidderRequest.BidderLabels.CookieFlag = metrics.CookieFlagNo } else { bidderRequest.BidderLabels.CookieFlag = metrics.CookieFlagYes @@ -642,7 +648,7 @@ func createSanitizedImpExt(impExt, impExtPrebid map[string]json.RawMessage) (map func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool { cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey) - if id, ok := explicitBuyerUIDs[givenBidder]; ok { + if id, ok := explicitBuyerUIDs[strings.ToLower(givenBidder)]; ok { req.User = copyWithBuyerUID(req.User, id) } else if hadCookie { req.User = copyWithBuyerUID(req.User, cookieId)