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

sovrn: Add video support #2232

Merged
merged 77 commits into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
dd18694
initial checkin of sovrn adapter
kevinKalmbach Jul 28, 2017
f619601
Merge remote-tracking branch 'upstream/master'
kevinKalmbach Aug 8, 2017
563787f
Merge remote-tracking branch 'upstream/master'
kevinKalmbach Aug 9, 2017
cd70e4a
Merge remote-tracking branch 'upstream/master'
kevinKalmbach Aug 16, 2017
446c8d8
some adapter updates from testing
aprakash-sovrn Aug 16, 2017
572725e
Merge remote-tracking branch 'upstream/master'
kevinKalmbach Sep 5, 2017
4d20c54
User sync url/params updates
aprakash-sovrn Oct 4, 2017
c61126a
merge upstream/master
aprakash-sovrn Oct 4, 2017
058319c
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Oct 16, 2017
0bd1577
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Oct 23, 2017
cd0de9b
sovrn adapter unit tests
aprakash-sovrn Oct 23, 2017
5d707f9
Merge remote-tracking branch 'prebid/master' into PSERV-19_sovrn_adapter
aprakash-sovrn Oct 27, 2017
12005e8
Updates to pass validation
aprakash-sovrn Oct 30, 2017
1ecb04e
Merge pull request #1 from sovrn/PSERV-19_sovrn_adapter
aprakash-sovrn Nov 3, 2017
1dc8299
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Nov 3, 2017
d284e95
Add Headers
Nov 15, 2017
20e2b1f
secure
Nov 17, 2017
c576243
Tests for headers
Nov 28, 2017
2a721ba
fix pixel endpoint params
Nov 29, 2017
48f2f32
Fix test for new pixel ep
Nov 30, 2017
bf1cd4f
Merge branch 'master' of https://github.com/prebid/prebid-server
Dec 1, 2017
a3b0275
Merge branch 'master' of https://github.com/prebid/prebid-server
Dec 5, 2017
06a29b2
fix test after os change
Dec 6, 2017
deaf51a
add info.yaml
Dec 6, 2017
16dcca8
Merge branch 'master' of https://github.com/prebid/prebid-server
Dec 8, 2017
43cc6dc
test no cookies behavior & adapter names
Dec 8, 2017
4595b2d
Add test for nocontent & notfound responses
Dec 8, 2017
a1f4cb6
Merge branch 'master' of https://github.com/prebid/prebid-server
Dec 8, 2017
8647533
remove semicolon
Dec 8, 2017
b91d1c4
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Dec 27, 2017
2721ae6
merge upstream master
aprakash-sovrn Jan 17, 2018
2477b94
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Jan 22, 2018
2ca2b68
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Jan 31, 2018
8278529
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Feb 2, 2018
048b418
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Feb 7, 2018
1ee0493
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Feb 14, 2018
64de231
Add Sovrn adapter
aprakash-sovrn Dec 27, 2017
38ab1e8
Merge remote-tracking branch 'prebid/master'
aprakash-sovrn Feb 20, 2018
79898d5
Review comments
aprakash-sovrn Feb 20, 2018
45306cf
couple more changes
aprakash-sovrn Feb 21, 2018
d8cad4d
Review comments, test fixes
aprakash-sovrn Feb 23, 2018
8b2c31a
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Feb 23, 2018
e0a95db
format fix
aprakash-sovrn Feb 23, 2018
2ffe1ae
Align field names with OpenRTB spec
aprakash-sovrn Feb 23, 2018
56289aa
Merge branch 'master' into master
dbemiller Mar 1, 2018
107fed4
Moved the info.yaml to the new spot.
dbemiller Mar 1, 2018
64abea6
Fixed build errors.
dbemiller Mar 1, 2018
6295412
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Apr 18, 2018
b109f7e
Merge branch 'master' of https://github.com/prebid/prebid-server
May 1, 2018
9ee163a
gdpr support for sovrn
May 2, 2018
cdf6506
Merge pull request #2 from sovrn/sovrn_gdpr
May 2, 2018
21315af
Delete debug
May 2, 2018
eaffe1b
Merge branch 'master' of https://github.com/prebid/prebid-server
Jun 20, 2018
2ba8ed5
This change, along with our internal updates should solve 574
Jul 19, 2018
773db5a
don't include bid in response if adm parsing errored
Jul 19, 2018
746cb3d
Merge branch 'master' of https://github.com/prebid/prebid-server
Jul 26, 2018
44cedfe
Switch tagid param to lowercase, since this is what clientside uses a…
Jul 26, 2018
f01da54
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Aug 2, 2018
0f909dd
Accept either camel- or lower-case tagid
aprakash-sovrn Aug 2, 2018
d206910
Merge pull request #3 from sovrn/sovrn_accept_tagid_with_camel_and_lo…
aprakash-sovrn Aug 2, 2018
bc09bb3
Accept camel- or lower-case tagid
dbemiller Aug 2, 2018
34cb1e3
prefer lower-case to camel-case
aprakash-sovrn Aug 3, 2018
c3cbbd7
Merge pull request #4 from sovrn/multi-case_tagid
aprakash-sovrn Aug 3, 2018
77c738f
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Oct 18, 2018
4cf6a48
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Aug 19, 2019
dee970d
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Aug 22, 2019
043b71b
Merge branch 'master' of https://github.com/prebid/prebid-server
aprakash-sovrn Sep 27, 2019
471c305
Merge branch 'prebid:master' into master
Jun 9, 2021
981f980
Accept bidfloor from impression.
rachelrj Jun 9, 2021
4fe7708
Merge pull request #5 from sovrn/sovrn-fix-issue#1787
rachelrj Jun 10, 2021
f8043c2
Merge branch 'prebid:master' into master
cpabst Apr 1, 2022
408ba00
Merge branch 'prebid:master' into master
cpabst Apr 15, 2022
ce28f3e
Merge branch 'prebid:master' into master
cpabst Apr 21, 2022
7d3c80f
Merge branch 'prebid:master' into master
cpabst May 3, 2022
b1a5d48
Merge branch 'prebid:master' into master
cpabst May 12, 2022
ad6ac9b
SOVRN: Add support for video requests
Apr 1, 2022
edd2ca2
More PR fixes
May 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"VARIANT": "1.16",
// Options
"INSTALL_NODE": "false",
"NODE_VERSION": "lts/*",
"NODE_VERSION": "lts/*"
}
},
"containerEnv": {
Expand Down
163 changes: 102 additions & 61 deletions adapters/sovrn/sovrn.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,6 @@ type SovrnAdapter struct {
}

func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
errs := make([]error, 0, len(request.Imp))

for i := 0; i < len(request.Imp); i++ {
_, err := preprocess(&request.Imp[i])
if err != nil {
errs = append(errs, err)
request.Imp = append(request.Imp[:i], request.Imp[i+1:]...)
i--
}
}

// If all the requests were malformed, don't bother making a server call with no impressions.
if len(request.Imp) == 0 {
return nil, errs
}

reqJSON, err := json.Marshal(request)
if err != nil {
errs = append(errs, err)
return nil, errs
}

headers := http.Header{}
headers.Add("Content-Type", "application/json")
if request.Device != nil {
Expand All @@ -61,6 +39,70 @@ func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt
}
}

errs := make([]error, 0, len(request.Imp))
var err error
validImps := make([]openrtb2.Imp, 0, len(request.Imp))

for _, imp := range request.Imp {
var bidderExt adapters.ExtImpBidder
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
errs = append(errs, &errortypes.BadInput{
Message: err.Error(),
})
continue
}

var sovrnExt openrtb_ext.ExtImpSovrn
if err := json.Unmarshal(bidderExt.Bidder, &sovrnExt); err != nil {
errs = append(errs, &errortypes.BadInput{
Message: err.Error(),
})
continue
}

tagId := getTagId(sovrnExt)
if tagId == "" {
errs = append(errs, &errortypes.BadInput{
Message: "Missing required parameter 'tagid'",
})
continue
}

imp.TagID = tagId

if imp.BidFloor == 0 && sovrnExt.BidFloor > 0 {
imp.BidFloor = sovrnExt.BidFloor
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please add coverage for this branch?

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. Fixed a bunch of other tests as well.

}

// Validate video params if appropriate
video := imp.Video
if video != nil {
if video.MIMEs == nil ||
video.MinDuration == 0 ||
video.MaxDuration == 0 ||
Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 May 2, 2022

Choose a reason for hiding this comment

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

Please review this logic again. For video endpoint there is a possibility to have only maxDuration when requireExactDuration if false or not specified. In this case the entire request will be rejected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll need to review this with product. I'll let you know how that conversation goes.

Copy link
Contributor

Choose a reason for hiding this comment

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

@cpabst Were you able to check about this with your team?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

He has been very busy. 😄
I'd like to keep it this way, and look at this idea as a future enhancement. I see others doing it the same way.

video.Protocols == nil {
errs = append(errs, &errortypes.BadInput{
Message: "Missing required video parameter",
})
continue
}
}

validImps = append(validImps, imp)
}

if len(validImps) == 0 {
return nil, errs
}

request.Imp = validImps

reqJSON, err := json.Marshal(request)
Copy link
Contributor

Choose a reason for hiding this comment

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

At this point, this request can have both valid and invalid imps because on L92 you're just reassigning the valid imps to the same place in the imps array of the request. You'd actually have to remove the invalid ones as you find them in the for loop so that you're only left with the valid ones or a much easier way would be to just create a new validImps array and keep appending each valid imp you find to that array and then outside the for loop, you can just replace request.Imp with that new validImps array before JSON marshalling

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 point. Done.

if err != nil {
errs = append(errs, err)
return nil, errs
}

return []*adapters.RequestData{{
Method: "POST",
Uri: s.URI,
Expand All @@ -75,78 +117,77 @@ func addHeaderIfNonEmpty(headers http.Header, headerName string, headerValue str
}
}

func (s *SovrnAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if response.StatusCode == http.StatusNoContent {
func (s *SovrnAdapter) MakeBids(request *openrtb2.BidRequest, bidderRequest *adapters.RequestData, bidderResponse *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if bidderResponse.StatusCode == http.StatusNoContent {
return nil, nil
}

if response.StatusCode == http.StatusBadRequest {
if bidderResponse.StatusCode == http.StatusBadRequest {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", bidderResponse.StatusCode),
}}
}

if response.StatusCode != http.StatusOK {
if bidderResponse.StatusCode != http.StatusOK {
return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", bidderResponse.StatusCode),
}}
}

var bidResp openrtb2.BidResponse
if err := json.Unmarshal(response.Body, &bidResp); err != nil {
var bidResponse openrtb2.BidResponse
if err := json.Unmarshal(bidderResponse.Body, &bidResponse); err != nil {
return nil, []error{&errortypes.BadServerResponse{
Message: err.Error(),
}}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
response := adapters.NewBidderResponseWithBidsCapacity(5)
errs := make([]error, 0)

for _, sb := range bidResp.SeatBid {
for i := 0; i < len(sb.Bid); i++ {
bid := sb.Bid[i]
for _, sb := range bidResponse.SeatBid {
for _, bid := range sb.Bid {
adm, err := url.QueryUnescape(bid.AdM)
if err == nil {
bid.AdM = adm
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{

bidType := openrtb_ext.BidTypeBanner

impIdx, impIdErr := getImpIdx(bid.ImpID, request)
if impIdErr != nil {
errs = append(errs, impIdErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a test case for this error condition

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.

continue
} else if request.Imp[impIdx].Video != nil {
bidType = openrtb_ext.BidTypeVideo
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned by @VeronikaSolovei9, this can return the wrong bid type in case where the imp is a multi-format imp. But also, since you're only looking at the first imp in the request, this might also return the wrong bid types if not all imps in the request are of same type. For example, say the first imp in the request is of type video but the second one is of type banner, then you'll be returning wrong bid type for the bid corresponding to the second imp.

We highly recommend using bid.Ext.MediaType to send back this information to Prebid Server.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm solving this presently with using the Bid.impid value to set bid type. We will look into using the recommended value in the future.

}
Copy link
Contributor

Choose a reason for hiding this comment

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

In case you return bid type in bid.ext we recommend to use this approach:

func getBidType(bid openrtb2.Bid, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {

It will also help to determine bid type correctly in case if req.imp is multi typed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do not support multi-typed imps yet.

Copy link
Contributor

Choose a reason for hiding this comment

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

You may not support it, but request may have it. In your code you take imp type from request and match it with response: request.Imp[impIdx]


response.Bids = append(response.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: openrtb_ext.BidTypeBanner,
BidType: bidType,
})
}
}
}

return bidResponse, nil
return response, errs
}

func preprocess(imp *openrtb2.Imp) (string, error) {
var bidderExt adapters.ExtImpBidder
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return "", &errortypes.BadInput{
Message: err.Error(),
}
func getTagId(sovrnExt openrtb_ext.ExtImpSovrn) string {
if len(sovrnExt.Tagid) > 0 {
return sovrnExt.Tagid
} else {
return sovrnExt.TagId
}
}

var sovrnExt openrtb_ext.ExtImpSovrn
if err := json.Unmarshal(bidderExt.Bidder, &sovrnExt); err != nil {
return "", &errortypes.BadInput{
Message: err.Error(),
func getImpIdx(impId string, request *openrtb2.BidRequest) (int, error) {
for idx, imp := range request.Imp {
if imp.ID == impId {
return idx, nil
}
}

imp.TagID = getTagid(sovrnExt)

if imp.BidFloor == 0 && sovrnExt.BidFloor > 0 {
imp.BidFloor = sovrnExt.BidFloor
}

return imp.TagID, nil
}

func getTagid(sovrnExt openrtb_ext.ExtImpSovrn) string {
if len(sovrnExt.Tagid) > 0 {
return sovrnExt.Tagid
} else {
return sovrnExt.TagId
return -1, &errortypes.BadInput{
Message: fmt.Sprintf("Imp ID %s in bid didn't match with any imp in the original request", impId),
}
}

Expand Down
Loading