github.com/prebid/prebid-server@v0.275.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/v19/openrtb2" 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 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 == 0 || 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 }) 133 134 } 135 136 return requestDataRequest, errs 137 } 138 139 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 140 if responseData.StatusCode == http.StatusNoContent { 141 return nil, nil 142 } 143 144 if responseData.StatusCode == http.StatusBadRequest { 145 err := &errortypes.BadInput{ 146 Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", 147 } 148 return nil, []error{err} 149 } 150 151 if responseData.StatusCode != http.StatusOK { 152 err := &errortypes.BadServerResponse{ 153 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), 154 } 155 return nil, []error{err} 156 } 157 158 var bidReq openrtb2.BidRequest 159 if err := json.Unmarshal(requestData.Body, &bidReq); err != nil { 160 return nil, []error{&errortypes.BadServerResponse{ 161 Message: err.Error(), 162 }} 163 } 164 165 var bidResp openrtb2.BidResponse 166 if err := json.Unmarshal(responseData.Body, &bidResp); err != nil { 167 return nil, []error{&errortypes.BadServerResponse{ 168 Message: err.Error(), 169 }} 170 } 171 172 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidReq.Imp)) 173 bidResponse.Currency = bidResp.Cur 174 175 for _, reqBid := range bidReq.Imp { 176 for _, seatBid := range bidResp.SeatBid { 177 for i := range seatBid.Bid { 178 179 bidType := getMediaType(seatBid.Bid[i].ImpID, reqBid) 180 181 if bidType == "video" { 182 seatBid.Bid[i].W = reqBid.Video.W 183 seatBid.Bid[i].H = reqBid.Video.H 184 } 185 186 b := &adapters.TypedBid{ 187 Bid: &seatBid.Bid[i], 188 BidType: bidType, 189 } 190 191 bidResponse.Bids = append(bidResponse.Bids, b) 192 } 193 } 194 } 195 196 return bidResponse, nil 197 } 198 199 func setHeaders(raiHeaders *http.Header) { 200 raiHeaders.Set("Content-Type", "application/json;charset=utf-8") 201 raiHeaders.Set("Accept", "application/json") 202 raiHeaders.Add("X-Openrtb-Version", "2.5") 203 } 204 205 func getIsUrlSecure(request *openrtb2.BidRequest) (isUrlSecure bool) { 206 if request.Site != nil { 207 if request.Site.Page != "" { 208 pageURL, err := url.Parse(request.Site.Page) 209 if err == nil { 210 if request.Site.Domain == "" { 211 request.Site.Domain = pageURL.Host 212 } 213 isUrlSecure = pageURL.Scheme == "https" 214 } 215 } 216 } 217 return 218 } 219 220 func validateDevice(request *openrtb2.BidRequest) (err error) { 221 if request.Device != nil && request.Device.IP == "" && request.Device.IPv6 == "" { 222 err = &errortypes.BadInput{ 223 Message: "request.Device.IP is required", 224 } 225 return err 226 } 227 return err 228 } 229 230 func parseImpExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpRichaudience, error) { 231 var bidderExt adapters.ExtImpBidder 232 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 233 err = &errortypes.BadInput{ 234 Message: fmt.Sprintf("not found parameters ext in ImpID : %s", imp.ID), 235 } 236 return nil, err 237 } 238 239 var richaudienceExt openrtb_ext.ExtImpRichaudience 240 if err := json.Unmarshal(bidderExt.Bidder, &richaudienceExt); err != nil { 241 err = &errortypes.BadInput{ 242 Message: fmt.Sprintf("invalid parameters ext in ImpID: %s", imp.ID), 243 } 244 return nil, err 245 } 246 247 return &richaudienceExt, nil 248 } 249 250 func getMediaType(impId string, imp openrtb2.Imp) openrtb_ext.BidType { 251 if imp.ID == impId { 252 if imp.Video != nil { 253 return openrtb_ext.BidTypeVideo 254 } 255 return openrtb_ext.BidTypeBanner 256 } 257 return "no bidtype assigned" 258 }