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