Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use bidder name instead of syncer key #2948

Merged
merged 7 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/bidderinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,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
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption is still generally true, but the bidder name is now important for activity control so this approach is no longer valid.


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*}}`)
SyntaxNode marked this conversation as resolved.
Show resolved Hide resolved
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