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

Extract FPD Merge To Separate Package #3533

Merged
merged 4 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
173 changes: 30 additions & 143 deletions firstpartydata/first_party_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ package firstpartydata

import (
"encoding/json"
"errors"
"fmt"

"github.com/prebid/openrtb/v20/openrtb2"
jsonpatch "gopkg.in/evanphx/json-patch.v4"

"github.com/prebid/prebid-server/v2/errortypes"
"github.com/prebid/prebid-server/v2/openrtb_ext"
"github.com/prebid/prebid-server/v2/ortb"
"github.com/prebid/prebid-server/v2/util/jsonutil"
"github.com/prebid/prebid-server/v2/ortb/merge"
"github.com/prebid/prebid-server/v2/util/ptrutil"
)

var (
ErrBadFPD = errors.New("invalid first party data ext")
)

const (
siteKey = "site"
appKey = "app"
Expand Down Expand Up @@ -195,42 +199,19 @@ func resolveUser(fpdConfig *openrtb_ext.ORTB2, bidRequestUser *openrtb2.User, gl
newUser.Data = openRtbGlobalFPD[userDataKey]
}
if fpdConfigUser != nil {
if err := mergeUser(newUser, fpdConfigUser); err != nil {
if mergedUser, err := merge.User(newUser, fpdConfigUser); err != nil {
if err == merge.ErrBadOverride {
return nil, ErrBadFPD
}
return nil, err
} else {
newUser = mergedUser
Copy link
Contributor

Choose a reason for hiding this comment

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

When err != nil evaluates to true we end up returning nil in both branches, do we really need mergedUser as a separate variable? We could even spare the else clause:

201     if fpdConfigUser != nil {
202 -       if mergedUser, err := merge.User(newUser, fpdConfigUser); err != nil {
    +       if newUser, err := merge.User(newUser, fpdConfigUser); err != nil {
203             if err == merge.ErrBadOverride {
204                 return nil, ErrBadFPD
205             }
206             return nil, err
207 -       } else {
208 -           newUser = mergedUser
209         }
210     }
firstpartydata/first_party_data.go

But I see this pattern repeated in other places below (mergedSite and mergedApp) should we modify to make it leaner? Also, why do merge.User, merge.Site and merge.App are now returning pointers? Is it to check for shared memory issues?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But I see this pattern repeated in other places below (mergedSite and mergedApp) should we modify to make it leaner?

Yes. My original intent was to not assign mergedUser if there is an error, but if there is an error there is no return path for newUser. Updated.

Also, why do merge.User, merge.Site and merge.App are now returning pointers?

They always did this. Before, they changed the memory address of the input pointer. Now it returns a separate pointer and leaves the input alone.

}
}

return newUser, nil
}

func mergeUser(v *openrtb2.User, overrideJSON json.RawMessage) error {
*v = *ortb.CloneUser(v)

// Track EXTs
// It's not necessary to track `ext` fields in array items because the array
// items will be replaced entirely with the override JSON, so no merge is required.
var ext, extGeo extMerger
ext.Track(&v.Ext)
if v.Geo != nil {
extGeo.Track(&v.Geo.Ext)
}

// Merge
if err := jsonutil.Unmarshal(overrideJSON, &v); err != nil {
return err
}

// Merge EXTs
if err := ext.Merge(); err != nil {
return err
}
if err := extGeo.Merge(); err != nil {
return err
}

return nil
}

func resolveSite(fpdConfig *openrtb_ext.ORTB2, bidRequestSite *openrtb2.Site, globalFPD map[string][]byte, openRtbGlobalFPD map[string][]openrtb2.Data, bidderName string) (*openrtb2.Site, error) {
var fpdConfigSite json.RawMessage

Expand Down Expand Up @@ -278,70 +259,23 @@ func resolveSite(fpdConfig *openrtb_ext.ORTB2, bidRequestSite *openrtb2.Site, gl
newSite.Content.Data = openRtbGlobalFPD[siteContentDataKey]
}
if fpdConfigSite != nil {
if err := mergeSite(newSite, fpdConfigSite, bidderName); err != nil {
if mergedSite, err := merge.Site(newSite, fpdConfigSite, bidderName); err != nil {
if err == merge.ErrBadOverride {
return nil, ErrBadFPD
}
return nil, err
} else {
newSite = mergedSite
}
}
return newSite, nil
}

func mergeSite(v *openrtb2.Site, overrideJSON json.RawMessage, bidderName string) error {
*v = *ortb.CloneSite(v)

// Track EXTs
// It's not necessary to track `ext` fields in array items because the array
// items will be replaced entirely with the override JSON, so no merge is required.
var ext, extPublisher, extContent, extContentProducer, extContentNetwork, extContentChannel extMerger
ext.Track(&v.Ext)
if v.Publisher != nil {
extPublisher.Track(&v.Publisher.Ext)
}
if v.Content != nil {
extContent.Track(&v.Content.Ext)
}
if v.Content != nil && v.Content.Producer != nil {
extContentProducer.Track(&v.Content.Producer.Ext)
}
if v.Content != nil && v.Content.Network != nil {
extContentNetwork.Track(&v.Content.Network.Ext)
}
if v.Content != nil && v.Content.Channel != nil {
extContentChannel.Track(&v.Content.Channel.Ext)
}

// Merge
if err := jsonutil.Unmarshal(overrideJSON, &v); err != nil {
return err
}

// Merge EXTs
if err := ext.Merge(); err != nil {
return err
}
if err := extPublisher.Merge(); err != nil {
return err
}
if err := extContent.Merge(); err != nil {
return err
}
if err := extContentProducer.Merge(); err != nil {
return err
}
if err := extContentNetwork.Merge(); err != nil {
return err
}
if err := extContentChannel.Merge(); err != nil {
return err
}

// Re-Validate Site
if v.ID == "" && v.Page == "" {
return &errortypes.BadInput{
Message: fmt.Sprintf("incorrect First Party Data for bidder %s: Site object cannot set empty page if req.site.id is empty", bidderName),
// Re-Validate Site
if newSite.ID == "" && newSite.Page == "" {
return nil, &errortypes.BadInput{
Message: fmt.Sprintf("incorrect First Party Data for bidder %s: Site object cannot set empty page if req.site.id is empty", bidderName),
}
}
}

return nil
return newSite, nil
}

func resolveApp(fpdConfig *openrtb_ext.ORTB2, bidRequestApp *openrtb2.App, globalFPD map[string][]byte, openRtbGlobalFPD map[string][]openrtb2.Data, bidderName string) (*openrtb2.App, error) {
Expand Down Expand Up @@ -394,66 +328,19 @@ func resolveApp(fpdConfig *openrtb_ext.ORTB2, bidRequestApp *openrtb2.App, globa
}

if fpdConfigApp != nil {
if err := mergeApp(newApp, fpdConfigApp); err != nil {
if mergedApp, err := merge.App(newApp, fpdConfigApp); err != nil {
if err == merge.ErrBadOverride {
return nil, ErrBadFPD
}
return nil, err
} else {
newApp = mergedApp
}
}

return newApp, nil
}

func mergeApp(v *openrtb2.App, overrideJSON json.RawMessage) error {
*v = *ortb.CloneApp(v)

// Track EXTs
// It's not necessary to track `ext` fields in array items because the array
// items will be replaced entirely with the override JSON, so no merge is required.
var ext, extPublisher, extContent, extContentProducer, extContentNetwork, extContentChannel extMerger
ext.Track(&v.Ext)
if v.Publisher != nil {
extPublisher.Track(&v.Publisher.Ext)
}
if v.Content != nil {
extContent.Track(&v.Content.Ext)
}
if v.Content != nil && v.Content.Producer != nil {
extContentProducer.Track(&v.Content.Producer.Ext)
}
if v.Content != nil && v.Content.Network != nil {
extContentNetwork.Track(&v.Content.Network.Ext)
}
if v.Content != nil && v.Content.Channel != nil {
extContentChannel.Track(&v.Content.Channel.Ext)
}

// Merge
if err := jsonutil.Unmarshal(overrideJSON, &v); err != nil {
return err
}

// Merge EXTs
if err := ext.Merge(); err != nil {
return err
}
if err := extPublisher.Merge(); err != nil {
return err
}
if err := extContent.Merge(); err != nil {
return err
}
if err := extContentProducer.Merge(); err != nil {
return err
}
if err := extContentNetwork.Merge(); err != nil {
return err
}
if err := extContentChannel.Merge(); err != nil {
return err
}

return nil
}

func buildExtData(data []byte) []byte {
res := make([]byte, 0, len(data)+len(`"{"data":}"`))
res = append(res, []byte(`{"data":`)...)
Expand Down
Loading
Loading