github.com/prebid/prebid-server/v2@v2.18.0/adapters/ucfunnel/ucfunnel.go (about)

     1  package ucfunnel
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"net/url"
     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/openrtb_ext"
    14  )
    15  
    16  type UcfunnelAdapter struct {
    17  	URI string
    18  }
    19  
    20  // Builder builds a new instance of the Ucfunnel adapter for the given bidder with the given config.
    21  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    22  	bidder := &UcfunnelAdapter{
    23  		URI: config.Endpoint,
    24  	}
    25  	return bidder, nil
    26  }
    27  
    28  func (a *UcfunnelAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
    29  	if response.StatusCode == http.StatusNoContent {
    30  		return nil, nil
    31  	}
    32  
    33  	if response.StatusCode == http.StatusBadRequest {
    34  		return nil, []error{&errortypes.BadInput{
    35  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    36  		}}
    37  	}
    38  
    39  	if response.StatusCode != http.StatusOK {
    40  		return nil, []error{&errortypes.BadServerResponse{
    41  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    42  		}}
    43  	}
    44  
    45  	var errs []error
    46  	var bidResp openrtb2.BidResponse
    47  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
    48  		return nil, []error{err}
    49  	}
    50  
    51  	var bidReq openrtb2.BidRequest
    52  	if err := json.Unmarshal(externalRequest.Body, &bidReq); err != nil {
    53  		return nil, []error{err}
    54  	}
    55  
    56  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
    57  	for _, sb := range bidResp.SeatBid {
    58  		for i := range sb.Bid {
    59  			bidType := getBidType(bidReq, sb.Bid[i].ImpID)
    60  			if (bidType == openrtb_ext.BidTypeBanner) || (bidType == openrtb_ext.BidTypeVideo) {
    61  				b := &adapters.TypedBid{
    62  					Bid:     &sb.Bid[i],
    63  					BidType: bidType,
    64  				}
    65  				bidResponse.Bids = append(bidResponse.Bids, b)
    66  			}
    67  		}
    68  	}
    69  	return bidResponse, errs
    70  }
    71  
    72  func (a *UcfunnelAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    73  	errs := make([]error, 0, len(request.Imp))
    74  
    75  	// If all the requests were malformed, don't bother making a server call with no impressions.
    76  	if len(request.Imp) == 0 {
    77  		return nil, []error{&errortypes.BadInput{
    78  			Message: fmt.Sprintf("No impression in the bid request\n"),
    79  		}}
    80  	}
    81  
    82  	partnerId, partnerErr := getPartnerId(request)
    83  	if partnerErr != nil {
    84  		return nil, partnerErr
    85  	}
    86  
    87  	reqJSON, err := json.Marshal(request)
    88  	if err != nil {
    89  		return nil, []error{err}
    90  	}
    91  
    92  	headers := http.Header{}
    93  	headers.Add("Content-Type", "application/json")
    94  
    95  	uri := a.URI + "/" + url.PathEscape(partnerId) + "/request"
    96  	return []*adapters.RequestData{{
    97  		Method:  "POST",
    98  		Uri:     uri,
    99  		Body:    reqJSON,
   100  		Headers: headers,
   101  		ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
   102  	}}, errs
   103  }
   104  
   105  func getPartnerId(request *openrtb2.BidRequest) (string, []error) {
   106  	var ext ExtBidderUcfunnel
   107  	var errs = []error{}
   108  	err := json.Unmarshal(request.Imp[0].Ext, &ext)
   109  	if err != nil {
   110  		errs = append(errs, err)
   111  		return "", errs
   112  	}
   113  	errs = checkBidderParameter(ext)
   114  	if errs != nil {
   115  		return "", errs
   116  	}
   117  	return ext.Bidder.PartnerId, nil
   118  }
   119  
   120  func checkBidderParameter(ext ExtBidderUcfunnel) []error {
   121  	var errs = []error{}
   122  	if len(ext.Bidder.PartnerId) == 0 || len(ext.Bidder.AdUnitId) == 0 {
   123  		errs = append(errs, fmt.Errorf("No PartnerId or AdUnitId in the bid request\n"))
   124  		return errs
   125  	}
   126  	return nil
   127  }
   128  
   129  func getBidType(bidReq openrtb2.BidRequest, impid string) openrtb_ext.BidType {
   130  	for i := range bidReq.Imp {
   131  		if bidReq.Imp[i].ID == impid {
   132  			if bidReq.Imp[i].Banner != nil {
   133  				return openrtb_ext.BidTypeBanner
   134  			} else if bidReq.Imp[i].Video != nil {
   135  				return openrtb_ext.BidTypeVideo
   136  			} else if bidReq.Imp[i].Audio != nil {
   137  				return openrtb_ext.BidTypeAudio
   138  			} else if bidReq.Imp[i].Native != nil {
   139  				return openrtb_ext.BidTypeNative
   140  			}
   141  		}
   142  	}
   143  	return openrtb_ext.BidTypeNative
   144  }
   145  
   146  type ExtBidderUcfunnel struct {
   147  	Bidder openrtb_ext.ExtImpUcfunnel `json:"bidder"`
   148  }