github.com/prebid/prebid-server/v2@v2.18.0/adapters/lockerdome/lockerdome.go (about) 1 package lockerdome 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/prebid/openrtb/v20/openrtb2" 9 "github.com/prebid/prebid-server/v2/adapters" 10 "github.com/prebid/prebid-server/v2/config" 11 "github.com/prebid/prebid-server/v2/errortypes" 12 "github.com/prebid/prebid-server/v2/openrtb_ext" 13 ) 14 15 const unexpectedStatusCodeMessage = "Unexpected status code: %d. Run with request.debug = 1 for more info" 16 17 // Implements Bidder interface. 18 type LockerDomeAdapter struct { 19 endpoint string 20 } 21 22 // MakeRequests makes the HTTP requests which should be made to fetch bids [from the bidder, in this case, LockerDome] 23 func (adapter *LockerDomeAdapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, extraReqInfo *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) { 24 25 numberOfImps := len(openRTBRequest.Imp) 26 27 if openRTBRequest.Imp == nil || numberOfImps == 0 { // lockerdometest/supplemental/empty_imps.json 28 err := &errortypes.BadInput{ 29 Message: "No valid impressions in the bid request.", 30 } 31 errs = append(errs, err) 32 return nil, errs 33 } 34 35 var indexesOfValidImps []int 36 for i := 0; i < numberOfImps; i++ { 37 // LockerDome currently only supports banner impressions, and requires data in the ext field. 38 if openRTBRequest.Imp[i].Banner == nil { // lockerdometest/supplemental/unsupported_imp_type.json 39 err := &errortypes.BadInput{ 40 Message: "LockerDome does not currently support non-banner types.", 41 } 42 errs = append(errs, err) 43 continue 44 } 45 var bidderExt adapters.ExtImpBidder 46 err := json.Unmarshal(openRTBRequest.Imp[i].Ext, &bidderExt) 47 if err != nil { // lockerdometest/supplemental/no_ext.json 48 err = &errortypes.BadInput{ 49 Message: "ext was not provided.", 50 } 51 errs = append(errs, err) 52 continue 53 } 54 var lockerdomeExt openrtb_ext.ExtImpLockerDome 55 err = json.Unmarshal(bidderExt.Bidder, &lockerdomeExt) 56 if err != nil { // lockerdometest/supplemental/no_adUnitId_param.json 57 err = &errortypes.BadInput{ 58 Message: "ext.bidder.adUnitId was not provided.", 59 } 60 errs = append(errs, err) 61 continue 62 } 63 if lockerdomeExt.AdUnitId == "" { // lockerdometest/supplemental/empty_adUnitId_param.json 64 err := &errortypes.BadInput{ 65 Message: "ext.bidder.adUnitId is empty.", 66 } 67 errs = append(errs, err) 68 continue 69 } 70 indexesOfValidImps = append(indexesOfValidImps, i) 71 } 72 if numberOfImps > len(indexesOfValidImps) { 73 var validImps []openrtb2.Imp 74 for j := 0; j < len(indexesOfValidImps); j++ { 75 validImps = append(validImps, openRTBRequest.Imp[j]) 76 } 77 if len(validImps) == 0 { 78 err := &errortypes.BadInput{ 79 Message: "No valid or supported impressions in the bid request.", 80 } 81 errs = append(errs, err) 82 return nil, errs 83 } else { 84 openRTBRequest.Imp = validImps 85 } 86 } 87 openRTBRequestJSON, err := json.Marshal(openRTBRequest) 88 if err != nil { 89 errs = append(errs, err) 90 return nil, errs 91 } 92 93 headers := http.Header{} 94 headers.Add("Content-Type", "application/json;charset=utf-8") 95 headers.Add("Accept", "application/json") 96 headers.Add("x-openrtb-version", "2.5") 97 98 requestToBidder := &adapters.RequestData{ 99 Method: "POST", 100 Uri: adapter.endpoint, 101 Body: openRTBRequestJSON, 102 Headers: headers, 103 ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), 104 } 105 106 requestsToBidder = append(requestsToBidder, requestToBidder) 107 108 return requestsToBidder, nil 109 110 } 111 112 // MakeBids unpacks the server's response into Bids. 113 func (adapter *LockerDomeAdapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (bidderResponse *adapters.BidderResponse, errs []error) { 114 115 if bidderRawResponse.StatusCode == http.StatusNoContent { 116 return nil, nil 117 } 118 119 if bidderRawResponse.StatusCode == http.StatusBadRequest { 120 return nil, []error{&errortypes.BadInput{ 121 Message: fmt.Sprintf(unexpectedStatusCodeMessage, bidderRawResponse.StatusCode), 122 }} 123 } 124 125 if bidderRawResponse.StatusCode != http.StatusOK { 126 return nil, []error{&errortypes.BadServerResponse{ 127 Message: fmt.Sprintf(unexpectedStatusCodeMessage, bidderRawResponse.StatusCode), 128 }} 129 } 130 131 var openRTBBidderResponse openrtb2.BidResponse 132 if err := json.Unmarshal(bidderRawResponse.Body, &openRTBBidderResponse); err != nil { 133 return nil, []error{ 134 fmt.Errorf("Error unmarshaling LockerDome bid response - %s", err.Error()), 135 } 136 } 137 138 if len(openRTBBidderResponse.SeatBid) == 0 { 139 return nil, nil 140 } 141 142 bidderResponse = adapters.NewBidderResponseWithBidsCapacity(len(openRTBBidderResponse.SeatBid[0].Bid)) 143 144 for _, seatBid := range openRTBBidderResponse.SeatBid { 145 for i := range seatBid.Bid { 146 typedBid := adapters.TypedBid{Bid: &seatBid.Bid[i], BidType: openrtb_ext.BidTypeBanner} 147 bidderResponse.Bids = append(bidderResponse.Bids, &typedBid) 148 } 149 } 150 return bidderResponse, nil 151 } 152 153 // Builder builds a new instance of the LockerDome adapter for the given bidder with the given config. 154 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 155 bidder := &LockerDomeAdapter{ 156 endpoint: config.Endpoint, 157 } 158 return bidder, nil 159 }