github.com/prebid/prebid-server@v0.275.0/adapters/adtrgtme/adtrgtme.go (about) 1 package adtrgtme 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/prebid/openrtb/v19/openrtb2" 9 10 "github.com/prebid/prebid-server/adapters" 11 "github.com/prebid/prebid-server/config" 12 "github.com/prebid/prebid-server/errortypes" 13 "github.com/prebid/prebid-server/openrtb_ext" 14 ) 15 16 type adapter struct { 17 endpoint string 18 } 19 20 // Builder builds a new instance of the Adtrgtme adapter for the given bidder with the given config. 21 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 22 bidder := &adapter{ 23 endpoint: config.Endpoint, 24 } 25 return bidder, nil 26 } 27 28 func (v *adapter) MakeRequests( 29 openRTBRequest *openrtb2.BidRequest, 30 requestInfo *adapters.ExtraRequestInfo, 31 ) ( 32 []*adapters.RequestData, 33 []error, 34 ) { 35 var requests []*adapters.RequestData 36 var errors []error 37 38 requestCopy := *openRTBRequest 39 for _, imp := range openRTBRequest.Imp { 40 siteID, err := getSiteIDFromImp(&imp) 41 if err != nil { 42 errors = append(errors, err) 43 continue 44 } 45 46 imp.Ext = nil 47 requestCopy.Imp = []openrtb2.Imp{imp} 48 49 requestBody, err := json.Marshal(requestCopy) 50 if err != nil { 51 errors = append(errors, err) 52 continue 53 } 54 55 requestData := &adapters.RequestData{ 56 Method: http.MethodPost, 57 Uri: v.buildRequestURI(siteID), 58 Body: requestBody, 59 Headers: makeRequestHeaders(openRTBRequest), 60 } 61 62 requests = append(requests, requestData) 63 } 64 return requests, errors 65 } 66 67 func getSiteIDFromImp(imp *openrtb2.Imp) (uint64, error) { 68 var bidderExt adapters.ExtImpBidder 69 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 70 return 0, &errortypes.BadInput{ 71 Message: "ext.bidder not provided", 72 } 73 } 74 var ext openrtb_ext.ExtImpAdtrgtme 75 if err := json.Unmarshal(bidderExt.Bidder, &ext); err != nil { 76 return 0, &errortypes.BadInput{ 77 Message: "ext.bidder not provided", 78 } 79 } 80 return ext.SiteID, nil 81 } 82 83 func (v *adapter) buildRequestURI(siteID uint64) string { 84 return fmt.Sprintf("%s?s=%d&prebid", v.endpoint, siteID) 85 } 86 87 func makeRequestHeaders(openRTBRequest *openrtb2.BidRequest) http.Header { 88 headers := http.Header{} 89 headers.Add("Content-Type", "application/json;charset=utf-8") 90 headers.Add("Accept", "application/json") 91 headers.Add("X-Openrtb-Version", "2.5") 92 93 if openRTBRequest.Device != nil { 94 if len(openRTBRequest.Device.UA) > 0 { 95 headers.Add("User-Agent", openRTBRequest.Device.UA) 96 } 97 98 if len(openRTBRequest.Device.IPv6) > 0 { 99 headers.Add("X-Forwarded-For", openRTBRequest.Device.IPv6) 100 } 101 102 if len(openRTBRequest.Device.IP) > 0 { 103 headers.Add("X-Forwarded-For", openRTBRequest.Device.IP) 104 } 105 } 106 return headers 107 } 108 109 func (v *adapter) checkResponseStatusCodes(response *adapters.ResponseData) error { 110 if response.StatusCode == http.StatusBadRequest { 111 return &errortypes.BadInput{ 112 Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode), 113 } 114 } 115 116 if response.StatusCode == http.StatusServiceUnavailable { 117 return &errortypes.BadInput{ 118 Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode), 119 } 120 } 121 122 if response.StatusCode != http.StatusOK { 123 return &errortypes.BadInput{ 124 Message: fmt.Sprintf("Unexpected status code: [ %d ]. Run with request.debug = 1 for more info", response.StatusCode), 125 } 126 } 127 128 return nil 129 } 130 131 func (v *adapter) MakeBids( 132 openRTBRequest *openrtb2.BidRequest, 133 requestToBidder *adapters.RequestData, 134 bidderRawResponse *adapters.ResponseData, 135 ) ( 136 *adapters.BidderResponse, 137 []error, 138 ) { 139 if bidderRawResponse.StatusCode == http.StatusNoContent { 140 return nil, nil 141 } 142 143 httpStatusError := v.checkResponseStatusCodes(bidderRawResponse) 144 if httpStatusError != nil { 145 return nil, []error{httpStatusError} 146 } 147 148 var response openrtb2.BidResponse 149 if err := json.Unmarshal(bidderRawResponse.Body, &response); err != nil { 150 return nil, []error{&errortypes.BadServerResponse{ 151 Message: "Bad Server Response", 152 }} 153 } 154 155 if len(response.SeatBid) == 0 { 156 return nil, []error{&errortypes.BadServerResponse{ 157 Message: "Empty SeatBid array", 158 }} 159 } 160 161 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(openRTBRequest.Imp)) 162 bidResponse.Currency = response.Cur 163 for _, seatBid := range response.SeatBid { 164 for i, bid := range seatBid.Bid { 165 bidType, err := getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp) 166 if err != nil { 167 return nil, []error{err} 168 } 169 170 b := &adapters.TypedBid{ 171 Bid: &seatBid.Bid[i], 172 BidType: bidType, 173 } 174 bidResponse.Bids = append(bidResponse.Bids, b) 175 } 176 } 177 return bidResponse, nil 178 } 179 180 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { 181 for _, imp := range imps { 182 if imp.ID == impId { 183 if imp.Banner != nil { 184 return openrtb_ext.BidTypeBanner, nil 185 } else { 186 return "", &errortypes.BadInput{ 187 Message: fmt.Sprintf("Unsupported bidtype for bid: \"%s\"", impId), 188 } 189 } 190 } 191 } 192 return "", &errortypes.BadInput{ 193 Message: fmt.Sprintf("Failed to find impression: \"%s\"", impId), 194 } 195 }