Repository: prebid/prebid-server
Pull request #1957 (2021-08-11 19:54:04)

Interstitial behavior fix for issue 1923
@SyntaxNode I added the logic to the main validate function but seem to have a bug in the above validateImp function from referencing the struct. Do I need to make a type conversion on imp.instl paramter? Sorry new to structs and that argument seems to be the issue. Adding the test function too. Fix for issue -> #1923 

SyntaxNode: > @SyntaxNode I added the logic to the main validate function but seem to have a bug in the above validateImp function from referencing the struct. Do I need to make a type conversion on imp.instl paramter? 

Looks like you figured it out. Indeed, you are using the imp.Instl parameter correctly. No type conversion is required.


SyntaxNode: Looks good now, please add new json tests for this new use case. I recommend looking at which tests failed when you had the logic inverted and use one of those as a template.
mansinahar: Looks pretty straightforward to me other than the above comment. Thanks for helping with this @ChrisHuie 
ChrisHuie: fixing this today. 

Patch:
diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go
index 1878c41f..80c62df1 100644
--- a/adapters/rubicon/rubicon.go
+++ b/adapters/rubicon/rubicon.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"github.com/buger/jsonparser"
 	"io/ioutil"
 	"net/http"
 	"net/url"
@@ -30,7 +31,6 @@ type RubiconAdapter struct {
 	XAPIPassword string
 }
 
-// used for cookies and such
 func (a *RubiconAdapter) Name() string {
 	return "rubicon"
 }
@@ -73,16 +73,17 @@ type rubiconImpExtRPTrack struct {
 	MintVersion string `json:"mint_version"`
 }
 
+type rubiconImpExt struct {
+	RP   rubiconImpExtRP `json:"rp,omitempty"`
+	GPID string          `json:"gpid,omitempty"`
+}
+
 type rubiconImpExtRP struct {
 	ZoneID int                  `json:"zone_id"`
 	Target json.RawMessage      `json:"target,omitempty"`
 	Track  rubiconImpExtRPTrack `json:"track"`
 }
 
-type rubiconImpExt struct {
-	RP rubiconImpExtRP `json:"rp"`
-}
-
 type rubiconUserExtRP struct {
 	Target json.RawMessage `json:"target,omitempty"`
 }
@@ -102,6 +103,7 @@ type rubiconUserExt struct {
 	TpID        []rubiconExtUserTpID     `json:"tpid,omitempty"`
 	RP          rubiconUserExtRP         `json:"rp"`
 	LiverampIdl string                   `json:"liveramp_idl,omitempty"`
+	Data        json.RawMessage          `json:"data,omitempty"`
 }
 
 type rubiconSiteExtRP struct {
@@ -131,18 +133,6 @@ type rubiconBannerExt struct {
 	RP rubiconBannerExtRP `json:"rp"`
 }
 
-type ExtImpContextData struct {
-	AdSlot string `json:"adslot,omitempty"`
-}
-
-type ExtImpContext struct {
-	Data ExtImpContextData `json:"data,omitempty"`
-}
-
-type ExtImpWithContext struct {
-	Context ExtImpContext `json:"context,omitempty"` // First Party Data context
-}
-
 // ***** Video Extension *****
 type rubiconVideoParams struct {
 	Language     string `json:"language,omitempty"`
@@ -701,11 +691,10 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 	requestImpCopy := request.Imp
 
 	rubiconRequest := *request
-	for i := 0; i < numRequests; i++ {
-		thisImp := requestImpCopy[i]
+	for _, imp := range requestImpCopy {
 
 		var bidderExt adapters.ExtImpBidder
-		if err = json.Unmarshal(thisImp.Ext, &bidderExt); err != nil {
+		if err = json.Unmarshal(imp.Ext, &bidderExt); err != nil {
 			errs = append(errs, &errortypes.BadInput{
 				Message: err.Error(),
 			})
@@ -720,36 +709,15 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			continue
 		}
 
-		target := rubiconExt.Inventory
-		if rubiconExt.Inventory != nil {
-			rubiconExtInventory := make(map[string]interface{})
-			if err := json.Unmarshal(rubiconExt.Inventory, &rubiconExtInventory); err != nil {
-				errs = append(errs, &errortypes.BadInput{
-					Message: err.Error(),
-				})
-				continue
-			}
-
-			var extImpWithContext ExtImpWithContext
-			if err := json.Unmarshal(thisImp.Ext, &extImpWithContext); err != nil {
-				errs = append(errs, &errortypes.BadInput{
-					Message: err.Error(),
-				})
-				continue
-			}
-
-			// Copy imp[].ext.context.data.adslot is copied to imp[].ext.rp.target.dfp_ad_unit_code,
-			// but with any leading slash dropped
-			adSlot := extImpWithContext.Context.Data.AdSlot
-			if adSlot != "" {
-				rubiconExtInventory["dfp_ad_unit_code"] = strings.TrimLeft(adSlot, "/")
-
-				target, err = json.Marshal(&rubiconExtInventory)
-				if err != nil {
-					errs = append(errs, err)
-					continue
-				}
-			}
+		target, err := updateImpRpTargetWithFpdAttributes(rubiconExt, imp, request.Site, request.App)
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+		adSlot, err := getAdSlot(imp)
+		if err != nil {
+			errs = append(errs, err)
+			continue
 		}
 
 		impExt := rubiconImpExt{
@@ -758,35 +726,36 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 				Target: target,
 				Track:  rubiconImpExtRPTrack{Mint: "", MintVersion: ""},
 			},
+			GPID: adSlot,
 		}
-		thisImp.Ext, err = json.Marshal(&impExt)
+		imp.Ext, err = json.Marshal(&impExt)
 		if err != nil {
 			errs = append(errs, err)
 			continue
 		}
 
-		resolvedBidFloor, err := resolveBidFloor(thisImp.BidFloor, thisImp.BidFloorCur, reqInfo)
+		resolvedBidFloor, err := resolveBidFloor(imp.BidFloor, imp.BidFloorCur, reqInfo)
 		if err != nil {
 			errs = append(errs, &errortypes.BadInput{
 				Message: fmt.Sprintf("Unable to convert provided bid floor currency from %s to USD",
-					thisImp.BidFloorCur),
+					imp.BidFloorCur),
 			})
 			continue
 		}
 
 		if resolvedBidFloor > 0 {
-			thisImp.BidFloorCur = "USD"
-			thisImp.BidFloor = resolvedBidFloor
+			imp.BidFloorCur = "USD"
+			imp.BidFloor = resolvedBidFloor
 		}
 
 		if request.User != nil {
 			userCopy := *request.User
-
-			target, err := updateExtWithIabAttribute(rubiconExt.Visitor, userCopy.Data, []int{4})
+			target, err := updateUserRpTargetWithFpdAttributes(rubiconExt.Visitor, userCopy)
 			if err != nil {
 				errs = append(errs, err)
 				continue
 			}
+
 			userExtRP := rubiconUserExt{RP: rubiconUserExtRP{Target: target}}
 
 			if request.User.Ext != nil {
@@ -822,6 +791,10 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 				errs = append(errs, err)
 				continue
 			}
+			userCopy.Geo = nil
+			userCopy.Yob = 0
+			userCopy.Gender = ""
+
 			rubiconRequest.User = &userCopy
 		}
 
@@ -832,13 +805,13 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			rubiconRequest.Device = &deviceCopy
 		}
 
-		isVideo := isVideo(thisImp)
+		isVideo := isVideo(imp)
 		if isVideo {
-			videoCopy := *thisImp.Video
+			videoCopy := *imp.Video
 
 			videoSizeId := rubiconExt.Video.VideoSizeID
 			if videoSizeId == 0 {
-				resolvedSizeId, err := resolveVideoSizeId(thisImp.Video.Placement, thisImp.Instl, thisImp.ID)
+				resolvedSizeId, err := resolveVideoSizeId(imp.Video.Placement, imp.Instl, imp.ID)
 				if err != nil {
 					errs = append(errs, err)
 					continue
@@ -853,23 +826,23 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			}
 			videoExt := rubiconVideoExt{Skip: rubiconExt.Video.Skip, SkipDelay: rubiconExt.Video.SkipDelay, VideoType: videoType, RP: rubiconVideoExtRP{SizeID: videoSizeId}}
 			videoCopy.Ext, err = json.Marshal(&videoExt)
-			thisImp.Video = &videoCopy
-			thisImp.Banner = nil
+			imp.Video = &videoCopy
+			imp.Banner = nil
 		} else {
-			primarySizeID, altSizeIDs, err := parseRubiconSizes(thisImp.Banner.Format)
+			primarySizeID, altSizeIDs, err := parseRubiconSizes(imp.Banner.Format)
 			if err != nil {
 				errs = append(errs, err)
 				continue
 			}
 			bannerExt := rubiconBannerExt{RP: rubiconBannerExtRP{SizeID: primarySizeID, AltSizeIDs: altSizeIDs, MIME: "text/html"}}
-			bannerCopy := *thisImp.Banner
+			bannerCopy := *imp.Banner
 			bannerCopy.Ext, err = json.Marshal(&bannerExt)
 			if err != nil {
 				errs = append(errs, err)
 				continue
 			}
-			thisImp.Banner = &bannerCopy
-			thisImp.Video = nil
+			imp.Banner = &bannerCopy
+			imp.Video = nil
 		}
 
 		pubExt := rubiconPubExt{RP: rubiconPubExtRP{AccountID: rubiconExt.AccountId}}
@@ -878,12 +851,16 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			siteCopy := *request.Site
 			siteExtRP := rubiconSiteExt{RP: rubiconSiteExtRP{SiteID: rubiconExt.SiteId}}
 			if siteCopy.Content != nil {
-				target, err := updateExtWithIabAttribute(nil, siteCopy.Content.Data, []int{1, 2})
-				if err != nil {
-					errs = append(errs, err)
-					continue
+				siteTarget := make(map[string]interface{})
+				updateExtWithIabAttribute(siteTarget, siteCopy.Content.Data, []int{1, 2, 5, 6})
+				if len(siteTarget) > 0 {
+					updatedSiteTarget, err := json.Marshal(siteTarget)
+					if err != nil {
+						errs = append(errs, err)
+						continue
+					}
+					siteExtRP.RP.Target = updatedSiteTarget
 				}
-				siteExtRP.RP.Target = target
 			}
 
 			siteCopy.Ext, err = json.Marshal(&siteExtRP)
@@ -910,7 +887,7 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			}
 		}
 
-		rubiconRequest.Imp = []openrtb2.Imp{thisImp}
+		rubiconRequest.Imp = []openrtb2.Imp{imp}
 		rubiconRequest.Cur = nil
 		rubiconRequest.Ext = nil
 
@@ -941,27 +918,272 @@ func resolveBidFloor(bidFloor float64, bidFloorCur string, reqInfo *adapters.Ext
 	return bidFloor, nil
 }
 
-func updateExtWithIabAttribute(target json.RawMessage, data []openrtb2.Data, segTaxes []int) (json.RawMessage, error) {
+func updateImpRpTargetWithFpdAttributes(extImp openrtb_ext.ExtImpRubicon, imp openrtb2.Imp,
+	site *openrtb2.Site, app *openrtb2.App) (json.RawMessage, error) {
+	existingTarget, _, _, err := jsonparser.Get(imp.Ext, "rp", "target")
+	if isNotKeyPathError(err) {
+		return nil, err
+	}
+	target, err := rawJSONToMap(existingTarget)
+	if err != nil {
+		return nil, err
+	}
+	err = populateFirstPartyDataAttributes(extImp.Inventory, target)
+	if err != nil {
+		return nil, err
+	}
+
+	if site != nil {
+		siteExtData, _, _, err := jsonparser.Get(site.Ext, "data")
+		if isNotKeyPathError(err) {
+			return nil, err
+		}
+		err = populateFirstPartyDataAttributes(siteExtData, target)
+		if err != nil {
+			return nil, err
+		}
+		if len(site.SectionCat) > 0 {
+			addStringArrayAttribute(site.SectionCat, target, "sectioncat")
+		}
+		if len(site.PageCat) > 0 {
+			addStringArrayAttribute(site.PageCat, target, "pagecat")
+		}
+		if site.Page != "" {
+			addStringAttribute(site.Page, target, "page")
+		}
+		if site.Ref != "" {
+			addStringAttribute(site.Ref, target, "ref")
+		}
+		if site.Search != "" {
+			addStringAttribute(site.Search, target, "search")
+		}
+	} else {
+		appExtData, _, _, err := jsonparser.Get(app.Ext, "data")
+		if isNotKeyPathError(err) {
+			return nil, err
+		}
+		err = populateFirstPartyDataAttributes(appExtData, target)
+		if err != nil {
+			return nil, err
+		}
+		if len(app.SectionCat) > 0 {
+			addStringArrayAttribute(app.SectionCat, target, "sectioncat")
+		}
+		if len(app.PageCat) > 0 {
+			addStringArrayAttribute(app.PageCat, target, "pagecat")
+		}
+	}
+
+	impExtContextAttributes, _, _, err := jsonparser.Get(imp.Ext, "context", "data")
+	if isNotKeyPathError(err) {
+		return nil, err
+	}
+
+	if len(impExtContextAttributes) > 0 {
+		err = populateFirstPartyDataAttributes(impExtContextAttributes, target)
+		if err != nil {
+			return nil, err
+		}
+	} else if impExtDataAttributes, _, _, err := jsonparser.Get(imp.Ext, "data"); err == nil && len(impExtDataAttributes) > 0 {
+		err = populateFirstPartyDataAttributes(impExtDataAttributes, target)
+		if err != nil {
+			return nil, err
+		}
+	}
+	if isNotKeyPathError(err) {
+		return nil, err
+	}
+
+	if len(extImp.Keywords) > 0 {
+		addStringArrayAttribute(extImp.Keywords, target, "keywords")
+	}
+	updatedTarget, err := json.Marshal(target)
+	if err != nil {
+		return nil, err
+	}
+	return updatedTarget, nil
+}
+
+func isNotKeyPathError(err error) bool {
+	return err != nil && err != jsonparser.KeyPathNotFoundError
+}
+
+func addStringAttribute(attribute string, target map[string]interface{}, attributeName string) {
+	target[attributeName] = [1]string{attribute}
+}
+
+func addStringArrayAttribute(attribute []string, target map[string]interface{}, attributeName string) {
+	target[attributeName] = attribute
+}
+
+func getAdSlot(imp openrtb2.Imp) (string, error) {
+	var adSlot string
+	var parsingError error
+	jsonparser.EachKey(imp.Ext, func(idx int, value []byte, vt jsonparser.ValueType, err error) {
+		switch idx {
+		case 0:
+			adServerContextName, err := jsonparser.GetString(value, "name")
+			if isNotKeyPathError(err) {
+				parsingError = err
+				return
+			}
+			if adServerContextName == "gam" {
+				contextAdSlot, err := jsonparser.GetString(value, "adslot")
+				if isNotKeyPathError(err) {
+					parsingError = err
+					return
+				}
+				adSlot = contextAdSlot
+			}
+		}
+	}, []string{"context", "data", "adserver"})
+
+	if parsingError != nil {
+		return "", parsingError
+	}
+
+	if adSlot != "" {
+		return adSlot, nil
+	}
+
+	jsonparser.EachKey(imp.Ext, func(idx int, value []byte, vt jsonparser.ValueType, err error) {
+		switch idx {
+		case 0:
+			adServerDataName, err := jsonparser.GetString(value, "name")
+			if isNotKeyPathError(err) {
+				parsingError = err
+				return
+			}
+			if adServerDataName == "gam" {
+				dataAdSlot, err := jsonparser.GetString(value, "adslot")
+				if isNotKeyPathError(err) {
+					parsingError = err
+					return
+				}
+				adSlot = dataAdSlot
+			}
+		}
+	}, []string{"data", "adserver"})
+
+	if parsingError != nil {
+		return "", parsingError
+	}
+
+	return adSlot, nil
+}
+
+func updateUserRpTargetWithFpdAttributes(visitor json.RawMessage, user openrtb2.User) (json.RawMessage, error) {
+	existingTarget, _, _, err := jsonparser.Get(user.Ext, "rp", "target")
+	if isNotKeyPathError(err) {
+		return nil, err
+	}
+	target, err := rawJSONToMap(existingTarget)
+	if err != nil {
+		return nil, err
+	}
+	err = populateFirstPartyDataAttributes(visitor, target)
+	if err != nil {
+		return nil, err
+	}
+	userExtData, _, _, err := jsonparser.Get(user.Ext, "data")
+	if isNotKeyPathError(err) {
+		return nil, err
+	}
+	err = populateFirstPartyDataAttributes(userExtData, target)
+	if err != nil {
+		return nil, err
+	}
+	updateExtWithIabAttribute(target, user.Data, []int{4})
+
+	updatedTarget, err := json.Marshal(target)
+	if err != nil {
+		return nil, err
+	}
+	return updatedTarget, nil
+}
+
+func updateExtWithIabAttribute(target map[string]interface{}, data []openrtb2.Data, segTaxes []int) {
 	var segmentIdsToCopy = getSegmentIdsToCopy(data, segTaxes)
 	if len(segmentIdsToCopy) == 0 {
-		return target, nil
+		return
+	}
+
+	target["iab"] = segmentIdsToCopy
+}
+
+func populateFirstPartyDataAttributes(source json.RawMessage, target map[string]interface{}) error {
+	sourceAsMap, err := rawJSONToMap(source)
+	if err != nil {
+		return err
+	}
+
+	for key, val := range sourceAsMap {
+		switch typedValue := val.(type) {
+		case string:
+			target[key] = [1]string{typedValue}
+		case float64:
+			if typedValue == float64(int(typedValue)) {
+				target[key] = [1]string{strconv.Itoa(int(typedValue))}
+			}
+		case bool:
+			target[key] = [1]string{strconv.FormatBool(typedValue)}
+		case []interface{}:
+			if isStringArray(typedValue) {
+				target[key] = typedValue
+			}
+			if isBoolArray(typedValue) {
+				target[key] = convertToStringArray(typedValue)
+			}
+		}
+	}
+	return nil
+}
+
+func isStringArray(array []interface{}) bool {
+	for _, val := range array {
+		if _, ok := val.(string); !ok {
+			return false
+		}
+	}
+
+	return true
+}
+
+func isBoolArray(array []interface{}) bool {
+	for _, val := range array {
+		if _, ok := val.(bool); !ok {
+			return false
+		}
 	}
 
-	extRPTarget := make(map[string]interface{})
+	return true
+}
 
-	if target != nil {
-		if err := json.Unmarshal(target, &extRPTarget); err != nil {
-			return nil, &errortypes.BadInput{Message: err.Error()}
+func convertToStringArray(arr []interface{}) []string {
+	var stringArray []string
+	for _, val := range arr {
+		if boolVal, ok := val.(bool); ok {
+			stringArray = append(stringArray, strconv.FormatBool(boolVal))
 		}
 	}
 
-	extRPTarget["iab"] = segmentIdsToCopy
+	return stringArray
+}
+
+func rawJSONToMap(message json.RawMessage) (map[string]interface{}, error) {
+	if message == nil {
+		return make(map[string]interface{}), nil
+	}
 
-	jsonTarget, err := json.Marshal(&extRPTarget)
+	return mapFromRawJSON(message)
+}
+func mapFromRawJSON(message json.RawMessage) (map[string]interface{}, error) {
+	targetAsMap := make(map[string]interface{})
+	err := json.Unmarshal(message, &targetAsMap)
 	if err != nil {
-		return nil, &errortypes.BadInput{Message: err.Error()}
+		return nil, err
 	}
-	return jsonTarget, nil
+	return targetAsMap, nil
 }
 
 func getSegmentIdsToCopy(data []openrtb2.Data, segTaxValues []int) []string {
diff --git a/adapters/yssp/yssp.go b/adapters/yahoossp/yahoossp.go
similarity index 93%
rename from adapters/yssp/yssp.go
rename to adapters/yahoossp/yahoossp.go
index a73398ca..652d57f9 100644
--- a/adapters/yssp/yssp.go
+++ b/adapters/yahoossp/yahoossp.go
@@ -1,4 +1,4 @@
-package yssp
+package yahoossp
 
 import (
 	"encoding/json"
@@ -41,8 +41,8 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 			continue
 		}
 
-		var ysspExt openrtb_ext.ExtImpYSSP
-		err = json.Unmarshal(bidderExt.Bidder, &ysspExt)
+		var yahoosspExt openrtb_ext.ExtImpYahooSSP
+		err = json.Unmarshal(bidderExt.Bidder, &yahoosspExt)
 		if err != nil {
 			err = &errortypes.BadInput{
 				Message: fmt.Sprintf("imp #%d: %s", idx, err.Error()),
@@ -64,7 +64,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E
 			reqCopy.App = &appCopy
 		}
 
-		if err := changeRequestForBidService(&reqCopy, &ysspExt); err != nil {
+		if err := changeRequestForBidService(&reqCopy, &yahoosspExt); err != nil {
 			errors = append(errors, err)
 			continue
 		}
@@ -147,7 +147,7 @@ func getImpInfo(impId string, imps []openrtb2.Imp) (bool, openrtb_ext.BidType) {
 	return exists, mediaType
 }
 
-func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb_ext.ExtImpYSSP) error {
+func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb_ext.ExtImpYahooSSP) error {
 	/* Always override the tag ID and (site ID or app ID) of the request */
 	request.Imp[0].TagID = extension.Pos
 	if request.Site != nil {
@@ -180,7 +180,7 @@ func changeRequestForBidService(request *openrtb2.BidRequest, extension *openrtb
 	return nil
 }
 
-// Builder builds a new instance of the YSSP adapter for the given bidder with the given config.
+// Builder builds a new instance of the YahooSSP adapter for the given bidder with the given config.
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
 	bidder := &adapter{
 		URI: config.Endpoint,
diff --git a/adapters/yieldlab/yieldlab.go b/adapters/yieldlab/yieldlab.go
index ee9170c2..66f12c8b 100644
--- a/adapters/yieldlab/yieldlab.go
+++ b/adapters/yieldlab/yieldlab.go
@@ -212,7 +212,15 @@ func (a *YieldlabAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa
 		Bids:     []*adapters.TypedBid{},
 	}
 
-	for i, bid := range bids {
+	adslotToImpMap := make(map[string]*openrtb2.Imp)
+	for i := 0; i < len(internalRequest.Imp); i++ {
+		adslotID := a.extractAdslotID(internalRequest.Imp[i])
+		if internalRequest.Imp[i].Video != nil || internalRequest.Imp[i].Banner != nil {
+			adslotToImpMap[adslotID] = &internalRequest.Imp[i]
+		}
+	}
+
+	for _, bid := range bids {
 		width, height, err := splitSize(bid.Adsize)
 		if err != nil {
 			return nil, []error{err}
@@ -225,33 +233,37 @@ func (a *YieldlabAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa
 			}
 		}
 
-		var bidType openrtb_ext.BidType
-		responseBid := &openrtb2.Bid{
-			ID:     strconv.FormatUint(bid.ID, 10),
-			Price:  float64(bid.Price) / 100,
-			ImpID:  internalRequest.Imp[i].ID,
-			CrID:   a.makeCreativeID(req, bid),
-			DealID: strconv.FormatUint(bid.Pid, 10),
-			W:      int64(width),
-			H:      int64(height),
-		}
+		if imp, exists := adslotToImpMap[strconv.FormatUint(bid.ID, 10)]; !exists {
+			continue
+		} else {
+			var bidType openrtb_ext.BidType
+			responseBid := &openrtb2.Bid{
+				ID:     strconv.FormatUint(bid.ID, 10),
+				Price:  float64(bid.Price) / 100,
+				ImpID:  imp.ID,
+				CrID:   a.makeCreativeID(req, bid),
+				DealID: strconv.FormatUint(bid.Pid, 10),
+				W:      int64(width),
+				H:      int64(height),
+			}
 
-		if internalRequest.Imp[i].Video != nil {
-			bidType = openrtb_ext.BidTypeVideo
-			responseBid.NURL = a.makeAdSourceURL(internalRequest, req, bid)
+			if imp.Video != nil {
+				bidType = openrtb_ext.BidTypeVideo
+				responseBid.NURL = a.makeAdSourceURL(internalRequest, req, bid)
 
-		} else if internalRequest.Imp[i].Banner != nil {
-			bidType = openrtb_ext.BidTypeBanner
-			responseBid.AdM = a.makeBannerAdSource(internalRequest, req, bid)
-		} else {
-			// Yieldlab adapter currently doesn't support Audio and Native ads
-			continue
-		}
+			} else if imp.Banner != nil {
+				bidType = openrtb_ext.BidTypeBanner
+				responseBid.AdM = a.makeBannerAdSource(internalRequest, req, bid)
+			} else {
+				// Yieldlab adapter currently doesn't support Audio and Native ads
+				continue
+			}
 
-		bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
-			BidType: bidType,
-			Bid:     responseBid,
-		})
+			bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
+				BidType: bidType,
+				Bid:     responseBid,
+			})
+		}
 	}
 
 	return bidderResponse, nil
@@ -259,6 +271,7 @@ func (a *YieldlabAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa
 
 func (a *YieldlabAdapter) findBidReq(adslotID uint64, params []*openrtb_ext.ExtImpYieldlab) *openrtb_ext.ExtImpYieldlab {
 	slotIdStr := strconv.FormatUint(adslotID, 10)
+
 	for _, p := range params {
 		if p.AdslotID == slotIdStr {
 			return p
@@ -268,6 +281,14 @@ func (a *YieldlabAdapter) findBidReq(adslotID uint64, params []*openrtb_ext.ExtI
 	return nil
 }
 
+func (a *YieldlabAdapter) extractAdslotID(internalRequestImp openrtb2.Imp) string {
+	bidderExt := new(adapters.ExtImpBidder)
+	json.Unmarshal(internalRequestImp.Ext, bidderExt)
+	yieldlabExt := new(openrtb_ext.ExtImpYieldlab)
+	json.Unmarshal(bidderExt.Bidder, yieldlabExt)
+	return yieldlabExt.AdslotID
+}
+
 func (a *YieldlabAdapter) makeBannerAdSource(req *openrtb2.BidRequest, ext *openrtb_ext.ExtImpYieldlab, res *bidResponse) string {
 	return fmt.Sprintf(adSourceBanner, a.makeAdSourceURL(req, ext, res))
 }
diff --git a/config/config.go b/config/config.go
index f6f6f187..75203b9f 100644
--- a/config/config.go
+++ b/config/config.go
@@ -511,9 +511,9 @@ func New(v *viper.Viper) (*Configuration, error) {
 		c.GDPR.NonStandardPublisherMap[c.GDPR.NonStandardPublishers[i]] = s
 	}
 
-	c.GDPR.EEACountriesMap = make(map[string]struct{})
-	for i := 0; i < len(c.GDPR.EEACountriesMap); i++ {
-		c.GDPR.NonStandardPublisherMap[c.GDPR.EEACountries[i]] = s
+	c.GDPR.EEACountriesMap = make(map[string]struct{}, len(c.GDPR.EEACountries))
+	for _, v := range c.GDPR.EEACountries {
+		c.GDPR.EEACountriesMap[v] = s
 	}
 
 	// To look for a purpose's vendor exceptions in O(1) time, for each purpose we fill this hash table located in the
@@ -869,6 +869,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.viewdeos.endpoint", "http://ghb.sync.viewdeos.com/pbs/ortb")
 	v.SetDefault("adapters.visx.endpoint", "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard:0.1.0")
 	v.SetDefault("adapters.vrtcal.endpoint", "http://rtb.vrtcal.com/bidder_prebid.vap?ssp=1804")
+	v.SetDefault("adapters.yahoossp.disabled", true)
 	v.SetDefault("adapters.yeahmobi.endpoint", "https://{{.Host}}/prebid/bid")
 	v.SetDefault("adapters.yieldlab.endpoint", "https://ad.yieldlab.net/yp/")
 	v.SetDefault("adapters.yieldmo.endpoint", "https://ads.yieldmo.com/exchange/prebid-server")
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 579d6687..44b05f40 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -548,7 +548,7 @@ func (deps *endpointDeps) validateImp(imp *openrtb2.Imp, aliases map[string]stri
 		return []error{fmt.Errorf("request.imp[%d] must contain at least one of \"banner\", \"video\", \"audio\", or \"native\"", index)}
 	}
 
-	if err := validateBanner(imp.Banner, index); err != nil {
+	if err := validateBanner(imp.Banner, index, isInterstitial(imp)); err != nil {
 		return []error{err}
 	}
 
@@ -576,7 +576,11 @@ func (deps *endpointDeps) validateImp(imp *openrtb2.Imp, aliases map[string]stri
 	return nil
 }
 
-func validateBanner(banner *openrtb2.Banner, impIndex int) error {
+func isInterstitial(imp *openrtb2.Imp) bool {
+	return imp.Instl == 1
+}
+
+func validateBanner(banner *openrtb2.Banner, impIndex int, isInterstitial bool) error {
 	if banner == nil {
 		return nil
 	}
@@ -606,7 +610,7 @@ func validateBanner(banner *openrtb2.Banner, impIndex int) error {
 	}
 
 	hasRootSize := banner.H != nil && banner.W != nil && *banner.H > 0 && *banner.W > 0
-	if !hasRootSize && len(banner.Format) == 0 {
+	if !hasRootSize && len(banner.Format) == 0 && !isInterstitial {
 		return fmt.Errorf("request.imp[%d].banner has no sizes. Define \"w\" and \"h\", or include \"format\" elements.", impIndex)
 	}
 
diff --git a/endpoints/openrtb2/sample-requests/invalid-whole/banner-no-size.json b/endpoints/openrtb2/sample-requests/invalid-whole/banner-no-size.json
new file mode 100644
index 00000000..555fba70
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/invalid-whole/banner-no-size.json
@@ -0,0 +1,24 @@
+{
+    "description": "Banner Ad Without Sizes Defined",
+    "mockBidRequest": {
+        "id": "some-request-id",
+        "site": {
+            "page": "test.somepage.com"
+        },
+        "imp": [{
+            "id": "some-imp-id",
+            "banner": {},
+            "ext": {
+                "prebid": {
+                    "bidder": {
+                        "appnexus": {
+                            "placementId": 12883451
+                        }
+                    }
+                }
+            }
+        }]
+    },
+    "expectedErrorMessage": "Invalid request: request.imp[0].banner has no sizes. Define \"w\" and \"h\", or include \"format\" elements.",
+    "expectedReturnCode": 400
+}
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/exemplary/interstitial-no-size.json b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/interstitial-no-size.json
new file mode 100644
index 00000000..6100769a
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/exemplary/interstitial-no-size.json
@@ -0,0 +1,38 @@
+{
+    "description": "Interstitial Banner Ad Without Sizes Defined",
+    "mockBidRequest": {
+        "id": "some-request-id",
+        "site": {
+            "page": "test.somepage.com"
+        },
+        "imp": [{
+            "id": "some-imp-id",
+            "instl": 1,
+            "banner": {},
+            "ext": {
+                "prebid": {
+                    "bidder": {
+                        "appnexus": {
+                            "placementId": 12883451
+                        }
+                    }
+                }
+            }
+        }]
+    },
+    "expectedBidResponse": {
+        "id": "some-request-id",
+        "seatbid": [{
+            "bid": [{
+                "id": "appnexus-bid",
+                "impid": "",
+                "price": 0
+            }],
+            "seat": "appnexus-bids"
+        }],
+        "bidid": "test bid id",
+        "cur": "USD",
+        "nbr": 0
+    },
+    "expectedReturnCode": 200
+}
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 630f18b6..c796df06 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -120,11 +120,11 @@ import (
 	"github.com/prebid/prebid-server/adapters/valueimpression"
 	"github.com/prebid/prebid-server/adapters/visx"
 	"github.com/prebid/prebid-server/adapters/vrtcal"
+	"github.com/prebid/prebid-server/adapters/yahoossp"
 	"github.com/prebid/prebid-server/adapters/yeahmobi"
 	"github.com/prebid/prebid-server/adapters/yieldlab"
 	"github.com/prebid/prebid-server/adapters/yieldmo"
 	"github.com/prebid/prebid-server/adapters/yieldone"
-	"github.com/prebid/prebid-server/adapters/yssp"
 	"github.com/prebid/prebid-server/adapters/zeroclickfraud"
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
@@ -252,15 +252,16 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderUnicorn:           unicorn.Builder,
 		openrtb_ext.BidderUnruly:            unruly.Builder,
 		openrtb_ext.BidderValueImpression:   valueimpression.Builder,
-		openrtb_ext.BidderVerizonMedia:      yssp.Builder,
+		openrtb_ext.BidderVerizonMedia:      yahoossp.Builder,
 		openrtb_ext.BidderViewdeos:          adtelligent.Builder,
 		openrtb_ext.BidderVisx:              visx.Builder,
 		openrtb_ext.BidderVrtcal:            vrtcal.Builder,
+		openrtb_ext.BidderYahooSSP:          yahoossp.Builder,
 		openrtb_ext.BidderYeahmobi:          yeahmobi.Builder,
 		openrtb_ext.BidderYieldlab:          yieldlab.Builder,
 		openrtb_ext.BidderYieldmo:           yieldmo.Builder,
 		openrtb_ext.BidderYieldone:          yieldone.Builder,
-		openrtb_ext.BidderYSSP:              yssp.Builder,
+		openrtb_ext.BidderYSSP:              yahoossp.Builder,
 		openrtb_ext.BidderZeroClickFraud:    zeroclickfraud.Builder,
 	}
 }
diff --git a/exchange/bidder.go b/exchange/bidder.go
index 28be854c..0bdaa648 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -180,24 +180,20 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, request *openrtb2.B
 		// If this is a test bid, capture debugging info from the requests.
 		// Write debug data to ext in case if:
 		// - headerDebugAllowed (debug override header specified correct) - it overrides all other debug restrictions
-		// - debugContextKey (url param) in true
 		// - account debug is allowed
 		// - bidder debug is allowed
 		if headerDebugAllowed {
 			seatBid.httpCalls = append(seatBid.httpCalls, makeExt(httpInfo))
 		} else {
-			debugInfo := ctx.Value(DebugContextKey)
-			if debugInfo != nil && debugInfo.(bool) {
-				if accountDebugAllowed {
-					if bidder.config.DebugInfo.Allow {
-						seatBid.httpCalls = append(seatBid.httpCalls, makeExt(httpInfo))
-					} else {
-						debugDisabledWarning := errortypes.Warning{
-							WarningCode: errortypes.BidderLevelDebugDisabledWarningCode,
-							Message:     "debug turned off for bidder",
-						}
-						errs = append(errs, &debugDisabledWarning)
+			if accountDebugAllowed {
+				if bidder.config.DebugInfo.Allow {
+					seatBid.httpCalls = append(seatBid.httpCalls, makeExt(httpInfo))
+				} else {
+					debugDisabledWarning := errortypes.Warning{
+						WarningCode: errortypes.BidderLevelDebugDisabledWarningCode,
+						Message:     "debug turned off for bidder",
 					}
+					errs = append(errs, &debugDisabledWarning)
 				}
 			}
 		}
diff --git a/exchange/exchange.go b/exchange/exchange.go
index f6ec713f..8b4b49e7 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -32,10 +32,6 @@ import (
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 )
 
-type ContextKey string
-
-const DebugContextKey = ContextKey("debugInfo")
-
 type extCacheInstructions struct {
 	cacheBids, cacheVAST, returnCreative bool
 }
@@ -188,18 +184,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 		_, targData.cacheHost, targData.cachePath = e.cache.GetExtCacheData()
 	}
 
-	if debugLog == nil {
-		debugLog = &DebugLog{Enabled: false, DebugEnabledOrOverridden: false}
-	}
-
-	requestDebugInfo := getDebugInfo(r.BidRequest, requestExt)
-
-	debugInfo := debugLog.DebugEnabledOrOverridden || (requestDebugInfo && r.Account.DebugAllow)
-	debugLog.Enabled = debugLog.DebugEnabledOrOverridden || r.Account.DebugAllow
-
-	if debugInfo {
-		ctx = e.makeDebugContext(ctx, debugInfo)
-	}
+	responseDebugAllow, accountDebugAllow, debugLog := getDebugInfo(r.BidRequest, requestExt, r.Account.DebugAllow, debugLog)
 
 	bidAdjustmentFactors := getExtBidAdjustmentFactors(requestExt)
 
@@ -224,7 +209,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 	// Get currency rates conversions for the auction
 	conversions := e.getAuctionCurrencyRates(requestExt.Prebid.CurrencyConversions)
 
-	adapterBids, adapterExtra, anyBidsReturned := e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, r.Account.DebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride)
+	adapterBids, adapterExtra, anyBidsReturned := e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, accountDebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride)
 
 	var auc *auction
 	var cacheErrs []error
@@ -268,7 +253,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 				errs = append(errs, dealErrs...)
 			}
 
-			bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, r, debugInfo, errs)
+			bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, r, responseDebugAllow, errs)
 			if debugLog.DebugEnabledOrOverridden {
 				if bidRespExtBytes, err := json.Marshal(bidResponseExt); err == nil {
 					debugLog.Data.Response = string(bidRespExtBytes)
@@ -286,9 +271,9 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 			targData.setTargeting(auc, r.BidRequest.App != nil, bidCategory)
 
 		}
-		bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, r, debugInfo, errs)
+		bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, r, responseDebugAllow, errs)
 	} else {
-		bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, r, debugInfo, errs)
+		bidResponseExt = e.makeExtBidResponse(adapterBids, adapterExtra, r, responseDebugAllow, errs)
 
 		if debugLog.DebugEnabledOrOverridden {
 
@@ -301,7 +286,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 		}
 	}
 
-	if !r.Account.DebugAllow && requestDebugInfo && !debugLog.DebugOverride {
+	if !accountDebugAllow && !debugLog.DebugOverride {
 		accountDebugDisabledWarning := openrtb_ext.ExtBidderMessage{
 			Code:    errortypes.AccountLevelDebugDisabledWarningCode,
 			Message: "debug turned off for account",
@@ -411,11 +396,6 @@ func updateHbPbCatDur(bid *pbsOrtbBid, dealTier openrtb_ext.DealTier, bidCategor
 	}
 }
 
-func (e *exchange) makeDebugContext(ctx context.Context, debugInfo bool) (debugCtx context.Context) {
-	debugCtx = context.WithValue(ctx, DebugContextKey, debugInfo)
-	return
-}
-
 func (e *exchange) makeAuctionContext(ctx context.Context, needsCache bool) (auctionCtx context.Context, cancel context.CancelFunc) {
 	auctionCtx = ctx
 	cancel = func() {}
diff --git a/exchange/utils.go b/exchange/utils.go
index 1277cffd..59cc7f1e 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -690,7 +690,30 @@ func getExtTargetData(requestExt *openrtb_ext.ExtRequest, cacheInstructions *ext
 	return targData
 }
 
-func getDebugInfo(bidRequest *openrtb2.BidRequest, requestExt *openrtb_ext.ExtRequest) bool {
+// getDebugInfo returns the boolean flags that allow for debug information in bidResponse.Ext, the SeatBid.httpcalls slice, and
+// also sets the debugLog information
+func getDebugInfo(bidRequest *openrtb2.BidRequest, requestExt *openrtb_ext.ExtRequest, accountDebugFlag bool, debugLog *DebugLog) (bool, bool, *DebugLog) {
+	requestDebugAllow := parseRequestDebugValues(bidRequest, requestExt)
+	debugLog = setDebugLogValues(accountDebugFlag, debugLog)
+
+	responseDebugAllow := (requestDebugAllow && accountDebugFlag) || debugLog.DebugEnabledOrOverridden
+	accountDebugAllow := (requestDebugAllow && accountDebugFlag) || (debugLog.DebugEnabledOrOverridden && accountDebugFlag)
+
+	return responseDebugAllow, accountDebugAllow, debugLog
+}
+
+// setDebugLogValues initializes the DebugLog if nil. It also sets the value of the debugInfo flag
+// used in HoldAuction
+func setDebugLogValues(accountDebugFlag bool, debugLog *DebugLog) *DebugLog {
+	if debugLog == nil {
+		debugLog = &DebugLog{}
+	}
+
+	debugLog.Enabled = debugLog.DebugEnabledOrOverridden || accountDebugFlag
+	return debugLog
+}
+
+func parseRequestDebugValues(bidRequest *openrtb2.BidRequest, requestExt *openrtb_ext.ExtRequest) bool {
 	return (bidRequest != nil && bidRequest.Test == 1) || (requestExt != nil && requestExt.Prebid.Debug)
 }
 
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 88f816c2..69ed1f42 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -195,6 +195,7 @@ const (
 	BidderVisx              BidderName = "visx"
 	BidderViewdeos          BidderName = "viewdeos"
 	BidderVrtcal            BidderName = "vrtcal"
+	BidderYahooSSP          BidderName = "yahoossp"
 	BidderYeahmobi          BidderName = "yeahmobi"
 	BidderYieldlab          BidderName = "yieldlab"
 	BidderYieldmo           BidderName = "yieldmo"
@@ -328,6 +329,7 @@ func CoreBidderNames() []BidderName {
 		BidderViewdeos,
 		BidderVisx,
 		BidderVrtcal,
+		BidderYahooSSP,
 		BidderYeahmobi,
 		BidderYieldlab,
 		BidderYieldmo,
diff --git a/openrtb_ext/imp_rubicon.go b/openrtb_ext/imp_rubicon.go
index ee43d965..f9b15ed3 100644
--- a/openrtb_ext/imp_rubicon.go
+++ b/openrtb_ext/imp_rubicon.go
@@ -10,6 +10,7 @@ type ExtImpRubicon struct {
 	SiteId    int                `json:"siteId"`
 	ZoneId    int                `json:"zoneId"`
 	Inventory json.RawMessage    `json:"inventory,omitempty"`
+	Keywords  []string           `json:"keywords,omitempty"`
 	Visitor   json.RawMessage    `json:"visitor,omitempty"`
 	Video     rubiconVideoParams `json:"video"`
 	Debug     impExtRubiconDebug `json:"debug,omitempty"`
diff --git a/openrtb_ext/imp_yahoossp.go b/openrtb_ext/imp_yahoossp.go
new file mode 100644
index 00000000..e3183c86
--- /dev/null
+++ b/openrtb_ext/imp_yahoossp.go
@@ -0,0 +1,7 @@
+package openrtb_ext
+
+// ExtImpYahooSSP defines the contract for bidrequest.imp[i].ext.yahoossp
+type ExtImpYahooSSP struct {
+	Dcn string `json:"dcn"`
+	Pos string `json:"pos"`
+}
diff --git a/openrtb_ext/imp_yssp.go b/openrtb_ext/imp_yssp.go
deleted file mode 100644
index 054836ec..00000000
--- a/openrtb_ext/imp_yssp.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package openrtb_ext
-
-// ExtImpYSSP defines the contract for bidrequest.imp[i].ext.yssp
-type ExtImpYSSP struct {
-	Dcn string `json:"dcn"`
-	Pos string `json:"pos"`
-}
diff --git a/static/bidder-info/yahoossp.yaml b/static/bidder-info/yahoossp.yaml
new file mode 100644
index 00000000..06d0cb18
--- /dev/null
+++ b/static/bidder-info/yahoossp.yaml
@@ -0,0 +1,15 @@
+maintainer:
+  email: "hb-fe-tech@oath.com"
+gvlVendorID: 25
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+  site:
+    mediaTypes:
+      - banner
+userSync:
+  # yahoossp supports user syncing, but requires configuration by the host. contact this
+  # bidder directly at the email address in this file to ask about enabling user sync.
+  supports:
+    - redirect
\ No newline at end of file
diff --git a/static/bidder-params/yahoossp.json b/static/bidder-params/yahoossp.json
new file mode 100644
index 00000000..9d971149
--- /dev/null
+++ b/static/bidder-params/yahoossp.json
@@ -0,0 +1,19 @@
+{
+	"$schema": "http://json-schema.org/draft-04/schema#",
+	"title": "YahooSSP Adapter Params",
+	"description": "A schema which validates params accepted by the YahooSSP adapter",
+	"type": "object",
+	"properties": {
+		"dcn": {
+			"type": "string",
+			"minLength": 1,
+			"description": "Site ID provided by One Mobile"
+		},
+		"pos": {
+			"type": "string",
+			"minLength": 1,
+			"description": "Placement ID"
+		}
+	},
+	"required": ["dcn", "pos"]
+}


Test patch:
diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go
index 2d4c962b..9bfa04fa 100644
--- a/adapters/rubicon/rubicon_test.go
+++ b/adapters/rubicon/rubicon_test.go
@@ -35,6 +35,12 @@ type rubiAppendTrackerUrlTestScenario struct {
 	expected string
 }
 
+type rubiPopulateFpdAttributesScenario struct {
+	source json.RawMessage
+	target map[string]interface{}
+	result map[string]interface{}
+}
+
 type rubiSetNetworkIdTestScenario struct {
 	bidExt            *openrtb_ext.ExtBidPrebid
 	buyer             string
@@ -1277,7 +1283,10 @@ func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
 				},
 				"context": {
 					"data": {
-						"adslot": "///test-adslot"
+                        "adserver": {
+                             "adslot": "/test-adslot",
+                             "name": "gam"
+                        }
 					}
 				}
 			}`),
@@ -1302,14 +1311,52 @@ func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
 	if err := json.Unmarshal(rubiconReq.Imp[0].Ext, &rpImpExt); err != nil {
 		t.Fatal("Error unmarshalling imp.ext")
 	}
+	assert.Equal(t, rpImpExt.GPID, "/test-adslot")
+}
 
-	rubiconExtInventory := make(map[string]interface{})
-	if err := json.Unmarshal(rpImpExt.RP.Target, &rubiconExtInventory); err != nil {
-		t.Fatal("Error unmarshalling imp.ext.rp.target")
+func TestOpenRTBFirstPartyDataPopulating(t *testing.T) {
+	testScenarios := []rubiPopulateFpdAttributesScenario{
+		{
+			source: json.RawMessage(`{"sourceKey": ["sourceValue", "sourceValue2"]}`),
+			target: map[string]interface{}{"targetKey": []interface{}{"targetValue"}},
+			result: map[string]interface{}{"targetKey": []interface{}{"targetValue"}, "sourceKey": []interface{}{"sourceValue", "sourceValue2"}},
+		},
+		{
+			source: json.RawMessage(`{"sourceKey": ["sourceValue", "sourceValue2"]}`),
+			target: make(map[string]interface{}),
+			result: map[string]interface{}{"sourceKey": []interface{}{"sourceValue", "sourceValue2"}},
+		},
+		{
+			source: json.RawMessage(`{"sourceKey": "sourceValue"}`),
+			target: make(map[string]interface{}),
+			result: map[string]interface{}{"sourceKey": [1]string{"sourceValue"}},
+		},
+		{
+			source: json.RawMessage(`{"sourceKey": true, "sourceKey2": [true, false, true]}`),
+			target: make(map[string]interface{}),
+			result: map[string]interface{}{"sourceKey": [1]string{"true"}, "sourceKey2": []string{"true", "false", "true"}},
+		},
+		{
+			source: json.RawMessage(`{"sourceKey": 1, "sourceKey2": [1, 2, 3]}`),
+			target: make(map[string]interface{}),
+			result: map[string]interface{}{"sourceKey": [1]string{"1"}},
+		},
+		{
+			source: json.RawMessage(`{"sourceKey": 1, "sourceKey2": 3.23}`),
+			target: make(map[string]interface{}),
+			result: map[string]interface{}{"sourceKey": [1]string{"1"}},
+		},
+		{
+			source: json.RawMessage(`{"sourceKey": {}}`),
+			target: make(map[string]interface{}),
+			result: make(map[string]interface{}),
+		},
 	}
 
-	assert.Equal(t, "test-adslot", rubiconExtInventory["dfp_ad_unit_code"],
-		"Unexpected dfp_ad_unit_code: %s", rubiconExtInventory["dfp_ad_unit_code"])
+	for _, scenario := range testScenarios {
+		populateFirstPartyDataAttributes(scenario.source, scenario.target)
+		assert.Equal(t, scenario.result, scenario.target)
+	}
 }
 
 func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
diff --git a/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json b/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json
new file mode 100644
index 00000000..eec396f8
--- /dev/null
+++ b/adapters/rubicon/rubicontest/exemplary/app-imp-fpd.json
@@ -0,0 +1,411 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "app": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ],
+      "sectioncat": [
+        "sectionCat1",
+        "sectionCat2"
+      ],
+      "ext": {
+        "data": {
+          "attr1": "val1",
+          "attr2": [
+            "val21",
+            "val22"
+          ],
+          "attr3": true,
+          "attr4": [
+            true,
+            false,
+            true,
+            true
+          ],
+          "attr5": 3,
+          "attr6": [
+            1,
+            2,
+            3
+          ],
+          "attr7": 1.23
+        }
+      }
+    },
+    "user": {
+      "yob": 2000,
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "gender": "f",
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ],
+      "ext": {
+        "data": {
+          "attr1": "val1",
+          "attr2": [
+            "val21",
+            "val22"
+          ],
+          "attr3": true,
+          "attr4": [
+            true,
+            false,
+            true,
+            true
+          ],
+          "attr5": 3,
+          "attr6": [
+            1,
+            2,
+            3
+          ],
+          "attr7": 1.23
+        }
+      }
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "video": {
+          "placement": 3,
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "context": {
+            "data": {
+              "adserver": {
+                "name": "gam",
+                "adslot": "someAdSlot"
+              },
+              "dataAttr1": "dataVal1",
+              "dataAttr2": "dataVal2"
+            }
+          },
+          "bidder": {
+            "video": {
+            },
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "app": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
+            "sectioncat": [
+              "sectionCat1",
+              "sectionCat2"
+            ],
+            "ext": {
+              "rp": {
+                "site_id": 113932
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "attr1": [
+                    "val1"
+                  ],
+                  "attr2": [
+                    "val21",
+                    "val22"
+                  ],
+                  "attr3": [
+                    "true"
+                  ],
+                  "attr4": [
+                    "true",
+                    "false",
+                    "true",
+                    "true"
+                  ],
+                  "attr5": [
+                    "3"
+                  ],
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            }
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "video": {
+                "placement": 3,
+                "ext": {
+                  "rp": {
+                    "size_id": 203
+                  }
+                },
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "gpid": "someAdSlot",
+                "rp": {
+                  "target": {
+                    "dataAttr1": [
+                      "dataVal1"
+                    ],
+                    "dataAttr2": [
+                      "dataVal2"
+                    ],
+                    "attr1": [
+                      "val1"
+                    ],
+                    "attr2": [
+                      "val21",
+                      "val22"
+                    ],
+                    "attr3": [
+                      "true"
+                    ],
+                    "attr4": [
+                      "true",
+                      "false",
+                      "true",
+                      "true"
+                    ],
+                    "attr5": [
+                      "3"
+                    ],
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ],
+                    "sectioncat": [
+                      "sectionCat1",
+                      "sectionCat2"
+                    ]
+                  },
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "some-test-ad",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "some-test-ad",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/rubicon/rubicontest/exemplary/simple-video.json b/adapters/rubicon/rubicontest/exemplary/simple-video.json
index 7e5274f2..592f9fb2 100644
--- a/adapters/rubicon/rubicontest/exemplary/simple-video.json
+++ b/adapters/rubicon/rubicontest/exemplary/simple-video.json
@@ -10,6 +10,10 @@
       "bundle": "com.wls.testwlsapplication"
     },
     "site": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ],
       "content": {
         "data": [
           {
@@ -49,6 +53,13 @@
       }
     },
     "user": {
+      "yob": 2000,
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "gender": "f",
       "data": [
         {
           "ext": {
@@ -148,6 +159,10 @@
             "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
           },
           "site": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
             "content": {
               "data": [
                 {
@@ -298,6 +313,12 @@
               },
               "ext": {
                 "rp": {
+                  "target": {
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ]
+                  },
                   "track": {
                     "mint": "",
                     "mint_version": ""
diff --git a/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json b/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json
new file mode 100644
index 00000000..56f5ce61
--- /dev/null
+++ b/adapters/rubicon/rubicontest/exemplary/site-imp-fpd.json
@@ -0,0 +1,542 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "site": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ],
+      "sectioncat": [
+        "sectionCat1",
+        "sectionCat2"
+      ],
+      "page": "somePage",
+      "ref": "someRef",
+      "search": "someSearch",
+      "ext": {
+        "data": {
+          "attr1": "val1",
+          "attr2": [
+            "val21",
+            "val22"
+          ],
+          "attr3": true,
+          "attr4": [
+            true,
+            false,
+            true,
+            true
+          ],
+          "attr5": 3,
+          "attr6": [
+            1,
+            2,
+            3
+          ],
+          "attr7": 1.23
+        }
+      },
+      "content": {
+        "data": [
+          {
+            "ext": {
+              "segtax": 1
+            },
+            "segment": [
+              {
+                "id": "idToCopy"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": "someValue"
+            },
+            "segment": [
+              {
+                "id": "shouldNotBeCopied"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": "2"
+            },
+            "segment": [
+              {
+                "id": "shouldNotBeCopied2"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": 2
+            },
+            "segment": [
+              {
+                "id": "idToCopy2"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": 5
+            },
+            "segment": [
+              {
+                "id": "idToCopy3"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": 6
+            },
+            "segment": [
+              {
+                "id": "idToCopy4"
+              }
+            ]
+          },
+          {
+            "ext": {
+              "segtax": [
+                2
+              ]
+            },
+            "segment": [
+              {
+                "id": "shouldNotBeCopied3"
+              }
+            ]
+          }
+        ]
+      }
+    },
+    "user": {
+      "yob": 2000,
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "gender": "f",
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ]
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "video": {
+          "placement": 3,
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "data": {
+            "adserver": {
+              "name": "gam",
+              "adslot": "someAdSlot"
+            },
+            "dataAttr1": "dataVal1",
+            "dataAttr2": "dataVal2"
+          },
+          "bidder": {
+            "video": {
+            },
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "site": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
+            "sectioncat": [
+              "sectionCat1",
+              "sectionCat2"
+            ],
+            "page": "somePage",
+            "ref": "someRef",
+            "search": "someSearch",
+            "content": {
+              "data": [
+                {
+                  "ext": {
+                    "segtax": 1
+                  },
+                  "segment": [
+                    {
+                      "id": "idToCopy"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": "someValue"
+                  },
+                  "segment": [
+                    {
+                      "id": "shouldNotBeCopied"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": "2"
+                  },
+                  "segment": [
+                    {
+                      "id": "shouldNotBeCopied2"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": 2
+                  },
+                  "segment": [
+                    {
+                      "id": "idToCopy2"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": 5
+                  },
+                  "segment": [
+                    {
+                      "id": "idToCopy3"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": 6
+                  },
+                  "segment": [
+                    {
+                      "id": "idToCopy4"
+                    }
+                  ]
+                },
+                {
+                  "ext": {
+                    "segtax": [
+                      2
+                    ]
+                  },
+                  "segment": [
+                    {
+                      "id": "shouldNotBeCopied3"
+                    }
+                  ]
+                }
+              ]
+            },
+            "ext": {
+              "rp": {
+                "site_id": 113932,
+                "target": {
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2",
+                    "idToCopy3",
+                    "idToCopy4"
+                  ]
+                }
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            }
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "video": {
+                "placement": 3,
+                "ext": {
+                  "rp": {
+                    "size_id": 203
+                  }
+                },
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "gpid": "someAdSlot",
+                "rp": {
+                  "target": {
+                    "dataAttr1": [
+                      "dataVal1"
+                    ],
+                    "dataAttr2": [
+                      "dataVal2"
+                    ],
+                    "attr1": [
+                      "val1"
+                    ],
+                    "attr2": [
+                      "val21",
+                      "val22"
+                    ],
+                    "attr3": [
+                      "true"
+                    ],
+                    "attr4": [
+                      "true",
+                      "false",
+                      "true",
+                      "true"
+                    ],
+                    "attr5": [
+                      "3"
+                    ],
+                    "page": [
+                      "somePage"
+                    ],
+                    "ref": [
+                      "someRef"
+                    ],
+                    "search": [
+                      "someSearch"
+                    ],
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ],
+                    "sectioncat": [
+                      "sectionCat1",
+                      "sectionCat2"
+                    ]
+                  },
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "some-test-ad",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "some-test-ad",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/rubicon/rubicontest/exemplary/user-fpd.json b/adapters/rubicon/rubicontest/exemplary/user-fpd.json
new file mode 100644
index 00000000..b2be736f
--- /dev/null
+++ b/adapters/rubicon/rubicontest/exemplary/user-fpd.json
@@ -0,0 +1,344 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "device": {
+      "ip": "123.123.123.123",
+      "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+    },
+    "site": {
+      "page": "somePage",
+      "ref": "someRef",
+      "search": "someSearch"
+    },
+    "user": {
+      "yob": 2000,
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "gender": "f",
+      "data": [
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "someValue"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": "4"
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": 4
+          },
+          "segment": [
+            {
+              "id": "idToCopy2"
+            }
+          ]
+        },
+        {
+          "ext": {
+            "segtax": [
+              4
+            ]
+          },
+          "segment": [
+            {
+              "id": "shouldNotBeCopied3"
+            }
+          ]
+        }
+      ],
+      "keywords": "someKeywords",
+      "ext": {
+        "rp": {
+          "target": {
+            "someKey": "someValue"
+          }
+        },
+        "data": {
+          "dataKey1": "dataValue1",
+          "dataKey2": [
+            "dataValue2",
+            "dataValue3"
+          ],
+          "dataKey3": true
+        }
+      }
+    },
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "instl": 1,
+        "video": {
+          "placement": 3,
+          "mimes": [
+            "video/mp4"
+          ],
+          "protocols": [
+            2,
+            5
+          ],
+          "w": 1024,
+          "h": 576
+        },
+        "ext": {
+          "data": {
+            "adserver": {
+              "name": "gam",
+              "adslot": "someAdSlot"
+            },
+            "dataAttr1": "dataVal1",
+            "dataAttr2": "dataVal2"
+          },
+          "bidder": {
+            "video": {
+            },
+            "accountId": 1001,
+            "siteId": 113932,
+            "zoneId": 535510
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "uri?tk_xint=pbs-test-tracker",
+        "body": {
+          "id": "test-request-id",
+          "device": {
+            "ext": {
+              "rp": {
+                "pixelratio": 0
+              }
+            },
+            "ip": "123.123.123.123",
+            "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+          },
+          "site": {
+            "page": "somePage",
+            "ref": "someRef",
+            "search": "someSearch",
+            "ext": {
+              "rp": {
+                "site_id": 113932
+              }
+            },
+            "publisher": {
+              "ext": {
+                "rp": {
+                  "account_id": 1001
+                }
+              }
+            }
+          },
+          "user": {
+            "data": [
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "someValue"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": "4"
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": 4
+                },
+                "segment": [
+                  {
+                    "id": "idToCopy2"
+                  }
+                ]
+              },
+              {
+                "ext": {
+                  "segtax": [
+                    4
+                  ]
+                },
+                "segment": [
+                  {
+                    "id": "shouldNotBeCopied3"
+                  }
+                ]
+              }
+            ],
+            "ext": {
+              "rp": {
+                "target": {
+                  "someKey": "someValue",
+                  "dataKey1": [
+                    "dataValue1"
+                  ],
+                  "dataKey2": [
+                    "dataValue2",
+                    "dataValue3"
+                  ],
+                  "dataKey3": [
+                    "true"
+                  ],
+                  "iab": [
+                    "idToCopy",
+                    "idToCopy2"
+                  ]
+                }
+              }
+            },
+            "keywords": "someKeywords"
+          },
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "instl": 1,
+              "video": {
+                "placement": 3,
+                "ext": {
+                  "rp": {
+                    "size_id": 203
+                  }
+                },
+                "mimes": [
+                  "video/mp4"
+                ],
+                "protocols": [
+                  2,
+                  5
+                ],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "gpid": "someAdSlot",
+                "rp": {
+                  "target": {
+                    "dataAttr1": [
+                      "dataVal1"
+                    ],
+                    "dataAttr2": [
+                      "dataVal2"
+                    ],
+                    "page": [
+                      "somePage"
+                    ],
+                    "ref": [
+                      "someRef"
+                    ],
+                    "search": [
+                      "someSearch"
+                    ]
+                  },
+                  "track": {
+                    "mint": "",
+                    "mint_version": ""
+                  },
+                  "zone_id": 535510
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test_bid_id",
+                  "impid": "test-imp-id",
+                  "price": 0.27543,
+                  "adm": "some-test-ad",
+                  "cid": "test_cid",
+                  "crid": "test_crid",
+                  "dealid": "test_dealid",
+                  "ext": {
+                    "prebid": {
+                      "type": "video"
+                    }
+                  }
+                }
+              ],
+              "seat": "adman"
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test_bid_id",
+            "impid": "test-imp-id",
+            "price": 0.27543,
+            "adm": "some-test-ad",
+            "cid": "test_cid",
+            "crid": "test_crid",
+            "dealid": "test_dealid",
+            "ext": {
+              "prebid": {
+                "type": "video"
+              }
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json
index 0be214da..a1e13815 100644
--- a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json
+++ b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json
@@ -10,6 +10,10 @@
       "bundle": "com.wls.testwlsapplication"
     },
     "site": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ],
       "content": {
       }
     },
@@ -113,6 +117,10 @@
             "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
           },
           "site": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
             "content": {
             },
             "ext": {
@@ -221,6 +229,12 @@
               },
               "ext": {
                 "rp": {
+                  "target": {
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ]
+                  },
                   "track": {
                     "mint": "",
                     "mint_version": ""
diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content.json b/adapters/rubicon/rubicontest/supplemental/no-site-content.json
index 2e830a2d..6630799b 100644
--- a/adapters/rubicon/rubicontest/supplemental/no-site-content.json
+++ b/adapters/rubicon/rubicontest/supplemental/no-site-content.json
@@ -10,6 +10,10 @@
       "bundle": "com.wls.testwlsapplication"
     },
     "site": {
+      "pagecat": [
+        "val1",
+        "val2"
+      ]
     },
     "user": {
       "data": [
@@ -111,6 +115,10 @@
             "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
           },
           "site": {
+            "pagecat": [
+              "val1",
+              "val2"
+            ],
             "ext": {
               "rp": {
                 "site_id": 113932
@@ -217,6 +225,12 @@
               },
               "ext": {
                 "rp": {
+                  "target": {
+                    "pagecat": [
+                      "val1",
+                      "val2"
+                    ]
+                  },
                   "track": {
                     "mint": "",
                     "mint_version": ""
diff --git a/adapters/yssp/params_test.go b/adapters/yahoossp/params_test.go
similarity index 61%
rename from adapters/yssp/params_test.go
rename to adapters/yahoossp/params_test.go
index 66146377..47d8d268 100644
--- a/adapters/yssp/params_test.go
+++ b/adapters/yahoossp/params_test.go
@@ -1,4 +1,4 @@
-package yssp
+package yahoossp
 
 import (
 	"encoding/json"
@@ -7,11 +7,11 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
-// This file actually intends to test static/bidder-params/yssp.json
+// This file actually intends to test static/bidder-params/yahoossp.json
 //
-// These also validate the format of the external API: request.imp[i].ext.yssp
+// These also validate the format of the external API: request.imp[i].ext.yahoossp
 
-// TestValidParams makes sure that the yssp schema accepts all imp.ext fields which we intend to support.
+// TestValidParams makes sure that the yahoossp schema accepts all imp.ext fields which we intend to support.
 func TestValidParams(t *testing.T) {
 	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
 	if err != nil {
@@ -19,13 +19,13 @@ func TestValidParams(t *testing.T) {
 	}
 
 	for _, validParam := range validParams {
-		if err := validator.Validate(openrtb_ext.BidderYSSP, json.RawMessage(validParam)); err != nil {
-			t.Errorf("Schema rejected yssp params: %s", validParam)
+		if err := validator.Validate(openrtb_ext.BidderYahooSSP, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected yahoossp params: %s", validParam)
 		}
 	}
 }
 
-// TestInvalidParams makes sure that the yssp schema rejects all the imp.ext fields we don't support.
+// TestInvalidParams makes sure that the yahoossp schema rejects all the imp.ext fields we don't support.
 func TestInvalidParams(t *testing.T) {
 	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
 	if err != nil {
@@ -33,7 +33,7 @@ func TestInvalidParams(t *testing.T) {
 	}
 
 	for _, invalidParam := range invalidParams {
-		if err := validator.Validate(openrtb_ext.BidderYSSP, json.RawMessage(invalidParam)); err == nil {
+		if err := validator.Validate(openrtb_ext.BidderYahooSSP, json.RawMessage(invalidParam)); err == nil {
 			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
 		}
 	}
diff --git a/adapters/yssp/yssp_test.go b/adapters/yahoossp/yahoossp_test.go
similarity index 56%
rename from adapters/yssp/yssp_test.go
rename to adapters/yahoossp/yahoossp_test.go
index ee99d672..214457c0 100644
--- a/adapters/yssp/yssp_test.go
+++ b/adapters/yahoossp/yahoossp_test.go
@@ -1,4 +1,4 @@
-package yssp
+package yahoossp
 
 import (
 	"testing"
@@ -9,8 +9,8 @@ import (
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
-func TestYSSPBidderEndpointConfig(t *testing.T) {
-	bidder, buildErr := Builder(openrtb_ext.BidderYSSP, config.Adapter{
+func TestYahooSSPBidderEndpointConfig(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderYahooSSP, config.Adapter{
 		Endpoint: "http://localhost/bid",
 	})
 
@@ -18,17 +18,17 @@ func TestYSSPBidderEndpointConfig(t *testing.T) {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
 	}
 
-	bidderYSSP := bidder.(*adapter)
+	bidderYahooSSP := bidder.(*adapter)
 
-	assert.Equal(t, "http://localhost/bid", bidderYSSP.URI)
+	assert.Equal(t, "http://localhost/bid", bidderYahooSSP.URI)
 }
 
 func TestJsonSamples(t *testing.T) {
-	bidder, buildErr := Builder(openrtb_ext.BidderYSSP, config.Adapter{})
+	bidder, buildErr := Builder(openrtb_ext.BidderYahooSSP, config.Adapter{})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
 	}
 
-	adapterstest.RunJSONBidderTest(t, "yssptest", bidder)
+	adapterstest.RunJSONBidderTest(t, "yahoossptest", bidder)
 }
diff --git a/adapters/yssp/yssptest/exemplary/simple-app-banner.json b/adapters/yahoossp/yahoossptest/exemplary/simple-app-banner.json
similarity index 98%
rename from adapters/yssp/yssptest/exemplary/simple-app-banner.json
rename to adapters/yahoossp/yahoossptest/exemplary/simple-app-banner.json
index a28913f8..319e22e3 100644
--- a/adapters/yssp/yssptest/exemplary/simple-app-banner.json
+++ b/adapters/yahoossp/yahoossptest/exemplary/simple-app-banner.json
@@ -77,7 +77,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yssp",
+              "seat": "yahoossp",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yssp/yssptest/exemplary/simple-banner.json b/adapters/yahoossp/yahoossptest/exemplary/simple-banner.json
similarity index 98%
rename from adapters/yssp/yssptest/exemplary/simple-banner.json
rename to adapters/yahoossp/yahoossptest/exemplary/simple-banner.json
index 4a71473b..344bbe9a 100644
--- a/adapters/yssp/yssptest/exemplary/simple-banner.json
+++ b/adapters/yahoossp/yahoossptest/exemplary/simple-banner.json
@@ -77,7 +77,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yssp",
+              "seat": "yahoossp",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yssp/yssptest/supplemental/empty-banner-format.json b/adapters/yahoossp/yahoossptest/supplemental/empty-banner-format.json
similarity index 100%
rename from adapters/yssp/yssptest/supplemental/empty-banner-format.json
rename to adapters/yahoossp/yahoossptest/supplemental/empty-banner-format.json
diff --git a/adapters/yssp/yssptest/supplemental/invalid-banner-width.json b/adapters/yahoossp/yahoossptest/supplemental/invalid-banner-width.json
similarity index 100%
rename from adapters/yssp/yssptest/supplemental/invalid-banner-width.json
rename to adapters/yahoossp/yahoossptest/supplemental/invalid-banner-width.json
diff --git a/adapters/yssp/yssptest/supplemental/non-banner-bids-ignored.json b/adapters/yahoossp/yahoossptest/supplemental/non-banner-bids-ignored.json
similarity index 98%
rename from adapters/yssp/yssptest/supplemental/non-banner-bids-ignored.json
rename to adapters/yahoossp/yahoossptest/supplemental/non-banner-bids-ignored.json
index 94772a4b..6f40e2a9 100644
--- a/adapters/yssp/yssptest/supplemental/non-banner-bids-ignored.json
+++ b/adapters/yahoossp/yahoossptest/supplemental/non-banner-bids-ignored.json
@@ -74,7 +74,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yssp",
+              "seat": "yahoossp",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "test-imp-id",
diff --git a/adapters/yssp/yssptest/supplemental/required-nobidder-info.json b/adapters/yahoossp/yahoossptest/supplemental/required-nobidder-info.json
similarity index 100%
rename from adapters/yssp/yssptest/supplemental/required-nobidder-info.json
rename to adapters/yahoossp/yahoossptest/supplemental/required-nobidder-info.json
diff --git a/adapters/yssp/yssptest/supplemental/server-error.json b/adapters/yahoossp/yahoossptest/supplemental/server-error.json
similarity index 100%
rename from adapters/yssp/yssptest/supplemental/server-error.json
rename to adapters/yahoossp/yahoossptest/supplemental/server-error.json
diff --git a/adapters/yssp/yssptest/supplemental/server-response-wrong-impid.json b/adapters/yahoossp/yahoossptest/supplemental/server-response-wrong-impid.json
similarity index 98%
rename from adapters/yssp/yssptest/supplemental/server-response-wrong-impid.json
rename to adapters/yahoossp/yahoossptest/supplemental/server-response-wrong-impid.json
index 1e893127..5b33f3af 100644
--- a/adapters/yssp/yssptest/supplemental/server-response-wrong-impid.json
+++ b/adapters/yahoossp/yahoossptest/supplemental/server-response-wrong-impid.json
@@ -76,7 +76,7 @@
           "id": "test-request-id",
           "seatbid": [
             {
-              "seat": "yssp",
+              "seat": "yahoossp",
               "bid": [{
                 "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
                 "impid": "wrong",
diff --git a/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json b/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json
new file mode 100644
index 00000000..c68748e3
--- /dev/null
+++ b/adapters/yieldlab/yieldlabtest/exemplary/multiple_impressions.json
@@ -0,0 +1,156 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 728,
+              "h": 90
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "adslotId": "12345",
+            "supplyId": "123456789",
+            "adSize": "728x90",
+            "targeting": {
+              "key1": "value1",
+              "key2": "value2"
+            },
+            "extId": "abc"
+          }
+        }
+      },
+      {
+        "id": "test-imp-id2",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "adslotId": "67890",
+            "supplyId": "123456789",
+            "adSize": "300x250",
+            "targeting": {
+              "key1": "value1",
+              "key2": "value2"
+            },
+            "extId": "abc"
+          }
+        }
+      }
+    ],
+    "user": {
+      "buyeruid": "34a53e82-0dc3-4815-8b7e-b725ede0361c"
+    },
+    "device": {
+      "ifa": "hello-ads",
+      "devicetype": 4,
+      "connectiontype": 6,
+      "geo": {
+        "lat": 51.499488,
+        "lon": -0.128953
+      },
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
+      "ip": "169.254.13.37",
+      "h": 1098,
+      "w": 814
+    },
+    "site": {
+      "id": "fake-site-id",
+      "publisher": {
+        "id": "1"
+      },
+      "page": "http://localhost:9090/gdpr.html"
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Cookie": [
+            "id=34a53e82-0dc3-4815-8b7e-b725ede0361c"
+          ],
+          "Referer": [
+            "http://localhost:9090/gdpr.html"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"
+          ],
+          "X-Forwarded-For": [
+            "169.254.13.37"
+          ]
+        },
+        "uri": "https://ad.yieldlab.net/testing/12345,67890?content=json&ids=ylid%3A34a53e82-0dc3-4815-8b7e-b725ede0361c&lat=51.499488&lon=-0.128953&pvid=true&t=key1%3Dvalue1%26key2%3Dvalue2&ts=testing&yl_rtb_connectiontype=6&yl_rtb_devicetype=4&yl_rtb_ifa=hello-ads"
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": [
+          {
+            "id": 12345,
+            "price": 201,
+            "advertiser": "yieldlab",
+            "adsize": "728x90",
+            "pid": 1234,
+            "did": 5678,
+            "pvid": "40cb3251-1e1e-4cfd-8edc-7d32dc1a21e5"
+          },
+          {
+            "id": 67890,
+            "price": 131,
+            "advertiser": "yieldlab",
+            "adsize": "300x250",
+            "pid": 1234,
+            "did": 5678,
+            "pvid": "40cb3251-1e1e-4cfd-8edc-7d32dc1a21e5"
+          }
+        ]
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "EUR",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<script src=\"https://ad.yieldlab.net/d/12345/123456789/728x90?id=abc&ids=ylid%3A34a53e82-0dc3-4815-8b7e-b725ede0361c&pvid=40cb3251-1e1e-4cfd-8edc-7d32dc1a21e5&ts=testing\"></script>",
+            "crid": "12345123433",
+            "dealid": "1234",
+            "id": "12345",
+            "impid": "test-imp-id",
+            "price": 2.01,
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        },
+        {
+          "bid": {
+            "adm": "<script src=\"https://ad.yieldlab.net/d/67890/123456789/300x250?id=abc&ids=ylid%3A34a53e82-0dc3-4815-8b7e-b725ede0361c&pvid=40cb3251-1e1e-4cfd-8edc-7d32dc1a21e5&ts=testing\"></script>",
+            "crid": "67890123433",
+            "dealid": "1234",
+            "id": "67890",
+            "impid": "test-imp-id2",
+            "price": 1.31,
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/yssp/yssptest/params/race/banner.json b/adapters/yssp/yssptest/params/race/banner.json
deleted file mode 100644
index 739ec3c0..00000000
--- a/adapters/yssp/yssptest/params/race/banner.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "dcn": "2345",
-  "pos": "header"
-}
diff --git a/config/config_test.go b/config/config_test.go
index b22b384d..03ad8846 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -228,7 +228,8 @@ var fullConfig = []byte(`
 gdpr:
   host_vendor_id: 15
   default_value: "1"
-  non_standard_publishers: ["siteID","fake-site-id","appID","agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA"]
+  non_standard_publishers: ["pub1", "pub2"]
+  eea_countries: ["eea1", "eea2"]
   tcf2:
     purpose1:
       enforce_vendors: false
@@ -440,19 +441,12 @@ func TestFullConfig(t *testing.T) {
 	cmpStrings(t, "gdpr.default_value", cfg.GDPR.DefaultValue, "1")
 
 	//Assert the NonStandardPublishers was correctly unmarshalled
-	cmpStrings(t, "gdpr.non_standard_publishers", cfg.GDPR.NonStandardPublishers[0], "siteID")
-	cmpStrings(t, "gdpr.non_standard_publishers", cfg.GDPR.NonStandardPublishers[1], "fake-site-id")
-	cmpStrings(t, "gdpr.non_standard_publishers", cfg.GDPR.NonStandardPublishers[2], "appID")
-	cmpStrings(t, "gdpr.non_standard_publishers", cfg.GDPR.NonStandardPublishers[3], "agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA")
-
-	//Assert the NonStandardPublisherMap hash table was built correctly
-	var found bool
-	for i := 0; i < len(cfg.GDPR.NonStandardPublishers); i++ {
-		_, found = cfg.GDPR.NonStandardPublisherMap[cfg.GDPR.NonStandardPublishers[i]]
-		cmpBools(t, "cfg.GDPR.NonStandardPublisherMap", found, true)
-	}
-	_, found = cfg.GDPR.NonStandardPublisherMap["appnexus"]
-	cmpBools(t, "cfg.GDPR.NonStandardPublisherMap", found, false)
+	assert.Equal(t, []string{"pub1", "pub2"}, cfg.GDPR.NonStandardPublishers, "gdpr.non_standard_publishers")
+	assert.Equal(t, map[string]struct{}{"pub1": {}, "pub2": {}}, cfg.GDPR.NonStandardPublisherMap, "gdpr.non_standard_publishers Hash Map")
+
+	// Assert EEA Countries was correctly unmarshalled and the EEACountriesMap built correctly.
+	assert.Equal(t, []string{"eea1", "eea2"}, cfg.GDPR.EEACountries, "gdpr.eea_countries")
+	assert.Equal(t, map[string]struct{}{"eea1": {}, "eea2": {}}, cfg.GDPR.EEACountriesMap, "gdpr.eea_countries Hash Map")
 
 	cmpBools(t, "ccpa.enforce", cfg.CCPA.Enforce, true)
 	cmpBools(t, "lmt.enforce", cfg.LMT.Enforce, true)
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index ebf18994..5f4a2902 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -3715,3 +3715,35 @@ type fakeUUIDGenerator struct {
 func (f fakeUUIDGenerator) Generate() (string, error) {
 	return f.id, f.err
 }
+
+func TestValidateBanner(t *testing.T) {
+	impIndex := 0
+
+	testCases := []struct {
+		description    string
+		banner         *openrtb2.Banner
+		impIndex       int
+		isInterstitial bool
+		expectedError  error
+	}{
+		{
+			description:    "isInterstitial Equals False (not set to 1)",
+			banner:         &openrtb2.Banner{W: nil, H: nil, Format: nil},
+			impIndex:       impIndex,
+			isInterstitial: false,
+			expectedError:  errors.New("request.imp[0].banner has no sizes. Define \"w\" and \"h\", or include \"format\" elements."),
+		},
+		{
+			description:    "isInterstitial Equals True (is set to 1)",
+			banner:         &openrtb2.Banner{W: nil, H: nil, Format: nil},
+			impIndex:       impIndex,
+			isInterstitial: true,
+			expectedError:  nil,
+		},
+	}
+
+	for _, test := range testCases {
+		result := validateBanner(test.banner, test.impIndex, test.isInterstitial)
+		assert.Equal(t, test.expectedError, result, test.description)
+	}
+}
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index 1591d353..1a630a96 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -69,7 +69,6 @@ func TestSingleBidder(t *testing.T) {
 	}
 
 	ctx := context.Background()
-	ctx = context.WithValue(ctx, DebugContextKey, true)
 
 	for _, test := range testCases {
 		mockBidderResponse := &adapters.BidderResponse{
@@ -170,7 +169,6 @@ func TestRequestBidRemovesSensitiveHeaders(t *testing.T) {
 
 	debugInfo := &config.DebugInfo{Allow: true}
 	ctx := context.Background()
-	ctx = context.WithValue(ctx, DebugContextKey, true)
 
 	bidder := adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo)
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
@@ -211,7 +209,6 @@ func TestSetGPCHeader(t *testing.T) {
 
 	debugInfo := &config.DebugInfo{Allow: true}
 	ctx := context.Background()
-	ctx = context.WithValue(ctx, DebugContextKey, true)
 
 	bidder := adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo)
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
@@ -249,7 +246,6 @@ func TestSetGPCHeaderNil(t *testing.T) {
 
 	debugInfo := &config.DebugInfo{Allow: true}
 	ctx := context.Background()
-	ctx = context.WithValue(ctx, DebugContextKey, true)
 
 	bidder := adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo)
 	currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index ed378e7b..6258d121 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -322,9 +322,6 @@ func TestDebugBehaviour(t *testing.T) {
 			openrtb_ext.BidderAppnexus: adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus, &config.DebugInfo{Allow: test.debugData.bidderLevelDebugAllowed}),
 		}
 
-		//request level debug key
-		ctx = context.WithValue(ctx, DebugContextKey, test.in.debug)
-
 		bidRequest.Test = test.in.test
 
 		if test.in.debug {
@@ -2025,38 +2022,6 @@ func TestTimeoutComputation(t *testing.T) {
 	}
 }
 
-func TestSetDebugContextKey(t *testing.T) {
-	// Test cases
-	testCases := []struct {
-		desc              string
-		inDebugInfo       bool
-		expectedDebugInfo bool
-	}{
-		{
-			desc:              "debugInfo flag on, we expect to find DebugContextKey key in context",
-			inDebugInfo:       true,
-			expectedDebugInfo: true,
-		},
-		{
-			desc:              "debugInfo flag off, we don't expect to find DebugContextKey key in context",
-			inDebugInfo:       false,
-			expectedDebugInfo: false,
-		},
-	}
-
-	// Setup test
-	ex := exchange{}
-
-	// Run tests
-	for _, test := range testCases {
-		auctionCtx := ex.makeDebugContext(context.Background(), test.inDebugInfo)
-
-		debugInfo := auctionCtx.Value(DebugContextKey)
-		assert.NotNil(t, debugInfo, "%s. Flag set, `debugInfo` shouldn't be nil")
-		assert.Equal(t, test.expectedDebugInfo, debugInfo.(bool), "Desc: %s. Incorrect value mapped to DebugContextKey(`debugInfo`) in the context\n", test.desc)
-	}
-}
-
 // TestExchangeJSON executes tests for all the *.json files in exchangetest.
 func TestExchangeJSON(t *testing.T) {
 	if specFiles, err := ioutil.ReadDir("./exchangetest"); err == nil {
@@ -2145,7 +2110,6 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 		auctionRequest.StartTime = time.Unix(0, spec.StartTime*1e+6)
 	}
 	ctx := context.Background()
-	ctx = context.WithValue(ctx, DebugContextKey, true)
 
 	bid, err := ex.HoldAuction(ctx, auctionRequest, debugLog)
 	responseTimes := extractResponseTimes(t, filename, bid)
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 6ce4b28a..14ebb8e9 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -1289,7 +1289,7 @@ func TestGetExtTargetData(t *testing.T) {
 	}
 }
 
-func TestGetDebugInfo(t *testing.T) {
+func TestParseRequestDebugValues(t *testing.T) {
 	type inTest struct {
 		bidRequest *openrtb2.BidRequest
 		requestExt *openrtb_ext.ExtRequest
@@ -1336,12 +1336,84 @@ func TestGetDebugInfo(t *testing.T) {
 		},
 	}
 	for _, test := range testCases {
-		actualDebugInfo := getDebugInfo(test.in.bidRequest, test.in.requestExt)
+		actualDebugInfo := parseRequestDebugValues(test.in.bidRequest, test.in.requestExt)
 
 		assert.Equal(t, test.out, actualDebugInfo, "%s. Unexpected debug value. \n", test.desc)
 	}
 }
 
+func TestSetDebugLogValues(t *testing.T) {
+
+	type aTest struct {
+		desc               string
+		inAccountDebugFlag bool
+		inDebugLog         *DebugLog
+		expectedDebugLog   *DebugLog
+	}
+
+	testGroups := []struct {
+		desc      string
+		testCases []aTest
+	}{
+
+		{
+			"nil debug log",
+			[]aTest{
+				{
+					desc:               "accountDebugFlag false, expect all false flags in resulting debugLog",
+					inAccountDebugFlag: false,
+					inDebugLog:         nil,
+					expectedDebugLog:   &DebugLog{},
+				},
+				{
+					desc:               "accountDebugFlag true, expect debugLog.Enabled to be true",
+					inAccountDebugFlag: true,
+					inDebugLog:         nil,
+					expectedDebugLog:   &DebugLog{Enabled: true},
+				},
+			},
+		},
+		{
+			"non-nil debug log",
+			[]aTest{
+				{
+					desc:               "both accountDebugFlag and DebugEnabledOrOverridden are false, expect debugLog.Enabled to be false",
+					inAccountDebugFlag: false,
+					inDebugLog:         &DebugLog{},
+					expectedDebugLog:   &DebugLog{},
+				},
+				{
+					desc:               "accountDebugFlag false but DebugEnabledOrOverridden is true, expect debugLog.Enabled to be true",
+					inAccountDebugFlag: false,
+					inDebugLog:         &DebugLog{DebugEnabledOrOverridden: true},
+					expectedDebugLog:   &DebugLog{DebugEnabledOrOverridden: true, Enabled: true},
+				},
+				{
+					desc:               "accountDebugFlag true but DebugEnabledOrOverridden is false, expect debugLog.Enabled to be true",
+					inAccountDebugFlag: true,
+					inDebugLog:         &DebugLog{},
+					expectedDebugLog:   &DebugLog{Enabled: true},
+				},
+				{
+					desc:               "Both accountDebugFlag and DebugEnabledOrOverridden are true, expect debugLog.Enabled to be true",
+					inAccountDebugFlag: true,
+					inDebugLog:         &DebugLog{DebugEnabledOrOverridden: true},
+					expectedDebugLog:   &DebugLog{DebugEnabledOrOverridden: true, Enabled: true},
+				},
+			},
+		},
+	}
+
+	for _, group := range testGroups {
+		for _, tc := range group.testCases {
+			// run
+			actualDebugLog := setDebugLogValues(tc.inAccountDebugFlag, tc.inDebugLog)
+			// assertions
+			assert.Equal(t, tc.expectedDebugLog, actualDebugLog, "%s. %s", group.desc, tc.desc)
+		}
+	}
+}
+
 func TestGetExtBidAdjustmentFactors(t *testing.T) {
 	testCases := []struct {
 		desc                    string
@@ -2164,6 +2236,118 @@ func TestRemoveUnpermissionedEidsUnmarshalErrors(t *testing.T) {
 	}
 }
 
+func TestGetDebugInfo(t *testing.T) {
+	type testInput struct {
+		debugEnabledOrOverridden bool
+		accountDebugFlag         bool
+	}
+	type testOut struct {
+		responseDebugAllow bool
+		accountDebugAllow  bool
+		debugLog           *DebugLog
+	}
+	type testCase struct {
+		in       testInput
+		expected testOut
+	}
+
+	testGroups := []struct {
+		desc   string
+		bidReq *openrtb2.BidRequest
+		tests  []testCase
+	}{
+		{
+			"Bid request doesn't call for debug info",
+			&openrtb2.BidRequest{Test: 0},
+			[]testCase{
+				{
+					testInput{debugEnabledOrOverridden: false, accountDebugFlag: false},
+					testOut{
+						responseDebugAllow: false,
+						accountDebugAllow:  false,
+						debugLog:           &DebugLog{Enabled: false},
+					},
+				},
+				{
+					testInput{debugEnabledOrOverridden: false, accountDebugFlag: true},
+					testOut{
+						responseDebugAllow: false,
+						accountDebugAllow:  false,
+						debugLog:           &DebugLog{Enabled: true},
+					},
+				},
+				{
+					testInput{debugEnabledOrOverridden: true, accountDebugFlag: false},
+					testOut{
+						responseDebugAllow: true,
+						accountDebugAllow:  false,
+						debugLog:           &DebugLog{DebugEnabledOrOverridden: true, Enabled: true},
+					},
+				},
+				{
+					testInput{debugEnabledOrOverridden: true, accountDebugFlag: true},
+					testOut{
+						responseDebugAllow: true,
+						accountDebugAllow:  true,
+						debugLog:           &DebugLog{DebugEnabledOrOverridden: true, Enabled: true},
+					},
+				},
+			},
+		},
+		{
+			"Bid request requires debug info",
+			&openrtb2.BidRequest{Test: 1},
+			[]testCase{
+				{
+					testInput{debugEnabledOrOverridden: false, accountDebugFlag: false},
+					testOut{
+						responseDebugAllow: false,
+						accountDebugAllow:  false,
+						debugLog:           &DebugLog{Enabled: false},
+					},
+				},
+				{
+					testInput{debugEnabledOrOverridden: false, accountDebugFlag: true},
+					testOut{
+						responseDebugAllow: true,
+						accountDebugAllow:  true,
+						debugLog:           &DebugLog{Enabled: true},
+					},
+				},
+				{
+					testInput{debugEnabledOrOverridden: true, accountDebugFlag: false},
+					testOut{
+						responseDebugAllow: true,
+						accountDebugAllow:  false,
+						debugLog:           &DebugLog{DebugEnabledOrOverridden: true, Enabled: true},
+					},
+				},
+				{
+					testInput{debugEnabledOrOverridden: true, accountDebugFlag: true},
+					testOut{
+						responseDebugAllow: true,
+						accountDebugAllow:  true,
+						debugLog:           &DebugLog{DebugEnabledOrOverridden: true, Enabled: true},
+					},
+				},
+			},
+		},
+	}
+	for _, group := range testGroups {
+		for i, tc := range group.tests {
+			inDebugLog := &DebugLog{DebugEnabledOrOverridden: tc.in.debugEnabledOrOverridden}
+
+			// run
+			responseDebugAllow, accountDebugAllow, debugLog := getDebugInfo(group.bidReq, nil, tc.in.accountDebugFlag, inDebugLog)
+
+			// assertions
+			assert.Equal(t, tc.expected.responseDebugAllow, responseDebugAllow, "%s - %d", group.desc, i)
+			assert.Equal(t, tc.expected.accountDebugAllow, accountDebugAllow, "%s - %d", group.desc, i)
+			assert.Equal(t, tc.expected.debugLog, debugLog, "%s - %d", group.desc, i)
+		}
+	}
+}
+
 func TestRemoveUnpermissionedEidsEmptyValidations(t *testing.T) {
 	testCases := []struct {
 		description string