Skip to content

Commit

Permalink
Use bidder name instead of syncer key (#2948)
Browse files Browse the repository at this point in the history
  • Loading branch information
VeronikaSolovei9 authored Jul 26, 2023
1 parent 33714f2 commit 831dd71
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 46 deletions.
2 changes: 1 addition & 1 deletion config/bidderinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ type SyncerEndpoint struct {
// startup:
//
// {{.ExternalURL}} - This will be replaced with the host server's externally reachable http path.
// {{.SyncerKey}} - This will be replaced with the syncer key.
// {{.BidderName}} - This will be replaced with the bidder name.
// {{.SyncType}} - This will be replaced with the sync type, either 'b' for iframe syncs or 'i'
// for redirect/image syncs.
// {{.UserMacro}} - This will be replaced with the bidder server's user id macro.
Expand Down
17 changes: 5 additions & 12 deletions endpoints/setuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ func NewSetUIDEndpoint(cfg *config.Configuration, syncersByBidder map[string]use
encoder := usersync.Base64Encoder{}
decoder := usersync.Base64Decoder{}

// convert map of syncers by bidder to map of syncers by key
// - its safe to assume that if multiple bidders map to the same key, the syncers are interchangeable.
syncersByKey := make(map[string]usersync.Syncer, len(syncersByBidder))
for _, v := range syncersByBidder {
syncersByKey[v.Key()] = v
}

return httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
so := analytics.SetUIDObject{
Status: http.StatusOK,
Expand All @@ -65,7 +58,7 @@ func NewSetUIDEndpoint(cfg *config.Configuration, syncersByBidder map[string]use

query := r.URL.Query()

syncer, err := getSyncer(query, syncersByKey)
syncer, err := getSyncer(query, syncersByBidder)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
Expand Down Expand Up @@ -313,14 +306,14 @@ func parseConsentFromGppStr(gppQueryValue string) (string, error) {
return gdprConsent, nil
}

func getSyncer(query url.Values, syncersByKey map[string]usersync.Syncer) (usersync.Syncer, error) {
key := query.Get("bidder")
func getSyncer(query url.Values, syncersByBidder map[string]usersync.Syncer) (usersync.Syncer, error) {
bidder := query.Get("bidder")

if key == "" {
if bidder == "" {
return nil, errors.New(`"bidder" query param is required`)
}

syncer, syncerExists := syncersByKey[key]
syncer, syncerExists := syncersByBidder[bidder]
if !syncerExists {
return nil, errors.New("The bidder name provided is not supported by Prebid Server")
}
Expand Down
2 changes: 1 addition & 1 deletion endpoints/setuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestSetUIDEndpoint(t *testing.T) {
description: "Set uid for valid bidder",
},
{
uri: "/setuid?bidder=adnxs&uid=123",
uri: "/setuid?bidder=appnexus&uid=123",
syncersBidderNameToKey: map[string]string{"appnexus": "adnxs"},
existingSyncs: nil,
gdprAllowsHostCookies: true,
Expand Down
14 changes: 8 additions & 6 deletions usersync/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ var ErrSyncerKeyRequired = errors.New("key is required")

// NewSyncer creates a new Syncer from the provided configuration, or return an error if macro substition
// fails or an endpoint url is invalid.
func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer) (Syncer, error) {
func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer, bidder string) (Syncer, error) {
if syncerConfig.Key == "" {
return nil, ErrSyncerKeyRequired
}
Expand All @@ -80,7 +80,7 @@ func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer) (Syncer,

if syncerConfig.IFrame != nil {
var err error
syncer.iframe, err = buildTemplate(syncerConfig.Key, setuidSyncTypeIFrame, hostConfig, syncerConfig.ExternalURL, *syncerConfig.IFrame)
syncer.iframe, err = buildTemplate(bidder, setuidSyncTypeIFrame, hostConfig, syncerConfig.ExternalURL, *syncerConfig.IFrame)
if err != nil {
return nil, fmt.Errorf("iframe %v", err)
}
Expand All @@ -91,7 +91,7 @@ func NewSyncer(hostConfig config.UserSync, syncerConfig config.Syncer) (Syncer,

if syncerConfig.Redirect != nil {
var err error
syncer.redirect, err = buildTemplate(syncerConfig.Key, setuidSyncTypeRedirect, hostConfig, syncerConfig.ExternalURL, *syncerConfig.Redirect)
syncer.redirect, err = buildTemplate(bidder, setuidSyncTypeRedirect, hostConfig, syncerConfig.ExternalURL, *syncerConfig.Redirect)
if err != nil {
return nil, fmt.Errorf("redirect %v", err)
}
Expand All @@ -114,29 +114,31 @@ func resolveDefaultSyncType(syncerConfig config.Syncer) SyncType {
var (
macroRegexExternalHost = regexp.MustCompile(`{{\s*\.ExternalURL\s*}}`)
macroRegexSyncerKey = regexp.MustCompile(`{{\s*\.SyncerKey\s*}}`)
macroRegexBidderName = regexp.MustCompile(`{{\s*\.BidderName\s*}}`)
macroRegexSyncType = regexp.MustCompile(`{{\s*\.SyncType\s*}}`)
macroRegexUserMacro = regexp.MustCompile(`{{\s*\.UserMacro\s*}}`)
macroRegexRedirect = regexp.MustCompile(`{{\s*\.RedirectURL\s*}}`)
macroRegex = regexp.MustCompile(`{{\s*\..*?\s*}}`)
)

func buildTemplate(key, syncTypeValue string, hostConfig config.UserSync, syncerExternalURL string, syncerEndpoint config.SyncerEndpoint) (*template.Template, error) {
func buildTemplate(bidderName, syncTypeValue string, hostConfig config.UserSync, syncerExternalURL string, syncerEndpoint config.SyncerEndpoint) (*template.Template, error) {
redirectTemplate := syncerEndpoint.RedirectURL
if redirectTemplate == "" {
redirectTemplate = hostConfig.RedirectURL
}

externalURL := chooseExternalURL(syncerEndpoint.ExternalURL, syncerExternalURL, hostConfig.ExternalURL)

redirectURL := macroRegexSyncerKey.ReplaceAllLiteralString(redirectTemplate, key)
redirectURL := macroRegexSyncerKey.ReplaceAllLiteralString(redirectTemplate, bidderName)
redirectURL = macroRegexBidderName.ReplaceAllLiteralString(redirectURL, bidderName)
redirectURL = macroRegexSyncType.ReplaceAllLiteralString(redirectURL, syncTypeValue)
redirectURL = macroRegexUserMacro.ReplaceAllLiteralString(redirectURL, syncerEndpoint.UserMacro)
redirectURL = macroRegexExternalHost.ReplaceAllLiteralString(redirectURL, externalURL)
redirectURL = escapeTemplate(redirectURL)

url := macroRegexRedirect.ReplaceAllString(syncerEndpoint.URL, redirectURL)

templateName := strings.ToLower(key) + "_usersync_url"
templateName := strings.ToLower(bidderName) + "_usersync_url"
return template.New(templateName).Parse(url)
}

Expand Down
27 changes: 23 additions & 4 deletions usersync/syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func TestNewSyncer(t *testing.T) {
testCases := []struct {
description string
givenKey string
givenBidderName string
givenIFrameConfig *config.SyncerEndpoint
givenRedirectConfig *config.SyncerEndpoint
givenExternalURL string
Expand All @@ -37,20 +38,23 @@ func TestNewSyncer(t *testing.T) {
{
description: "Missing Key",
givenKey: "",
givenBidderName: "",
givenIFrameConfig: iframeConfig,
givenRedirectConfig: nil,
expectedError: "key is required",
},
{
description: "Missing Endpoints",
givenKey: "a",
givenBidderName: "bidderA",
givenIFrameConfig: nil,
givenRedirectConfig: nil,
expectedError: "at least one endpoint (iframe and/or redirect) is required",
},
{
description: "IFrame & Redirect Endpoints",
givenKey: "a",
givenBidderName: "bidderA",
givenIFrameConfig: iframeConfig,
givenRedirectConfig: redirectConfig,
expectedDefault: SyncTypeIFrame,
Expand All @@ -60,34 +64,39 @@ func TestNewSyncer(t *testing.T) {
{
description: "IFrame - Parse Error",
givenKey: "a",
givenBidderName: "bidderA",
givenIFrameConfig: errParseConfig,
givenRedirectConfig: nil,
expectedError: "iframe template: a_usersync_url:1: function \"malformed\" not defined",
expectedError: "iframe template: biddera_usersync_url:1: function \"malformed\" not defined",
},
{
description: "IFrame - Validation Error",
givenKey: "a",
givenBidderName: "bidderA",
givenIFrameConfig: errInvalidConfig,
givenRedirectConfig: nil,
expectedError: "iframe composed url: \"notAURL:http%3A%2F%2Fhost.com%2Fhost\" is invalid",
},
{
description: "Redirect - Parse Error",
givenKey: "a",
givenBidderName: "bidderA",
givenIFrameConfig: nil,
givenRedirectConfig: errParseConfig,
expectedError: "redirect template: a_usersync_url:1: function \"malformed\" not defined",
expectedError: "redirect template: biddera_usersync_url:1: function \"malformed\" not defined",
},
{
description: "Redirect - Validation Error",
givenKey: "a",
givenBidderName: "bidderA",
givenIFrameConfig: nil,
givenRedirectConfig: errInvalidConfig,
expectedError: "redirect composed url: \"notAURL:http%3A%2F%2Fhost.com%2Fhost\" is invalid",
},
{
description: "Syncer Level External URL",
givenKey: "a",
givenBidderName: "bidderA",
givenExternalURL: "http://syncer.com",
givenIFrameConfig: iframeConfig,
givenRedirectConfig: redirectConfig,
Expand All @@ -106,7 +115,7 @@ func TestNewSyncer(t *testing.T) {
ExternalURL: test.givenExternalURL,
}

result, err := NewSyncer(hostConfig, syncerConfig)
result, err := NewSyncer(hostConfig, syncerConfig, test.givenBidderName)

if test.expectedError == "" {
assert.NoError(t, err, test.description+":err")
Expand Down Expand Up @@ -196,7 +205,7 @@ func TestBuildTemplate(t *testing.T) {
expectedRendered: "hasNoComposedMacros,gdpr=A",
},
{
description: "All Composed Macros",
description: "All Composed Macros - SyncerKey",
givenSyncerEndpoint: config.SyncerEndpoint{
URL: "https://bidder.com/sync?redirect={{.RedirectURL}}",
RedirectURL: "{{.ExternalURL}}/setuid?bidder={{.SyncerKey}}&f={{.SyncType}}&gdpr={{.GDPR}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&uid={{.UserMacro}}",
Expand All @@ -205,6 +214,16 @@ func TestBuildTemplate(t *testing.T) {
},
expectedRendered: "https://bidder.com/sync?redirect=http%3A%2F%2Fsyncer.com%2Fsetuid%3Fbidder%3DanyKey%26f%3Dx%26gdpr%3DA%26gpp%3DD%26gpp_sid%3D1%26uid%3D%24UID%24",
},
{
description: "All Composed Macros - BidderName",
givenSyncerEndpoint: config.SyncerEndpoint{
URL: "https://bidder.com/sync?redirect={{.RedirectURL}}",
RedirectURL: "{{.ExternalURL}}/setuid?bidder={{.BidderName}}&f={{.SyncType}}&gdpr={{.GDPR}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&uid={{.UserMacro}}",
ExternalURL: "http://syncer.com",
UserMacro: "$UID$",
},
expectedRendered: "https://bidder.com/sync?redirect=http%3A%2F%2Fsyncer.com%2Fsetuid%3Fbidder%3DanyKey%26f%3Dx%26gdpr%3DA%26gpp%3DD%26gpp_sid%3D1%26uid%3D%24UID%24",
},
{
description: "Redirect URL + External URL From Host",
givenSyncerEndpoint: config.SyncerEndpoint{
Expand Down
19 changes: 9 additions & 10 deletions usersync/syncersbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,16 @@ func BuildSyncers(hostConfig *config.Configuration, bidderInfos config.BidderInf
continue
}

syncer, err := NewSyncer(hostUserSyncConfig, primaryCfg.cfg)
if err != nil {
errs = append(errs, SyncerBuildError{
Bidder: primaryCfg.name,
SyncerKey: key,
Err: err,
})
continue
}

for _, bidder := range cfgGroup {
syncer, err := NewSyncer(hostUserSyncConfig, primaryCfg.cfg, bidder.name)
if err != nil {
errs = append(errs, SyncerBuildError{
Bidder: primaryCfg.name,
SyncerKey: key,
Err: err,
})
continue
}
syncers[bidder.name] = syncer
}
}
Expand Down
25 changes: 13 additions & 12 deletions usersync/syncersbuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestBuildSyncers(t *testing.T) {
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAPopulated},
expectedIFramesURLs: map[string]string{
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fa%2Fhost",
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder1%2Fhost",
},
},
{
Expand All @@ -64,25 +64,25 @@ func TestBuildSyncers(t *testing.T) {
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAError},
expectedErrors: []string{
"cannot create syncer for bidder bidder1 with key a: iframe template: a_usersync_url:1: function \"xRedirectURL\" not defined",
"cannot create syncer for bidder bidder1 with key a: iframe template: bidder1_usersync_url:1: function \"xRedirectURL\" not defined",
},
},
{
description: "Many - Different Syncers",
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAPopulated, "bidder2": infoKeyBPopulated},
expectedIFramesURLs: map[string]string{
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fa%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fb%2Fhost",
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder1%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder2%2Fhost",
},
},
{
description: "Many - Same Syncers - One Primary",
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAPopulated, "bidder2": infoKeyAEmpty},
expectedIFramesURLs: map[string]string{
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fa%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fa%2Fhost",
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder1%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder2%2Fhost",
},
},
{
Expand All @@ -106,39 +106,40 @@ func TestBuildSyncers(t *testing.T) {
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAEmpty, "bidder2": infoKeyAError},
expectedErrors: []string{
"cannot create syncer for bidder bidder2 with key a: iframe template: a_usersync_url:1: function \"xRedirectURL\" not defined",
"cannot create syncer for bidder bidder2 with key a: iframe template: bidder1_usersync_url:1: function \"xRedirectURL\" not defined",
"cannot create syncer for bidder bidder2 with key a: iframe template: bidder2_usersync_url:1: function \"xRedirectURL\" not defined",
},
},
{
description: "Many - Empty Syncers Ignored",
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": {}, "bidder2": infoKeyBPopulated},
expectedIFramesURLs: map[string]string{
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fb%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder2%2Fhost",
},
},
{
description: "Many - Disabled Syncers Ignored",
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyADisabled, "bidder2": infoKeyBPopulated},
expectedIFramesURLs: map[string]string{
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fb%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder2%2Fhost",
},
},
{
description: "Many - Supports Only Syncers Ignored",
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyASupportsOnly, "bidder2": infoKeyBPopulated},
expectedIFramesURLs: map[string]string{
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fb%2Fhost",
"bidder2": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhost.com%2Fbidder2%2Fhost",
},
},
{
description: "Many - Multiple Errors",
givenConfig: hostConfig,
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAError, "bidder2": infoKeyBEmpty},
expectedErrors: []string{
"cannot create syncer for bidder bidder1 with key a: iframe template: a_usersync_url:1: function \"xRedirectURL\" not defined",
"cannot create syncer for bidder bidder1 with key a: iframe template: bidder1_usersync_url:1: function \"xRedirectURL\" not defined",
"cannot create syncer for bidder bidder2 with key b: at least one endpoint (iframe and/or redirect) is required",
},
},
Expand All @@ -147,7 +148,7 @@ func TestBuildSyncers(t *testing.T) {
givenConfig: config.Configuration{ExternalURL: "http://host.com", UserSync: config.UserSync{ExternalURL: "http://hostoverride.com", RedirectURL: "{{.ExternalURL}}/{{.SyncerKey}}/host"}},
givenBidderInfos: map[string]config.BidderInfo{"bidder1": infoKeyAPopulated},
expectedIFramesURLs: map[string]string{
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhostoverride.com%2Fa%2Fhost",
"bidder1": "https://bidder.com/iframe?redirect=http%3A%2F%2Fhostoverride.com%2Fbidder1%2Fhost",
},
},
}
Expand Down

0 comments on commit 831dd71

Please sign in to comment.