This repository has been archived by the owner on Dec 22, 2022. It is now read-only.
forked from prebid/prebid-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
26 changed files
with
971 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
package beintoo | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
|
||
"github.com/mxmCherry/openrtb" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
type BeintooAdapter struct { | ||
endpoint string | ||
} | ||
|
||
func (a *BeintooAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
var errors []error | ||
|
||
if len(request.Imp) == 0 { | ||
return nil, []error{&errortypes.BadInput{ | ||
Message: fmt.Sprintf("No Imps in Bid Request"), | ||
}} | ||
} | ||
|
||
if errors := preprocess(request); errors != nil && len(errors) > 0 { | ||
return nil, append(errors, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Error in preprocess of Imp, err: %s", errors), | ||
}) | ||
} | ||
|
||
data, err := json.Marshal(request) | ||
if err != nil { | ||
return nil, []error{&errortypes.BadInput{ | ||
Message: fmt.Sprintf("Error in packaging request to JSON"), | ||
}} | ||
} | ||
|
||
headers := http.Header{} | ||
headers.Add("Content-Type", "application/json;charset=utf-8") | ||
headers.Add("Accept", "application/json") | ||
|
||
if request.Device != nil { | ||
addHeaderIfNonEmpty(headers, "User-Agent", request.Device.UA) | ||
addHeaderIfNonEmpty(headers, "X-Forwarded-For", request.Device.IP) | ||
addHeaderIfNonEmpty(headers, "Accept-Language", request.Device.Language) | ||
if request.Device.DNT != nil { | ||
addHeaderIfNonEmpty(headers, "DNT", strconv.Itoa(int(*request.Device.DNT))) | ||
} | ||
} | ||
if request.Site != nil { | ||
addHeaderIfNonEmpty(headers, "Referer", request.Site.Page) | ||
} | ||
|
||
return []*adapters.RequestData{{ | ||
Method: "POST", | ||
Uri: a.endpoint, | ||
Body: data, | ||
Headers: headers, | ||
}}, errors | ||
} | ||
|
||
func unpackImpExt(imp *openrtb.Imp) (*openrtb_ext.ExtImpBeintoo, error) { | ||
var bidderExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: err.Error(), | ||
} | ||
} | ||
|
||
var beintooExt openrtb_ext.ExtImpBeintoo | ||
if err := json.Unmarshal(bidderExt.Bidder, &beintooExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("ignoring imp id=%s, invalid ImpExt", imp.ID), | ||
} | ||
} | ||
|
||
tagIDValidation, err := strconv.ParseInt(beintooExt.TagID, 10, 64) | ||
if err != nil || tagIDValidation == 0 { | ||
return nil, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("ignoring imp id=%s, invalid tagid must be a String of numbers", imp.ID), | ||
} | ||
} | ||
|
||
return &beintooExt, nil | ||
} | ||
|
||
func buildImpBanner(imp *openrtb.Imp) error { | ||
imp.Ext = nil | ||
|
||
if imp.Banner == nil { | ||
return &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Request needs to include a Banner object"), | ||
} | ||
} | ||
|
||
bannerCopy := *imp.Banner | ||
banner := &bannerCopy | ||
|
||
if banner.W == nil && banner.H == nil { | ||
if len(banner.Format) == 0 { | ||
return &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Need at least one size to build request"), | ||
} | ||
} | ||
format := banner.Format[0] | ||
banner.Format = banner.Format[1:] | ||
banner.W = &format.W | ||
banner.H = &format.H | ||
imp.Banner = banner | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Add Beintoo required properties to Imp object | ||
func addImpProps(imp *openrtb.Imp, secure *int8, BeintooExt *openrtb_ext.ExtImpBeintoo) { | ||
imp.TagID = BeintooExt.TagID | ||
imp.Secure = secure | ||
|
||
if BeintooExt.BidFloor != "" { | ||
bidFloor, err := strconv.ParseFloat(BeintooExt.BidFloor, 64) | ||
if err != nil { | ||
bidFloor = 0 | ||
} | ||
|
||
if bidFloor > 0 { | ||
imp.BidFloor = bidFloor | ||
} | ||
} | ||
|
||
return | ||
} | ||
|
||
// Adding header fields to request header | ||
func addHeaderIfNonEmpty(headers http.Header, headerName string, headerValue string) { | ||
if len(headerValue) > 0 { | ||
headers.Add(headerName, headerValue) | ||
} | ||
} | ||
|
||
// Handle request errors and formatting to be sent to Beintoo | ||
func preprocess(request *openrtb.BidRequest) []error { | ||
errors := make([]error, 0, len(request.Imp)) | ||
resImps := make([]openrtb.Imp, 0, len(request.Imp)) | ||
secure := int8(0) | ||
|
||
if request.Site != nil && request.Site.Page != "" { | ||
pageURL, err := url.Parse(request.Site.Page) | ||
if err == nil && pageURL.Scheme == "https" { | ||
secure = int8(1) | ||
} | ||
} | ||
|
||
for _, imp := range request.Imp { | ||
beintooExt, err := unpackImpExt(&imp) | ||
if err != nil { | ||
errors = append(errors, err) | ||
return errors | ||
} | ||
|
||
addImpProps(&imp, &secure, beintooExt) | ||
|
||
if err := buildImpBanner(&imp); err != nil { | ||
errors = append(errors, err) | ||
return errors | ||
} | ||
resImps = append(resImps, imp) | ||
} | ||
|
||
request.Imp = resImps | ||
|
||
return errors | ||
} | ||
|
||
// MakeBids make the bids for the bid response. | ||
func (a *BeintooAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
|
||
if response.StatusCode == http.StatusNoContent { | ||
// no bid response | ||
return nil, nil | ||
} | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Invalid Status Returned: %d. Run with request.debug = 1 for more info", response.StatusCode), | ||
}} | ||
} | ||
|
||
var bidResp openrtb.BidResponse | ||
|
||
if err := json.Unmarshal(response.Body, &bidResp); err != nil { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Unable to unpackage bid response. Error: %s", err.Error()), | ||
}} | ||
} | ||
|
||
bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) | ||
|
||
for _, sb := range bidResp.SeatBid { | ||
for i := range sb.Bid { | ||
sb.Bid[i].ImpID = sb.Bid[i].ID | ||
|
||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &sb.Bid[i], | ||
BidType: "banner", | ||
}) | ||
} | ||
} | ||
|
||
return bidResponse, nil | ||
|
||
} | ||
|
||
func NewBeintooBidder(endpoint string) *BeintooAdapter { | ||
return &BeintooAdapter{ | ||
endpoint: endpoint, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package beintoo | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
beintooAdapter := NewBeintooBidder("https://ib.beintoo.com") | ||
adapterstest.RunJSONBidderTest(t, "beintootest", beintooAdapter) | ||
} |
117 changes: 117 additions & 0 deletions
117
adapters/beintoo/beintootest/exemplary/minimal-banner.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
{ | ||
"mockBidRequest": { | ||
"id": "some_test_auction", | ||
"imp": [{ | ||
"id": "some_test_ad_id", | ||
"banner": { | ||
"format": [{ | ||
"w": 300, | ||
"h": 250 | ||
}], | ||
"w": 300, | ||
"h": 250 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"tagid": "25251" | ||
} | ||
} | ||
}], | ||
"device": { | ||
"ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", | ||
"ip": "123.123.123.123", | ||
"dnt": 1 | ||
}, | ||
"site": { | ||
"domain": "www.publisher.com", | ||
"page": "http://www.publisher.com/awesome/site?with=some¶meters=here" | ||
} | ||
}, | ||
|
||
"httpCalls": [{ | ||
"expectedRequest": { | ||
"uri": "https://ib.beintoo.com", | ||
"headers": { | ||
"Accept": [ | ||
"application/json" | ||
], | ||
"Content-Type": [ | ||
"application/json;charset=utf-8" | ||
], | ||
"X-Forwarded-For": [ | ||
"123.123.123.123" | ||
], | ||
"Referer": [ | ||
"http://www.publisher.com/awesome/site?with=some¶meters=here" | ||
], | ||
"Dnt": [ | ||
"1" | ||
], | ||
"User-Agent": [ | ||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36" | ||
] | ||
}, | ||
"body": { | ||
"id": "some_test_auction", | ||
"imp": [{ | ||
"id": "some_test_ad_id", | ||
"banner": { | ||
"format": [{ | ||
"w": 300, | ||
"h": 250 | ||
}], | ||
"w": 300, | ||
"h": 250 | ||
}, | ||
"tagid": "25251", | ||
"secure": 0 | ||
}], | ||
"site": { | ||
"domain": "www.publisher.com", | ||
"page": "http://www.publisher.com/awesome/site?with=some¶meters=here" | ||
}, | ||
"device": { | ||
"ua": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36", | ||
"ip": "123.123.123.123", | ||
"dnt": 1 | ||
} | ||
} | ||
}, | ||
"mockResponse": { | ||
"status": 200, | ||
"body": { | ||
"id": "some_test_auction", | ||
"seatbid": [{ | ||
"seat": "12356", | ||
"bid": [{ | ||
"adm": "<div id=\"123456789_ad\"><script>!function(){console.log\"Hello, world.\";}();<\/script><\/div>", | ||
"id": "uuid", | ||
"impid": "some_test_ad_id", | ||
"ttl": 300, | ||
"crid": "94395500", | ||
"w": 300, | ||
"price": 2.942808, | ||
"adid": "94395500", | ||
"h": 250 | ||
}] | ||
}], | ||
"cur": "USD" | ||
} | ||
} | ||
}], | ||
|
||
"expectedBids": [{ | ||
"bid": { | ||
"adm": "<div id=\"123456789_ad\"><script>!function(){console.log\"Hello, world.\";}();<\/script><\/div>", | ||
"id": "uuid", | ||
"impid": "some_test_ad_id", | ||
"ttl": 300, | ||
"crid": "94395500", | ||
"w": 300, | ||
"price": 2.942808, | ||
"adid": "94395500", | ||
"h": 250 | ||
}, | ||
"type": "banner" | ||
}] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"tagid": "25251", | ||
"bidfloor": "0.01" | ||
} |
Oops, something went wrong.