github.com/prebid/prebid-server@v0.275.0/openrtb_ext/request_wrapper.go (about)

     1  package openrtb_ext
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  
     7  	"github.com/prebid/openrtb/v19/openrtb2"
     8  	"github.com/prebid/prebid-server/util/maputil"
     9  	"github.com/prebid/prebid-server/util/ptrutil"
    10  	"github.com/prebid/prebid-server/util/sliceutil"
    11  )
    12  
    13  // RequestWrapper wraps the OpenRTB request to provide a storage location for unmarshalled ext fields, so they
    14  // will not need to be unmarshalled multiple times.
    15  //
    16  // To start with, the wrapper can be created for a request 'req' via:
    17  // reqWrapper := openrtb_ext.RequestWrapper{BidRequest: req}
    18  //
    19  // In order to access an object's ext field, fetch it via:
    20  // userExt, err := reqWrapper.GetUserExt()
    21  // or other Get method as appropriate.
    22  //
    23  // To read or write values, use the Ext objects Get and Set methods. If you need to write to a field that has its own Set
    24  // method, use that to set the value rather than using SetExt() with that change done in the map; when rewritting the
    25  // ext JSON the code will overwrite the the values in the map with the values stored in the seperate fields.
    26  //
    27  // userPrebid := userExt.GetPrebid()
    28  // userExt.SetConsent(consentString)
    29  //
    30  // The GetExt() and SetExt() should only be used to access fields that have not already been resolved in the object.
    31  // Using SetExt() at all is a strong hint that the ext object should be extended to support the new fields being set
    32  // in the map.
    33  //
    34  // NOTE: The RequestWrapper methods (particularly the ones calling (un)Marshal are not thread safe)
    35  type RequestWrapper struct {
    36  	*openrtb2.BidRequest
    37  	impWrappers         []*ImpWrapper
    38  	impWrappersAccessed bool
    39  	userExt             *UserExt
    40  	deviceExt           *DeviceExt
    41  	requestExt          *RequestExt
    42  	appExt              *AppExt
    43  	regExt              *RegExt
    44  	siteExt             *SiteExt
    45  	sourceExt           *SourceExt
    46  }
    47  
    48  const (
    49  	jsonEmptyObjectLength               = 2
    50  	consentedProvidersSettingsStringKey = "ConsentedProvidersSettings"
    51  	consentedProvidersSettingsListKey   = "consented_providers_settings"
    52  	consentKey                          = "consent"
    53  	ampKey                              = "amp"
    54  	eidsKey                             = "eids"
    55  	gdprKey                             = "gdpr"
    56  	prebidKey                           = "prebid"
    57  	dataKey                             = "data"
    58  	schainKey                           = "schain"
    59  	us_privacyKey                       = "us_privacy"
    60  )
    61  
    62  // LenImp returns the number of impressions without causing the creation of ImpWrapper objects.
    63  func (rw *RequestWrapper) LenImp() int {
    64  	if rw.impWrappersAccessed {
    65  		return len(rw.impWrappers)
    66  	}
    67  
    68  	return len(rw.Imp)
    69  }
    70  
    71  func (rw *RequestWrapper) GetImp() []*ImpWrapper {
    72  	if rw.impWrappersAccessed {
    73  		return rw.impWrappers
    74  	}
    75  
    76  	// There is minimal difference between nil and empty arrays in Go, but it matters
    77  	// for json encoding. In practice there will always be at least one impression,
    78  	// so this is an optimization for tests with (appropriately) incomplete requests.
    79  	if rw.Imp != nil {
    80  		rw.impWrappers = make([]*ImpWrapper, len(rw.Imp))
    81  		for i := range rw.Imp {
    82  			rw.impWrappers[i] = &ImpWrapper{Imp: &rw.Imp[i]}
    83  		}
    84  	}
    85  
    86  	rw.impWrappersAccessed = true
    87  
    88  	return rw.impWrappers
    89  }
    90  
    91  func (rw *RequestWrapper) SetImp(imps []*ImpWrapper) {
    92  	rw.impWrappers = imps
    93  	rw.impWrappersAccessed = true
    94  }
    95  
    96  func (rw *RequestWrapper) GetUserExt() (*UserExt, error) {
    97  	if rw.userExt != nil {
    98  		return rw.userExt, nil
    99  	}
   100  	rw.userExt = &UserExt{}
   101  	if rw.BidRequest == nil || rw.User == nil || rw.User.Ext == nil {
   102  		return rw.userExt, rw.userExt.unmarshal(json.RawMessage{})
   103  	}
   104  
   105  	return rw.userExt, rw.userExt.unmarshal(rw.User.Ext)
   106  }
   107  
   108  func (rw *RequestWrapper) GetDeviceExt() (*DeviceExt, error) {
   109  	if rw.deviceExt != nil {
   110  		return rw.deviceExt, nil
   111  	}
   112  	rw.deviceExt = &DeviceExt{}
   113  	if rw.BidRequest == nil || rw.Device == nil || rw.Device.Ext == nil {
   114  		return rw.deviceExt, rw.deviceExt.unmarshal(json.RawMessage{})
   115  	}
   116  	return rw.deviceExt, rw.deviceExt.unmarshal(rw.Device.Ext)
   117  }
   118  
   119  func (rw *RequestWrapper) GetRequestExt() (*RequestExt, error) {
   120  	if rw.requestExt != nil {
   121  		return rw.requestExt, nil
   122  	}
   123  	rw.requestExt = &RequestExt{}
   124  	if rw.BidRequest == nil || rw.Ext == nil {
   125  		return rw.requestExt, rw.requestExt.unmarshal(json.RawMessage{})
   126  	}
   127  	return rw.requestExt, rw.requestExt.unmarshal(rw.Ext)
   128  }
   129  
   130  func (rw *RequestWrapper) GetAppExt() (*AppExt, error) {
   131  	if rw.appExt != nil {
   132  		return rw.appExt, nil
   133  	}
   134  	rw.appExt = &AppExt{}
   135  	if rw.BidRequest == nil || rw.App == nil || rw.App.Ext == nil {
   136  		return rw.appExt, rw.appExt.unmarshal(json.RawMessage{})
   137  	}
   138  	return rw.appExt, rw.appExt.unmarshal(rw.App.Ext)
   139  }
   140  
   141  func (rw *RequestWrapper) GetRegExt() (*RegExt, error) {
   142  	if rw.regExt != nil {
   143  		return rw.regExt, nil
   144  	}
   145  	rw.regExt = &RegExt{}
   146  	if rw.BidRequest == nil || rw.Regs == nil || rw.Regs.Ext == nil {
   147  		return rw.regExt, rw.regExt.unmarshal(json.RawMessage{})
   148  	}
   149  	return rw.regExt, rw.regExt.unmarshal(rw.Regs.Ext)
   150  }
   151  
   152  func (rw *RequestWrapper) GetSiteExt() (*SiteExt, error) {
   153  	if rw.siteExt != nil {
   154  		return rw.siteExt, nil
   155  	}
   156  	rw.siteExt = &SiteExt{}
   157  	if rw.BidRequest == nil || rw.Site == nil || rw.Site.Ext == nil {
   158  		return rw.siteExt, rw.siteExt.unmarshal(json.RawMessage{})
   159  	}
   160  	return rw.siteExt, rw.siteExt.unmarshal(rw.Site.Ext)
   161  }
   162  
   163  func (rw *RequestWrapper) GetSourceExt() (*SourceExt, error) {
   164  	if rw.sourceExt != nil {
   165  		return rw.sourceExt, nil
   166  	}
   167  	rw.sourceExt = &SourceExt{}
   168  	if rw.BidRequest == nil || rw.Source == nil || rw.Source.Ext == nil {
   169  		return rw.sourceExt, rw.sourceExt.unmarshal(json.RawMessage{})
   170  	}
   171  	return rw.sourceExt, rw.sourceExt.unmarshal(rw.Source.Ext)
   172  }
   173  
   174  func (rw *RequestWrapper) RebuildRequest() error {
   175  	if rw.BidRequest == nil {
   176  		return errors.New("Requestwrapper RebuildRequest called on a nil BidRequest")
   177  	}
   178  
   179  	if err := rw.rebuildImp(); err != nil {
   180  		return err
   181  	}
   182  	if err := rw.rebuildUserExt(); err != nil {
   183  		return err
   184  	}
   185  	if err := rw.rebuildDeviceExt(); err != nil {
   186  		return err
   187  	}
   188  	if err := rw.rebuildRequestExt(); err != nil {
   189  		return err
   190  	}
   191  	if err := rw.rebuildAppExt(); err != nil {
   192  		return err
   193  	}
   194  	if err := rw.rebuildRegExt(); err != nil {
   195  		return err
   196  	}
   197  	if err := rw.rebuildSiteExt(); err != nil {
   198  		return err
   199  	}
   200  	if err := rw.rebuildSourceExt(); err != nil {
   201  		return err
   202  	}
   203  
   204  	return nil
   205  }
   206  
   207  func (rw *RequestWrapper) rebuildImp() error {
   208  	if !rw.impWrappersAccessed {
   209  		return nil
   210  	}
   211  
   212  	if rw.impWrappers == nil {
   213  		rw.Imp = nil
   214  		return nil
   215  	}
   216  
   217  	rw.Imp = make([]openrtb2.Imp, len(rw.impWrappers))
   218  	for i := range rw.impWrappers {
   219  		if err := rw.impWrappers[i].RebuildImp(); err != nil {
   220  			return err
   221  		}
   222  		rw.Imp[i] = *rw.impWrappers[i].Imp
   223  	}
   224  
   225  	return nil
   226  }
   227  
   228  func (rw *RequestWrapper) rebuildUserExt() error {
   229  	if rw.userExt == nil || !rw.userExt.Dirty() {
   230  		return nil
   231  	}
   232  
   233  	userJson, err := rw.userExt.marshal()
   234  	if err != nil {
   235  		return err
   236  	}
   237  
   238  	if userJson != nil && rw.User == nil {
   239  		rw.User = &openrtb2.User{Ext: userJson}
   240  	} else if rw.User != nil {
   241  		rw.User.Ext = userJson
   242  	}
   243  
   244  	return nil
   245  }
   246  
   247  func (rw *RequestWrapper) rebuildDeviceExt() error {
   248  	if rw.deviceExt == nil || !rw.deviceExt.Dirty() {
   249  		return nil
   250  	}
   251  
   252  	deviceJson, err := rw.deviceExt.marshal()
   253  	if err != nil {
   254  		return err
   255  	}
   256  
   257  	if deviceJson != nil && rw.Device == nil {
   258  		rw.Device = &openrtb2.Device{Ext: deviceJson}
   259  	} else if rw.Device != nil {
   260  		rw.Device.Ext = deviceJson
   261  	}
   262  
   263  	return nil
   264  }
   265  
   266  func (rw *RequestWrapper) rebuildRequestExt() error {
   267  	if rw.requestExt == nil || !rw.requestExt.Dirty() {
   268  		return nil
   269  	}
   270  
   271  	requestJson, err := rw.requestExt.marshal()
   272  	if err != nil {
   273  		return err
   274  	}
   275  
   276  	rw.Ext = requestJson
   277  
   278  	return nil
   279  }
   280  
   281  func (rw *RequestWrapper) rebuildAppExt() error {
   282  	if rw.appExt == nil || !rw.appExt.Dirty() {
   283  		return nil
   284  	}
   285  
   286  	appJson, err := rw.appExt.marshal()
   287  	if err != nil {
   288  		return err
   289  	}
   290  
   291  	if appJson != nil && rw.App == nil {
   292  		rw.App = &openrtb2.App{Ext: appJson}
   293  	} else if rw.App != nil {
   294  		rw.App.Ext = appJson
   295  	}
   296  
   297  	return nil
   298  }
   299  
   300  func (rw *RequestWrapper) rebuildRegExt() error {
   301  	if rw.regExt == nil || !rw.regExt.Dirty() {
   302  		return nil
   303  	}
   304  
   305  	regsJson, err := rw.regExt.marshal()
   306  	if err != nil {
   307  		return err
   308  	}
   309  
   310  	if regsJson != nil && rw.Regs == nil {
   311  		rw.Regs = &openrtb2.Regs{Ext: regsJson}
   312  	} else if rw.Regs != nil {
   313  		rw.Regs.Ext = regsJson
   314  	}
   315  
   316  	return nil
   317  }
   318  
   319  func (rw *RequestWrapper) rebuildSiteExt() error {
   320  	if rw.siteExt == nil || !rw.siteExt.Dirty() {
   321  		return nil
   322  	}
   323  
   324  	siteJson, err := rw.siteExt.marshal()
   325  	if err != nil {
   326  		return err
   327  	}
   328  
   329  	if siteJson != nil && rw.Site == nil {
   330  		rw.Site = &openrtb2.Site{Ext: siteJson}
   331  	} else if rw.Site != nil {
   332  		rw.Site.Ext = siteJson
   333  	}
   334  
   335  	return nil
   336  }
   337  
   338  func (rw *RequestWrapper) rebuildSourceExt() error {
   339  	if rw.sourceExt == nil || !rw.sourceExt.Dirty() {
   340  		return nil
   341  	}
   342  
   343  	sourceJson, err := rw.sourceExt.marshal()
   344  	if err != nil {
   345  		return err
   346  	}
   347  
   348  	if sourceJson != nil && rw.Source == nil {
   349  		rw.Source = &openrtb2.Source{Ext: sourceJson}
   350  	} else if rw.Source != nil {
   351  		rw.Source.Ext = sourceJson
   352  	}
   353  
   354  	return nil
   355  }
   356  
   357  func (rw *RequestWrapper) Clone() *RequestWrapper {
   358  	if rw == nil {
   359  		return nil
   360  	}
   361  	clone := *rw
   362  	newImpWrappers := make([]*ImpWrapper, len(rw.impWrappers))
   363  	for i, iw := range rw.impWrappers {
   364  		newImpWrappers[i] = iw.Clone()
   365  	}
   366  	clone.impWrappers = newImpWrappers
   367  	clone.userExt = rw.userExt.Clone()
   368  	clone.deviceExt = rw.deviceExt.Clone()
   369  	clone.requestExt = rw.requestExt.Clone()
   370  	clone.appExt = rw.appExt.Clone()
   371  	clone.regExt = rw.regExt.Clone()
   372  	clone.siteExt = rw.siteExt.Clone()
   373  	clone.sourceExt = rw.sourceExt.Clone()
   374  
   375  	return &clone
   376  }
   377  
   378  // ---------------------------------------------------------------
   379  // UserExt provides an interface for request.user.ext
   380  // ---------------------------------------------------------------
   381  
   382  type UserExt struct {
   383  	ext                                map[string]json.RawMessage
   384  	extDirty                           bool
   385  	consent                            *string
   386  	consentDirty                       bool
   387  	prebid                             *ExtUserPrebid
   388  	prebidDirty                        bool
   389  	eids                               *[]openrtb2.EID
   390  	eidsDirty                          bool
   391  	consentedProvidersSettingsIn       *ConsentedProvidersSettingsIn
   392  	consentedProvidersSettingsInDirty  bool
   393  	consentedProvidersSettingsOut      *ConsentedProvidersSettingsOut
   394  	consentedProvidersSettingsOutDirty bool
   395  }
   396  
   397  func (ue *UserExt) unmarshal(extJson json.RawMessage) error {
   398  	if len(ue.ext) != 0 || ue.Dirty() {
   399  		return nil
   400  	}
   401  
   402  	ue.ext = make(map[string]json.RawMessage)
   403  
   404  	if len(extJson) == 0 {
   405  		return nil
   406  	}
   407  
   408  	if err := json.Unmarshal(extJson, &ue.ext); err != nil {
   409  		return err
   410  	}
   411  
   412  	consentJson, hasConsent := ue.ext[consentKey]
   413  	if hasConsent {
   414  		if err := json.Unmarshal(consentJson, &ue.consent); err != nil {
   415  			return err
   416  		}
   417  	}
   418  
   419  	prebidJson, hasPrebid := ue.ext[prebidKey]
   420  	if hasPrebid {
   421  		ue.prebid = &ExtUserPrebid{}
   422  		if err := json.Unmarshal(prebidJson, ue.prebid); err != nil {
   423  			return err
   424  		}
   425  	}
   426  
   427  	eidsJson, hasEids := ue.ext[eidsKey]
   428  	if hasEids {
   429  		ue.eids = &[]openrtb2.EID{}
   430  		if err := json.Unmarshal(eidsJson, ue.eids); err != nil {
   431  			return err
   432  		}
   433  	}
   434  
   435  	if consentedProviderSettingsJson, hasCPSettings := ue.ext[consentedProvidersSettingsStringKey]; hasCPSettings {
   436  		ue.consentedProvidersSettingsIn = &ConsentedProvidersSettingsIn{}
   437  		if err := json.Unmarshal(consentedProviderSettingsJson, ue.consentedProvidersSettingsIn); err != nil {
   438  			return err
   439  		}
   440  	}
   441  
   442  	if consentedProviderSettingsJson, hasCPSettings := ue.ext[consentedProvidersSettingsListKey]; hasCPSettings {
   443  		ue.consentedProvidersSettingsOut = &ConsentedProvidersSettingsOut{}
   444  		if err := json.Unmarshal(consentedProviderSettingsJson, ue.consentedProvidersSettingsOut); err != nil {
   445  			return err
   446  		}
   447  	}
   448  
   449  	return nil
   450  }
   451  
   452  func (ue *UserExt) marshal() (json.RawMessage, error) {
   453  	if ue.consentDirty {
   454  		if ue.consent != nil && len(*ue.consent) > 0 {
   455  			consentJson, err := json.Marshal(ue.consent)
   456  			if err != nil {
   457  				return nil, err
   458  			}
   459  			ue.ext[consentKey] = json.RawMessage(consentJson)
   460  		} else {
   461  			delete(ue.ext, consentKey)
   462  		}
   463  		ue.consentDirty = false
   464  	}
   465  
   466  	if ue.prebidDirty {
   467  		if ue.prebid != nil {
   468  			prebidJson, err := json.Marshal(ue.prebid)
   469  			if err != nil {
   470  				return nil, err
   471  			}
   472  			if len(prebidJson) > jsonEmptyObjectLength {
   473  				ue.ext[prebidKey] = json.RawMessage(prebidJson)
   474  			} else {
   475  				delete(ue.ext, prebidKey)
   476  			}
   477  		} else {
   478  			delete(ue.ext, prebidKey)
   479  		}
   480  		ue.prebidDirty = false
   481  	}
   482  
   483  	if ue.consentedProvidersSettingsInDirty {
   484  		if ue.consentedProvidersSettingsIn != nil {
   485  			cpSettingsJson, err := json.Marshal(ue.consentedProvidersSettingsIn)
   486  			if err != nil {
   487  				return nil, err
   488  			}
   489  			if len(cpSettingsJson) > jsonEmptyObjectLength {
   490  				ue.ext[consentedProvidersSettingsStringKey] = json.RawMessage(cpSettingsJson)
   491  			} else {
   492  				delete(ue.ext, consentedProvidersSettingsStringKey)
   493  			}
   494  		} else {
   495  			delete(ue.ext, consentedProvidersSettingsStringKey)
   496  		}
   497  		ue.consentedProvidersSettingsInDirty = false
   498  	}
   499  
   500  	if ue.consentedProvidersSettingsOutDirty {
   501  		if ue.consentedProvidersSettingsOut != nil {
   502  			cpSettingsJson, err := json.Marshal(ue.consentedProvidersSettingsOut)
   503  			if err != nil {
   504  				return nil, err
   505  			}
   506  			if len(cpSettingsJson) > jsonEmptyObjectLength {
   507  				ue.ext[consentedProvidersSettingsListKey] = json.RawMessage(cpSettingsJson)
   508  			} else {
   509  				delete(ue.ext, consentedProvidersSettingsListKey)
   510  			}
   511  		} else {
   512  			delete(ue.ext, consentedProvidersSettingsListKey)
   513  		}
   514  		ue.consentedProvidersSettingsOutDirty = false
   515  	}
   516  
   517  	if ue.eidsDirty {
   518  		if ue.eids != nil && len(*ue.eids) > 0 {
   519  			eidsJson, err := json.Marshal(ue.eids)
   520  			if err != nil {
   521  				return nil, err
   522  			}
   523  			ue.ext[eidsKey] = json.RawMessage(eidsJson)
   524  		} else {
   525  			delete(ue.ext, eidsKey)
   526  		}
   527  		ue.eidsDirty = false
   528  	}
   529  
   530  	ue.extDirty = false
   531  	if len(ue.ext) == 0 {
   532  		return nil, nil
   533  	}
   534  	return json.Marshal(ue.ext)
   535  }
   536  
   537  func (ue *UserExt) Dirty() bool {
   538  	return ue.extDirty || ue.eidsDirty || ue.prebidDirty || ue.consentDirty || ue.consentedProvidersSettingsInDirty || ue.consentedProvidersSettingsOutDirty
   539  }
   540  
   541  func (ue *UserExt) GetExt() map[string]json.RawMessage {
   542  	ext := make(map[string]json.RawMessage)
   543  	for k, v := range ue.ext {
   544  		ext[k] = v
   545  	}
   546  	return ext
   547  }
   548  
   549  func (ue *UserExt) SetExt(ext map[string]json.RawMessage) {
   550  	ue.ext = ext
   551  	ue.extDirty = true
   552  }
   553  
   554  func (ue *UserExt) GetConsent() *string {
   555  	if ue.consent == nil {
   556  		return nil
   557  	}
   558  	consent := *ue.consent
   559  	return &consent
   560  }
   561  
   562  func (ue *UserExt) SetConsent(consent *string) {
   563  	ue.consent = consent
   564  	ue.consentDirty = true
   565  }
   566  
   567  // GetConsentedProvidersSettingsIn() returns a reference to a copy of ConsentedProvidersSettingsIn, a struct that
   568  // has a string field formatted as a Google's Additional Consent string
   569  func (ue *UserExt) GetConsentedProvidersSettingsIn() *ConsentedProvidersSettingsIn {
   570  	if ue.consentedProvidersSettingsIn == nil {
   571  		return nil
   572  	}
   573  	consentedProvidersSettingsIn := *ue.consentedProvidersSettingsIn
   574  	return &consentedProvidersSettingsIn
   575  }
   576  
   577  // SetConsentedProvidersSettingsIn() sets ConsentedProvidersSettingsIn, a struct that
   578  // has a string field formatted as a Google's Additional Consent string
   579  func (ue *UserExt) SetConsentedProvidersSettingsIn(cpSettings *ConsentedProvidersSettingsIn) {
   580  	ue.consentedProvidersSettingsIn = cpSettings
   581  	ue.consentedProvidersSettingsInDirty = true
   582  }
   583  
   584  // GetConsentedProvidersSettingsOut() returns a reference to a copy of ConsentedProvidersSettingsOut, a struct that
   585  // has an int array field listing Google's Additional Consent string elements
   586  func (ue *UserExt) GetConsentedProvidersSettingsOut() *ConsentedProvidersSettingsOut {
   587  	if ue.consentedProvidersSettingsOut == nil {
   588  		return nil
   589  	}
   590  	consentedProvidersSettingsOut := *ue.consentedProvidersSettingsOut
   591  	return &consentedProvidersSettingsOut
   592  }
   593  
   594  // SetConsentedProvidersSettingsIn() sets ConsentedProvidersSettingsOut, a struct that
   595  // has an int array field listing Google's Additional Consent string elements. This
   596  // function overrides an existing ConsentedProvidersSettingsOut object, if any
   597  func (ue *UserExt) SetConsentedProvidersSettingsOut(cpSettings *ConsentedProvidersSettingsOut) {
   598  	if cpSettings == nil {
   599  		return
   600  	}
   601  
   602  	ue.consentedProvidersSettingsOut = cpSettings
   603  	ue.consentedProvidersSettingsOutDirty = true
   604  	return
   605  }
   606  
   607  func (ue *UserExt) GetPrebid() *ExtUserPrebid {
   608  	if ue.prebid == nil {
   609  		return nil
   610  	}
   611  	prebid := *ue.prebid
   612  	return &prebid
   613  }
   614  
   615  func (ue *UserExt) SetPrebid(prebid *ExtUserPrebid) {
   616  	ue.prebid = prebid
   617  	ue.prebidDirty = true
   618  }
   619  
   620  func (ue *UserExt) GetEid() *[]openrtb2.EID {
   621  	if ue.eids == nil {
   622  		return nil
   623  	}
   624  	eids := *ue.eids
   625  	return &eids
   626  }
   627  
   628  func (ue *UserExt) SetEid(eid *[]openrtb2.EID) {
   629  	ue.eids = eid
   630  	ue.eidsDirty = true
   631  }
   632  
   633  func (ue *UserExt) Clone() *UserExt {
   634  	if ue == nil {
   635  		return nil
   636  	}
   637  	clone := *ue
   638  	clone.ext = maputil.Clone(ue.ext)
   639  
   640  	if ue.consent != nil {
   641  		clonedConsent := *ue.consent
   642  		clone.consent = &clonedConsent
   643  	}
   644  
   645  	if ue.prebid != nil {
   646  		clone.prebid = &ExtUserPrebid{}
   647  		clone.prebid.BuyerUIDs = maputil.Clone(ue.prebid.BuyerUIDs)
   648  	}
   649  
   650  	if ue.eids != nil {
   651  		clonedEids := make([]openrtb2.EID, len(*ue.eids))
   652  		for i, eid := range *ue.eids {
   653  			newEid := eid
   654  			newEid.UIDs = sliceutil.Clone(eid.UIDs)
   655  			clonedEids[i] = newEid
   656  		}
   657  		clone.eids = &clonedEids
   658  	}
   659  
   660  	if ue.consentedProvidersSettingsIn != nil {
   661  		clone.consentedProvidersSettingsIn = &ConsentedProvidersSettingsIn{ConsentedProvidersString: ue.consentedProvidersSettingsIn.ConsentedProvidersString}
   662  	}
   663  	if ue.consentedProvidersSettingsOut != nil {
   664  		clone.consentedProvidersSettingsOut = &ConsentedProvidersSettingsOut{ConsentedProvidersList: sliceutil.Clone(ue.consentedProvidersSettingsOut.ConsentedProvidersList)}
   665  	}
   666  
   667  	return &clone
   668  }
   669  
   670  // ---------------------------------------------------------------
   671  // RequestExt provides an interface for request.ext
   672  // ---------------------------------------------------------------
   673  
   674  type RequestExt struct {
   675  	ext         map[string]json.RawMessage
   676  	extDirty    bool
   677  	prebid      *ExtRequestPrebid
   678  	prebidDirty bool
   679  	schain      *openrtb2.SupplyChain // ORTB 2.4 location
   680  	schainDirty bool
   681  }
   682  
   683  func (re *RequestExt) unmarshal(extJson json.RawMessage) error {
   684  	if len(re.ext) != 0 || re.Dirty() {
   685  		return nil
   686  	}
   687  
   688  	re.ext = make(map[string]json.RawMessage)
   689  
   690  	if len(extJson) == 0 {
   691  		return nil
   692  	}
   693  
   694  	if err := json.Unmarshal(extJson, &re.ext); err != nil {
   695  		return err
   696  	}
   697  
   698  	prebidJson, hasPrebid := re.ext[prebidKey]
   699  	if hasPrebid {
   700  		re.prebid = &ExtRequestPrebid{}
   701  		if err := json.Unmarshal(prebidJson, re.prebid); err != nil {
   702  			return err
   703  		}
   704  	}
   705  
   706  	schainJson, hasSChain := re.ext[schainKey]
   707  	if hasSChain {
   708  		re.schain = &openrtb2.SupplyChain{}
   709  		if err := json.Unmarshal(schainJson, re.schain); err != nil {
   710  			return err
   711  		}
   712  	}
   713  
   714  	return nil
   715  }
   716  
   717  func (re *RequestExt) marshal() (json.RawMessage, error) {
   718  	if re.prebidDirty {
   719  		if re.prebid != nil {
   720  			prebidJson, err := json.Marshal(re.prebid)
   721  			if err != nil {
   722  				return nil, err
   723  			}
   724  			if len(prebidJson) > jsonEmptyObjectLength {
   725  				re.ext[prebidKey] = json.RawMessage(prebidJson)
   726  			} else {
   727  				delete(re.ext, prebidKey)
   728  			}
   729  		} else {
   730  			delete(re.ext, prebidKey)
   731  		}
   732  		re.prebidDirty = false
   733  	}
   734  
   735  	if re.schainDirty {
   736  		if re.schain != nil {
   737  			schainJson, err := json.Marshal(re.schain)
   738  			if err != nil {
   739  				return nil, err
   740  			}
   741  			if len(schainJson) > jsonEmptyObjectLength {
   742  				re.ext[schainKey] = json.RawMessage(schainJson)
   743  			} else {
   744  				delete(re.ext, schainKey)
   745  			}
   746  		} else {
   747  			delete(re.ext, schainKey)
   748  		}
   749  		re.schainDirty = false
   750  	}
   751  
   752  	re.extDirty = false
   753  	if len(re.ext) == 0 {
   754  		return nil, nil
   755  	}
   756  	return json.Marshal(re.ext)
   757  }
   758  
   759  func (re *RequestExt) Dirty() bool {
   760  	return re.extDirty || re.prebidDirty || re.schainDirty
   761  }
   762  
   763  func (re *RequestExt) GetExt() map[string]json.RawMessage {
   764  	ext := make(map[string]json.RawMessage)
   765  	for k, v := range re.ext {
   766  		ext[k] = v
   767  	}
   768  	return ext
   769  }
   770  
   771  func (re *RequestExt) SetExt(ext map[string]json.RawMessage) {
   772  	re.ext = ext
   773  	re.extDirty = true
   774  }
   775  
   776  func (re *RequestExt) GetPrebid() *ExtRequestPrebid {
   777  	if re == nil || re.prebid == nil {
   778  		return nil
   779  	}
   780  	prebid := *re.prebid
   781  	return &prebid
   782  }
   783  
   784  func (re *RequestExt) SetPrebid(prebid *ExtRequestPrebid) {
   785  	re.prebid = prebid
   786  	re.prebidDirty = true
   787  }
   788  
   789  // These schain methods on the request.ext are only for ORTB 2.4 backwards compatibility and
   790  // should not be used for any other purposes. To access ORTB 2.5 schains, see source.ext.schain
   791  // or request.ext.prebid.schains.
   792  func (re *RequestExt) GetSChain() *openrtb2.SupplyChain {
   793  	if re.schain == nil {
   794  		return nil
   795  	}
   796  	schain := *re.schain
   797  	return &schain
   798  }
   799  
   800  func (re *RequestExt) SetSChain(schain *openrtb2.SupplyChain) {
   801  	re.schain = schain
   802  	re.schainDirty = true
   803  }
   804  
   805  func (re *RequestExt) Clone() *RequestExt {
   806  	if re == nil {
   807  		return nil
   808  	}
   809  
   810  	clone := *re
   811  	clone.ext = maputil.Clone(re.ext)
   812  
   813  	if re.prebid != nil {
   814  		clone.prebid = re.prebid.Clone()
   815  	}
   816  
   817  	clone.schain = cloneSupplyChain(re.schain)
   818  
   819  	return &clone
   820  }
   821  
   822  // ---------------------------------------------------------------
   823  // DeviceExt provides an interface for request.device.ext
   824  // ---------------------------------------------------------------
   825  // NOTE: openrtb_ext/device.go:ParseDeviceExtATTS() uses ext.atts, as read only, via jsonparser, only for IOS.
   826  // Doesn't seem like we will see any performance savings by parsing atts at this point, and as it is read only,
   827  // we don't need to worry about write conflicts. Note here in case additional uses of atts evolve as things progress.
   828  // ---------------------------------------------------------------
   829  
   830  type DeviceExt struct {
   831  	ext         map[string]json.RawMessage
   832  	extDirty    bool
   833  	prebid      *ExtDevicePrebid
   834  	prebidDirty bool
   835  }
   836  
   837  func (de *DeviceExt) unmarshal(extJson json.RawMessage) error {
   838  	if len(de.ext) != 0 || de.Dirty() {
   839  		return nil
   840  	}
   841  
   842  	de.ext = make(map[string]json.RawMessage)
   843  
   844  	if len(extJson) == 0 {
   845  		return nil
   846  	}
   847  
   848  	if err := json.Unmarshal(extJson, &de.ext); err != nil {
   849  		return err
   850  	}
   851  
   852  	prebidJson, hasPrebid := de.ext[prebidKey]
   853  	if hasPrebid {
   854  		de.prebid = &ExtDevicePrebid{}
   855  		if err := json.Unmarshal(prebidJson, de.prebid); err != nil {
   856  			return err
   857  		}
   858  	}
   859  
   860  	return nil
   861  }
   862  
   863  func (de *DeviceExt) marshal() (json.RawMessage, error) {
   864  	if de.prebidDirty {
   865  		if de.prebid != nil {
   866  			prebidJson, err := json.Marshal(de.prebid)
   867  			if err != nil {
   868  				return nil, err
   869  			}
   870  			if len(prebidJson) > jsonEmptyObjectLength {
   871  				de.ext[prebidKey] = json.RawMessage(prebidJson)
   872  			} else {
   873  				delete(de.ext, prebidKey)
   874  			}
   875  		} else {
   876  			delete(de.ext, prebidKey)
   877  		}
   878  		de.prebidDirty = false
   879  	}
   880  
   881  	de.extDirty = false
   882  	if len(de.ext) == 0 {
   883  		return nil, nil
   884  	}
   885  	return json.Marshal(de.ext)
   886  }
   887  
   888  func (de *DeviceExt) Dirty() bool {
   889  	return de.extDirty || de.prebidDirty
   890  }
   891  
   892  func (de *DeviceExt) GetExt() map[string]json.RawMessage {
   893  	ext := make(map[string]json.RawMessage)
   894  	for k, v := range de.ext {
   895  		ext[k] = v
   896  	}
   897  	return ext
   898  }
   899  
   900  func (de *DeviceExt) SetExt(ext map[string]json.RawMessage) {
   901  	de.ext = ext
   902  	de.extDirty = true
   903  }
   904  
   905  func (de *DeviceExt) GetPrebid() *ExtDevicePrebid {
   906  	if de.prebid == nil {
   907  		return nil
   908  	}
   909  	prebid := *de.prebid
   910  	return &prebid
   911  }
   912  
   913  func (de *DeviceExt) SetPrebid(prebid *ExtDevicePrebid) {
   914  	de.prebid = prebid
   915  	de.prebidDirty = true
   916  }
   917  
   918  func (de *DeviceExt) Clone() *DeviceExt {
   919  	if de == nil {
   920  		return nil
   921  	}
   922  
   923  	clone := *de
   924  	clone.ext = maputil.Clone(de.ext)
   925  
   926  	if de.prebid != nil {
   927  		clonedPrebid := *de.prebid
   928  		if clonedPrebid.Interstitial != nil {
   929  			clonedInterstitial := *de.prebid.Interstitial
   930  			clonedPrebid.Interstitial = &clonedInterstitial
   931  		}
   932  		clone.prebid = &clonedPrebid
   933  	}
   934  
   935  	return &clone
   936  }
   937  
   938  // ---------------------------------------------------------------
   939  // AppExt provides an interface for request.app.ext
   940  // ---------------------------------------------------------------
   941  
   942  type AppExt struct {
   943  	ext         map[string]json.RawMessage
   944  	extDirty    bool
   945  	prebid      *ExtAppPrebid
   946  	prebidDirty bool
   947  }
   948  
   949  func (ae *AppExt) unmarshal(extJson json.RawMessage) error {
   950  	if len(ae.ext) != 0 || ae.Dirty() {
   951  		return nil
   952  	}
   953  
   954  	ae.ext = make(map[string]json.RawMessage)
   955  
   956  	if len(extJson) == 0 {
   957  		return nil
   958  	}
   959  
   960  	if err := json.Unmarshal(extJson, &ae.ext); err != nil {
   961  		return err
   962  	}
   963  
   964  	prebidJson, hasPrebid := ae.ext[prebidKey]
   965  	if hasPrebid {
   966  		ae.prebid = &ExtAppPrebid{}
   967  		if err := json.Unmarshal(prebidJson, ae.prebid); err != nil {
   968  			return err
   969  		}
   970  	}
   971  
   972  	return nil
   973  }
   974  
   975  func (ae *AppExt) marshal() (json.RawMessage, error) {
   976  	if ae.prebidDirty {
   977  		if ae.prebid != nil {
   978  			prebidJson, err := json.Marshal(ae.prebid)
   979  			if err != nil {
   980  				return nil, err
   981  			}
   982  			if len(prebidJson) > jsonEmptyObjectLength {
   983  				ae.ext[prebidKey] = json.RawMessage(prebidJson)
   984  			} else {
   985  				delete(ae.ext, prebidKey)
   986  			}
   987  		} else {
   988  			delete(ae.ext, prebidKey)
   989  		}
   990  		ae.prebidDirty = false
   991  	}
   992  
   993  	ae.extDirty = false
   994  	if len(ae.ext) == 0 {
   995  		return nil, nil
   996  	}
   997  	return json.Marshal(ae.ext)
   998  }
   999  
  1000  func (ae *AppExt) Dirty() bool {
  1001  	return ae.extDirty || ae.prebidDirty
  1002  }
  1003  
  1004  func (ae *AppExt) GetExt() map[string]json.RawMessage {
  1005  	ext := make(map[string]json.RawMessage)
  1006  	for k, v := range ae.ext {
  1007  		ext[k] = v
  1008  	}
  1009  	return ext
  1010  }
  1011  
  1012  func (ae *AppExt) SetExt(ext map[string]json.RawMessage) {
  1013  	ae.ext = ext
  1014  	ae.extDirty = true
  1015  }
  1016  
  1017  func (ae *AppExt) GetPrebid() *ExtAppPrebid {
  1018  	if ae.prebid == nil {
  1019  		return nil
  1020  	}
  1021  	prebid := *ae.prebid
  1022  	return &prebid
  1023  }
  1024  
  1025  func (ae *AppExt) SetPrebid(prebid *ExtAppPrebid) {
  1026  	ae.prebid = prebid
  1027  	ae.prebidDirty = true
  1028  }
  1029  
  1030  func (ae *AppExt) Clone() *AppExt {
  1031  	if ae == nil {
  1032  		return nil
  1033  	}
  1034  
  1035  	clone := *ae
  1036  	clone.ext = maputil.Clone(ae.ext)
  1037  
  1038  	clone.prebid = ptrutil.Clone(ae.prebid)
  1039  
  1040  	return &clone
  1041  }
  1042  
  1043  // ---------------------------------------------------------------
  1044  // RegExt provides an interface for request.regs.ext
  1045  // ---------------------------------------------------------------
  1046  
  1047  type RegExt struct {
  1048  	ext            map[string]json.RawMessage
  1049  	extDirty       bool
  1050  	gdpr           *int8
  1051  	gdprDirty      bool
  1052  	usPrivacy      string
  1053  	usPrivacyDirty bool
  1054  }
  1055  
  1056  func (re *RegExt) unmarshal(extJson json.RawMessage) error {
  1057  	if len(re.ext) != 0 || re.Dirty() {
  1058  		return nil
  1059  	}
  1060  
  1061  	re.ext = make(map[string]json.RawMessage)
  1062  
  1063  	if len(extJson) == 0 {
  1064  		return nil
  1065  	}
  1066  
  1067  	if err := json.Unmarshal(extJson, &re.ext); err != nil {
  1068  		return err
  1069  	}
  1070  
  1071  	gdprJson, hasGDPR := re.ext[gdprKey]
  1072  	if hasGDPR {
  1073  		if err := json.Unmarshal(gdprJson, &re.gdpr); err != nil {
  1074  			return errors.New("gdpr must be an integer")
  1075  		}
  1076  	}
  1077  
  1078  	uspJson, hasUsp := re.ext[us_privacyKey]
  1079  	if hasUsp {
  1080  		if err := json.Unmarshal(uspJson, &re.usPrivacy); err != nil {
  1081  			return err
  1082  		}
  1083  	}
  1084  
  1085  	return nil
  1086  }
  1087  
  1088  func (re *RegExt) marshal() (json.RawMessage, error) {
  1089  	if re.gdprDirty {
  1090  		if re.gdpr != nil {
  1091  			rawjson, err := json.Marshal(re.gdpr)
  1092  			if err != nil {
  1093  				return nil, err
  1094  			}
  1095  			re.ext[gdprKey] = rawjson
  1096  		} else {
  1097  			delete(re.ext, gdprKey)
  1098  		}
  1099  		re.gdprDirty = false
  1100  	}
  1101  
  1102  	if re.usPrivacyDirty {
  1103  		if len(re.usPrivacy) > 0 {
  1104  			rawjson, err := json.Marshal(re.usPrivacy)
  1105  			if err != nil {
  1106  				return nil, err
  1107  			}
  1108  			re.ext[us_privacyKey] = rawjson
  1109  		} else {
  1110  			delete(re.ext, us_privacyKey)
  1111  		}
  1112  		re.usPrivacyDirty = false
  1113  	}
  1114  
  1115  	re.extDirty = false
  1116  	if len(re.ext) == 0 {
  1117  		return nil, nil
  1118  	}
  1119  	return json.Marshal(re.ext)
  1120  }
  1121  
  1122  func (re *RegExt) Dirty() bool {
  1123  	return re.extDirty || re.gdprDirty || re.usPrivacyDirty
  1124  }
  1125  
  1126  func (re *RegExt) GetExt() map[string]json.RawMessage {
  1127  	ext := make(map[string]json.RawMessage)
  1128  	for k, v := range re.ext {
  1129  		ext[k] = v
  1130  	}
  1131  	return ext
  1132  }
  1133  
  1134  func (re *RegExt) SetExt(ext map[string]json.RawMessage) {
  1135  	re.ext = ext
  1136  	re.extDirty = true
  1137  }
  1138  
  1139  func (re *RegExt) GetGDPR() *int8 {
  1140  	gdpr := re.gdpr
  1141  	return gdpr
  1142  }
  1143  
  1144  func (re *RegExt) SetGDPR(gdpr *int8) {
  1145  	re.gdpr = gdpr
  1146  	re.gdprDirty = true
  1147  }
  1148  
  1149  func (re *RegExt) GetUSPrivacy() string {
  1150  	uSPrivacy := re.usPrivacy
  1151  	return uSPrivacy
  1152  }
  1153  
  1154  func (re *RegExt) SetUSPrivacy(usPrivacy string) {
  1155  	re.usPrivacy = usPrivacy
  1156  	re.usPrivacyDirty = true
  1157  }
  1158  
  1159  func (re *RegExt) Clone() *RegExt {
  1160  	if re == nil {
  1161  		return nil
  1162  	}
  1163  
  1164  	clone := *re
  1165  	clone.ext = maputil.Clone(re.ext)
  1166  
  1167  	clone.gdpr = ptrutil.Clone(re.gdpr)
  1168  
  1169  	return &clone
  1170  }
  1171  
  1172  // ---------------------------------------------------------------
  1173  // SiteExt provides an interface for request.site.ext
  1174  // ---------------------------------------------------------------
  1175  
  1176  type SiteExt struct {
  1177  	ext      map[string]json.RawMessage
  1178  	extDirty bool
  1179  	amp      *int8
  1180  	ampDirty bool
  1181  }
  1182  
  1183  func (se *SiteExt) unmarshal(extJson json.RawMessage) error {
  1184  	if len(se.ext) != 0 || se.Dirty() {
  1185  		return nil
  1186  	}
  1187  
  1188  	se.ext = make(map[string]json.RawMessage)
  1189  
  1190  	if len(extJson) == 0 {
  1191  		return nil
  1192  	}
  1193  
  1194  	if err := json.Unmarshal(extJson, &se.ext); err != nil {
  1195  		return err
  1196  	}
  1197  
  1198  	ampJson, hasAmp := se.ext[ampKey]
  1199  	if hasAmp {
  1200  		if err := json.Unmarshal(ampJson, &se.amp); err != nil {
  1201  			return errors.New(`request.site.ext.amp must be either 1, 0, or undefined`)
  1202  		}
  1203  	}
  1204  
  1205  	return nil
  1206  }
  1207  
  1208  func (se *SiteExt) marshal() (json.RawMessage, error) {
  1209  	if se.ampDirty {
  1210  		if se.amp != nil {
  1211  			ampJson, err := json.Marshal(se.amp)
  1212  			if err != nil {
  1213  				return nil, err
  1214  			}
  1215  			se.ext[ampKey] = json.RawMessage(ampJson)
  1216  		} else {
  1217  			delete(se.ext, ampKey)
  1218  		}
  1219  		se.ampDirty = false
  1220  	}
  1221  
  1222  	se.extDirty = false
  1223  	if len(se.ext) == 0 {
  1224  		return nil, nil
  1225  	}
  1226  	return json.Marshal(se.ext)
  1227  }
  1228  
  1229  func (se *SiteExt) Dirty() bool {
  1230  	return se.extDirty || se.ampDirty
  1231  }
  1232  
  1233  func (se *SiteExt) GetExt() map[string]json.RawMessage {
  1234  	ext := make(map[string]json.RawMessage)
  1235  	for k, v := range se.ext {
  1236  		ext[k] = v
  1237  	}
  1238  	return ext
  1239  }
  1240  
  1241  func (se *SiteExt) SetExt(ext map[string]json.RawMessage) {
  1242  	se.ext = ext
  1243  	se.extDirty = true
  1244  }
  1245  
  1246  func (se *SiteExt) GetAmp() *int8 {
  1247  	return se.amp
  1248  }
  1249  
  1250  func (se *SiteExt) SetAmp(amp *int8) {
  1251  	se.amp = amp
  1252  	se.ampDirty = true
  1253  }
  1254  
  1255  func (se *SiteExt) Clone() *SiteExt {
  1256  	if se == nil {
  1257  		return nil
  1258  	}
  1259  
  1260  	clone := *se
  1261  	clone.ext = maputil.Clone(se.ext)
  1262  	clone.amp = ptrutil.Clone(se.amp)
  1263  
  1264  	return &clone
  1265  }
  1266  
  1267  // ---------------------------------------------------------------
  1268  // SourceExt provides an interface for request.source.ext
  1269  // ---------------------------------------------------------------
  1270  
  1271  type SourceExt struct {
  1272  	ext         map[string]json.RawMessage
  1273  	extDirty    bool
  1274  	schain      *openrtb2.SupplyChain
  1275  	schainDirty bool
  1276  }
  1277  
  1278  func (se *SourceExt) unmarshal(extJson json.RawMessage) error {
  1279  	if len(se.ext) != 0 || se.Dirty() {
  1280  		return nil
  1281  	}
  1282  
  1283  	se.ext = make(map[string]json.RawMessage)
  1284  
  1285  	if len(extJson) == 0 {
  1286  		return nil
  1287  	}
  1288  
  1289  	if err := json.Unmarshal(extJson, &se.ext); err != nil {
  1290  		return err
  1291  	}
  1292  
  1293  	schainJson, hasSChain := se.ext[schainKey]
  1294  	if hasSChain {
  1295  		if err := json.Unmarshal(schainJson, &se.schain); err != nil {
  1296  			return err
  1297  		}
  1298  	}
  1299  
  1300  	return nil
  1301  }
  1302  
  1303  func (se *SourceExt) marshal() (json.RawMessage, error) {
  1304  	if se.schainDirty {
  1305  		if se.schain != nil {
  1306  			schainJson, err := json.Marshal(se.schain)
  1307  			if err != nil {
  1308  				return nil, err
  1309  			}
  1310  			if len(schainJson) > jsonEmptyObjectLength {
  1311  				se.ext[schainKey] = json.RawMessage(schainJson)
  1312  			} else {
  1313  				delete(se.ext, schainKey)
  1314  			}
  1315  		} else {
  1316  			delete(se.ext, schainKey)
  1317  		}
  1318  		se.schainDirty = false
  1319  	}
  1320  
  1321  	se.extDirty = false
  1322  	if len(se.ext) == 0 {
  1323  		return nil, nil
  1324  	}
  1325  	return json.Marshal(se.ext)
  1326  }
  1327  
  1328  func (se *SourceExt) Dirty() bool {
  1329  	return se.extDirty || se.schainDirty
  1330  }
  1331  
  1332  func (se *SourceExt) GetExt() map[string]json.RawMessage {
  1333  	ext := make(map[string]json.RawMessage)
  1334  	for k, v := range se.ext {
  1335  		ext[k] = v
  1336  	}
  1337  	return ext
  1338  }
  1339  
  1340  func (se *SourceExt) SetExt(ext map[string]json.RawMessage) {
  1341  	se.ext = ext
  1342  	se.extDirty = true
  1343  }
  1344  
  1345  func (se *SourceExt) GetSChain() *openrtb2.SupplyChain {
  1346  	if se.schain == nil {
  1347  		return nil
  1348  	}
  1349  	schain := *se.schain
  1350  	return &schain
  1351  }
  1352  
  1353  func (se *SourceExt) SetSChain(schain *openrtb2.SupplyChain) {
  1354  	se.schain = schain
  1355  	se.schainDirty = true
  1356  }
  1357  
  1358  func (se *SourceExt) Clone() *SourceExt {
  1359  	if se == nil {
  1360  		return nil
  1361  	}
  1362  
  1363  	clone := *se
  1364  	clone.ext = maputil.Clone(se.ext)
  1365  
  1366  	clone.schain = cloneSupplyChain(se.schain)
  1367  
  1368  	return &clone
  1369  }
  1370  
  1371  // ImpWrapper wraps an OpenRTB impression object to provide storage for unmarshalled ext fields, so they
  1372  // will not need to be unmarshalled multiple times. It is intended to use the ImpWrapper via the RequestWrapper
  1373  // and follow the same usage conventions.
  1374  type ImpWrapper struct {
  1375  	*openrtb2.Imp
  1376  	impExt *ImpExt
  1377  }
  1378  
  1379  func (w *ImpWrapper) GetImpExt() (*ImpExt, error) {
  1380  	if w.impExt != nil {
  1381  		return w.impExt, nil
  1382  	}
  1383  	w.impExt = &ImpExt{}
  1384  	if w.Imp == nil || w.Ext == nil {
  1385  		return w.impExt, w.impExt.unmarshal(json.RawMessage{})
  1386  	}
  1387  	return w.impExt, w.impExt.unmarshal(w.Ext)
  1388  }
  1389  
  1390  func (w *ImpWrapper) RebuildImp() error {
  1391  	if w.Imp == nil {
  1392  		return errors.New("ImpWrapper RebuildImp called on a nil Imp")
  1393  	}
  1394  
  1395  	if err := w.rebuildImpExt(); err != nil {
  1396  		return err
  1397  	}
  1398  
  1399  	return nil
  1400  }
  1401  
  1402  func (w *ImpWrapper) rebuildImpExt() error {
  1403  	if w.impExt == nil || !w.impExt.Dirty() {
  1404  		return nil
  1405  	}
  1406  
  1407  	impJson, err := w.impExt.marshal()
  1408  	if err != nil {
  1409  		return err
  1410  	}
  1411  
  1412  	w.Ext = impJson
  1413  
  1414  	return nil
  1415  }
  1416  
  1417  func (w *ImpWrapper) Clone() *ImpWrapper {
  1418  	if w == nil {
  1419  		return nil
  1420  	}
  1421  
  1422  	clone := *w
  1423  	clone.impExt = w.impExt.Clone()
  1424  
  1425  	return &clone
  1426  }
  1427  
  1428  // ---------------------------------------------------------------
  1429  // ImpExt provides an interface for imp.ext
  1430  // ---------------------------------------------------------------
  1431  
  1432  type ImpExt struct {
  1433  	ext         map[string]json.RawMessage
  1434  	extDirty    bool
  1435  	prebid      *ExtImpPrebid
  1436  	data        *ExtImpData
  1437  	prebidDirty bool
  1438  	tid         string
  1439  	gpId        string
  1440  	tidDirty    bool
  1441  }
  1442  
  1443  func (e *ImpExt) unmarshal(extJson json.RawMessage) error {
  1444  	if len(e.ext) != 0 || e.Dirty() {
  1445  		return nil
  1446  	}
  1447  
  1448  	e.ext = make(map[string]json.RawMessage)
  1449  
  1450  	if len(extJson) == 0 {
  1451  		return nil
  1452  	}
  1453  
  1454  	if err := json.Unmarshal(extJson, &e.ext); err != nil {
  1455  		return err
  1456  	}
  1457  
  1458  	prebidJson, hasPrebid := e.ext[prebidKey]
  1459  	if hasPrebid {
  1460  		e.prebid = &ExtImpPrebid{}
  1461  		if err := json.Unmarshal(prebidJson, e.prebid); err != nil {
  1462  			return err
  1463  		}
  1464  	}
  1465  
  1466  	dataJson, hasData := e.ext[dataKey]
  1467  	if hasData {
  1468  		e.data = &ExtImpData{}
  1469  		if err := json.Unmarshal(dataJson, e.data); err != nil {
  1470  			return err
  1471  		}
  1472  	}
  1473  
  1474  	tidJson, hasTid := e.ext["tid"]
  1475  	if hasTid {
  1476  		if err := json.Unmarshal(tidJson, &e.tid); err != nil {
  1477  			return err
  1478  		}
  1479  	}
  1480  
  1481  	gpIdJson, hasGpId := e.ext["gpid"]
  1482  	if hasGpId {
  1483  		if err := json.Unmarshal(gpIdJson, &e.gpId); err != nil {
  1484  			return err
  1485  		}
  1486  	}
  1487  
  1488  	return nil
  1489  }
  1490  
  1491  func (e *ImpExt) marshal() (json.RawMessage, error) {
  1492  	if e.prebidDirty {
  1493  		if e.prebid != nil {
  1494  			prebidJson, err := json.Marshal(e.prebid)
  1495  			if err != nil {
  1496  				return nil, err
  1497  			}
  1498  			if len(prebidJson) > jsonEmptyObjectLength {
  1499  				e.ext[prebidKey] = json.RawMessage(prebidJson)
  1500  			} else {
  1501  				delete(e.ext, prebidKey)
  1502  			}
  1503  		} else {
  1504  			delete(e.ext, prebidKey)
  1505  		}
  1506  		e.prebidDirty = false
  1507  	}
  1508  
  1509  	if e.tidDirty {
  1510  		if len(e.tid) > 0 {
  1511  			tidJson, err := json.Marshal(e.tid)
  1512  			if err != nil {
  1513  				return nil, err
  1514  			}
  1515  			e.ext["tid"] = tidJson
  1516  		} else {
  1517  			delete(e.ext, "tid")
  1518  		}
  1519  		e.tidDirty = false
  1520  	}
  1521  
  1522  	e.extDirty = false
  1523  	if len(e.ext) == 0 {
  1524  		return nil, nil
  1525  	}
  1526  	return json.Marshal(e.ext)
  1527  }
  1528  
  1529  func (e *ImpExt) Dirty() bool {
  1530  	return e.extDirty || e.prebidDirty || e.tidDirty
  1531  }
  1532  
  1533  func (e *ImpExt) GetExt() map[string]json.RawMessage {
  1534  	ext := make(map[string]json.RawMessage)
  1535  	for k, v := range e.ext {
  1536  		ext[k] = v
  1537  	}
  1538  	return ext
  1539  }
  1540  
  1541  func (e *ImpExt) SetExt(ext map[string]json.RawMessage) {
  1542  	e.ext = ext
  1543  	e.extDirty = true
  1544  }
  1545  
  1546  func (e *ImpExt) GetPrebid() *ExtImpPrebid {
  1547  	if e.prebid == nil {
  1548  		return nil
  1549  	}
  1550  	prebid := *e.prebid
  1551  	return &prebid
  1552  }
  1553  
  1554  func (e *ImpExt) GetOrCreatePrebid() *ExtImpPrebid {
  1555  	if e.prebid == nil {
  1556  		e.prebid = &ExtImpPrebid{}
  1557  	}
  1558  	return e.GetPrebid()
  1559  }
  1560  
  1561  func (e *ImpExt) SetPrebid(prebid *ExtImpPrebid) {
  1562  	e.prebid = prebid
  1563  	e.prebidDirty = true
  1564  }
  1565  
  1566  func (e *ImpExt) GetData() *ExtImpData {
  1567  	if e.data == nil {
  1568  		return nil
  1569  	}
  1570  	data := *e.data
  1571  	return &data
  1572  }
  1573  
  1574  func (e *ImpExt) GetTid() string {
  1575  	tid := e.tid
  1576  	return tid
  1577  }
  1578  
  1579  func (e *ImpExt) SetTid(tid string) {
  1580  	e.tid = tid
  1581  	e.tidDirty = true
  1582  }
  1583  
  1584  func (e *ImpExt) GetGpId() string {
  1585  	gpId := e.gpId
  1586  	return gpId
  1587  }
  1588  
  1589  func CreateImpExtForTesting(ext map[string]json.RawMessage, prebid *ExtImpPrebid) ImpExt {
  1590  	return ImpExt{ext: ext, prebid: prebid}
  1591  }
  1592  
  1593  func (e *ImpExt) Clone() *ImpExt {
  1594  	if e == nil {
  1595  		return nil
  1596  	}
  1597  
  1598  	clone := *e
  1599  	clone.ext = maputil.Clone(e.ext)
  1600  
  1601  	if e.prebid != nil {
  1602  		clonedPrebid := *e.prebid
  1603  		clonedPrebid.StoredRequest = ptrutil.Clone(e.prebid.StoredRequest)
  1604  		clonedPrebid.StoredAuctionResponse = ptrutil.Clone(e.prebid.StoredAuctionResponse)
  1605  		if e.prebid.StoredBidResponse != nil {
  1606  			clonedPrebid.StoredBidResponse = make([]ExtStoredBidResponse, len(e.prebid.StoredBidResponse))
  1607  			for i, sbr := range e.prebid.StoredBidResponse {
  1608  				clonedPrebid.StoredBidResponse[i] = sbr
  1609  				clonedPrebid.StoredBidResponse[i].ReplaceImpId = ptrutil.Clone(sbr.ReplaceImpId)
  1610  			}
  1611  		}
  1612  		clonedPrebid.IsRewardedInventory = ptrutil.Clone(e.prebid.IsRewardedInventory)
  1613  		clonedPrebid.Bidder = maputil.Clone(e.prebid.Bidder)
  1614  		clonedPrebid.Options = ptrutil.Clone(e.prebid.Options)
  1615  		clonedPrebid.Floors = ptrutil.Clone(e.prebid.Floors)
  1616  		clone.prebid = &clonedPrebid
  1617  	}
  1618  
  1619  	return &clone
  1620  }