github.com/prebid/prebid-server@v0.275.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/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/macros"
    14  	"github.com/prebid/prebid-server/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  	}}, nil
    87  }
    88  
    89  func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtBizzclick, error) {
    90  	var bidderExt adapters.ExtImpBidder
    91  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    92  		return nil, &errortypes.BadInput{
    93  			Message: "ext.bidder not provided",
    94  		}
    95  	}
    96  	var bizzclickExt openrtb_ext.ExtBizzclick
    97  	if err := json.Unmarshal(bidderExt.Bidder, &bizzclickExt); err != nil {
    98  		return nil, &errortypes.BadInput{
    99  			Message: "ext.bidder not provided",
   100  		}
   101  	}
   102  
   103  	return &bizzclickExt, nil
   104  }
   105  
   106  func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtBizzclick) (string, error) {
   107  	endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID, SourceId: params.PlacementID}
   108  	return macros.ResolveMacros(a.endpoint, endpointParams)
   109  }
   110  
   111  func (a *adapter) checkResponseStatusCodes(response *adapters.ResponseData) error {
   112  	if response.StatusCode == http.StatusBadRequest {
   113  		return &errortypes.BadInput{
   114  			Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode),
   115  		}
   116  	}
   117  
   118  	if response.StatusCode == http.StatusServiceUnavailable {
   119  		return &errortypes.BadServerResponse{
   120  			Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
   121  		}
   122  	}
   123  
   124  	if response.StatusCode != http.StatusOK {
   125  		return &errortypes.BadServerResponse{
   126  			Message: fmt.Sprintf("Unexpected status code: [ %d ]. Run with request.debug = 1 for more info", response.StatusCode),
   127  		}
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  func (a *adapter) MakeBids(
   134  	openRTBRequest *openrtb2.BidRequest,
   135  	requestToBidder *adapters.RequestData,
   136  	bidderRawResponse *adapters.ResponseData,
   137  ) (
   138  	bidderResponse *adapters.BidderResponse,
   139  	errs []error,
   140  ) {
   141  	if bidderRawResponse.StatusCode == http.StatusNoContent {
   142  		return nil, nil
   143  	}
   144  
   145  	httpStatusError := a.checkResponseStatusCodes(bidderRawResponse)
   146  	if httpStatusError != nil {
   147  		return nil, []error{httpStatusError}
   148  	}
   149  
   150  	responseBody := bidderRawResponse.Body
   151  	var bidResp openrtb2.BidResponse
   152  	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
   153  		return nil, []error{&errortypes.BadServerResponse{
   154  			Message: "Bad Server Response",
   155  		}}
   156  	}
   157  
   158  	if len(bidResp.SeatBid) == 0 {
   159  		return nil, []error{&errortypes.BadServerResponse{
   160  			Message: "Empty SeatBid array",
   161  		}}
   162  	}
   163  
   164  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
   165  	sb := bidResp.SeatBid[0]
   166  	var bidsArray []*adapters.TypedBid
   167  
   168  	for idx, bid := range sb.Bid {
   169  		bidsArray = append(bidsArray, &adapters.TypedBid{
   170  			Bid:     &sb.Bid[idx],
   171  			BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
   172  		})
   173  	}
   174  
   175  	bidResponse.Bids = bidsArray
   176  	return bidResponse, nil
   177  }
   178  
   179  func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
   180  	mediaType := openrtb_ext.BidTypeBanner
   181  	for _, imp := range imps {
   182  		if imp.ID == impId {
   183  			if imp.Video != nil {
   184  				mediaType = openrtb_ext.BidTypeVideo
   185  			} else if imp.Native != nil {
   186  				mediaType = openrtb_ext.BidTypeNative
   187  			}
   188  			return mediaType
   189  		}
   190  	}
   191  	return mediaType
   192  }