github.com/prebid/prebid-server@v0.275.0/adapters/imds/imds.go (about) 1 package imds 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "net/url" 8 "text/template" 9 10 "github.com/prebid/openrtb/v19/openrtb2" 11 "github.com/prebid/prebid-server/adapters" 12 "github.com/prebid/prebid-server/config" 13 "github.com/prebid/prebid-server/errortypes" 14 "github.com/prebid/prebid-server/macros" 15 "github.com/prebid/prebid-server/openrtb_ext" 16 ) 17 18 const adapterVersion string = "pbs-go/1.0.0" 19 20 type adapter struct { 21 EndpointTemplate *template.Template 22 } 23 24 type SyncEndpointTemplateParams struct { 25 SeatId string 26 TagId string 27 } 28 29 type ReqExt struct { 30 SeatId string `json:"seatId"` 31 } 32 33 // Builder builds a new instance of the Imds adapter for the given bidder with the given config. 34 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 35 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 36 if err != nil { 37 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 38 } 39 40 bidder := &adapter{ 41 EndpointTemplate: template, 42 } 43 return bidder, nil 44 } 45 46 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 47 var errs []error 48 var bidRequests []*adapters.RequestData 49 50 adapterReq, errors := a.makeRequest(request) 51 if adapterReq != nil { 52 bidRequests = append(bidRequests, adapterReq) 53 } 54 errs = append(errs, errors...) 55 56 return bidRequests, errs 57 } 58 59 func (a *adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, []error) { 60 var errs []error 61 var validImps []openrtb2.Imp 62 var re *ReqExt 63 var firstExtImp *openrtb_ext.ExtImpImds = nil 64 65 for _, imp := range request.Imp { 66 validExtImpObj, err := getExtImpObj(&imp) // getExtImpObj returns {seatId:"", tagId:""} 67 if err != nil { 68 errs = append(errs, err) 69 continue 70 } 71 // if the bid request is missing seatId or TagId then ignore it 72 if validExtImpObj.SeatId == "" || validExtImpObj.TagId == "" { 73 errs = append(errs, &errortypes.BadServerResponse{ 74 Message: fmt.Sprintf("Invalid Impression"), 75 }) 76 continue 77 } 78 // right here is where we need to take out the tagId and then add it to imp 79 imp.TagID = validExtImpObj.TagId 80 validImps = append(validImps, imp) 81 if firstExtImp == nil { 82 firstExtImp = validExtImpObj 83 } 84 } 85 86 if len(validImps) == 0 { 87 return nil, errs 88 } 89 90 var err error 91 92 if firstExtImp == nil || firstExtImp.SeatId == "" || firstExtImp.TagId == "" { 93 return nil, append(errs, &errortypes.BadServerResponse{ 94 Message: fmt.Sprintf("Invalid Impression"), 95 }) 96 } 97 // this is where the empty seatId is filled 98 re = &ReqExt{SeatId: firstExtImp.SeatId} 99 100 // create JSON Request Body 101 request.Imp = validImps 102 request.Ext, err = json.Marshal(re) 103 if err != nil { 104 return nil, append(errs, err) 105 } 106 107 reqJSON, err := json.Marshal(request) 108 if err != nil { 109 return nil, append(errs, err) 110 } 111 112 // set Request Headers 113 headers := http.Header{} 114 headers.Add("Content-Type", "application/json;charset=utf-8") 115 headers.Add("Accept", "application/json") 116 117 // create Request Uri 118 reqUri, err := a.buildEndpointURL(firstExtImp) 119 if err != nil { 120 return nil, append(errs, err) 121 } 122 123 return &adapters.RequestData{ 124 Method: http.MethodPost, 125 Uri: reqUri, 126 Body: reqJSON, 127 Headers: headers, 128 }, errs 129 } 130 131 // Builds enpoint url based on adapter-specific pub settings from imp.ext 132 func (adapter *adapter) buildEndpointURL(params *openrtb_ext.ExtImpImds) (string, error) { 133 return macros.ResolveMacros(adapter.EndpointTemplate, macros.EndpointTemplateParams{AccountID: url.QueryEscape(params.SeatId), SourceId: url.QueryEscape(adapterVersion)}) 134 } 135 136 func getExtImpObj(imp *openrtb2.Imp) (*openrtb_ext.ExtImpImds, error) { 137 var bidderExt adapters.ExtImpBidder 138 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 139 return nil, &errortypes.BadInput{ 140 Message: err.Error(), 141 } 142 } 143 144 var imdsExt openrtb_ext.ExtImpImds 145 if err := json.Unmarshal(bidderExt.Bidder, &imdsExt); err != nil { 146 return nil, &errortypes.BadInput{ 147 Message: err.Error(), 148 } 149 } 150 151 return &imdsExt, nil 152 } 153 154 // MakeBids make the bids for the bid response. 155 func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 156 const errorMessage string = "Unexpected status code: %d. Run with request.debug = 1 for more info" 157 switch { 158 case response.StatusCode == http.StatusNoContent: 159 return nil, nil 160 case response.StatusCode == http.StatusBadRequest: 161 return nil, []error{&errortypes.BadInput{ 162 Message: fmt.Sprintf(errorMessage, response.StatusCode), 163 }} 164 case response.StatusCode != http.StatusOK: 165 return nil, []error{&errortypes.BadServerResponse{ 166 Message: fmt.Sprintf(errorMessage, response.StatusCode), 167 }} 168 } 169 170 var bidResp openrtb2.BidResponse 171 172 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 173 return nil, []error{err} 174 } 175 176 bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) 177 178 for _, sb := range bidResp.SeatBid { 179 for i := range sb.Bid { 180 var mediaType = getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp) 181 if mediaType != openrtb_ext.BidTypeBanner && mediaType != openrtb_ext.BidTypeVideo { 182 continue 183 } 184 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 185 Bid: &sb.Bid[i], 186 BidType: mediaType, 187 }) 188 } 189 } 190 return bidResponse, nil 191 } 192 193 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType { 194 mediaType := openrtb_ext.BidTypeBanner 195 for _, imp := range imps { 196 if imp.ID == impId { 197 if imp.Banner != nil { 198 break 199 } 200 if imp.Video != nil { 201 mediaType = openrtb_ext.BidTypeVideo 202 break 203 } 204 if imp.Native != nil { 205 mediaType = openrtb_ext.BidTypeNative 206 break 207 } 208 if imp.Audio != nil { 209 mediaType = openrtb_ext.BidTypeAudio 210 break 211 } 212 } 213 } 214 return mediaType 215 }