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  }