github.com/prebid/prebid-server/v2@v2.18.0/adapters/yahooAds/yahooAds.go (about) 1 package yahooAds 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 "github.com/prebid/prebid-server/v2/util/ptrutil" 14 ) 15 16 type adapter struct { 17 URI string 18 } 19 20 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 21 var errors []error 22 23 reqs := make([]*adapters.RequestData, 0, len(request.Imp)) 24 headers := http.Header{} 25 26 headers.Add("Content-Type", "application/json;charset=utf-8") 27 headers.Add("Accept", "application/json") 28 headers.Add("x-openrtb-version", "2.5") 29 30 if request.Device != nil && request.Device.UA != "" { 31 headers.Set("User-Agent", request.Device.UA) 32 } 33 34 for idx, imp := range request.Imp { 35 var bidderExt adapters.ExtImpBidder 36 err := json.Unmarshal(imp.Ext, &bidderExt) 37 if err != nil { 38 err = &errortypes.BadInput{ 39 Message: fmt.Sprintf("imp #%d: ext.bidder not provided", idx), 40 } 41 errors = append(errors, err) 42 continue 43 } 44 45 var yahooAdsExt openrtb_ext.ExtImpYahooAds 46 err = json.Unmarshal(bidderExt.Bidder, &yahooAdsExt) 47 if err != nil { 48 err = &errortypes.BadInput{ 49 Message: fmt.Sprintf("imp #%d: %s", idx, err.Error()), 50 } 51 errors = append(errors, err) 52 continue 53 } 54 55 // Split up multi-impression requests into multiple requests so that 56 // each split request is only associated to a single impression 57 reqCopy := *request 58 reqCopy.Imp = []openrtb2.Imp{imp} 59 60 if request.Site != nil { 61 siteCopy := *request.Site 62 reqCopy.Site = &siteCopy 63 } else if request.App != nil { 64 appCopy := *request.App 65 reqCopy.App = &appCopy 66 } 67 68 if err := changeRequestForBidService(&reqCopy, &yahooAdsExt); err != nil { 69 errors = append(errors, err) 70 continue 71 } 72 73 reqJSON, err := json.Marshal(&reqCopy) 74 if err != nil { 75 errors = append(errors, err) 76 continue 77 } 78 79 reqs = append(reqs, &adapters.RequestData{ 80 Method: "POST", 81 Uri: a.URI, 82 Body: reqJSON, 83 Headers: headers, 84 ImpIDs: openrtb_ext.GetImpIDs(reqCopy.Imp), 85 }) 86 } 87 88 return reqs, errors 89 } 90 91 func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 92 93 if response.StatusCode == http.StatusNoContent { 94 return nil, nil 95 } 96 97 if response.StatusCode != http.StatusOK { 98 return nil, []error{&errortypes.BadServerResponse{ 99 Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode), 100 }} 101 } 102 103 var bidResp openrtb2.BidResponse 104 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 105 return nil, []error{&errortypes.BadServerResponse{ 106 Message: fmt.Sprintf("Bad server response: %d.", err), 107 }} 108 } 109 110 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp)) 111 112 for _, sb := range bidResp.SeatBid { 113 for _, bid := range sb.Bid { 114 bid := bid 115 exists, mediaTypeId := getImpInfo(bid.ImpID, internalRequest.Imp) 116 if !exists { 117 return nil, []error{&errortypes.BadServerResponse{ 118 Message: fmt.Sprintf("Unknown ad unit code '%s'", bid.ImpID), 119 }} 120 } 121 122 if openrtb_ext.BidTypeBanner != mediaTypeId && 123 openrtb_ext.BidTypeVideo != mediaTypeId { 124 //only banner and video are mediaTypeId, anything else is ignored 125 continue 126 } 127 128 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 129 Bid: &bid, 130 BidType: mediaTypeId, 131 }) 132 } 133 } 134 135 return bidResponse, nil 136 } 137 138 func getImpInfo(impId string, imps []openrtb2.Imp) (bool, openrtb_ext.BidType) { 139 var mediaType openrtb_ext.BidType 140 var exists bool 141 for _, imp := range imps { 142 if imp.ID == impId { 143 exists = true 144 if imp.Banner != nil { 145 mediaType = openrtb_ext.BidTypeBanner 146 } else if imp.Video != nil { 147 mediaType = openrtb_ext.BidTypeVideo 148 } 149 break 150 } 151 } 152 return exists, mediaType 153 } 154 155 func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb_ext.ExtImpYahooAds) error { 156 /* Always override the tag ID and (site ID or app ID) of the request */ 157 request.Imp[0].TagID = extension.Pos 158 if request.Site != nil { 159 request.Site.ID = extension.Dcn 160 } else if request.App != nil { 161 request.App.ID = extension.Dcn 162 } 163 164 if request.Imp[0].Banner != nil { 165 banner := *request.Imp[0].Banner 166 request.Imp[0].Banner = &banner 167 168 err := validateBanner(&banner) 169 if err != nil { 170 return err 171 } 172 } 173 174 if request.Regs != nil && request.Regs.GPP != "" { 175 requestRegs := *request.Regs 176 if requestRegs.Ext == nil { 177 requestRegs.Ext = json.RawMessage("{}") 178 } 179 var regsExt map[string]json.RawMessage 180 err := json.Unmarshal(requestRegs.Ext, ®sExt) 181 if err != nil { 182 return err 183 } 184 regsExt["gpp"], err = json.Marshal(&requestRegs.GPP) 185 186 if requestRegs.GPPSID != nil { 187 regsExt["gpp_sid"], err = json.Marshal(&requestRegs.GPPSID) 188 if err != nil { 189 return err 190 } 191 } 192 193 requestRegs.Ext, err = json.Marshal(®sExt) 194 if err != nil { 195 return err 196 } 197 requestRegs.GPP = "" 198 requestRegs.GPPSID = nil 199 request.Regs = &requestRegs 200 } 201 202 return nil 203 } 204 205 func validateBanner(banner *openrtb2.Banner) error { 206 if banner.W != nil && banner.H != nil { 207 if *banner.W == 0 || *banner.H == 0 { 208 return fmt.Errorf("Invalid sizes provided for Banner %dx%d", *banner.W, *banner.H) 209 } 210 return nil 211 } 212 213 if len(banner.Format) == 0 { 214 return fmt.Errorf("No sizes provided for Banner %v", banner.Format) 215 } 216 217 banner.W = ptrutil.ToPtr(banner.Format[0].W) 218 banner.H = ptrutil.ToPtr(banner.Format[0].H) 219 220 return nil 221 } 222 223 // Builder builds a new instance of the YahooAds adapter for the given bidder with the given config. 224 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 225 bidder := &adapter{ 226 URI: config.Endpoint, 227 } 228 return bidder, nil 229 }