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