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 }