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

Make user.ext.prebid.buyeruids bidder name case insensitive #3152

Merged
merged 10 commits into from
Oct 17, 2023

Conversation

Sonali-More-Xandr
Copy link
Contributor

We need to handle case insensitivity for user.ext.prebid.buyeruids biddernames. This PR updates the biddername look up to use the normalized names for buyeruids.BIDDER.

partially resolves #2400

@Sonali-More-Xandr
Copy link
Contributor Author

@bsardo We need this PR to go out with PBS 2.0. Can you please help me understand me why this PR is marked blocked and if there is something pending from my side

@bsardo
Copy link
Collaborator

bsardo commented Sep 28, 2023

Hi @Sonali-More-Xandr. We originally blocked this because we thought it conflicted with #3107 and we wanted to see that merged first, but on second look it appears that was a mistake so I'll remove the label.

@bsardo bsardo removed the blocked label Sep 28, 2023
@@ -49,6 +49,7 @@ func TestGoodAmpRequests(t *testing.T) {
"imp-with-stored-resp.json",
"gdpr-no-consentstring.json",
"gdpr.json",
"aliased-buyeruids-case-insensitive.json",
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that you have two test case files that you added for this PR. Would it mean that it also needs to be added in this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Added it in 07427d6

"ext": {
"prebid": {
"bidder": {
"YahooAds": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also add a test case for the request that has an alias in the request.ext.prebid.aliases field.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added in b43a4cf

onkarvhanumante
onkarvhanumante previously approved these changes Oct 9, 2023
@bsardo bsardo assigned VeronikaSolovei9 and unassigned AlexBVolcy Oct 9, 2023
Comment on lines 1819 to 1821
normalizedCoreBidder, _ := openrtb_ext.NormalizeBidderName(bidderName)
coreBidder := normalizedCoreBidder.String()
if _, ok := deps.bidderMap[coreBidder]; !ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: in this PR here https://github.com/prebid/prebid-server/pull/3187/files#diff-785f5ab5ebde657757f3b3c34bf30a939782678d61bf1ea43f844c4f22a012d9R155:~:text=normalizeBidderName%20%20%20%20%20%20%20normalizeBidderName @SyntaxNode introduced a new function in endpoint deps.
This validation function already has deps. Could you please pull latest changes from main branch and call normalize bidder name through the normalizedCoreBidder, _ := deps.normalizeBidderName(bidderName). With this change code will be more consistent.

Other than this looks good, local testing looks good too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you, Veronika! Updated it in 49a8d0e

@bsardo bsardo added the PBS 2.0 label Oct 10, 2023
@VeronikaSolovei9
Copy link
Contributor

VeronikaSolovei9 commented Oct 12, 2023

Sonali, thank you for your updates!
I want to apologize. At the moment I tested your PR at the first time, I misunderstood how this should work.
(I did the same mistake for my StoredBidResponses PR and had to fix it... )

Here is a desired behavior.
Let's say we have a request with one imp. In the imp.ext we have this config:

"ext": {
                        "prebid": {
                            "bidder": {
                                "APPnexus": {
                                    "placementId": 1
                                },
                                "appNEXUS": {
                                    "placementId": 2
                                },
                                "amx": {}
                            }
                        }
                    }

We also have this config in user.ext.prebid.buyerids:

"user": {
                "id": "userId",
                "ext": {
                    "prebid": {
                        "buyeruids": {
                            "APPnexUS": "12345"
                        }
                    }
                }
            }

in this case "buyeruids": {"APPnexUS": "12345"} should be applied to both "APPnexus" and "appNEXUS", because we need to support case-insesitive comparisons, not case sensitive as it is now.
My mistake was to check that user.ext.prebid."buyeruids": { "APPnexus": "12345" } will be only applied to "APPnexus". This is not right, it should be applied to any "appnexus" in imp.ext.

In order to fix this, add next change on top of existing ones in this PR: utils.go -> func prepareUser should be changed to this:

func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)

	buyerIdSet := false
	for bidderName, id := range explicitBuyerUIDs {
		if strings.EqualFold(bidderName, givenBidder) {
			req.User = copyWithBuyerUID(req.User, id)
			buyerIdSet = true
                         break 
		}
	}
	if !buyerIdSet && hadCookie {
		req.User = copyWithBuyerUID(req.User, cookieId)
	}

	return hadCookie
}

Also I would like you to add a test that explicitly tests what data goes to what bidder. Put this test in exchange/exchangetest/ directory. This test has 3 bidders in imp.ext. 2 of them are "apnexus" in different casing and one amx. It also has a req.user.ext.prebid.buyerids{"APPnexUS": "12345"}.
In outgoingRequests there are 3 requests we expect to be executed: APPnexus, appNEXUS and amx. Only APPnexus and appNEXUS will receive user.buyeruid: "12345" -> test_buyerids.json

@onkarvhanumante
Copy link
Contributor

onkarvhanumante commented Oct 13, 2023

master code

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 {
  	req.User = copyWithBuyerUID(req.User, id)
  } else if hadCookie {
  	req.User = copyWithBuyerUID(req.User, cookieId)
  }

  return hadCookie
}

suggested code #3152 (comment)

func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)

	buyerIdSet := false
	for bidderName, id := range explicitBuyerUIDs {
		if strings.EqualFold(bidderName, givenBidder) {
			req.User = copyWithBuyerUID(req.User, id)
			buyerIdSet = true
                         break 
		}
	}
	if !buyerIdSet && hadCookie {
		req.User = copyWithBuyerUID(req.User, cookieId)
	}

	return hadCookie
}

Thanks @VeronikaSolovei9 for above suggestion. But something to note is this will change increase time complexity of prepareUser(). Also prepareUser() is called within the loop.

for bidder, imps := range impsByBidder {
coreBidder := resolveBidder(bidder, aliases)
reqCopy := *req.BidRequest
reqCopy.Imp = imps
sChainWriter.Write(&reqCopy, bidder)
reqCopy.Ext, err = buildRequestExtForBidder(bidder, req.BidRequest.Ext, requestExt, bidderParamsInReqExt, auctionRequest.Account.AlternateBidderCodes)
if err != nil {
return nil, []error{err}
}
if err := removeUnpermissionedEids(&reqCopy, bidder, requestExt); err != nil {
errs = append(errs, fmt.Errorf("unable to enforce request.ext.prebid.data.eidpermissions because %v", err))
continue
}
bidderRequest := BidderRequest{
BidderName: openrtb_ext.BidderName(bidder),
BidderCoreName: coreBidder,
BidRequest: &reqCopy,
BidderLabels: metrics.AdapterLabels{
Source: auctionRequest.LegacyLabels.Source,
RType: auctionRequest.LegacyLabels.RType,
Adapter: coreBidder,
PubID: auctionRequest.LegacyLabels.PubID,
CookieFlag: auctionRequest.LegacyLabels.CookieFlag,
AdapterBids: metrics.AdapterBidPresent,
},
}
syncerKey := bidderToSyncerKey[string(coreBidder)]
if hadSync := prepareUser(&reqCopy, bidder, syncerKey, explicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil {

How about preparing lowercase key map from explicitBuyerUIDs outside impsByBidder loop and could lookup using strings.ToLower() in prepareUser(). Preparing lowercase key map will incur less complexity.

lowerCaseExplicitBuyerUIDs = ... code to have lower case bidder name keys from explicitBuyerUIDs map

 for bidder, imps := range impsByBidder { 
 	coreBidder := resolveBidder(bidder, aliases) 
  
 	reqCopy := *req.BidRequest 
 	reqCopy.Imp = imps 
  
 	sChainWriter.Write(&reqCopy, bidder) 
        ...
        if hadSync := prepareUser(&reqCopy, bidder, syncerKey, explicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil { 
...

func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, lowerCaseExplicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)

	if id, ok := lowerCaseExplicitBuyerUIDs [strings.ToLower(givenBidder)]; ok {
		req.User = copyWithBuyerUID(req.User, id)
	} else if hadCookie {
		req.User = copyWithBuyerUID(req.User, cookieId)
	}

	return hadCookie
}

@VeronikaSolovei9
Copy link
Contributor

Sure, if this gives the same result! As long as attached test passes and data is returned as expected.

@SyntaxNode SyntaxNode merged commit b3e5d1d into master Oct 17, 2023
3 checks passed
@SyntaxNode SyntaxNode deleted the PBS-1257-1 branch November 17, 2023 22:13
svamiftah pushed a commit to sovrn/prebid-server that referenced this pull request Nov 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bidder names should be case insensitive
7 participants