github.com/prebid/prebid-server/v2@v2.18.0/adapters/richaudience/richaudience.go (about) 1 package richaudience 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "net/url" 8 9 "github.com/prebid/openrtb/v20/openrtb2" 10 "github.com/prebid/prebid-server/v2/adapters" 11 "github.com/prebid/prebid-server/v2/config" 12 "github.com/prebid/prebid-server/v2/errortypes" 13 "github.com/prebid/prebid-server/v2/openrtb_ext" 14 ) 15 16 type adapter struct { 17 endpoint string 18 } 19 20 // Builder builds a new instance of the RichAudience 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 (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 29 var requestDataRequest []*adapters.RequestData 30 errs := make([]error, 0, len(request.Imp)) 31 raiHeaders := http.Header{} 32 setHeaders(&raiHeaders) 33 34 isUrlSecure := getIsUrlSecure(request) 35 36 if err := validateDevice(request); err != nil { 37 errs = append(errs, &errortypes.BadInput{ 38 Message: err.Error(), 39 }) 40 return nil, errs 41 } 42 43 for _, imp := range request.Imp { 44 var secure = int8(0) 45 46 raiExt, err := parseImpExt(&imp) 47 if err != nil { 48 errs = append(errs, &errortypes.BadInput{ 49 Message: err.Error(), 50 }) 51 continue 52 } 53 54 if request.App != nil { 55 appCopy := *request.App 56 request.App = &appCopy 57 58 request.App.Keywords = "tagid=" + imp.TagID 59 } 60 61 if request.Site != nil { 62 siteCopy := *request.Site 63 request.Site = &siteCopy 64 65 request.Site.Keywords = "tagid=" + imp.TagID 66 } 67 68 if raiExt != nil { 69 if raiExt.Pid != "" { 70 imp.TagID = raiExt.Pid 71 } 72 73 if raiExt.Test { 74 if request.Device != nil { 75 deviceCopy := *request.Device 76 request.Device = &deviceCopy 77 } else { 78 request.Device = &openrtb2.Device{} 79 } 80 81 request.Device.IP = "11.222.33.44" 82 request.Test = int8(1) 83 } 84 85 if raiExt.BidFloorCur != "" { 86 imp.BidFloorCur = raiExt.BidFloorCur 87 } else if imp.BidFloorCur == "" { 88 imp.BidFloorCur = "USD" 89 } 90 } 91 if isUrlSecure { 92 secure = int8(1) 93 } 94 95 imp.Secure = &secure 96 97 if imp.Banner != nil { 98 if imp.Banner.W == nil && imp.Banner.H == nil { 99 if len(imp.Banner.Format) == 0 { 100 errs = append(errs, &errortypes.BadInput{ 101 Message: "request.Banner.Format is required", 102 }) 103 continue 104 } 105 } 106 } 107 108 if imp.Video != nil { 109 if imp.Video.W == nil || *imp.Video.W == 0 || imp.Video.H == nil || *imp.Video.H == 0 { 110 errs = append(errs, &errortypes.BadInput{ 111 Message: "request.Video.Sizes is required", 112 }) 113 continue 114 } 115 } 116 117 request.Imp = []openrtb2.Imp{imp} 118 119 req, err := json.Marshal(request) 120 if err != nil { 121 errs = append(errs, &errortypes.BadInput{ 122 Message: err.Error(), 123 }) 124 continue 125 } 126 127 requestDataRequest = append(requestDataRequest, &adapters.RequestData{ 128 Method: "POST", 129 Uri: a.endpoint, 130 Body: req, 131 Headers: raiHeaders, 132 ImpIDs: openrtb_ext.GetImpIDs(request.Imp), 133 }) 134 135 } 136 137 return requestDataRequest, errs 138 } 139 140 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 141 if responseData.StatusCode == http.StatusNoContent { 142 return nil, nil 143 } 144 145 if responseData.StatusCode == http.StatusBadRequest { 146 err := &errortypes.BadInput{ 147 Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", 148 } 149 return nil, []error{err} 150 } 151 152 if responseData.StatusCode != http.StatusOK { 153 err := &errortypes.BadServerResponse{ 154 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), 155 } 156 return nil, []error{err} 157 } 158 159 var bidReq openrtb2.BidRequest 160 if err := json.Unmarshal(requestData.Body, &bidReq); err != nil { 161 return nil, []error{&errortypes.BadServerResponse{ 162 Message: err.Error(), 163 }} 164 } 165 166 var bidResp openrtb2.BidResponse 167 if err := json.Unmarshal(responseData.Body, &bidResp); err != nil { 168 return nil, []error{&errortypes.BadServerResponse{ 169 Message: err.Error(), 170 }} 171 } 172 173 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidReq.Imp)) 174 bidResponse.Currency = bidResp.Cur 175 176 for _, reqBid := range bidReq.Imp { 177 for _, seatBid := range bidResp.SeatBid { 178 for i := range seatBid.Bid { 179 180 bidType := getMediaType(seatBid.Bid[i].ImpID, reqBid) 181 182 if bidType == "video" { 183 seatBid.Bid[i].W = *reqBid.Video.W 184 seatBid.Bid[i].H = *reqBid.Video.H 185 } 186 187 b := &adapters.TypedBid{ 188 Bid: &seatBid.Bid[i], 189 BidType: bidType, 190 } 191 192 bidResponse.Bids = append(bidResponse.Bids, b) 193 } 194 } 195 } 196 197 return bidResponse, nil 198 } 199 200 func setHeaders(raiHeaders *http.Header) { 201 raiHeaders.Set("Content-Type", "application/json;charset=utf-8") 202 raiHeaders.Set("Accept", "application/json") 203 raiHeaders.Add("X-Openrtb-Version", "2.5") 204 } 205 206 func getIsUrlSecure(request *openrtb2.BidRequest) (isUrlSecure bool) { 207 if request.Site != nil { 208 if request.Site.Page != "" { 209 pageURL, err := url.Parse(request.Site.Page) 210 if err == nil { 211 if request.Site.Domain == "" { 212 request.Site.Domain = pageURL.Host 213 } 214 isUrlSecure = pageURL.Scheme == "https" 215 } 216 } 217 } 218 return 219 } 220 221 func validateDevice(request *openrtb2.BidRequest) (err error) { 222 if request.Device != nil && request.Device.IP == "" && request.Device.IPv6 == "" { 223 err = &errortypes.BadInput{ 224 Message: "request.Device.IP is required", 225 } 226 return err 227 } 228 return err 229 } 230 231 func parseImpExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpRichaudience, error) { 232 var bidderExt adapters.ExtImpBidder 233 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 234 err = &errortypes.BadInput{ 235 Message: fmt.Sprintf("not found parameters ext in ImpID : %s", imp.ID), 236 } 237 return nil, err 238 } 239 240 var richaudienceExt openrtb_ext.ExtImpRichaudience 241 if err := json.Unmarshal(bidderExt.Bidder, &richaudienceExt); err != nil { 242 err = &errortypes.BadInput{ 243 Message: fmt.Sprintf("invalid parameters ext in ImpID: %s", imp.ID), 244 } 245 return nil, err 246 } 247 248 return &richaudienceExt, nil 249 } 250 251 func getMediaType(impId string, imp openrtb2.Imp) openrtb_ext.BidType { 252 if imp.ID == impId { 253 if imp.Video != nil { 254 return openrtb_ext.BidTypeVideo 255 } 256 return openrtb_ext.BidTypeBanner 257 } 258 return "no bidtype assigned" 259 }