github.com/prebid/prebid-server/v2@v2.18.0/exchange/utils.go (about)

     1  package exchange
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"math/rand"
    10  	"strings"
    11  
    12  	"github.com/prebid/prebid-server/v2/ortb"
    13  
    14  	"github.com/prebid/go-gdpr/vendorconsent"
    15  	gpplib "github.com/prebid/go-gpp"
    16  	gppConstants "github.com/prebid/go-gpp/constants"
    17  	"github.com/prebid/openrtb/v20/openrtb2"
    18  
    19  	"github.com/prebid/prebid-server/v2/config"
    20  	"github.com/prebid/prebid-server/v2/errortypes"
    21  	"github.com/prebid/prebid-server/v2/firstpartydata"
    22  	"github.com/prebid/prebid-server/v2/gdpr"
    23  	"github.com/prebid/prebid-server/v2/metrics"
    24  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    25  	"github.com/prebid/prebid-server/v2/privacy"
    26  	"github.com/prebid/prebid-server/v2/privacy/ccpa"
    27  	"github.com/prebid/prebid-server/v2/privacy/lmt"
    28  	"github.com/prebid/prebid-server/v2/schain"
    29  	"github.com/prebid/prebid-server/v2/stored_responses"
    30  	"github.com/prebid/prebid-server/v2/util/jsonutil"
    31  	"github.com/prebid/prebid-server/v2/util/ptrutil"
    32  )
    33  
    34  var errInvalidRequestExt = errors.New("request.ext is invalid")
    35  
    36  var channelTypeMap = map[metrics.RequestType]config.ChannelType{
    37  	metrics.ReqTypeAMP:       config.ChannelAMP,
    38  	metrics.ReqTypeORTB2App:  config.ChannelApp,
    39  	metrics.ReqTypeVideo:     config.ChannelVideo,
    40  	metrics.ReqTypeORTB2Web:  config.ChannelWeb,
    41  	metrics.ReqTypeORTB2DOOH: config.ChannelDOOH,
    42  }
    43  
    44  const unknownBidder string = ""
    45  
    46  type requestSplitter struct {
    47  	bidderToSyncerKey map[string]string
    48  	me                metrics.MetricsEngine
    49  	privacyConfig     config.Privacy
    50  	gdprPermsBuilder  gdpr.PermissionsBuilder
    51  	hostSChainNode    *openrtb2.SupplyChainNode
    52  	bidderInfo        config.BidderInfos
    53  }
    54  
    55  // cleanOpenRTBRequests splits the input request into requests which are sanitized for each bidder. Intended behavior is:
    56  //
    57  //  1. BidRequest.Imp[].Ext will only contain the "prebid" field and a "bidder" field which has the params for the intended Bidder.
    58  //  2. Every BidRequest.Imp[] requested Bids from the Bidder who keys it.
    59  //  3. BidRequest.User.BuyerUID will be set to that Bidder's ID.
    60  func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context,
    61  	auctionReq AuctionRequest,
    62  	requestExt *openrtb_ext.ExtRequest,
    63  	gdprSignal gdpr.Signal,
    64  	gdprEnforced bool,
    65  	bidAdjustmentFactors map[string]float64,
    66  ) (allowedBidderRequests []BidderRequest, privacyLabels metrics.PrivacyLabels, errs []error) {
    67  	req := auctionReq.BidRequestWrapper
    68  
    69  	requestAliases, requestAliasesGVLIDs, errs := getRequestAliases(req)
    70  	if len(errs) > 0 {
    71  		return
    72  	}
    73  
    74  	allowedBidderRequests = make([]BidderRequest, 0)
    75  
    76  	bidderImpWithBidResp := stored_responses.InitStoredBidResponses(req.BidRequest, auctionReq.StoredBidResponses)
    77  
    78  	impsByBidder, err := splitImps(req.BidRequest.Imp)
    79  	if err != nil {
    80  		errs = []error{err}
    81  		return
    82  	}
    83  
    84  	var allBidderRequests []BidderRequest
    85  	var allBidderRequestErrs []error
    86  	allBidderRequests, allBidderRequestErrs = getAuctionBidderRequests(auctionReq, requestExt, rs.bidderToSyncerKey, impsByBidder, requestAliases, rs.hostSChainNode)
    87  	if allBidderRequestErrs != nil {
    88  		errs = append(errs, allBidderRequestErrs...)
    89  	}
    90  
    91  	bidderNameToBidderReq := buildBidResponseRequest(req.BidRequest, bidderImpWithBidResp, requestAliases, auctionReq.BidderImpReplaceImpID)
    92  	//this function should be executed after getAuctionBidderRequests
    93  	allBidderRequests = mergeBidderRequests(allBidderRequests, bidderNameToBidderReq)
    94  
    95  	var gpp gpplib.GppContainer
    96  	if req.BidRequest.Regs != nil && len(req.BidRequest.Regs.GPP) > 0 {
    97  		var gppErrs []error
    98  		gpp, gppErrs = gpplib.Parse(req.BidRequest.Regs.GPP)
    99  		if len(gppErrs) > 0 {
   100  			errs = append(errs, gppErrs[0])
   101  		}
   102  	}
   103  
   104  	if auctionReq.Account.PriceFloors.IsAdjustForBidAdjustmentEnabled() {
   105  		//Apply BidAdjustmentFactor to imp.BidFloor
   106  		applyBidAdjustmentToFloor(allBidderRequests, bidAdjustmentFactors)
   107  	}
   108  
   109  	consent, err := getConsent(req, gpp)
   110  	if err != nil {
   111  		errs = append(errs, err)
   112  	}
   113  
   114  	ccpaEnforcer, err := extractCCPA(req.BidRequest, rs.privacyConfig, &auctionReq.Account, requestAliases, channelTypeMap[auctionReq.LegacyLabels.RType], gpp)
   115  	if err != nil {
   116  		errs = append(errs, err)
   117  	}
   118  
   119  	lmtEnforcer := extractLMT(req.BidRequest, rs.privacyConfig)
   120  
   121  	// request level privacy policies
   122  	coppa := req.BidRequest.Regs != nil && req.BidRequest.Regs.COPPA == 1
   123  	lmt := lmtEnforcer.ShouldEnforce(unknownBidder)
   124  
   125  	privacyLabels.CCPAProvided = ccpaEnforcer.CanEnforce()
   126  	privacyLabels.CCPAEnforced = ccpaEnforcer.ShouldEnforce(unknownBidder)
   127  	privacyLabels.COPPAEnforced = coppa
   128  	privacyLabels.LMTEnforced = lmt
   129  
   130  	var gdprPerms gdpr.Permissions = &gdpr.AlwaysAllow{}
   131  
   132  	if gdprEnforced {
   133  		privacyLabels.GDPREnforced = true
   134  		parsedConsent, err := vendorconsent.ParseString(consent)
   135  		if err == nil {
   136  			version := int(parsedConsent.Version())
   137  			privacyLabels.GDPRTCFVersion = metrics.TCFVersionToValue(version)
   138  		}
   139  
   140  		gdprRequestInfo := gdpr.RequestInfo{
   141  			AliasGVLIDs: requestAliasesGVLIDs,
   142  			Consent:     consent,
   143  			GDPRSignal:  gdprSignal,
   144  			PublisherID: auctionReq.LegacyLabels.PubID,
   145  		}
   146  		gdprPerms = rs.gdprPermsBuilder(auctionReq.TCF2Config, gdprRequestInfo)
   147  	}
   148  
   149  	// bidder level privacy policies
   150  	for _, bidderRequest := range allBidderRequests {
   151  		// fetchBids activity
   152  		scopedName := privacy.Component{Type: privacy.ComponentTypeBidder, Name: bidderRequest.BidderName.String()}
   153  		fetchBidsActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityFetchBids, scopedName, privacy.NewRequestFromBidRequest(*req))
   154  		if !fetchBidsActivityAllowed {
   155  			// skip the call to a bidder if fetchBids activity is not allowed
   156  			// do not add this bidder to allowedBidderRequests
   157  			continue
   158  		}
   159  
   160  		var auctionPermissions gdpr.AuctionPermissions
   161  		var gdprErr error
   162  
   163  		if gdprEnforced {
   164  			auctionPermissions, gdprErr = gdprPerms.AuctionActivitiesAllowed(ctx, bidderRequest.BidderCoreName, bidderRequest.BidderName)
   165  			if !auctionPermissions.AllowBidRequest {
   166  				// auction request is not permitted by GDPR
   167  				// do not add this bidder to allowedBidderRequests
   168  				rs.me.RecordAdapterGDPRRequestBlocked(bidderRequest.BidderCoreName)
   169  				continue
   170  			}
   171  		}
   172  
   173  		ipConf := privacy.IPConf{IPV6: auctionReq.Account.Privacy.IPv6Config, IPV4: auctionReq.Account.Privacy.IPv4Config}
   174  
   175  		// FPD should be applied before policies, otherwise it overrides policies and activities restricted data
   176  		applyFPD(auctionReq.FirstPartyData, bidderRequest)
   177  
   178  		reqWrapper := &openrtb_ext.RequestWrapper{
   179  			BidRequest: ortb.CloneBidRequestPartial(bidderRequest.BidRequest),
   180  		}
   181  
   182  		passIDActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitUserFPD, scopedName, privacy.NewRequestFromBidRequest(*req))
   183  		buyerUIDSet := reqWrapper.User != nil && reqWrapper.User.BuyerUID != ""
   184  		buyerUIDRemoved := false
   185  		if !passIDActivityAllowed {
   186  			privacy.ScrubUserFPD(reqWrapper)
   187  			buyerUIDRemoved = true
   188  		} else {
   189  			// run existing policies (GDPR, CCPA, COPPA, LMT)
   190  			// potentially block passing IDs based on GDPR
   191  			if gdprEnforced && (gdprErr != nil || !auctionPermissions.PassID) {
   192  				privacy.ScrubGdprID(reqWrapper)
   193  				buyerUIDRemoved = true
   194  			}
   195  			// potentially block passing IDs based on CCPA
   196  			if ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) {
   197  				privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", false)
   198  				buyerUIDRemoved = true
   199  			}
   200  		}
   201  		if buyerUIDSet && buyerUIDRemoved {
   202  			rs.me.RecordAdapterBuyerUIDScrubbed(bidderRequest.BidderCoreName)
   203  		}
   204  
   205  		passGeoActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitPreciseGeo, scopedName, privacy.NewRequestFromBidRequest(*req))
   206  		if !passGeoActivityAllowed {
   207  			privacy.ScrubGeoAndDeviceIP(reqWrapper, ipConf)
   208  		} else {
   209  			// run existing policies (GDPR, CCPA, COPPA, LMT)
   210  			// potentially block passing geo based on GDPR
   211  			if gdprEnforced && (gdprErr != nil || !auctionPermissions.PassGeo) {
   212  				privacy.ScrubGeoAndDeviceIP(reqWrapper, ipConf)
   213  			}
   214  			// potentially block passing geo based on CCPA
   215  			if ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) {
   216  				privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", false)
   217  			}
   218  		}
   219  
   220  		if lmt || coppa {
   221  			privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", coppa)
   222  		}
   223  
   224  		passTIDAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitTIDs, scopedName, privacy.NewRequestFromBidRequest(*req))
   225  		if !passTIDAllowed {
   226  			privacy.ScrubTID(reqWrapper)
   227  		}
   228  
   229  		err := reqWrapper.RebuildRequest()
   230  		if err != nil {
   231  			errs = append(errs, err)
   232  		}
   233  		bidderRequest.BidRequest = reqWrapper.BidRequest
   234  
   235  		allowedBidderRequests = append(allowedBidderRequests, bidderRequest)
   236  
   237  		// GPP downgrade: always downgrade unless we can confirm GPP is supported
   238  		if shouldSetLegacyPrivacy(rs.bidderInfo, string(bidderRequest.BidderCoreName)) {
   239  			setLegacyGDPRFromGPP(bidderRequest.BidRequest, gpp)
   240  			setLegacyUSPFromGPP(bidderRequest.BidRequest, gpp)
   241  		}
   242  	}
   243  
   244  	return
   245  }
   246  
   247  func shouldSetLegacyPrivacy(bidderInfo config.BidderInfos, bidder string) bool {
   248  	binfo, defined := bidderInfo[bidder]
   249  
   250  	if !defined || binfo.OpenRTB == nil {
   251  		return true
   252  	}
   253  
   254  	return !binfo.OpenRTB.GPPSupported
   255  }
   256  
   257  func ccpaEnabled(account *config.Account, privacyConfig config.Privacy, requestType config.ChannelType) bool {
   258  	if accountEnabled := account.CCPA.EnabledForChannelType(requestType); accountEnabled != nil {
   259  		return *accountEnabled
   260  	}
   261  	return privacyConfig.CCPA.Enforce
   262  }
   263  
   264  func extractCCPA(orig *openrtb2.BidRequest, privacyConfig config.Privacy, account *config.Account, requestAliases map[string]string, requestType config.ChannelType, gpp gpplib.GppContainer) (privacy.PolicyEnforcer, error) {
   265  	// Quick extra wrapper until RequestWrapper makes its way into CleanRequests
   266  	ccpaPolicy, err := ccpa.ReadFromRequestWrapper(&openrtb_ext.RequestWrapper{BidRequest: orig}, gpp)
   267  	if err != nil {
   268  		return privacy.NilPolicyEnforcer{}, err
   269  	}
   270  
   271  	validBidders := GetValidBidders(requestAliases)
   272  	ccpaParsedPolicy, err := ccpaPolicy.Parse(validBidders)
   273  	if err != nil {
   274  		return privacy.NilPolicyEnforcer{}, err
   275  	}
   276  
   277  	ccpaEnforcer := privacy.EnabledPolicyEnforcer{
   278  		Enabled:        ccpaEnabled(account, privacyConfig, requestType),
   279  		PolicyEnforcer: ccpaParsedPolicy,
   280  	}
   281  	return ccpaEnforcer, nil
   282  }
   283  
   284  func extractLMT(orig *openrtb2.BidRequest, privacyConfig config.Privacy) privacy.PolicyEnforcer {
   285  	return privacy.EnabledPolicyEnforcer{
   286  		Enabled:        privacyConfig.LMT.Enforce,
   287  		PolicyEnforcer: lmt.ReadFromRequest(orig),
   288  	}
   289  }
   290  
   291  func ExtractReqExtBidderParamsMap(bidRequest *openrtb2.BidRequest) (map[string]json.RawMessage, error) {
   292  	if bidRequest == nil {
   293  		return nil, errors.New("error bidRequest should not be nil")
   294  	}
   295  
   296  	reqExt := &openrtb_ext.ExtRequest{}
   297  	if len(bidRequest.Ext) > 0 {
   298  		err := jsonutil.Unmarshal(bidRequest.Ext, &reqExt)
   299  		if err != nil {
   300  			return nil, fmt.Errorf("error decoding Request.ext : %s", err.Error())
   301  		}
   302  	}
   303  
   304  	if reqExt.Prebid.BidderParams == nil {
   305  		return nil, nil
   306  	}
   307  
   308  	var bidderParams map[string]json.RawMessage
   309  	err := jsonutil.Unmarshal(reqExt.Prebid.BidderParams, &bidderParams)
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  
   314  	return bidderParams, nil
   315  }
   316  
   317  func getAuctionBidderRequests(auctionRequest AuctionRequest,
   318  	requestExt *openrtb_ext.ExtRequest,
   319  	bidderToSyncerKey map[string]string,
   320  	impsByBidder map[string][]openrtb2.Imp,
   321  	requestAliases map[string]string,
   322  	hostSChainNode *openrtb2.SupplyChainNode) ([]BidderRequest, []error) {
   323  
   324  	bidderRequests := make([]BidderRequest, 0, len(impsByBidder))
   325  	req := auctionRequest.BidRequestWrapper
   326  	explicitBuyerUIDs, err := extractBuyerUIDs(req.BidRequest.User)
   327  	if err != nil {
   328  		return nil, []error{err}
   329  	}
   330  
   331  	bidderParamsInReqExt, err := ExtractReqExtBidderParamsMap(req.BidRequest)
   332  	if err != nil {
   333  		return nil, []error{err}
   334  	}
   335  
   336  	sChainWriter, err := schain.NewSChainWriter(requestExt, hostSChainNode)
   337  	if err != nil {
   338  		return nil, []error{err}
   339  	}
   340  
   341  	lowerCaseExplicitBuyerUIDs := make(map[string]string)
   342  	for bidder, uid := range explicitBuyerUIDs {
   343  		lowerKey := strings.ToLower(bidder)
   344  		lowerCaseExplicitBuyerUIDs[lowerKey] = uid
   345  	}
   346  
   347  	var errs []error
   348  	for bidder, imps := range impsByBidder {
   349  		coreBidder, isRequestAlias := resolveBidder(bidder, requestAliases)
   350  
   351  		reqCopy := *req.BidRequest
   352  		reqCopy.Imp = imps
   353  
   354  		sChainWriter.Write(&reqCopy, bidder)
   355  
   356  		reqCopy.Ext, err = buildRequestExtForBidder(bidder, req.BidRequest.Ext, requestExt, bidderParamsInReqExt, auctionRequest.Account.AlternateBidderCodes)
   357  		if err != nil {
   358  			return nil, []error{err}
   359  		}
   360  
   361  		if err := removeUnpermissionedEids(&reqCopy, bidder, requestExt); err != nil {
   362  			errs = append(errs, fmt.Errorf("unable to enforce request.ext.prebid.data.eidpermissions because %v", err))
   363  			continue
   364  		}
   365  
   366  		bidderRequest := BidderRequest{
   367  			BidderName:     openrtb_ext.BidderName(bidder),
   368  			BidderCoreName: coreBidder,
   369  			IsRequestAlias: isRequestAlias,
   370  			BidRequest:     &reqCopy,
   371  			BidderLabels: metrics.AdapterLabels{
   372  				Source:      auctionRequest.LegacyLabels.Source,
   373  				RType:       auctionRequest.LegacyLabels.RType,
   374  				Adapter:     coreBidder,
   375  				PubID:       auctionRequest.LegacyLabels.PubID,
   376  				CookieFlag:  auctionRequest.LegacyLabels.CookieFlag,
   377  				AdapterBids: metrics.AdapterBidPresent,
   378  			},
   379  		}
   380  
   381  		syncerKey := bidderToSyncerKey[string(coreBidder)]
   382  		if hadSync := prepareUser(&reqCopy, bidder, syncerKey, lowerCaseExplicitBuyerUIDs, auctionRequest.UserSyncs); !hadSync && req.BidRequest.App == nil {
   383  			bidderRequest.BidderLabels.CookieFlag = metrics.CookieFlagNo
   384  		} else {
   385  			bidderRequest.BidderLabels.CookieFlag = metrics.CookieFlagYes
   386  		}
   387  
   388  		bidderRequests = append(bidderRequests, bidderRequest)
   389  	}
   390  	return bidderRequests, errs
   391  }
   392  
   393  func buildRequestExtForBidder(bidder string, requestExt json.RawMessage, requestExtParsed *openrtb_ext.ExtRequest, bidderParamsInReqExt map[string]json.RawMessage, cfgABC *openrtb_ext.ExtAlternateBidderCodes) (json.RawMessage, error) {
   394  	// Resolve alternatebiddercode for current bidder
   395  	var reqABC *openrtb_ext.ExtAlternateBidderCodes
   396  	if len(requestExt) != 0 && requestExtParsed != nil && requestExtParsed.Prebid.AlternateBidderCodes != nil {
   397  		reqABC = requestExtParsed.Prebid.AlternateBidderCodes
   398  	}
   399  	alternateBidderCodes := buildRequestExtAlternateBidderCodes(bidder, cfgABC, reqABC)
   400  
   401  	if (len(requestExt) == 0 || requestExtParsed == nil) && alternateBidderCodes == nil {
   402  		return nil, nil
   403  	}
   404  
   405  	// Resolve Bidder Params
   406  	var bidderParams json.RawMessage
   407  	if bidderParamsInReqExt != nil {
   408  		bidderParams = bidderParamsInReqExt[bidder]
   409  	}
   410  
   411  	// Copy Allowed Fields
   412  	// Per: https://docs.prebid.org/prebid-server/endpoints/openrtb2/pbs-endpoint-auction.html#prebid-server-ortb2-extension-summary
   413  	prebid := openrtb_ext.ExtRequestPrebid{
   414  		BidderParams:         bidderParams,
   415  		AlternateBidderCodes: alternateBidderCodes,
   416  	}
   417  
   418  	if requestExtParsed != nil {
   419  		prebid.Channel = requestExtParsed.Prebid.Channel
   420  		prebid.CurrencyConversions = requestExtParsed.Prebid.CurrencyConversions
   421  		prebid.Debug = requestExtParsed.Prebid.Debug
   422  		prebid.Integration = requestExtParsed.Prebid.Integration
   423  		prebid.MultiBid = buildRequestExtMultiBid(bidder, requestExtParsed.Prebid.MultiBid, alternateBidderCodes)
   424  		prebid.Sdk = requestExtParsed.Prebid.Sdk
   425  		prebid.Server = requestExtParsed.Prebid.Server
   426  	}
   427  
   428  	// Marshal New Prebid Object
   429  	prebidJson, err := jsonutil.Marshal(prebid)
   430  	if err != nil {
   431  		return nil, err
   432  	}
   433  
   434  	// Parse Existing Ext
   435  	extMap := make(map[string]json.RawMessage)
   436  	if len(requestExt) != 0 {
   437  		if err := jsonutil.Unmarshal(requestExt, &extMap); err != nil {
   438  			return nil, err
   439  		}
   440  	}
   441  
   442  	// Update Ext With Prebid Json
   443  	if bytes.Equal(prebidJson, []byte(`{}`)) {
   444  		delete(extMap, "prebid")
   445  	} else {
   446  		extMap["prebid"] = prebidJson
   447  	}
   448  
   449  	if len(extMap) > 0 {
   450  		return jsonutil.Marshal(extMap)
   451  	} else {
   452  		return nil, nil
   453  	}
   454  }
   455  
   456  func buildRequestExtAlternateBidderCodes(bidder string, accABC *openrtb_ext.ExtAlternateBidderCodes, reqABC *openrtb_ext.ExtAlternateBidderCodes) *openrtb_ext.ExtAlternateBidderCodes {
   457  
   458  	if altBidderCodes := copyExtAlternateBidderCodes(bidder, reqABC); altBidderCodes != nil {
   459  		return altBidderCodes
   460  	}
   461  
   462  	if altBidderCodes := copyExtAlternateBidderCodes(bidder, accABC); altBidderCodes != nil {
   463  		return altBidderCodes
   464  	}
   465  
   466  	return nil
   467  }
   468  
   469  func copyExtAlternateBidderCodes(bidder string, altBidderCodes *openrtb_ext.ExtAlternateBidderCodes) *openrtb_ext.ExtAlternateBidderCodes {
   470  	if altBidderCodes != nil {
   471  		alternateBidderCodes := &openrtb_ext.ExtAlternateBidderCodes{
   472  			Enabled: altBidderCodes.Enabled,
   473  		}
   474  
   475  		if bidderCodes, ok := altBidderCodes.IsBidderInAlternateBidderCodes(bidder); ok {
   476  			alternateBidderCodes.Bidders = map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{
   477  				bidder: bidderCodes,
   478  			}
   479  		}
   480  
   481  		return alternateBidderCodes
   482  	}
   483  	return nil
   484  }
   485  
   486  func buildRequestExtMultiBid(adapter string, reqMultiBid []*openrtb_ext.ExtMultiBid, adapterABC *openrtb_ext.ExtAlternateBidderCodes) []*openrtb_ext.ExtMultiBid {
   487  	adapterMultiBid := make([]*openrtb_ext.ExtMultiBid, 0)
   488  	for _, multiBid := range reqMultiBid {
   489  		if multiBid.Bidder != "" {
   490  			if strings.ToLower(multiBid.Bidder) == adapter || isBidderInExtAlternateBidderCodes(adapter, strings.ToLower(multiBid.Bidder), adapterABC) {
   491  				adapterMultiBid = append(adapterMultiBid, multiBid)
   492  			}
   493  		} else {
   494  			for _, bidder := range multiBid.Bidders {
   495  				if strings.ToLower(bidder) == adapter || isBidderInExtAlternateBidderCodes(adapter, strings.ToLower(bidder), adapterABC) {
   496  					adapterMultiBid = append(adapterMultiBid, &openrtb_ext.ExtMultiBid{
   497  						Bidders: []string{bidder},
   498  						MaxBids: multiBid.MaxBids,
   499  					})
   500  				}
   501  			}
   502  		}
   503  	}
   504  
   505  	if len(adapterMultiBid) > 0 {
   506  		return adapterMultiBid
   507  	}
   508  
   509  	return nil
   510  }
   511  
   512  func isBidderInExtAlternateBidderCodes(adapter, currentMultiBidBidder string, adapterABC *openrtb_ext.ExtAlternateBidderCodes) bool {
   513  	if adapterABC != nil {
   514  		if abc, ok := adapterABC.Bidders[adapter]; ok {
   515  			for _, bidder := range abc.AllowedBidderCodes {
   516  				if bidder == "*" || bidder == currentMultiBidBidder {
   517  					return true
   518  				}
   519  			}
   520  		}
   521  	}
   522  	return false
   523  }
   524  
   525  // extractBuyerUIDs parses the values from user.ext.prebid.buyeruids, and then deletes those values from the ext.
   526  // This prevents a Bidder from using these values to figure out who else is involved in the Auction.
   527  func extractBuyerUIDs(user *openrtb2.User) (map[string]string, error) {
   528  	if user == nil {
   529  		return nil, nil
   530  	}
   531  	if len(user.Ext) == 0 {
   532  		return nil, nil
   533  	}
   534  
   535  	var userExt openrtb_ext.ExtUser
   536  	if err := jsonutil.Unmarshal(user.Ext, &userExt); err != nil {
   537  		return nil, err
   538  	}
   539  	if userExt.Prebid == nil {
   540  		return nil, nil
   541  	}
   542  
   543  	// The API guarantees that user.ext.prebid.buyeruids exists and has at least one ID defined,
   544  	// as long as user.ext.prebid exists.
   545  	buyerUIDs := userExt.Prebid.BuyerUIDs
   546  	userExt.Prebid = nil
   547  
   548  	// Remarshal (instead of removing) if the ext has other known fields
   549  	if userExt.Consent != "" || len(userExt.Eids) > 0 {
   550  		if newUserExtBytes, err := jsonutil.Marshal(userExt); err != nil {
   551  			return nil, err
   552  		} else {
   553  			user.Ext = newUserExtBytes
   554  		}
   555  	} else {
   556  		user.Ext = nil
   557  	}
   558  	return buyerUIDs, nil
   559  }
   560  
   561  // splitImps takes a list of Imps and returns a map of imps which have been sanitized for each bidder.
   562  //
   563  // For example, suppose imps has two elements. One goes to rubicon, while the other goes to appnexus and index.
   564  // The returned map will have three keys: rubicon, appnexus, and index--each with one Imp.
   565  // The "imp.ext" value of the appnexus Imp will only contain the "prebid" values, and "appnexus" value at the "bidder" key.
   566  // The "imp.ext" value of the rubicon Imp will only contain the "prebid" values, and "rubicon" value at the "bidder" key.
   567  //
   568  // The goal here is so that Bidders only get Imps and Imp.Ext values which are intended for them.
   569  func splitImps(imps []openrtb2.Imp) (map[string][]openrtb2.Imp, error) {
   570  	bidderImps := make(map[string][]openrtb2.Imp)
   571  
   572  	for i, imp := range imps {
   573  		var impExt map[string]json.RawMessage
   574  		if err := jsonutil.UnmarshalValid(imp.Ext, &impExt); err != nil {
   575  			return nil, fmt.Errorf("invalid json for imp[%d]: %v", i, err)
   576  		}
   577  
   578  		var impExtPrebid map[string]json.RawMessage
   579  		if impExtPrebidJSON, exists := impExt[openrtb_ext.PrebidExtKey]; exists {
   580  			// validation already performed by impExt unmarshal. no error is possible here, proven by tests.
   581  			jsonutil.Unmarshal(impExtPrebidJSON, &impExtPrebid)
   582  		}
   583  
   584  		var impExtPrebidBidder map[string]json.RawMessage
   585  		if impExtPrebidBidderJSON, exists := impExtPrebid[openrtb_ext.PrebidExtBidderKey]; exists {
   586  			// validation already performed by impExt unmarshal. no error is possible here, proven by tests.
   587  			jsonutil.Unmarshal(impExtPrebidBidderJSON, &impExtPrebidBidder)
   588  		}
   589  
   590  		sanitizedImpExt, err := createSanitizedImpExt(impExt, impExtPrebid)
   591  		if err != nil {
   592  			return nil, fmt.Errorf("unable to remove other bidder fields for imp[%d]: %v", i, err)
   593  		}
   594  
   595  		for bidder, bidderExt := range impExtPrebidBidder {
   596  			impCopy := imp
   597  
   598  			sanitizedImpExt[openrtb_ext.PrebidExtBidderKey] = bidderExt
   599  
   600  			impExtJSON, err := jsonutil.Marshal(sanitizedImpExt)
   601  			if err != nil {
   602  				return nil, fmt.Errorf("unable to remove other bidder fields for imp[%d]: cannot marshal ext: %v", i, err)
   603  			}
   604  			impCopy.Ext = impExtJSON
   605  
   606  			bidderImps[bidder] = append(bidderImps[bidder], impCopy)
   607  		}
   608  	}
   609  
   610  	return bidderImps, nil
   611  }
   612  
   613  var allowedImpExtFields = map[string]interface{}{
   614  	openrtb_ext.AuctionEnvironmentKey:       struct{}{},
   615  	openrtb_ext.FirstPartyDataExtKey:        struct{}{},
   616  	openrtb_ext.FirstPartyDataContextExtKey: struct{}{},
   617  	openrtb_ext.GPIDKey:                     struct{}{},
   618  	openrtb_ext.SKAdNExtKey:                 struct{}{},
   619  	openrtb_ext.TIDKey:                      struct{}{},
   620  }
   621  
   622  var allowedImpExtPrebidFields = map[string]interface{}{
   623  	openrtb_ext.IsRewardedInventoryKey: struct{}{},
   624  	openrtb_ext.OptionsKey:             struct{}{},
   625  }
   626  
   627  func createSanitizedImpExt(impExt, impExtPrebid map[string]json.RawMessage) (map[string]json.RawMessage, error) {
   628  	sanitizedImpExt := make(map[string]json.RawMessage, 6)
   629  	sanitizedImpPrebidExt := make(map[string]json.RawMessage, 2)
   630  
   631  	// copy allowed imp[].ext.prebid fields
   632  	for k := range allowedImpExtPrebidFields {
   633  		if v, exists := impExtPrebid[k]; exists {
   634  			sanitizedImpPrebidExt[k] = v
   635  		}
   636  	}
   637  
   638  	// marshal sanitized imp[].ext.prebid
   639  	if len(sanitizedImpPrebidExt) > 0 {
   640  		if impExtPrebidJSON, err := jsonutil.Marshal(sanitizedImpPrebidExt); err == nil {
   641  			sanitizedImpExt[openrtb_ext.PrebidExtKey] = impExtPrebidJSON
   642  		} else {
   643  			return nil, fmt.Errorf("cannot marshal ext.prebid: %v", err)
   644  		}
   645  	}
   646  
   647  	// copy reserved imp[].ext fields known to not be bidder names
   648  	for k := range allowedImpExtFields {
   649  		if v, exists := impExt[k]; exists {
   650  			sanitizedImpExt[k] = v
   651  		}
   652  	}
   653  
   654  	return sanitizedImpExt, nil
   655  }
   656  
   657  // prepareUser changes req.User so that it's ready for the given bidder.
   658  // This *will* mutate the request, but will *not* mutate any objects nested inside it.
   659  //
   660  // In this function, "givenBidder" may or may not be an alias. "coreBidder" must *not* be an alias.
   661  // It returns true if a Cookie User Sync existed, and false otherwise.
   662  func prepareUser(req *openrtb2.BidRequest, givenBidder, syncerKey string, explicitBuyerUIDs map[string]string, usersyncs IdFetcher) bool {
   663  	cookieId, hadCookie, _ := usersyncs.GetUID(syncerKey)
   664  
   665  	if id, ok := explicitBuyerUIDs[strings.ToLower(givenBidder)]; ok {
   666  		req.User = copyWithBuyerUID(req.User, id)
   667  	} else if hadCookie {
   668  		req.User = copyWithBuyerUID(req.User, cookieId)
   669  	}
   670  
   671  	return hadCookie
   672  }
   673  
   674  // copyWithBuyerUID either overwrites the BuyerUID property on user with the argument, or returns
   675  // a new (empty) User with the BuyerUID already set.
   676  func copyWithBuyerUID(user *openrtb2.User, buyerUID string) *openrtb2.User {
   677  	if user == nil {
   678  		return &openrtb2.User{
   679  			BuyerUID: buyerUID,
   680  		}
   681  	}
   682  	if user.BuyerUID == "" {
   683  		clone := *user
   684  		clone.BuyerUID = buyerUID
   685  		return &clone
   686  	}
   687  	return user
   688  }
   689  
   690  // removeUnpermissionedEids modifies the request to remove any request.user.ext.eids not permissions for the specific bidder
   691  func removeUnpermissionedEids(request *openrtb2.BidRequest, bidder string, requestExt *openrtb_ext.ExtRequest) error {
   692  	// ensure request might have eids (as much as we can check before unmarshalling)
   693  	if request.User == nil || len(request.User.Ext) == 0 {
   694  		return nil
   695  	}
   696  
   697  	// ensure request has eid permissions to enforce
   698  	if requestExt == nil || requestExt.Prebid.Data == nil || len(requestExt.Prebid.Data.EidPermissions) == 0 {
   699  		return nil
   700  	}
   701  
   702  	// low level unmarshal to preserve other request.user.ext values. prebid server is non-destructive.
   703  	var userExt map[string]json.RawMessage
   704  	if err := jsonutil.Unmarshal(request.User.Ext, &userExt); err != nil {
   705  		return err
   706  	}
   707  
   708  	eidsJSON, eidsSpecified := userExt["eids"]
   709  	if !eidsSpecified {
   710  		return nil
   711  	}
   712  
   713  	var eids []openrtb2.EID
   714  	if err := jsonutil.Unmarshal(eidsJSON, &eids); err != nil {
   715  		return err
   716  	}
   717  
   718  	// exit early if there are no eids (empty array)
   719  	if len(eids) == 0 {
   720  		return nil
   721  	}
   722  
   723  	// translate eid permissions to a map for quick lookup
   724  	eidRules := make(map[string][]string)
   725  	for _, p := range requestExt.Prebid.Data.EidPermissions {
   726  		eidRules[p.Source] = p.Bidders
   727  	}
   728  
   729  	eidsAllowed := make([]openrtb2.EID, 0, len(eids))
   730  	for _, eid := range eids {
   731  		allowed := false
   732  		if rule, hasRule := eidRules[eid.Source]; hasRule {
   733  			for _, ruleBidder := range rule {
   734  				if ruleBidder == "*" || strings.EqualFold(ruleBidder, bidder) {
   735  					allowed = true
   736  					break
   737  				}
   738  			}
   739  		} else {
   740  			allowed = true
   741  		}
   742  
   743  		if allowed {
   744  			eidsAllowed = append(eidsAllowed, eid)
   745  		}
   746  	}
   747  
   748  	// exit early if all eids are allowed and nothing needs to be removed
   749  	if len(eids) == len(eidsAllowed) {
   750  		return nil
   751  	}
   752  
   753  	// marshal eidsAllowed back to userExt
   754  	if len(eidsAllowed) == 0 {
   755  		delete(userExt, "eids")
   756  	} else {
   757  		eidsRaw, err := jsonutil.Marshal(eidsAllowed)
   758  		if err != nil {
   759  			return err
   760  		}
   761  		userExt["eids"] = eidsRaw
   762  	}
   763  
   764  	// exit early if userExt is empty
   765  	if len(userExt) == 0 {
   766  		setUserExtWithCopy(request, nil)
   767  		return nil
   768  	}
   769  
   770  	userExtJSON, err := jsonutil.Marshal(userExt)
   771  	if err != nil {
   772  		return err
   773  	}
   774  	setUserExtWithCopy(request, userExtJSON)
   775  	return nil
   776  }
   777  
   778  func setUserExtWithCopy(request *openrtb2.BidRequest, userExtJSON json.RawMessage) {
   779  	userCopy := *request.User
   780  	userCopy.Ext = userExtJSON
   781  	request.User = &userCopy
   782  }
   783  
   784  // resolveBidder returns the known BidderName associated with bidder, if bidder is an alias. If it's not an alias, the bidder is returned.
   785  func resolveBidder(bidder string, requestAliases map[string]string) (openrtb_ext.BidderName, bool) {
   786  	normalisedBidderName, _ := openrtb_ext.NormalizeBidderName(bidder)
   787  
   788  	if coreBidder, ok := requestAliases[bidder]; ok {
   789  		return openrtb_ext.BidderName(coreBidder), true
   790  	}
   791  
   792  	return normalisedBidderName, false
   793  }
   794  
   795  func getRequestAliases(req *openrtb_ext.RequestWrapper) (map[string]string, map[string]uint16, []error) {
   796  	reqExt, err := req.GetRequestExt()
   797  	if err != nil {
   798  		return nil, nil, []error{errInvalidRequestExt}
   799  	}
   800  
   801  	if prebid := reqExt.GetPrebid(); prebid != nil {
   802  		return prebid.Aliases, prebid.AliasGVLIDs, nil
   803  	}
   804  
   805  	return nil, nil, nil
   806  }
   807  
   808  func GetValidBidders(requestAliases map[string]string) map[string]struct{} {
   809  	validBidders := openrtb_ext.BuildBidderNameHashSet()
   810  
   811  	for k := range requestAliases {
   812  		validBidders[k] = struct{}{}
   813  	}
   814  
   815  	return validBidders
   816  }
   817  
   818  // Quick little randomizer for a list of strings. Stuffing it in utils to keep other files clean
   819  func randomizeList(list []openrtb_ext.BidderName) {
   820  	l := len(list)
   821  	perm := rand.Perm(l)
   822  	var j int
   823  	for i := 0; i < l; i++ {
   824  		j = perm[i]
   825  		list[i], list[j] = list[j], list[i]
   826  	}
   827  }
   828  
   829  func getExtCacheInstructions(requestExtPrebid *openrtb_ext.ExtRequestPrebid) extCacheInstructions {
   830  	//returnCreative defaults to true
   831  	cacheInstructions := extCacheInstructions{returnCreative: true}
   832  	foundBidsRC := false
   833  	foundVastRC := false
   834  
   835  	if requestExtPrebid != nil && requestExtPrebid.Cache != nil {
   836  		if requestExtPrebid.Cache.Bids != nil {
   837  			cacheInstructions.cacheBids = true
   838  			if requestExtPrebid.Cache.Bids.ReturnCreative != nil {
   839  				cacheInstructions.returnCreative = *requestExtPrebid.Cache.Bids.ReturnCreative
   840  				foundBidsRC = true
   841  			}
   842  		}
   843  
   844  		if requestExtPrebid.Cache.VastXML != nil {
   845  			cacheInstructions.cacheVAST = true
   846  			if requestExtPrebid.Cache.VastXML.ReturnCreative != nil {
   847  				cacheInstructions.returnCreative = *requestExtPrebid.Cache.VastXML.ReturnCreative
   848  				foundVastRC = true
   849  			}
   850  		}
   851  	}
   852  
   853  	if foundBidsRC && foundVastRC {
   854  		cacheInstructions.returnCreative = *requestExtPrebid.Cache.Bids.ReturnCreative || *requestExtPrebid.Cache.VastXML.ReturnCreative
   855  	}
   856  
   857  	return cacheInstructions
   858  }
   859  
   860  func getExtTargetData(requestExtPrebid *openrtb_ext.ExtRequestPrebid, cacheInstructions extCacheInstructions) *targetData {
   861  	if requestExtPrebid != nil && requestExtPrebid.Targeting != nil {
   862  		return &targetData{
   863  			includeWinners:            *requestExtPrebid.Targeting.IncludeWinners,
   864  			includeBidderKeys:         *requestExtPrebid.Targeting.IncludeBidderKeys,
   865  			includeCacheBids:          cacheInstructions.cacheBids,
   866  			includeCacheVast:          cacheInstructions.cacheVAST,
   867  			includeFormat:             requestExtPrebid.Targeting.IncludeFormat,
   868  			priceGranularity:          *requestExtPrebid.Targeting.PriceGranularity,
   869  			mediaTypePriceGranularity: requestExtPrebid.Targeting.MediaTypePriceGranularity,
   870  			preferDeals:               requestExtPrebid.Targeting.PreferDeals,
   871  			alwaysIncludeDeals:        requestExtPrebid.Targeting.AlwaysIncludeDeals,
   872  		}
   873  	}
   874  
   875  	return nil
   876  }
   877  
   878  // getDebugInfo returns the boolean flags that allow for debug information in bidResponse.Ext, the SeatBid.httpcalls slice, and
   879  // also sets the debugLog information
   880  func getDebugInfo(test int8, requestExtPrebid *openrtb_ext.ExtRequestPrebid, accountDebugFlag bool, debugLog *DebugLog) (bool, bool, *DebugLog) {
   881  	requestDebugAllow := parseRequestDebugValues(test, requestExtPrebid)
   882  	debugLog = setDebugLogValues(accountDebugFlag, debugLog)
   883  
   884  	responseDebugAllow := (requestDebugAllow && accountDebugFlag) || debugLog.DebugEnabledOrOverridden
   885  	accountDebugAllow := (requestDebugAllow && accountDebugFlag) || (debugLog.DebugEnabledOrOverridden && accountDebugFlag)
   886  
   887  	return responseDebugAllow, accountDebugAllow, debugLog
   888  }
   889  
   890  // setDebugLogValues initializes the DebugLog if nil. It also sets the value of the debugInfo flag
   891  // used in HoldAuction
   892  func setDebugLogValues(accountDebugFlag bool, debugLog *DebugLog) *DebugLog {
   893  	if debugLog == nil {
   894  		debugLog = &DebugLog{}
   895  	}
   896  
   897  	debugLog.Enabled = debugLog.DebugEnabledOrOverridden || accountDebugFlag
   898  	return debugLog
   899  }
   900  
   901  func parseRequestDebugValues(test int8, requestExtPrebid *openrtb_ext.ExtRequestPrebid) bool {
   902  	return test == 1 || (requestExtPrebid != nil && requestExtPrebid.Debug)
   903  }
   904  
   905  func getExtBidAdjustmentFactors(requestExtPrebid *openrtb_ext.ExtRequestPrebid) map[string]float64 {
   906  	if requestExtPrebid != nil && requestExtPrebid.BidAdjustmentFactors != nil {
   907  		caseInsensitiveMap := make(map[string]float64, len(requestExtPrebid.BidAdjustmentFactors))
   908  		for bidder, bidAdjFactor := range requestExtPrebid.BidAdjustmentFactors {
   909  			caseInsensitiveMap[strings.ToLower(bidder)] = bidAdjFactor
   910  		}
   911  		return caseInsensitiveMap
   912  	}
   913  	return nil
   914  }
   915  
   916  func applyFPD(fpd map[openrtb_ext.BidderName]*firstpartydata.ResolvedFirstPartyData, r BidderRequest) {
   917  	if fpd == nil {
   918  		return
   919  	}
   920  
   921  	bidder := r.BidderCoreName
   922  	if r.IsRequestAlias {
   923  		bidder = r.BidderName
   924  	}
   925  
   926  	fpdToApply, exists := fpd[bidder]
   927  	if !exists || fpdToApply == nil {
   928  		return
   929  	}
   930  
   931  	if fpdToApply.Site != nil {
   932  		r.BidRequest.Site = fpdToApply.Site
   933  	}
   934  
   935  	if fpdToApply.App != nil {
   936  		r.BidRequest.App = fpdToApply.App
   937  	}
   938  
   939  	if fpdToApply.User != nil {
   940  		//BuyerUID is a value obtained between fpd extraction and fpd application.
   941  		//BuyerUID needs to be set back to fpd before applying this fpd to final bidder request
   942  		if r.BidRequest.User != nil && len(r.BidRequest.User.BuyerUID) > 0 {
   943  			fpdToApply.User.BuyerUID = r.BidRequest.User.BuyerUID
   944  		}
   945  		r.BidRequest.User = fpdToApply.User
   946  	}
   947  }
   948  
   949  func buildBidResponseRequest(req *openrtb2.BidRequest,
   950  	bidderImpResponses stored_responses.BidderImpsWithBidResponses,
   951  	requestAliases map[string]string,
   952  	bidderImpReplaceImpID stored_responses.BidderImpReplaceImpID) map[openrtb_ext.BidderName]BidderRequest {
   953  
   954  	bidderToBidderResponse := make(map[openrtb_ext.BidderName]BidderRequest)
   955  
   956  	for bidderName, impResps := range bidderImpResponses {
   957  		resolvedBidder, isRequestAlias := resolveBidder(string(bidderName), requestAliases)
   958  		bidderToBidderResponse[bidderName] = BidderRequest{
   959  			BidRequest:            req,
   960  			BidderCoreName:        resolvedBidder,
   961  			BidderName:            bidderName,
   962  			BidderStoredResponses: impResps,
   963  			ImpReplaceImpId:       bidderImpReplaceImpID[string(bidderName)],
   964  			IsRequestAlias:        isRequestAlias,
   965  			BidderLabels:          metrics.AdapterLabels{Adapter: resolvedBidder},
   966  		}
   967  	}
   968  	return bidderToBidderResponse
   969  }
   970  
   971  func mergeBidderRequests(allBidderRequests []BidderRequest, bidderNameToBidderReq map[openrtb_ext.BidderName]BidderRequest) []BidderRequest {
   972  	if len(allBidderRequests) == 0 && len(bidderNameToBidderReq) == 0 {
   973  		return allBidderRequests
   974  	}
   975  	if len(allBidderRequests) == 0 && len(bidderNameToBidderReq) > 0 {
   976  		for _, v := range bidderNameToBidderReq {
   977  			allBidderRequests = append(allBidderRequests, v)
   978  		}
   979  		return allBidderRequests
   980  	} else if len(allBidderRequests) > 0 && len(bidderNameToBidderReq) > 0 {
   981  		//merge bidder requests with real imps and imps with stored resp
   982  		for bn, br := range bidderNameToBidderReq {
   983  			found := false
   984  			for i, ar := range allBidderRequests {
   985  				if ar.BidderName == bn {
   986  					//bidder req with real imps and imps with stored resp
   987  					allBidderRequests[i].BidderStoredResponses = br.BidderStoredResponses
   988  					found = true
   989  					break
   990  				}
   991  			}
   992  			if !found {
   993  				//bidder req with stored bid responses only
   994  				br.BidRequest.Imp = nil // to indicate this bidder request has bidder responses only
   995  				allBidderRequests = append(allBidderRequests, br)
   996  			}
   997  		}
   998  	}
   999  	return allBidderRequests
  1000  }
  1001  
  1002  func setLegacyGDPRFromGPP(r *openrtb2.BidRequest, gpp gpplib.GppContainer) {
  1003  	if r.Regs != nil && r.Regs.GDPR == nil {
  1004  		if r.Regs.GPPSID != nil {
  1005  			// Set to 0 unless SID exists
  1006  			regs := *r.Regs
  1007  			regs.GDPR = ptrutil.ToPtr[int8](0)
  1008  			for _, id := range r.Regs.GPPSID {
  1009  				if id == int8(gppConstants.SectionTCFEU2) {
  1010  					regs.GDPR = ptrutil.ToPtr[int8](1)
  1011  				}
  1012  			}
  1013  			r.Regs = &regs
  1014  		}
  1015  	}
  1016  
  1017  	if r.User == nil || len(r.User.Consent) == 0 {
  1018  		for _, sec := range gpp.Sections {
  1019  			if sec.GetID() == gppConstants.SectionTCFEU2 {
  1020  				var user openrtb2.User
  1021  				if r.User == nil {
  1022  					user = openrtb2.User{}
  1023  				} else {
  1024  					user = *r.User
  1025  				}
  1026  				user.Consent = sec.GetValue()
  1027  				r.User = &user
  1028  			}
  1029  		}
  1030  	}
  1031  
  1032  }
  1033  func setLegacyUSPFromGPP(r *openrtb2.BidRequest, gpp gpplib.GppContainer) {
  1034  	if r.Regs == nil {
  1035  		return
  1036  	}
  1037  
  1038  	if len(r.Regs.USPrivacy) > 0 || r.Regs.GPPSID == nil {
  1039  		return
  1040  	}
  1041  	for _, sid := range r.Regs.GPPSID {
  1042  		if sid == int8(gppConstants.SectionUSPV1) {
  1043  			for _, sec := range gpp.Sections {
  1044  				if sec.GetID() == gppConstants.SectionUSPV1 {
  1045  					regs := *r.Regs
  1046  					regs.USPrivacy = sec.GetValue()
  1047  					r.Regs = &regs
  1048  				}
  1049  			}
  1050  		}
  1051  	}
  1052  
  1053  }
  1054  
  1055  func WrapJSONInData(data []byte) []byte {
  1056  	res := make([]byte, 0, len(data))
  1057  	res = append(res, []byte(`{"data":`)...)
  1058  	res = append(res, data...)
  1059  	res = append(res, []byte(`}`)...)
  1060  	return res
  1061  }
  1062  
  1063  func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
  1064  	mType := bid.MType
  1065  	var bidType openrtb_ext.BidType
  1066  	if mType > 0 {
  1067  		switch mType {
  1068  		case openrtb2.MarkupBanner:
  1069  			bidType = openrtb_ext.BidTypeBanner
  1070  		case openrtb2.MarkupVideo:
  1071  			bidType = openrtb_ext.BidTypeVideo
  1072  		case openrtb2.MarkupAudio:
  1073  			bidType = openrtb_ext.BidTypeAudio
  1074  		case openrtb2.MarkupNative:
  1075  			bidType = openrtb_ext.BidTypeNative
  1076  		default:
  1077  			return bidType, fmt.Errorf("Failed to parse bid mType for impression \"%s\"", bid.ImpID)
  1078  		}
  1079  	} else {
  1080  		var err error
  1081  		bidType, err = getPrebidMediaTypeForBid(bid)
  1082  		if err != nil {
  1083  			return bidType, err
  1084  		}
  1085  	}
  1086  	return bidType, nil
  1087  }
  1088  
  1089  func getPrebidMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
  1090  	var err error
  1091  	var bidType openrtb_ext.BidType
  1092  
  1093  	if bid.Ext != nil {
  1094  		var bidExt openrtb_ext.ExtBid
  1095  		err = jsonutil.Unmarshal(bid.Ext, &bidExt)
  1096  		if err == nil && bidExt.Prebid != nil {
  1097  			if bidType, err = openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)); err == nil {
  1098  				return bidType, nil
  1099  			}
  1100  		}
  1101  	}
  1102  
  1103  	errMsg := fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID)
  1104  	if err != nil {
  1105  		errMsg = fmt.Sprintf("%s, %s", errMsg, err.Error())
  1106  	}
  1107  
  1108  	return bidType, &errortypes.BadServerResponse{
  1109  		Message: errMsg,
  1110  	}
  1111  }
  1112  
  1113  func applyBidAdjustmentToFloor(allBidderRequests []BidderRequest, bidAdjustmentFactors map[string]float64) {
  1114  
  1115  	if len(bidAdjustmentFactors) == 0 {
  1116  		return
  1117  	}
  1118  
  1119  	for _, bidderRequest := range allBidderRequests {
  1120  		bidAdjustment := 1.0
  1121  
  1122  		if bidAdjustemntValue, ok := bidAdjustmentFactors[string(bidderRequest.BidderName)]; ok {
  1123  			bidAdjustment = bidAdjustemntValue
  1124  		}
  1125  
  1126  		if bidAdjustment != 1.0 {
  1127  			for index, imp := range bidderRequest.BidRequest.Imp {
  1128  				imp.BidFloor = imp.BidFloor / bidAdjustment
  1129  				bidderRequest.BidRequest.Imp[index] = imp
  1130  			}
  1131  		}
  1132  	}
  1133  }