github.com/prebid/prebid-server@v0.275.0/adapters/richaudience/richaudience.go (about)

     1  package richaudience
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"net/url"
     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/openrtb_ext"
    14  )
    15  
    16  type adapter struct {
    17  	endpoint string
    18  }
    19  
    20  // Builder builds a new instance of the RichAudience 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 := &adapter{
    23  		endpoint: config.Endpoint,
    24  	}
    25  	return bidder, nil
    26  }
    27  
    28  func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    29  	var requestDataRequest []*adapters.RequestData
    30  	errs := make([]error, 0, len(request.Imp))
    31  	raiHeaders := http.Header{}
    32  	setHeaders(&raiHeaders)
    33  
    34  	isUrlSecure := getIsUrlSecure(request)
    35  
    36  	if err := validateDevice(request); err != nil {
    37  		errs = append(errs, &errortypes.BadInput{
    38  			Message: err.Error(),
    39  		})
    40  		return nil, errs
    41  	}
    42  
    43  	for _, imp := range request.Imp {
    44  		var secure = int8(0)
    45  
    46  		raiExt, err := parseImpExt(&imp)
    47  		if err != nil {
    48  			errs = append(errs, &errortypes.BadInput{
    49  				Message: err.Error(),
    50  			})
    51  			continue
    52  		}
    53  
    54  		if request.App != nil {
    55  			appCopy := *request.App
    56  			request.App = &appCopy
    57  
    58  			request.App.Keywords = "tagid=" + imp.TagID
    59  		}
    60  
    61  		if request.Site != nil {
    62  			siteCopy := *request.Site
    63  			request.Site = &siteCopy
    64  
    65  			request.Site.Keywords = "tagid=" + imp.TagID
    66  		}
    67  
    68  		if raiExt != nil {
    69  			if raiExt.Pid != "" {
    70  				imp.TagID = raiExt.Pid
    71  			}
    72  
    73  			if raiExt.Test {
    74  				if request.Device != nil {
    75  					deviceCopy := *request.Device
    76  					request.Device = &deviceCopy
    77  				} else {
    78  					request.Device = &openrtb2.Device{}
    79  				}
    80  
    81  				request.Device.IP = "11.222.33.44"
    82  				request.Test = int8(1)
    83  			}
    84  
    85  			if raiExt.BidFloorCur != "" {
    86  				imp.BidFloorCur = raiExt.BidFloorCur
    87  			} else if imp.BidFloorCur == "" {
    88  				imp.BidFloorCur = "USD"
    89  			}
    90  		}
    91  		if isUrlSecure {
    92  			secure = int8(1)
    93  		}
    94  
    95  		imp.Secure = &secure
    96  
    97  		if imp.Banner != nil {
    98  			if imp.Banner.W == nil && imp.Banner.H == nil {
    99  				if len(imp.Banner.Format) == 0 {
   100  					errs = append(errs, &errortypes.BadInput{
   101  						Message: "request.Banner.Format is required",
   102  					})
   103  					continue
   104  				}
   105  			}
   106  		}
   107  
   108  		if imp.Video != nil {
   109  			if imp.Video.W == 0 || imp.Video.H == 0 {
   110  				errs = append(errs, &errortypes.BadInput{
   111  					Message: "request.Video.Sizes is required",
   112  				})
   113  				continue
   114  			}
   115  		}
   116  
   117  		request.Imp = []openrtb2.Imp{imp}
   118  
   119  		req, err := json.Marshal(request)
   120  		if err != nil {
   121  			errs = append(errs, &errortypes.BadInput{
   122  				Message: err.Error(),
   123  			})
   124  			continue
   125  		}
   126  
   127  		requestDataRequest = append(requestDataRequest, &adapters.RequestData{
   128  			Method:  "POST",
   129  			Uri:     a.endpoint,
   130  			Body:    req,
   131  			Headers: raiHeaders,
   132  		})
   133  
   134  	}
   135  
   136  	return requestDataRequest, errs
   137  }
   138  
   139  func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   140  	if responseData.StatusCode == http.StatusNoContent {
   141  		return nil, nil
   142  	}
   143  
   144  	if responseData.StatusCode == http.StatusBadRequest {
   145  		err := &errortypes.BadInput{
   146  			Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.",
   147  		}
   148  		return nil, []error{err}
   149  	}
   150  
   151  	if responseData.StatusCode != http.StatusOK {
   152  		err := &errortypes.BadServerResponse{
   153  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode),
   154  		}
   155  		return nil, []error{err}
   156  	}
   157  
   158  	var bidReq openrtb2.BidRequest
   159  	if err := json.Unmarshal(requestData.Body, &bidReq); err != nil {
   160  		return nil, []error{&errortypes.BadServerResponse{
   161  			Message: err.Error(),
   162  		}}
   163  	}
   164  
   165  	var bidResp openrtb2.BidResponse
   166  	if err := json.Unmarshal(responseData.Body, &bidResp); err != nil {
   167  		return nil, []error{&errortypes.BadServerResponse{
   168  			Message: err.Error(),
   169  		}}
   170  	}
   171  
   172  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidReq.Imp))
   173  	bidResponse.Currency = bidResp.Cur
   174  
   175  	for _, reqBid := range bidReq.Imp {
   176  		for _, seatBid := range bidResp.SeatBid {
   177  			for i := range seatBid.Bid {
   178  
   179  				bidType := getMediaType(seatBid.Bid[i].ImpID, reqBid)
   180  
   181  				if bidType == "video" {
   182  					seatBid.Bid[i].W = reqBid.Video.W
   183  					seatBid.Bid[i].H = reqBid.Video.H
   184  				}
   185  
   186  				b := &adapters.TypedBid{
   187  					Bid:     &seatBid.Bid[i],
   188  					BidType: bidType,
   189  				}
   190  
   191  				bidResponse.Bids = append(bidResponse.Bids, b)
   192  			}
   193  		}
   194  	}
   195  
   196  	return bidResponse, nil
   197  }
   198  
   199  func setHeaders(raiHeaders *http.Header) {
   200  	raiHeaders.Set("Content-Type", "application/json;charset=utf-8")
   201  	raiHeaders.Set("Accept", "application/json")
   202  	raiHeaders.Add("X-Openrtb-Version", "2.5")
   203  }
   204  
   205  func getIsUrlSecure(request *openrtb2.BidRequest) (isUrlSecure bool) {
   206  	if request.Site != nil {
   207  		if request.Site.Page != "" {
   208  			pageURL, err := url.Parse(request.Site.Page)
   209  			if err == nil {
   210  				if request.Site.Domain == "" {
   211  					request.Site.Domain = pageURL.Host
   212  				}
   213  				isUrlSecure = pageURL.Scheme == "https"
   214  			}
   215  		}
   216  	}
   217  	return
   218  }
   219  
   220  func validateDevice(request *openrtb2.BidRequest) (err error) {
   221  	if request.Device != nil && request.Device.IP == "" && request.Device.IPv6 == "" {
   222  		err = &errortypes.BadInput{
   223  			Message: "request.Device.IP is required",
   224  		}
   225  		return err
   226  	}
   227  	return err
   228  }
   229  
   230  func parseImpExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpRichaudience, error) {
   231  	var bidderExt adapters.ExtImpBidder
   232  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
   233  		err = &errortypes.BadInput{
   234  			Message: fmt.Sprintf("not found parameters ext in ImpID : %s", imp.ID),
   235  		}
   236  		return nil, err
   237  	}
   238  
   239  	var richaudienceExt openrtb_ext.ExtImpRichaudience
   240  	if err := json.Unmarshal(bidderExt.Bidder, &richaudienceExt); err != nil {
   241  		err = &errortypes.BadInput{
   242  			Message: fmt.Sprintf("invalid parameters ext in ImpID: %s", imp.ID),
   243  		}
   244  		return nil, err
   245  	}
   246  
   247  	return &richaudienceExt, nil
   248  }
   249  
   250  func getMediaType(impId string, imp openrtb2.Imp) openrtb_ext.BidType {
   251  	if imp.ID == impId {
   252  		if imp.Video != nil {
   253  			return openrtb_ext.BidTypeVideo
   254  		}
   255  		return openrtb_ext.BidTypeBanner
   256  	}
   257  	return "no bidtype assigned"
   258  }