Skip to content
This repository was archived by the owner on Dec 22, 2022. It is now read-only.

Commit 42e6765

Browse files
authored
Pass Through First Party Context Data (prebid#1479)
1 parent 22c454c commit 42e6765

12 files changed

+769
-23
lines changed

endpoints/openrtb2/auction.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,8 @@ func (deps *endpointDeps) validateImpExt(imp *openrtb.Imp, aliases map[string]st
765765
}
766766

767767
// Also accept bidder exts within imp[...].ext.prebid.bidder
768-
// NOTE: This is not part of the official API, we are not expecting clients
769-
// migrate from imp[...].ext.${BIDDER} to imp[...].ext.prebid.bidder.${BIDDER}
768+
// NOTE: This is not part of the official API yet, so we are not expecting clients
769+
// to migrate from imp[...].ext.${BIDDER} to imp[...].ext.prebid.bidder.${BIDDER}
770770
// at this time
771771
// https://github.com/prebid/prebid-server/pull/846#issuecomment-476352224
772772
if rawPrebidExt, ok := bidderExts[openrtb_ext.PrebidExtKey]; ok {
@@ -785,7 +785,7 @@ func (deps *endpointDeps) validateImpExt(imp *openrtb.Imp, aliases map[string]st
785785
/* Process all the bidder exts in the request */
786786
disabledBidders := []string{}
787787
for bidder, ext := range bidderExts {
788-
if bidder != openrtb_ext.PrebidExtKey {
788+
if isBidderToValidate(bidder) {
789789
coreBidder := bidder
790790
if tmp, isAlias := aliases[bidder]; isAlias {
791791
coreBidder = tmp
@@ -820,12 +820,20 @@ func (deps *endpointDeps) validateImpExt(imp *openrtb.Imp, aliases map[string]st
820820
// TODO #713 Fix this here
821821
if len(bidderExts) < 1 {
822822
errL = append(errL, fmt.Errorf("request.imp[%d].ext must contain at least one bidder", impIndex))
823-
return errL
824823
}
825824

826825
return errL
827826
}
828827

828+
func isBidderToValidate(bidder string) bool {
829+
// PrebidExtKey is a special case for the prebid config section and is not considered a bidder.
830+
831+
// FirstPartyDataContextExtKey is a special case for the first party data context section
832+
// and is not considered a bidder.
833+
834+
return bidder != openrtb_ext.PrebidExtKey && bidder != openrtb_ext.FirstPartyDataContextExtKey
835+
}
836+
829837
func (deps *endpointDeps) parseBidExt(ext json.RawMessage) (*openrtb_ext.ExtRequest, error) {
830838
if len(ext) < 1 {
831839
return nil, nil

endpoints/openrtb2/auction_test.go

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ func TestGoodRequests(t *testing.T) {
141141
supplementary.assert(t)
142142
}
143143

144+
func TestFirstPartyDataRequests(t *testing.T) {
145+
validRequests := &getResponseFromDirectory{
146+
dir: "sample-requests/first-party-data",
147+
payloadGetter: getRequestPayload,
148+
messageGetter: nilReturner,
149+
expectedCode: http.StatusOK,
150+
}
151+
validRequests.assert(t)
152+
}
153+
144154
// TestGoodNativeRequests makes sure we return 200s on well-formed Native requests.
145155
func TestGoodNativeRequests(t *testing.T) {
146156
tests := &getResponseFromDirectory{
@@ -1127,10 +1137,73 @@ func TestDisabledBidder(t *testing.T) {
11271137
}
11281138
}
11291139

1130-
func TestValidateImpExtDisabledBidder(t *testing.T) {
1131-
imp := &openrtb.Imp{
1132-
Ext: json.RawMessage(`{"appnexus":{"placement_id":555},"unknownbidder":{"foo":"bar"}}`),
1140+
func TestValidateImpExt(t *testing.T) {
1141+
testCases := []struct {
1142+
description string
1143+
impExt json.RawMessage
1144+
expectedImpExt string
1145+
expectedErrs []error
1146+
}{
1147+
{
1148+
description: "Empty",
1149+
impExt: nil,
1150+
expectedImpExt: "",
1151+
expectedErrs: []error{errors.New("request.imp[0].ext is required")},
1152+
},
1153+
{
1154+
description: "Valid Bidder",
1155+
impExt: json.RawMessage(`{"appnexus":{"placement_id":555}}`),
1156+
expectedImpExt: `{"appnexus":{"placement_id":555}}`,
1157+
expectedErrs: []error{},
1158+
},
1159+
{
1160+
description: "Valid Bidder + Disabled Bidder",
1161+
impExt: json.RawMessage(`{"appnexus":{"placement_id":555},"unknownbidder":{"foo":"bar"}}`),
1162+
expectedImpExt: `{"appnexus":{"placement_id":555}}`,
1163+
expectedErrs: []error{&errortypes.BidderTemporarilyDisabled{Message: "The bidder 'unknownbidder' has been disabled."}},
1164+
},
1165+
{
1166+
description: "Valid Bidder + Disabled Bidder + First Party Data Context",
1167+
impExt: json.RawMessage(`{"appnexus":{"placement_id":555},"unknownbidder":{"foo":"bar"},"context":{"data":{"keywords":"prebid server example"}}}`),
1168+
expectedImpExt: `{"appnexus":{"placement_id":555},"context":{"data":{"keywords":"prebid server example"}}}`,
1169+
expectedErrs: []error{&errortypes.BidderTemporarilyDisabled{Message: "The bidder 'unknownbidder' has been disabled."}},
1170+
},
1171+
{
1172+
description: "Valid Bidder + First Party Data Context",
1173+
impExt: json.RawMessage(`{"appnexus":{"placement_id":555},"context":{"data":{"keywords":"prebid server example"}}}`),
1174+
expectedImpExt: `{"appnexus":{"placement_id":555},"context":{"data":{"keywords":"prebid server example"}}}`,
1175+
expectedErrs: []error{},
1176+
},
1177+
{
1178+
description: "Valid Prebid Ext Bidder",
1179+
impExt: json.RawMessage(`{"prebid":{"bidder":{"appnexus":{"placement_id":555}}}}`),
1180+
expectedImpExt: `{"prebid":{"bidder":{"appnexus":{"placement_id":555}}}}`,
1181+
expectedErrs: []error{},
1182+
// request.imp[x].ext.prebid.bidder.{biddername} is only promoted/copied to request.ext.{biddername} if there is at least one disabled bidder.
1183+
},
1184+
{
1185+
description: "Valid Prebid Ext Bidder + First Party Data Context",
1186+
impExt: json.RawMessage(`{"prebid":{"bidder":{"appnexus":{"placement_id":555}}} ,"context":{"data":{"keywords":"prebid server example"}}}`),
1187+
expectedImpExt: `{"prebid":{"bidder":{"appnexus":{"placement_id":555}}},"context":{"data":{"keywords":"prebid server example"}}}`,
1188+
expectedErrs: []error{},
1189+
// request.imp[x].ext.prebid.bidder.{biddername} is only promoted/copied to request.ext.{biddername} if there is at least one disabled bidder.
1190+
},
1191+
{
1192+
description: "Valid Prebid Ext Bidder + Disabled Bidder",
1193+
impExt: json.RawMessage(`{"prebid":{"bidder":{"appnexus":{"placement_id":555},"unknownbidder":{"foo":"bar"}}}}`),
1194+
expectedImpExt: `{"prebid":{"bidder":{"appnexus":{"placement_id": 555},"unknownbidder":{"foo":"bar"}}},"appnexus":{"placement_id":555}}`,
1195+
expectedErrs: []error{&errortypes.BidderTemporarilyDisabled{Message: "The bidder 'unknownbidder' has been disabled."}},
1196+
// request.imp[x].ext.prebid.bidder.{biddername} disabled bidders are not removed. if there is a disabled bidder, the valid ones are promoted/copied to request.ext.{biddername}.
1197+
},
1198+
{
1199+
description: "Valid Prebid Ext Bidder + Disabled Bidder + First Party Data Context",
1200+
impExt: json.RawMessage(`{"prebid":{"bidder":{"appnexus":{"placement_id":555},"unknownbidder":{"foo":"bar"}}},"context":{"data":{"keywords":"prebid server example"}}}`),
1201+
expectedImpExt: `{"prebid":{"bidder":{"appnexus":{"placement_id": 555},"unknownbidder":{"foo":"bar"}}},"appnexus":{"placement_id":555},"context":{"data":{"keywords":"prebid server example"}}}`,
1202+
expectedErrs: []error{&errortypes.BidderTemporarilyDisabled{Message: "The bidder 'unknownbidder' has been disabled."}},
1203+
// request.imp[x].ext.prebid.bidder.{biddername} disabled bidders are not removed. if there is a disabled bidder, the valid ones are promoted/copied to request.ext.{biddername}.
1204+
},
11331205
}
1206+
11341207
deps := &endpointDeps{
11351208
&nobidExchange{},
11361209
newParamsValidator(t),
@@ -1149,9 +1222,19 @@ func TestValidateImpExtDisabledBidder(t *testing.T) {
11491222
nil,
11501223
hardcodedResponseIPValidator{response: true},
11511224
}
1152-
errs := deps.validateImpExt(imp, nil, 0)
1153-
assert.JSONEq(t, `{"appnexus":{"placement_id":555}}`, string(imp.Ext))
1154-
assert.Equal(t, []error{&errortypes.BidderTemporarilyDisabled{Message: "The bidder 'unknownbidder' has been disabled."}}, errs)
1225+
1226+
for _, test := range testCases {
1227+
imp := &openrtb.Imp{Ext: test.impExt}
1228+
1229+
errs := deps.validateImpExt(imp, nil, 0)
1230+
1231+
if len(test.expectedImpExt) > 0 {
1232+
assert.JSONEq(t, test.expectedImpExt, string(imp.Ext))
1233+
} else {
1234+
assert.Empty(t, imp.Ext)
1235+
}
1236+
assert.Equal(t, test.expectedErrs, errs)
1237+
}
11551238
}
11561239

11571240
func validRequest(t *testing.T, filename string) string {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"description": "The imp.ext.context field is valid for First Party Data and should be exempted from bidder name validation.",
3+
4+
"requestPayload": {
5+
"id": "some-request-id",
6+
"site": {
7+
"page": "test.somepage.com"
8+
},
9+
"imp": [{
10+
"id": "some-imp-id",
11+
"banner": {
12+
"format": [{
13+
"w": 600,
14+
"h": 500
15+
}, {
16+
"w": 300,
17+
"h": 600
18+
}]
19+
},
20+
"ext": {
21+
"appnexus": {
22+
"placementId": 12883451
23+
},
24+
"context": {
25+
"data": {
26+
"keywords": "prebid server example"
27+
}
28+
}
29+
}
30+
}]
31+
}
32+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"description": "The imp.ext.context field is valid for First Party Data and should be exempted from bidder name validation.",
3+
4+
"requestPayload": {
5+
"id": "some-request-id",
6+
"site": {
7+
"page": "test.somepage.com"
8+
},
9+
"imp": [{
10+
"id": "some-imp-id",
11+
"banner": {
12+
"format": [{
13+
"w": 600,
14+
"h": 500
15+
}, {
16+
"w": 300,
17+
"h": 600
18+
}]
19+
},
20+
"ext": {
21+
"prebid": {
22+
"bidder": {
23+
"appnexus": {
24+
"placementId": 12883451
25+
}
26+
}
27+
},
28+
"context": {
29+
"data": {
30+
"keywords": "prebid server example"
31+
}
32+
}
33+
}
34+
}]
35+
}
36+
}

0 commit comments

Comments
 (0)