github.com/prebid/prebid-server/v2@v2.18.0/adapters/bizzclick/bizzclick.go (about) 1 package bizzclick 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "text/template" 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/macros" 14 "github.com/prebid/prebid-server/v2/openrtb_ext" 15 ) 16 17 type adapter struct { 18 endpoint *template.Template 19 } 20 21 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 22 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 23 if err != nil { 24 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 25 } 26 27 bidder := &adapter{ 28 endpoint: template, 29 } 30 return bidder, nil 31 } 32 33 func getHeaders(request *openrtb2.BidRequest) http.Header { 34 headers := http.Header{} 35 headers.Add("Content-Type", "application/json;charset=utf-8") 36 headers.Add("Accept", "application/json") 37 headers.Add("X-Openrtb-Version", "2.5") 38 39 if request.Device != nil { 40 if len(request.Device.UA) > 0 { 41 headers.Add("User-Agent", request.Device.UA) 42 } 43 44 if len(request.Device.IPv6) > 0 { 45 headers.Add("X-Forwarded-For", request.Device.IPv6) 46 } 47 48 if len(request.Device.IP) > 0 { 49 headers.Add("X-Forwarded-For", request.Device.IP) 50 } 51 } 52 53 return headers 54 } 55 56 func (a *adapter) MakeRequests( 57 openRTBRequest *openrtb2.BidRequest, 58 reqInfo *adapters.ExtraRequestInfo, 59 ) ( 60 requestsToBidder []*adapters.RequestData, 61 errs []error, 62 ) { 63 bizzclickExt, err := a.getImpressionExt(&openRTBRequest.Imp[0]) 64 if err != nil { 65 return nil, []error{err} 66 } 67 68 for idx := range openRTBRequest.Imp { 69 openRTBRequest.Imp[idx].Ext = nil 70 } 71 url, err := a.buildEndpointURL(bizzclickExt) 72 if err != nil { 73 return nil, []error{err} 74 } 75 76 reqJSON, err := json.Marshal(openRTBRequest) 77 if err != nil { 78 return nil, []error{err} 79 } 80 81 return []*adapters.RequestData{{ 82 Method: http.MethodPost, 83 Body: reqJSON, 84 Uri: url, 85 Headers: getHeaders(openRTBRequest), 86 ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), 87 }}, nil 88 } 89 90 func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtBizzclick, error) { 91 var bidderExt adapters.ExtImpBidder 92 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 93 return nil, &errortypes.BadInput{ 94 Message: "ext.bidder not provided", 95 } 96 } 97 var bizzclickExt openrtb_ext.ExtBizzclick 98 if err := json.Unmarshal(bidderExt.Bidder, &bizzclickExt); err != nil { 99 return nil, &errortypes.BadInput{ 100 Message: "ext.bidder not provided", 101 } 102 } 103 104 return &bizzclickExt, nil 105 } 106 107 func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtBizzclick) (string, error) { 108 host := "us-e-node1" 109 if params.Host != "" { 110 host = params.Host 111 } 112 sourceId := params.SourceID 113 if params.SourceID == "" { 114 sourceId = params.PlacementID 115 } 116 endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID, SourceId: sourceId, Host: host} 117 return macros.ResolveMacros(a.endpoint, endpointParams) 118 } 119 120 func (a *adapter) checkResponseStatusCodes(response *adapters.ResponseData) error { 121 if response.StatusCode == http.StatusBadRequest { 122 return &errortypes.BadInput{ 123 Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode), 124 } 125 } 126 127 if response.StatusCode == http.StatusServiceUnavailable { 128 return &errortypes.BadServerResponse{ 129 Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode), 130 } 131 } 132 133 if response.StatusCode != http.StatusOK { 134 return &errortypes.BadServerResponse{ 135 Message: fmt.Sprintf("Unexpected status code: [ %d ]. Run with request.debug = 1 for more info", response.StatusCode), 136 } 137 } 138 139 return nil 140 } 141 142 func (a *adapter) MakeBids( 143 openRTBRequest *openrtb2.BidRequest, 144 requestToBidder *adapters.RequestData, 145 bidderRawResponse *adapters.ResponseData, 146 ) ( 147 bidderResponse *adapters.BidderResponse, 148 errs []error, 149 ) { 150 if bidderRawResponse.StatusCode == http.StatusNoContent { 151 return nil, nil 152 } 153 154 httpStatusError := a.checkResponseStatusCodes(bidderRawResponse) 155 if httpStatusError != nil { 156 return nil, []error{httpStatusError} 157 } 158 159 responseBody := bidderRawResponse.Body 160 var bidResp openrtb2.BidResponse 161 if err := json.Unmarshal(responseBody, &bidResp); err != nil { 162 return nil, []error{&errortypes.BadServerResponse{ 163 Message: "Bad Server Response", 164 }} 165 } 166 167 if len(bidResp.SeatBid) == 0 { 168 return nil, []error{&errortypes.BadServerResponse{ 169 Message: "Empty SeatBid array", 170 }} 171 } 172 173 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) 174 sb := bidResp.SeatBid[0] 175 var bidsArray []*adapters.TypedBid 176 177 for idx, bid := range sb.Bid { 178 bidsArray = append(bidsArray, &adapters.TypedBid{ 179 Bid: &sb.Bid[idx], 180 BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp), 181 }) 182 } 183 184 bidResponse.Bids = bidsArray 185 return bidResponse, nil 186 } 187 188 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType { 189 mediaType := openrtb_ext.BidTypeBanner 190 for _, imp := range imps { 191 if imp.ID == impId { 192 if imp.Video != nil { 193 mediaType = openrtb_ext.BidTypeVideo 194 } else if imp.Native != nil { 195 mediaType = openrtb_ext.BidTypeNative 196 } 197 return mediaType 198 } 199 } 200 return mediaType 201 }