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

     1  package yahooAds
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/prebid/openrtb/v19/openrtb2"
     9  	"github.com/prebid/prebid-server/adapters"
    10  	"github.com/prebid/prebid-server/config"
    11  	"github.com/prebid/prebid-server/errortypes"
    12  	"github.com/prebid/prebid-server/openrtb_ext"
    13  )
    14  
    15  type adapter struct {
    16  	URI string
    17  }
    18  
    19  func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    20  	var errors []error
    21  
    22  	reqs := make([]*adapters.RequestData, 0, len(request.Imp))
    23  	headers := http.Header{}
    24  
    25  	headers.Add("Content-Type", "application/json;charset=utf-8")
    26  	headers.Add("Accept", "application/json")
    27  	headers.Add("x-openrtb-version", "2.5")
    28  
    29  	if request.Device != nil && request.Device.UA != "" {
    30  		headers.Set("User-Agent", request.Device.UA)
    31  	}
    32  
    33  	for idx, imp := range request.Imp {
    34  		var bidderExt adapters.ExtImpBidder
    35  		err := json.Unmarshal(imp.Ext, &bidderExt)
    36  		if err != nil {
    37  			err = &errortypes.BadInput{
    38  				Message: fmt.Sprintf("imp #%d: ext.bidder not provided", idx),
    39  			}
    40  			errors = append(errors, err)
    41  			continue
    42  		}
    43  
    44  		var yahooAdsExt openrtb_ext.ExtImpYahooAds
    45  		err = json.Unmarshal(bidderExt.Bidder, &yahooAdsExt)
    46  		if err != nil {
    47  			err = &errortypes.BadInput{
    48  				Message: fmt.Sprintf("imp #%d: %s", idx, err.Error()),
    49  			}
    50  			errors = append(errors, err)
    51  			continue
    52  		}
    53  
    54  		// Split up multi-impression requests into multiple requests so that
    55  		// each split request is only associated to a single impression
    56  		reqCopy := *request
    57  		reqCopy.Imp = []openrtb2.Imp{imp}
    58  
    59  		if request.Site != nil {
    60  			siteCopy := *request.Site
    61  			reqCopy.Site = &siteCopy
    62  		} else if request.App != nil {
    63  			appCopy := *request.App
    64  			reqCopy.App = &appCopy
    65  		}
    66  
    67  		if err := changeRequestForBidService(&reqCopy, &yahooAdsExt); err != nil {
    68  			errors = append(errors, err)
    69  			continue
    70  		}
    71  
    72  		reqJSON, err := json.Marshal(&reqCopy)
    73  		if err != nil {
    74  			errors = append(errors, err)
    75  			continue
    76  		}
    77  
    78  		reqs = append(reqs, &adapters.RequestData{
    79  			Method:  "POST",
    80  			Uri:     a.URI,
    81  			Body:    reqJSON,
    82  			Headers: headers,
    83  		})
    84  	}
    85  
    86  	return reqs, errors
    87  }
    88  
    89  func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
    90  
    91  	if response.StatusCode == http.StatusNoContent {
    92  		return nil, nil
    93  	}
    94  
    95  	if response.StatusCode != http.StatusOK {
    96  		return nil, []error{&errortypes.BadServerResponse{
    97  			Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode),
    98  		}}
    99  	}
   100  
   101  	var bidResp openrtb2.BidResponse
   102  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   103  		return nil, []error{&errortypes.BadServerResponse{
   104  			Message: fmt.Sprintf("Bad server response: %d.", err),
   105  		}}
   106  	}
   107  
   108  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp))
   109  
   110  	for _, sb := range bidResp.SeatBid {
   111  		for _, bid := range sb.Bid {
   112  			bid := bid
   113  			exists, mediaTypeId := getImpInfo(bid.ImpID, internalRequest.Imp)
   114  			if !exists {
   115  				return nil, []error{&errortypes.BadServerResponse{
   116  					Message: fmt.Sprintf("Unknown ad unit code '%s'", bid.ImpID),
   117  				}}
   118  			}
   119  
   120  			if openrtb_ext.BidTypeBanner != mediaTypeId &&
   121  				openrtb_ext.BidTypeVideo != mediaTypeId {
   122  				//only banner and video are mediaTypeId, anything else is ignored
   123  				continue
   124  			}
   125  
   126  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   127  				Bid:     &bid,
   128  				BidType: mediaTypeId,
   129  			})
   130  		}
   131  	}
   132  
   133  	return bidResponse, nil
   134  }
   135  
   136  func getImpInfo(impId string, imps []openrtb2.Imp) (bool, openrtb_ext.BidType) {
   137  	var mediaType openrtb_ext.BidType
   138  	var exists bool
   139  	for _, imp := range imps {
   140  		if imp.ID == impId {
   141  			exists = true
   142  			if imp.Banner != nil {
   143  				mediaType = openrtb_ext.BidTypeBanner
   144  			} else if imp.Video != nil {
   145  				mediaType = openrtb_ext.BidTypeVideo
   146  			}
   147  			break
   148  		}
   149  	}
   150  	return exists, mediaType
   151  }
   152  
   153  func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb_ext.ExtImpYahooAds) error {
   154  	/* Always override the tag ID and (site ID or app ID) of the request */
   155  	request.Imp[0].TagID = extension.Pos
   156  	if request.Site != nil {
   157  		request.Site.ID = extension.Dcn
   158  	} else if request.App != nil {
   159  		request.App.ID = extension.Dcn
   160  	}
   161  
   162  	if request.Imp[0].Banner != nil {
   163  		banner := *request.Imp[0].Banner
   164  		request.Imp[0].Banner = &banner
   165  
   166  		err := validateBanner(&banner)
   167  		if err != nil {
   168  			return err
   169  		}
   170  	}
   171  
   172  	if request.Regs != nil && request.Regs.GPP != "" {
   173  		requestRegs := *request.Regs
   174  		if requestRegs.Ext == nil {
   175  			requestRegs.Ext = json.RawMessage("{}")
   176  		}
   177  		var regsExt map[string]json.RawMessage
   178  		err := json.Unmarshal(requestRegs.Ext, &regsExt)
   179  		if err != nil {
   180  			return err
   181  		}
   182  		regsExt["gpp"], err = json.Marshal(&requestRegs.GPP)
   183  
   184  		if requestRegs.GPPSID != nil {
   185  			regsExt["gpp_sid"], err = json.Marshal(&requestRegs.GPPSID)
   186  			if err != nil {
   187  				return err
   188  			}
   189  		}
   190  
   191  		requestRegs.Ext, err = json.Marshal(&regsExt)
   192  		if err != nil {
   193  			return err
   194  		}
   195  		requestRegs.GPP = ""
   196  		requestRegs.GPPSID = nil
   197  		request.Regs = &requestRegs
   198  	}
   199  
   200  	return nil
   201  }
   202  
   203  func validateBanner(banner *openrtb2.Banner) error {
   204  	if banner.W != nil && banner.H != nil {
   205  		if *banner.W == 0 || *banner.H == 0 {
   206  			return fmt.Errorf("Invalid sizes provided for Banner %dx%d", *banner.W, *banner.H)
   207  		}
   208  		return nil
   209  	}
   210  
   211  	if len(banner.Format) == 0 {
   212  		return fmt.Errorf("No sizes provided for Banner %v", banner.Format)
   213  	}
   214  
   215  	banner.W = openrtb2.Int64Ptr(banner.Format[0].W)
   216  	banner.H = openrtb2.Int64Ptr(banner.Format[0].H)
   217  
   218  	return nil
   219  }
   220  
   221  // Builder builds a new instance of the YahooAds adapter for the given bidder with the given config.
   222  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   223  	bidder := &adapter{
   224  		URI: config.Endpoint,
   225  	}
   226  	return bidder, nil
   227  }