github.com/prebid/prebid-server/v2@v2.18.0/config/config.go (about) 1 package config 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/url" 8 "reflect" 9 "strings" 10 "time" 11 12 "github.com/golang/glog" 13 "github.com/prebid/go-gdpr/consentconstants" 14 "github.com/prebid/openrtb/v20/openrtb2" 15 "github.com/prebid/prebid-server/v2/errortypes" 16 "github.com/prebid/prebid-server/v2/openrtb_ext" 17 "github.com/prebid/prebid-server/v2/util/jsonutil" 18 "github.com/spf13/viper" 19 ) 20 21 // Configuration specifies the static application config. 22 type Configuration struct { 23 ExternalURL string `mapstructure:"external_url"` 24 Host string `mapstructure:"host"` 25 Port int `mapstructure:"port"` 26 UnixSocketEnable bool `mapstructure:"unix_socket_enable"` 27 UnixSocketName string `mapstructure:"unix_socket_name"` 28 Client HTTPClient `mapstructure:"http_client"` 29 CacheClient HTTPClient `mapstructure:"http_client_cache"` 30 Admin Admin `mapstructure:"admin"` 31 AdminPort int `mapstructure:"admin_port"` 32 Compression Compression `mapstructure:"compression"` 33 // GarbageCollectorThreshold allocates virtual memory (in bytes) which is not used by PBS but 34 // serves as a hack to trigger the garbage collector only when the heap reaches at least this size. 35 // More info: https://github.com/golang/go/issues/48409 36 GarbageCollectorThreshold int `mapstructure:"garbage_collector_threshold"` 37 // StatusResponse is the string which will be returned by the /status endpoint when things are OK. 38 // If empty, it will return a 204 with no content. 39 StatusResponse string `mapstructure:"status_response"` 40 AuctionTimeouts AuctionTimeouts `mapstructure:"auction_timeouts_ms"` 41 TmaxAdjustments TmaxAdjustments `mapstructure:"tmax_adjustments"` 42 CacheURL Cache `mapstructure:"cache"` 43 ExtCacheURL ExternalCache `mapstructure:"external_cache"` 44 RecaptchaSecret string `mapstructure:"recaptcha_secret"` 45 HostCookie HostCookie `mapstructure:"host_cookie"` 46 Metrics Metrics `mapstructure:"metrics"` 47 StoredRequests StoredRequests `mapstructure:"stored_requests"` 48 StoredRequestsAMP StoredRequests `mapstructure:"stored_amp_req"` 49 CategoryMapping StoredRequests `mapstructure:"category_mapping"` 50 VTrack VTrack `mapstructure:"vtrack"` 51 Event Event `mapstructure:"event"` 52 Accounts StoredRequests `mapstructure:"accounts"` 53 UserSync UserSync `mapstructure:"user_sync"` 54 // Note that StoredVideo refers to stored video requests, and has nothing to do with caching video creatives. 55 StoredVideo StoredRequests `mapstructure:"stored_video_req"` 56 StoredResponses StoredRequests `mapstructure:"stored_responses"` 57 // StoredRequestsTimeout defines the number of milliseconds before a timeout occurs with stored requests fetch 58 StoredRequestsTimeout int `mapstructure:"stored_requests_timeout_ms"` 59 60 MaxRequestSize int64 `mapstructure:"max_request_size"` 61 Analytics Analytics `mapstructure:"analytics"` 62 AMPTimeoutAdjustment int64 `mapstructure:"amp_timeout_adjustment_ms"` 63 GDPR GDPR `mapstructure:"gdpr"` 64 CCPA CCPA `mapstructure:"ccpa"` 65 LMT LMT `mapstructure:"lmt"` 66 CurrencyConverter CurrencyConverter `mapstructure:"currency_converter"` 67 DefReqConfig DefReqConfig `mapstructure:"default_request"` 68 69 VideoStoredRequestRequired bool `mapstructure:"video_stored_request_required"` 70 71 // Array of blacklisted apps that is used to create the hash table BlacklistedAppMap so App.ID's can be instantly accessed. 72 BlacklistedApps []string `mapstructure:"blacklisted_apps,flow"` 73 BlacklistedAppMap map[string]bool 74 // Is publisher/account ID required to be submitted in the OpenRTB2 request 75 AccountRequired bool `mapstructure:"account_required"` 76 // AccountDefaults defines default settings for valid accounts that are partially defined 77 // and provides a way to set global settings that can be overridden at account level. 78 AccountDefaults Account `mapstructure:"account_defaults"` 79 // accountDefaultsJSON is the internal serialized form of AccountDefaults used for json merge 80 accountDefaultsJSON json.RawMessage 81 // Local private file containing SSL certificates 82 PemCertsFile string `mapstructure:"certificates_file"` 83 // Custom headers to handle request timeouts from queueing infrastructure 84 RequestTimeoutHeaders RequestTimeoutHeaders `mapstructure:"request_timeout_headers"` 85 // Debug/logging flags go here 86 Debug Debug `mapstructure:"debug"` 87 // RequestValidation specifies the request validation options. 88 RequestValidation RequestValidation `mapstructure:"request_validation"` 89 // When true, PBS will assign a randomly generated UUID to req.Source.TID if it is empty 90 AutoGenSourceTID bool `mapstructure:"auto_gen_source_tid"` 91 //When true, new bid id will be generated in seatbid[].bid[].ext.prebid.bidid and used in event urls instead 92 GenerateBidID bool `mapstructure:"generate_bid_id"` 93 // GenerateRequestID overrides the bidrequest.id in an AMP Request or an App Stored Request with a generated UUID if set to true. The default is false. 94 GenerateRequestID bool `mapstructure:"generate_request_id"` 95 HostSChainNode *openrtb2.SupplyChainNode `mapstructure:"host_schain_node"` 96 // Experiment configures non-production ready features. 97 Experiment Experiment `mapstructure:"experiment"` 98 DataCenter string `mapstructure:"datacenter"` 99 // BidderInfos supports adapter overrides in extra configs like pbs.json, pbs.yaml, etc. 100 // Refers to main.go `configFileName` constant 101 BidderInfos BidderInfos `mapstructure:"adapters"` 102 // Hooks provides a way to specify hook execution plan for specific endpoints and stages 103 Hooks Hooks `mapstructure:"hooks"` 104 Validations Validations `mapstructure:"validations"` 105 PriceFloors PriceFloors `mapstructure:"price_floors"` 106 } 107 108 type Admin struct { 109 Enabled bool `mapstructure:"enabled"` 110 } 111 type PriceFloors struct { 112 Enabled bool `mapstructure:"enabled"` 113 Fetcher PriceFloorFetcher `mapstructure:"fetcher"` 114 } 115 116 type PriceFloorFetcher struct { 117 HttpClient HTTPClient `mapstructure:"http_client"` 118 CacheSize int `mapstructure:"cache_size_mb"` 119 Worker int `mapstructure:"worker"` 120 Capacity int `mapstructure:"capacity"` 121 MaxRetries int `mapstructure:"max_retries"` 122 } 123 124 const MIN_COOKIE_SIZE_BYTES = 500 125 126 type HTTPClient struct { 127 MaxConnsPerHost int `mapstructure:"max_connections_per_host"` 128 MaxIdleConns int `mapstructure:"max_idle_connections"` 129 MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` 130 IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` 131 } 132 133 func (cfg *Configuration) validate(v *viper.Viper) []error { 134 var errs []error 135 errs = cfg.AuctionTimeouts.validate(errs) 136 errs = cfg.StoredRequests.validate(errs) 137 if cfg.StoredRequestsTimeout <= 0 { 138 errs = append(errs, fmt.Errorf("cfg.stored_requests_timeout_ms must be > 0. Got %d", cfg.StoredRequestsTimeout)) 139 } 140 errs = cfg.StoredRequestsAMP.validate(errs) 141 errs = cfg.Accounts.validate(errs) 142 errs = cfg.CategoryMapping.validate(errs) 143 errs = cfg.StoredVideo.validate(errs) 144 errs = cfg.Metrics.validate(errs) 145 if cfg.MaxRequestSize < 0 { 146 errs = append(errs, fmt.Errorf("cfg.max_request_size must be >= 0. Got %d", cfg.MaxRequestSize)) 147 } 148 errs = cfg.GDPR.validate(v, errs) 149 errs = cfg.CurrencyConverter.validate(errs) 150 errs = cfg.Debug.validate(errs) 151 errs = cfg.ExtCacheURL.validate(errs) 152 errs = cfg.AccountDefaults.PriceFloors.validate(errs) 153 if cfg.AccountDefaults.Disabled { 154 glog.Warning(`With account_defaults.disabled=true, host-defined accounts must exist and have "disabled":false. All other requests will be rejected.`) 155 } 156 157 if cfg.AccountDefaults.Events.Enabled { 158 glog.Warning(`account_defaults.events has no effect as the feature is under development.`) 159 } 160 161 errs = cfg.Experiment.validate(errs) 162 errs = cfg.BidderInfos.validate(errs) 163 errs = cfg.AccountDefaults.Privacy.IPv6Config.Validate(errs) 164 errs = cfg.AccountDefaults.Privacy.IPv4Config.Validate(errs) 165 166 return errs 167 } 168 169 type AuctionTimeouts struct { 170 // The default timeout is used if the user's request didn't define one. Use 0 if there's no default. 171 Default uint64 `mapstructure:"default"` 172 // The max timeout is used as an absolute cap, to prevent excessively long ones. Use 0 for no cap 173 Max uint64 `mapstructure:"max"` 174 } 175 176 func (cfg *AuctionTimeouts) validate(errs []error) []error { 177 if cfg.Max < cfg.Default { 178 errs = append(errs, fmt.Errorf("auction_timeouts_ms.max cannot be less than auction_timeouts_ms.default. max=%d, default=%d", cfg.Max, cfg.Default)) 179 } 180 return errs 181 } 182 183 func (data *ExternalCache) validate(errs []error) []error { 184 if data.Host == "" && data.Path == "" { 185 // Both host and path can be blank. No further validation needed 186 return errs 187 } 188 189 if data.Scheme != "" && data.Scheme != "http" && data.Scheme != "https" { 190 return append(errs, errors.New("External cache Scheme must be http or https if specified")) 191 } 192 193 // Either host or path or both not empty, validate. 194 if data.Host == "" && data.Path != "" || data.Host != "" && data.Path == "" { 195 return append(errs, errors.New("external cache Host and Path must both be specified")) 196 } 197 if strings.HasSuffix(data.Host, "/") { 198 return append(errs, fmt.Errorf("external cache Host '%s' must not end with a path separator", data.Host)) 199 } 200 if strings.Contains(data.Host, "://") { 201 return append(errs, fmt.Errorf("external cache Host must not specify a protocol. '%s'", data.Host)) 202 } 203 if !strings.HasPrefix(data.Path, "/") { 204 return append(errs, fmt.Errorf("external cache Path '%s' must begin with a path separator", data.Path)) 205 } 206 207 urlObj, err := url.Parse("https://" + data.Host + data.Path) 208 if err != nil { 209 return append(errs, fmt.Errorf("external cache Path validation error: %s ", err.Error())) 210 } 211 if urlObj.Host != data.Host { 212 return append(errs, fmt.Errorf("external cache Host '%s' is invalid", data.Host)) 213 } 214 if urlObj.Path != data.Path { 215 return append(errs, fmt.Errorf("external cache Path is invalid")) 216 } 217 218 return errs 219 } 220 221 // LimitAuctionTimeout returns the min of requested or cfg.MaxAuctionTimeout. 222 // Both values treat "0" as "infinite". 223 func (cfg *AuctionTimeouts) LimitAuctionTimeout(requested time.Duration) time.Duration { 224 if requested == 0 && cfg.Default != 0 { 225 return time.Duration(cfg.Default) * time.Millisecond 226 } 227 if cfg.Max > 0 { 228 maxTimeout := time.Duration(cfg.Max) * time.Millisecond 229 if requested == 0 || requested > maxTimeout { 230 return maxTimeout 231 } 232 } 233 return requested 234 } 235 236 // Privacy is a grouping of privacy related configs to assist in dependency injection. 237 type Privacy struct { 238 CCPA CCPA 239 GDPR GDPR 240 LMT LMT 241 } 242 243 type GDPR struct { 244 Enabled bool `mapstructure:"enabled"` 245 HostVendorID int `mapstructure:"host_vendor_id"` 246 DefaultValue string `mapstructure:"default_value"` 247 Timeouts GDPRTimeouts `mapstructure:"timeouts_ms"` 248 NonStandardPublishers []string `mapstructure:"non_standard_publishers,flow"` 249 NonStandardPublisherMap map[string]struct{} 250 TCF2 TCF2 `mapstructure:"tcf2"` 251 AMPException bool `mapstructure:"amp_exception"` // Deprecated: Use account-level GDPR settings (gdpr.integration_enabled.amp) instead 252 // EEACountries (EEA = European Economic Area) are a list of countries where we should assume GDPR applies. 253 // If the gdpr flag is unset in a request, but geo.country is set, we will assume GDPR applies if and only 254 // if the country matches one on this list. If both the GDPR flag and country are not set, we default 255 // to DefaultValue 256 EEACountries []string `mapstructure:"eea_countries"` 257 EEACountriesMap map[string]struct{} 258 } 259 260 func (cfg *GDPR) validate(v *viper.Viper, errs []error) []error { 261 if !v.IsSet("gdpr.default_value") { 262 errs = append(errs, fmt.Errorf("gdpr.default_value is required and must be specified")) 263 } else if cfg.DefaultValue != "0" && cfg.DefaultValue != "1" { 264 errs = append(errs, fmt.Errorf("gdpr.default_value must be 0 or 1")) 265 } 266 if cfg.HostVendorID < 0 || cfg.HostVendorID > 0xffff { 267 errs = append(errs, fmt.Errorf("gdpr.host_vendor_id must be in the range [0, %d]. Got %d", 0xffff, cfg.HostVendorID)) 268 } 269 if cfg.HostVendorID == 0 { 270 glog.Warning("gdpr.host_vendor_id was not specified. Host company GDPR checks will be skipped.") 271 } 272 if cfg.AMPException { 273 errs = append(errs, fmt.Errorf("gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)")) 274 } 275 return cfg.validatePurposes(errs) 276 } 277 278 func (cfg *GDPR) validatePurposes(errs []error) []error { 279 purposeConfigs := []TCF2Purpose{ 280 cfg.TCF2.Purpose1, 281 cfg.TCF2.Purpose2, 282 cfg.TCF2.Purpose3, 283 cfg.TCF2.Purpose4, 284 cfg.TCF2.Purpose5, 285 cfg.TCF2.Purpose6, 286 cfg.TCF2.Purpose7, 287 cfg.TCF2.Purpose8, 288 cfg.TCF2.Purpose9, 289 cfg.TCF2.Purpose10, 290 } 291 292 for i := 0; i < len(purposeConfigs); i++ { 293 enforceAlgoValue := purposeConfigs[i].EnforceAlgo 294 enforceAlgoField := fmt.Sprintf("gdpr.tcf2.purpose%d.enforce_algo", (i + 1)) 295 296 if enforceAlgoValue != TCF2EnforceAlgoFull && enforceAlgoValue != TCF2EnforceAlgoBasic { 297 errs = append(errs, fmt.Errorf("%s must be \"basic\" or \"full\". Got %s", enforceAlgoField, enforceAlgoValue)) 298 } 299 } 300 return errs 301 } 302 303 type GDPRTimeouts struct { 304 InitVendorlistFetch int `mapstructure:"init_vendorlist_fetches"` 305 ActiveVendorlistFetch int `mapstructure:"active_vendorlist_fetch"` 306 } 307 308 func (t *GDPRTimeouts) InitTimeout() time.Duration { 309 return time.Duration(t.InitVendorlistFetch) * time.Millisecond 310 } 311 312 func (t *GDPRTimeouts) ActiveTimeout() time.Duration { 313 return time.Duration(t.ActiveVendorlistFetch) * time.Millisecond 314 } 315 316 const ( 317 TCF2EnforceAlgoBasic = "basic" 318 TCF2EnforceAlgoFull = "full" 319 ) 320 321 type TCF2EnforcementAlgo int 322 323 const ( 324 TCF2UndefinedEnforcement TCF2EnforcementAlgo = iota 325 TCF2BasicEnforcement 326 TCF2FullEnforcement 327 ) 328 329 // TCF2 defines the TCF2 specific configurations for GDPR 330 type TCF2 struct { 331 Enabled bool `mapstructure:"enabled"` 332 Purpose1 TCF2Purpose `mapstructure:"purpose1"` 333 Purpose2 TCF2Purpose `mapstructure:"purpose2"` 334 Purpose3 TCF2Purpose `mapstructure:"purpose3"` 335 Purpose4 TCF2Purpose `mapstructure:"purpose4"` 336 Purpose5 TCF2Purpose `mapstructure:"purpose5"` 337 Purpose6 TCF2Purpose `mapstructure:"purpose6"` 338 Purpose7 TCF2Purpose `mapstructure:"purpose7"` 339 Purpose8 TCF2Purpose `mapstructure:"purpose8"` 340 Purpose9 TCF2Purpose `mapstructure:"purpose9"` 341 Purpose10 TCF2Purpose `mapstructure:"purpose10"` 342 // Map of purpose configs for easy purpose lookup 343 PurposeConfigs map[consentconstants.Purpose]*TCF2Purpose 344 SpecialFeature1 TCF2SpecialFeature `mapstructure:"special_feature1"` 345 PurposeOneTreatment TCF2PurposeOneTreatment `mapstructure:"purpose_one_treatment"` 346 } 347 348 // ChannelEnabled checks if a given channel type is enabled. All channel types are considered either 349 // enabled or disabled based on the Enabled flag. 350 func (t *TCF2) ChannelEnabled(channelType ChannelType) bool { 351 return t.Enabled 352 } 353 354 // IsEnabled indicates if TCF2 is enabled 355 func (t *TCF2) IsEnabled() bool { 356 return t.Enabled 357 } 358 359 // PurposeEnforced checks if full enforcement is turned on for a given purpose. With full enforcement enabled, the 360 // GDPR full enforcement algorithm will execute for that purpose determining legal basis; otherwise it's skipped. 361 func (t *TCF2) PurposeEnforced(purpose consentconstants.Purpose) (enforce bool) { 362 if t.PurposeConfigs[purpose] == nil { 363 return false 364 } 365 return t.PurposeConfigs[purpose].EnforcePurpose 366 } 367 368 // PurposeEnforcementAlgo returns the default enforcement algorithm for a given purpose 369 func (t *TCF2) PurposeEnforcementAlgo(purpose consentconstants.Purpose) (enforcement TCF2EnforcementAlgo) { 370 if c, exists := t.PurposeConfigs[purpose]; exists { 371 return c.EnforceAlgoID 372 } 373 return TCF2FullEnforcement 374 } 375 376 // PurposeEnforcingVendors checks if enforcing vendors is turned on for a given purpose. With enforcing vendors 377 // enabled, the GDPR full enforcement algorithm considers the GVL when determining legal basis; otherwise it's skipped. 378 func (t *TCF2) PurposeEnforcingVendors(purpose consentconstants.Purpose) (enforce bool) { 379 if t.PurposeConfigs[purpose] == nil { 380 return false 381 } 382 return t.PurposeConfigs[purpose].EnforceVendors 383 } 384 385 // PurposeVendorExceptions returns the vendor exception map for a given purpose if it exists, otherwise it returns 386 // an empty map of vendor exceptions 387 func (t *TCF2) PurposeVendorExceptions(purpose consentconstants.Purpose) (vendorExceptions map[string]struct{}) { 388 c, exists := t.PurposeConfigs[purpose] 389 390 if exists && c.VendorExceptionMap != nil { 391 return c.VendorExceptionMap 392 } 393 return make(map[string]struct{}, 0) 394 } 395 396 // FeatureOneEnforced checks if special feature one is enforced. If it is enforced, PBS will determine whether geo 397 // information may be passed through in the bid request. 398 func (t *TCF2) FeatureOneEnforced() bool { 399 return t.SpecialFeature1.Enforce 400 } 401 402 // FeatureOneVendorException checks if the specified bidder is considered a vendor exception for special feature one. 403 // If a bidder is a vendor exception, PBS will bypass the pass geo calculation passing the geo information in the bid request. 404 func (t *TCF2) FeatureOneVendorException(bidder openrtb_ext.BidderName) bool { 405 if _, ok := t.SpecialFeature1.VendorExceptionMap[bidder]; ok { 406 return true 407 } 408 return false 409 } 410 411 // PurposeOneTreatmentEnabled checks if purpose one treatment is enabled. 412 func (t *TCF2) PurposeOneTreatmentEnabled() bool { 413 return t.PurposeOneTreatment.Enabled 414 } 415 416 // PurposeOneTreatmentAccessAllowed checks if purpose one treatment access is allowed. 417 func (t *TCF2) PurposeOneTreatmentAccessAllowed() bool { 418 return t.PurposeOneTreatment.AccessAllowed 419 } 420 421 // Making a purpose struct so purpose specific details can be added later. 422 type TCF2Purpose struct { 423 EnforceAlgo string `mapstructure:"enforce_algo"` 424 // Integer representation of enforcement algo for performance improvement on compares 425 EnforceAlgoID TCF2EnforcementAlgo 426 EnforcePurpose bool `mapstructure:"enforce_purpose"` 427 EnforceVendors bool `mapstructure:"enforce_vendors"` 428 // Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed 429 VendorExceptions []string `mapstructure:"vendor_exceptions"` 430 VendorExceptionMap map[string]struct{} 431 } 432 433 type TCF2SpecialFeature struct { 434 Enforce bool `mapstructure:"enforce"` 435 // Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed 436 VendorExceptions []openrtb_ext.BidderName `mapstructure:"vendor_exceptions"` 437 VendorExceptionMap map[openrtb_ext.BidderName]struct{} 438 } 439 440 type TCF2PurposeOneTreatment struct { 441 Enabled bool `mapstructure:"enabled"` 442 AccessAllowed bool `mapstructure:"access_allowed"` 443 } 444 445 type CCPA struct { 446 Enforce bool `mapstructure:"enforce"` 447 } 448 449 type LMT struct { 450 Enforce bool `mapstructure:"enforce"` 451 } 452 453 type Analytics struct { 454 File FileLogs `mapstructure:"file"` 455 Agma AgmaAnalytics `mapstructure:"agma"` 456 Pubstack Pubstack `mapstructure:"pubstack"` 457 } 458 459 type CurrencyConverter struct { 460 FetchURL string `mapstructure:"fetch_url"` 461 FetchIntervalSeconds int `mapstructure:"fetch_interval_seconds"` 462 StaleRatesSeconds int `mapstructure:"stale_rates_seconds"` 463 } 464 465 func (cfg *CurrencyConverter) validate(errs []error) []error { 466 if cfg.FetchIntervalSeconds < 0 { 467 errs = append(errs, fmt.Errorf("currency_converter.fetch_interval_seconds must be in the range [0, %d]. Got %d", 0xffff, cfg.FetchIntervalSeconds)) 468 } 469 return errs 470 } 471 472 type AgmaAnalytics struct { 473 Enabled bool `mapstructure:"enabled"` 474 Endpoint AgmaAnalyticsHttpEndpoint `mapstructure:"endpoint"` 475 Buffers AgmaAnalyticsBuffer `mapstructure:"buffers"` 476 Accounts []AgmaAnalyticsAccount `mapstructure:"accounts"` 477 } 478 479 type AgmaAnalyticsHttpEndpoint struct { 480 Url string `mapstructure:"url"` 481 Timeout string `mapstructure:"timeout"` 482 Gzip bool `mapstructure:"gzip"` 483 } 484 485 type AgmaAnalyticsBuffer struct { 486 BufferSize string `mapstructure:"size"` 487 EventCount int `mapstructure:"count"` 488 Timeout string `mapstructure:"timeout"` 489 } 490 491 type AgmaAnalyticsAccount struct { 492 Code string `mapstructure:"code"` 493 PublisherId string `mapstructure:"publisher_id"` 494 SiteAppId string `mapstructure:"site_app_id"` 495 } 496 497 // FileLogs Corresponding config for FileLogger as a PBS Analytics Module 498 type FileLogs struct { 499 Filename string `mapstructure:"filename"` 500 } 501 502 type Pubstack struct { 503 Enabled bool `mapstructure:"enabled"` 504 ScopeId string `mapstructure:"scopeid"` 505 IntakeUrl string `mapstructure:"endpoint"` 506 Buffers PubstackBuffer `mapstructure:"buffers"` 507 ConfRefresh string `mapstructure:"configuration_refresh_delay"` 508 } 509 510 type PubstackBuffer struct { 511 BufferSize string `mapstructure:"size"` 512 EventCount int `mapstructure:"count"` 513 Timeout string `mapstructure:"timeout"` 514 } 515 516 type VTrack struct { 517 TimeoutMS int64 `mapstructure:"timeout_ms"` 518 AllowUnknownBidder bool `mapstructure:"allow_unknown_bidder"` 519 Enabled bool `mapstructure:"enabled"` 520 } 521 522 type Event struct { 523 TimeoutMS int64 `mapstructure:"timeout_ms"` 524 } 525 526 type HostCookie struct { 527 Domain string `mapstructure:"domain"` 528 Family string `mapstructure:"family"` 529 CookieName string `mapstructure:"cookie_name"` 530 OptOutURL string `mapstructure:"opt_out_url"` 531 OptInURL string `mapstructure:"opt_in_url"` 532 MaxCookieSizeBytes int `mapstructure:"max_cookie_size_bytes"` 533 OptOutCookie Cookie `mapstructure:"optout_cookie"` 534 // Cookie timeout in days 535 TTL int64 `mapstructure:"ttl_days"` 536 } 537 538 func (cfg *HostCookie) TTLDuration() time.Duration { 539 return time.Duration(cfg.TTL) * time.Hour * 24 540 } 541 542 type RequestTimeoutHeaders struct { 543 RequestTimeInQueue string `mapstructure:"request_time_in_queue"` 544 RequestTimeoutInQueue string `mapstructure:"request_timeout_in_queue"` 545 } 546 547 type Metrics struct { 548 Influxdb InfluxMetrics `mapstructure:"influxdb"` 549 Prometheus PrometheusMetrics `mapstructure:"prometheus"` 550 Disabled DisabledMetrics `mapstructure:"disabled_metrics"` 551 } 552 553 type DisabledMetrics struct { 554 // True if we want to stop collecting account-to-adapter metrics 555 AccountAdapterDetails bool `mapstructure:"account_adapter_details"` 556 557 // True if we want to stop collecting account debug request metrics 558 AccountDebug bool `mapstructure:"account_debug"` 559 560 // True if we want to stop collecting account stored respponses metrics 561 AccountStoredResponses bool `mapstructure:"account_stored_responses"` 562 563 // True if we don't want to collect metrics about the connections prebid 564 // server establishes with bidder servers such as the number of connections 565 // that were created or reused. 566 AdapterConnectionMetrics bool `mapstructure:"adapter_connections_metrics"` 567 568 // True if we don't want to collect the per adapter buyer UID scrubbed metric 569 AdapterBuyerUIDScrubbed bool `mapstructure:"adapter_buyeruid_scrubbed"` 570 571 // True if we don't want to collect the per adapter GDPR request blocked metric 572 AdapterGDPRRequestBlocked bool `mapstructure:"adapter_gdpr_request_blocked"` 573 574 // True if we want to stop collecting account modules metrics 575 AccountModulesMetrics bool `mapstructure:"account_modules_metrics"` 576 } 577 578 func (cfg *Metrics) validate(errs []error) []error { 579 return cfg.Prometheus.validate(errs) 580 } 581 582 type InfluxMetrics struct { 583 Host string `mapstructure:"host"` 584 Database string `mapstructure:"database"` 585 Measurement string `mapstructure:"measurement"` 586 Username string `mapstructure:"username"` 587 Password string `mapstructure:"password"` 588 AlignTimestamps bool `mapstructure:"align_timestamps"` 589 MetricSendInterval int `mapstructure:"metric_send_interval"` 590 } 591 592 type PrometheusMetrics struct { 593 Port int `mapstructure:"port"` 594 Namespace string `mapstructure:"namespace"` 595 Subsystem string `mapstructure:"subsystem"` 596 TimeoutMillisRaw int `mapstructure:"timeout_ms"` 597 } 598 599 func (cfg *PrometheusMetrics) validate(errs []error) []error { 600 if cfg.Port > 0 && cfg.TimeoutMillisRaw <= 0 { 601 errs = append(errs, fmt.Errorf("metrics.prometheus.timeout_ms must be positive if metrics.prometheus.port is defined. Got timeout=%d and port=%d", cfg.TimeoutMillisRaw, cfg.Port)) 602 } 603 return errs 604 } 605 606 func (m *PrometheusMetrics) Timeout() time.Duration { 607 return time.Duration(m.TimeoutMillisRaw) * time.Millisecond 608 } 609 610 // ExternalCache configures the externally accessible cache url. 611 type ExternalCache struct { 612 Scheme string `mapstructure:"scheme"` 613 Host string `mapstructure:"host"` 614 Path string `mapstructure:"path"` 615 } 616 617 // Cache configures the url used internally by Prebid Server to communicate with Prebid Cache. 618 type Cache struct { 619 Scheme string `mapstructure:"scheme"` 620 Host string `mapstructure:"host"` 621 Query string `mapstructure:"query"` 622 623 // A static timeout here is not ideal. This is a hack because we have some aggressive timelines for OpenRTB support. 624 // This value specifies how much time the prebid server host expects a call to prebid cache to take. 625 // 626 // OpenRTB allows the caller to specify the auction timeout. Prebid Server will subtract _this_ amount of time 627 // from the timeout it gives demand sources to respond. 628 // 629 // In reality, the cache response time will probably fluctuate with the traffic over time. Someday, 630 // this should be replaced by code which tracks the response time of recent cache calls and 631 // adjusts the time dynamically. 632 ExpectedTimeMillis int `mapstructure:"expected_millis"` 633 634 DefaultTTLs DefaultTTLs `mapstructure:"default_ttl_seconds"` 635 } 636 637 // Default TTLs to use to cache bids for different types of imps. 638 type DefaultTTLs struct { 639 Banner int `mapstructure:"banner"` 640 Video int `mapstructure:"video"` 641 Native int `mapstructure:"native"` 642 Audio int `mapstructure:"audio"` 643 } 644 645 type Cookie struct { 646 Name string `mapstructure:"name"` 647 Value string `mapstructure:"value"` 648 } 649 650 // AliasConfig will define the various source(s) or the default aliases 651 // Currently only filesystem is supported, but keeping the config structure 652 type DefReqConfig struct { 653 Type string `mapstructure:"type"` 654 FileSystem DefReqFiles `mapstructure:"file"` 655 AliasInfo bool `mapstructure:"alias_info"` 656 } 657 658 type DefReqFiles struct { 659 FileName string `mapstructure:"name"` 660 } 661 662 type Debug struct { 663 TimeoutNotification TimeoutNotification `mapstructure:"timeout_notification"` 664 OverrideToken string `mapstructure:"override_token"` 665 } 666 667 type Server struct { 668 ExternalUrl string 669 GvlID int 670 DataCenter string 671 } 672 673 func (server *Server) Empty() bool { 674 return server == nil || (server.DataCenter == "" && server.ExternalUrl == "" && server.GvlID == 0) 675 } 676 677 func (cfg *Debug) validate(errs []error) []error { 678 return cfg.TimeoutNotification.validate(errs) 679 } 680 681 type TimeoutNotification struct { 682 // Log timeout notifications in the application log 683 Log bool `mapstructure:"log"` 684 // Fraction of notifications to log 685 SamplingRate float32 `mapstructure:"sampling_rate"` 686 // Only log failures 687 FailOnly bool `mapstructure:"fail_only"` 688 } 689 690 type Validations struct { 691 BannerCreativeMaxSize string `mapstructure:"banner_creative_max_size" json:"banner_creative_max_size"` 692 SecureMarkup string `mapstructure:"secure_markup" json:"secure_markup"` 693 MaxCreativeWidth int64 `mapstructure:"max_creative_width" json:"max_creative_width"` 694 MaxCreativeHeight int64 `mapstructure:"max_creative_height" json:"max_creative_height"` 695 } 696 697 const ( 698 ValidationEnforce string = "enforce" 699 ValidationWarn string = "warn" 700 ValidationSkip string = "skip" 701 ) 702 703 func (host *Validations) SetBannerCreativeMaxSize(account Validations) { 704 if len(account.BannerCreativeMaxSize) > 0 { 705 host.BannerCreativeMaxSize = account.BannerCreativeMaxSize 706 } 707 } 708 709 func (cfg *TimeoutNotification) validate(errs []error) []error { 710 if cfg.SamplingRate < 0.0 || cfg.SamplingRate > 1.0 { 711 errs = append(errs, fmt.Errorf("debug.timeout_notification.sampling_rate must be positive and not greater than 1.0. Got %f", cfg.SamplingRate)) 712 } 713 return errs 714 } 715 716 // New uses viper to get our server configurations. 717 func New(v *viper.Viper, bidderInfos BidderInfos, normalizeBidderName func(string) (openrtb_ext.BidderName, bool)) (*Configuration, error) { 718 var c Configuration 719 if err := v.Unmarshal(&c); err != nil { 720 return nil, fmt.Errorf("viper failed to unmarshal app config: %v", err) 721 } 722 723 if err := c.RequestValidation.Parse(); err != nil { 724 return nil, err 725 } 726 727 if err := isValidCookieSize(c.HostCookie.MaxCookieSizeBytes); err != nil { 728 glog.Fatal(fmt.Printf("Max cookie size %d cannot be less than %d \n", c.HostCookie.MaxCookieSizeBytes, MIN_COOKIE_SIZE_BYTES)) 729 return nil, err 730 } 731 732 if err := UnpackDSADefault(c.AccountDefaults.Privacy.DSA); err != nil { 733 return nil, fmt.Errorf("invalid default account DSA: %v", err) 734 } 735 736 // Update account defaults and generate base json for patch 737 c.AccountDefaults.CacheTTL = c.CacheURL.DefaultTTLs // comment this out to set explicitly in config 738 739 if err := c.MarshalAccountDefaults(); err != nil { 740 return nil, err 741 } 742 743 // To look for a request's publisher_id in the NonStandardPublishers list in 744 // O(1) time, we fill this hash table located in the NonStandardPublisherMap field of GDPR 745 var s struct{} 746 c.GDPR.NonStandardPublisherMap = make(map[string]struct{}) 747 for i := 0; i < len(c.GDPR.NonStandardPublishers); i++ { 748 c.GDPR.NonStandardPublisherMap[c.GDPR.NonStandardPublishers[i]] = s 749 } 750 751 c.GDPR.EEACountriesMap = make(map[string]struct{}, len(c.GDPR.EEACountries)) 752 for _, v := range c.GDPR.EEACountries { 753 c.GDPR.EEACountriesMap[v] = s 754 } 755 756 // for each purpose we capture a reference to the purpose config in a map for easy purpose config lookup 757 c.GDPR.TCF2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 758 1: &c.GDPR.TCF2.Purpose1, 759 2: &c.GDPR.TCF2.Purpose2, 760 3: &c.GDPR.TCF2.Purpose3, 761 4: &c.GDPR.TCF2.Purpose4, 762 5: &c.GDPR.TCF2.Purpose5, 763 6: &c.GDPR.TCF2.Purpose6, 764 7: &c.GDPR.TCF2.Purpose7, 765 8: &c.GDPR.TCF2.Purpose8, 766 9: &c.GDPR.TCF2.Purpose9, 767 10: &c.GDPR.TCF2.Purpose10, 768 } 769 770 // As an alternative to performing several string compares per request, we set the integer representation of 771 // the enforcement algorithm on each purpose config 772 for _, pc := range c.GDPR.TCF2.PurposeConfigs { 773 if pc.EnforceAlgo == TCF2EnforceAlgoBasic { 774 pc.EnforceAlgoID = TCF2BasicEnforcement 775 } else { 776 pc.EnforceAlgoID = TCF2FullEnforcement 777 } 778 } 779 780 // To look for a purpose's vendor exceptions in O(1) time, for each purpose we fill this hash table with bidders/analytics 781 // adapters located in the VendorExceptions field of the GDPR.TCF2.PurposeX struct defined in this file 782 for _, pc := range c.GDPR.TCF2.PurposeConfigs { 783 pc.VendorExceptionMap = make(map[string]struct{}) 784 for v := 0; v < len(pc.VendorExceptions); v++ { 785 adapterName := pc.VendorExceptions[v] 786 pc.VendorExceptionMap[adapterName] = struct{}{} 787 } 788 } 789 790 // To look for a special feature's vendor exceptions in O(1) time, we fill this hash table with bidders located in the 791 // VendorExceptions field of the GDPR.TCF2.SpecialFeature1 struct defined in this file 792 c.GDPR.TCF2.SpecialFeature1.VendorExceptionMap = make(map[openrtb_ext.BidderName]struct{}) 793 for v := 0; v < len(c.GDPR.TCF2.SpecialFeature1.VendorExceptions); v++ { 794 bidderName := c.GDPR.TCF2.SpecialFeature1.VendorExceptions[v] 795 c.GDPR.TCF2.SpecialFeature1.VendorExceptionMap[bidderName] = struct{}{} 796 } 797 798 // To look for a request's app_id in O(1) time, we fill this hash table located in the 799 // the BlacklistedApps field of the Configuration struct defined in this file 800 c.BlacklistedAppMap = make(map[string]bool) 801 for i := 0; i < len(c.BlacklistedApps); i++ { 802 c.BlacklistedAppMap[c.BlacklistedApps[i]] = true 803 } 804 805 // Migrate combo stored request config to separate stored_reqs and amp stored_reqs configs. 806 resolvedStoredRequestsConfig(&c) 807 808 configBidderInfosWithNillableFields, err := setConfigBidderInfoNillableFields(v, c.BidderInfos) 809 if err != nil { 810 return nil, err 811 } 812 mergedBidderInfos, err := applyBidderInfoConfigOverrides(configBidderInfosWithNillableFields, bidderInfos, normalizeBidderName) 813 if err != nil { 814 return nil, err 815 } 816 c.BidderInfos = mergedBidderInfos 817 818 glog.Info("Logging the resolved configuration:") 819 logGeneral(reflect.ValueOf(c), " \t") 820 if errs := c.validate(v); len(errs) > 0 { 821 return &c, errortypes.NewAggregateError("validation errors", errs) 822 } 823 824 return &c, nil 825 } 826 827 type bidderInfoNillableFields struct { 828 Disabled *bool `yaml:"disabled" mapstructure:"disabled"` 829 ModifyingVastXmlAllowed *bool `yaml:"modifyingVastXmlAllowed" mapstructure:"modifyingVastXmlAllowed"` 830 } 831 type nillableFieldBidderInfos map[string]nillableFieldBidderInfo 832 type nillableFieldBidderInfo struct { 833 nillableFields bidderInfoNillableFields 834 bidderInfo BidderInfo 835 } 836 837 func setConfigBidderInfoNillableFields(v *viper.Viper, bidderInfos BidderInfos) (nillableFieldBidderInfos, error) { 838 if len(bidderInfos) == 0 || v == nil { 839 return nil, nil 840 } 841 infos := make(nillableFieldBidderInfos, len(bidderInfos)) 842 843 for bidderName, bidderInfo := range bidderInfos { 844 info := nillableFieldBidderInfo{bidderInfo: bidderInfo} 845 846 if err := v.UnmarshalKey("adapters."+bidderName+".disabled", &info.nillableFields.Disabled); err != nil { 847 return nil, fmt.Errorf("viper failed to unmarshal bidder config disabled: %v", err) 848 } 849 if err := v.UnmarshalKey("adapters."+bidderName+".modifyingvastxmlallowed", &info.nillableFields.ModifyingVastXmlAllowed); err != nil { 850 return nil, fmt.Errorf("viper failed to unmarshal bidder config modifyingvastxmlallowed: %v", err) 851 } 852 infos[bidderName] = info 853 } 854 return infos, nil 855 } 856 857 // MarshalAccountDefaults compiles AccountDefaults into the JSON format used for merge patch 858 func (cfg *Configuration) MarshalAccountDefaults() error { 859 var err error 860 if cfg.accountDefaultsJSON, err = jsonutil.Marshal(cfg.AccountDefaults); err != nil { 861 glog.Warningf("converting %+v to json: %v", cfg.AccountDefaults, err) 862 } 863 return err 864 } 865 866 // UnpackDSADefault validates the JSON DSA default object string by unmarshaling and maps it to a struct 867 func UnpackDSADefault(dsa *AccountDSA) error { 868 if dsa == nil || len(dsa.Default) == 0 { 869 return nil 870 } 871 return jsonutil.Unmarshal([]byte(dsa.Default), &dsa.DefaultUnpacked) 872 } 873 874 // AccountDefaultsJSON returns the precompiled JSON form of account_defaults 875 func (cfg *Configuration) AccountDefaultsJSON() json.RawMessage { 876 return cfg.accountDefaultsJSON 877 } 878 879 // GetBaseURL allows for protocol relative URL if scheme is empty 880 func (cfg *Cache) GetBaseURL() string { 881 cfg.Scheme = strings.ToLower(cfg.Scheme) 882 if strings.Contains(cfg.Scheme, "https") { 883 return fmt.Sprintf("https://%s", cfg.Host) 884 } 885 if strings.Contains(cfg.Scheme, "http") { 886 return fmt.Sprintf("http://%s", cfg.Host) 887 } 888 return fmt.Sprintf("//%s", cfg.Host) 889 } 890 891 func (cfg *Configuration) GetCachedAssetURL(uuid string) string { 892 return fmt.Sprintf("%s/cache?%s", cfg.CacheURL.GetBaseURL(), strings.Replace(cfg.CacheURL.Query, "%PBS_CACHE_UUID%", uuid, 1)) 893 } 894 895 // Set the default config values for the viper object we are using. 896 func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { 897 if filename != "" { 898 v.SetConfigName(filename) 899 v.AddConfigPath(".") 900 v.AddConfigPath("/etc/config") 901 } 902 903 // Fixes #475: Some defaults will be set just so they are accessible via environment variables 904 // (basically so viper knows they exist) 905 v.SetDefault("external_url", "http://localhost:8000") 906 v.SetDefault("host", "") 907 v.SetDefault("port", 8000) 908 v.SetDefault("unix_socket_enable", false) // boolean which decide if the socket-server will be started. 909 v.SetDefault("unix_socket_name", "prebid-server.sock") // path of the socket's file which must be listened. 910 v.SetDefault("admin_port", 6060) 911 v.SetDefault("admin.enabled", true) // boolean to determine if admin listener will be started. 912 v.SetDefault("garbage_collector_threshold", 0) 913 v.SetDefault("status_response", "") 914 v.SetDefault("datacenter", "") 915 v.SetDefault("auction_timeouts_ms.default", 0) 916 v.SetDefault("auction_timeouts_ms.max", 0) 917 v.SetDefault("cache.scheme", "") 918 v.SetDefault("cache.host", "") 919 v.SetDefault("cache.query", "") 920 v.SetDefault("cache.expected_millis", 10) 921 v.SetDefault("cache.default_ttl_seconds.banner", 0) 922 v.SetDefault("cache.default_ttl_seconds.video", 0) 923 v.SetDefault("cache.default_ttl_seconds.native", 0) 924 v.SetDefault("cache.default_ttl_seconds.audio", 0) 925 v.SetDefault("external_cache.scheme", "") 926 v.SetDefault("external_cache.host", "") 927 v.SetDefault("external_cache.path", "") 928 v.SetDefault("recaptcha_secret", "") 929 v.SetDefault("host_cookie.domain", "") 930 v.SetDefault("host_cookie.family", "") 931 v.SetDefault("host_cookie.cookie_name", "") 932 v.SetDefault("host_cookie.opt_out_url", "") 933 v.SetDefault("host_cookie.opt_in_url", "") 934 v.SetDefault("host_cookie.optout_cookie.name", "") 935 v.SetDefault("host_cookie.value", "") 936 v.SetDefault("host_cookie.ttl_days", 90) 937 v.SetDefault("host_cookie.max_cookie_size_bytes", 0) 938 v.SetDefault("host_schain_node", nil) 939 v.SetDefault("validations.banner_creative_max_size", ValidationSkip) 940 v.SetDefault("validations.secure_markup", ValidationSkip) 941 v.SetDefault("validations.max_creative_size.height", 0) 942 v.SetDefault("validations.max_creative_size.width", 0) 943 v.SetDefault("http_client.max_connections_per_host", 0) // unlimited 944 v.SetDefault("http_client.max_idle_connections", 400) 945 v.SetDefault("http_client.max_idle_connections_per_host", 10) 946 v.SetDefault("http_client.idle_connection_timeout_seconds", 60) 947 v.SetDefault("http_client_cache.max_connections_per_host", 0) // unlimited 948 v.SetDefault("http_client_cache.max_idle_connections", 10) 949 v.SetDefault("http_client_cache.max_idle_connections_per_host", 2) 950 v.SetDefault("http_client_cache.idle_connection_timeout_seconds", 60) 951 // no metrics configured by default (metrics{host|database|username|password}) 952 v.SetDefault("metrics.disabled_metrics.account_adapter_details", false) 953 v.SetDefault("metrics.disabled_metrics.account_debug", true) 954 v.SetDefault("metrics.disabled_metrics.account_stored_responses", true) 955 v.SetDefault("metrics.disabled_metrics.adapter_connections_metrics", true) 956 v.SetDefault("metrics.disabled_metrics.adapter_buyeruid_scrubbed", true) 957 v.SetDefault("metrics.disabled_metrics.adapter_gdpr_request_blocked", false) 958 v.SetDefault("metrics.influxdb.host", "") 959 v.SetDefault("metrics.influxdb.database", "") 960 v.SetDefault("metrics.influxdb.measurement", "") 961 v.SetDefault("metrics.influxdb.username", "") 962 v.SetDefault("metrics.influxdb.password", "") 963 v.SetDefault("metrics.influxdb.align_timestamps", false) 964 v.SetDefault("metrics.influxdb.metric_send_interval", 20) 965 v.SetDefault("metrics.prometheus.port", 0) 966 v.SetDefault("metrics.prometheus.namespace", "") 967 v.SetDefault("metrics.prometheus.subsystem", "") 968 v.SetDefault("metrics.prometheus.timeout_ms", 10000) 969 v.SetDefault("category_mapping.filesystem.enabled", true) 970 v.SetDefault("category_mapping.filesystem.directorypath", "./static/category-mapping") 971 v.SetDefault("category_mapping.http.endpoint", "") 972 v.SetDefault("stored_requests_timeout_ms", 50) 973 v.SetDefault("stored_requests.database.connection.driver", "") 974 v.SetDefault("stored_requests.database.connection.dbname", "") 975 v.SetDefault("stored_requests.database.connection.host", "") 976 v.SetDefault("stored_requests.database.connection.port", 0) 977 v.SetDefault("stored_requests.database.connection.user", "") 978 v.SetDefault("stored_requests.database.connection.password", "") 979 v.SetDefault("stored_requests.database.connection.query_string", "") 980 v.SetDefault("stored_requests.database.connection.tls.root_cert", "") 981 v.SetDefault("stored_requests.database.connection.tls.client_cert", "") 982 v.SetDefault("stored_requests.database.connection.tls.client_key", "") 983 v.SetDefault("stored_requests.database.fetcher.query", "") 984 v.SetDefault("stored_requests.database.fetcher.amp_query", "") 985 v.SetDefault("stored_requests.database.initialize_caches.timeout_ms", 0) 986 v.SetDefault("stored_requests.database.initialize_caches.query", "") 987 v.SetDefault("stored_requests.database.initialize_caches.amp_query", "") 988 v.SetDefault("stored_requests.database.poll_for_updates.refresh_rate_seconds", 0) 989 v.SetDefault("stored_requests.database.poll_for_updates.timeout_ms", 0) 990 v.SetDefault("stored_requests.database.poll_for_updates.query", "") 991 v.SetDefault("stored_requests.database.poll_for_updates.amp_query", "") 992 v.SetDefault("stored_requests.filesystem.enabled", false) 993 v.SetDefault("stored_requests.filesystem.directorypath", "./stored_requests/data/by_id") 994 v.SetDefault("stored_requests.directorypath", "./stored_requests/data/by_id") 995 v.SetDefault("stored_requests.http.endpoint", "") 996 v.SetDefault("stored_requests.http.amp_endpoint", "") 997 v.SetDefault("stored_requests.in_memory_cache.type", "none") 998 v.SetDefault("stored_requests.in_memory_cache.ttl_seconds", 0) 999 v.SetDefault("stored_requests.in_memory_cache.request_cache_size_bytes", 0) 1000 v.SetDefault("stored_requests.in_memory_cache.imp_cache_size_bytes", 0) 1001 v.SetDefault("stored_requests.in_memory_cache.resp_cache_size_bytes", 0) 1002 v.SetDefault("stored_requests.cache_events_api", false) 1003 v.SetDefault("stored_requests.http_events.endpoint", "") 1004 v.SetDefault("stored_requests.http_events.amp_endpoint", "") 1005 v.SetDefault("stored_requests.http_events.refresh_rate_seconds", 0) 1006 v.SetDefault("stored_requests.http_events.timeout_ms", 0) 1007 // stored_video is short for stored_video_requests. 1008 // PBS is not in the business of storing video content beyond the normal prebid cache system. 1009 v.SetDefault("stored_video_req.database.connection.driver", "") 1010 v.SetDefault("stored_video_req.database.connection.dbname", "") 1011 v.SetDefault("stored_video_req.database.connection.host", "") 1012 v.SetDefault("stored_video_req.database.connection.port", 0) 1013 v.SetDefault("stored_video_req.database.connection.user", "") 1014 v.SetDefault("stored_video_req.database.connection.password", "") 1015 v.SetDefault("stored_video_req.database.connection.query_string", "") 1016 v.SetDefault("stored_video_req.database.connection.tls.root_cert", "") 1017 v.SetDefault("stored_video_req.database.connection.tls.client_cert", "") 1018 v.SetDefault("stored_video_req.database.connection.tls.client_key", "") 1019 v.SetDefault("stored_video_req.database.fetcher.query", "") 1020 v.SetDefault("stored_video_req.database.fetcher.amp_query", "") 1021 v.SetDefault("stored_video_req.database.initialize_caches.timeout_ms", 0) 1022 v.SetDefault("stored_video_req.database.initialize_caches.query", "") 1023 v.SetDefault("stored_video_req.database.initialize_caches.amp_query", "") 1024 v.SetDefault("stored_video_req.database.poll_for_updates.refresh_rate_seconds", 0) 1025 v.SetDefault("stored_video_req.database.poll_for_updates.timeout_ms", 0) 1026 v.SetDefault("stored_video_req.database.poll_for_updates.query", "") 1027 v.SetDefault("stored_video_req.database.poll_for_updates.amp_query", "") 1028 v.SetDefault("stored_video_req.filesystem.enabled", false) 1029 v.SetDefault("stored_video_req.filesystem.directorypath", "") 1030 v.SetDefault("stored_video_req.http.endpoint", "") 1031 v.SetDefault("stored_video_req.in_memory_cache.type", "none") 1032 v.SetDefault("stored_video_req.in_memory_cache.ttl_seconds", 0) 1033 v.SetDefault("stored_video_req.in_memory_cache.request_cache_size_bytes", 0) 1034 v.SetDefault("stored_video_req.in_memory_cache.imp_cache_size_bytes", 0) 1035 v.SetDefault("stored_video_req.in_memory_cache.resp_cache_size_bytes", 0) 1036 v.SetDefault("stored_video_req.cache_events.enabled", false) 1037 v.SetDefault("stored_video_req.cache_events.endpoint", "") 1038 v.SetDefault("stored_video_req.http_events.endpoint", "") 1039 v.SetDefault("stored_video_req.http_events.refresh_rate_seconds", 0) 1040 v.SetDefault("stored_video_req.http_events.timeout_ms", 0) 1041 v.SetDefault("stored_responses.database.connection.driver", "") 1042 v.SetDefault("stored_responses.database.connection.dbname", "") 1043 v.SetDefault("stored_responses.database.connection.host", "") 1044 v.SetDefault("stored_responses.database.connection.port", 0) 1045 v.SetDefault("stored_responses.database.connection.user", "") 1046 v.SetDefault("stored_responses.database.connection.password", "") 1047 v.SetDefault("stored_responses.database.connection.query_string", "") 1048 v.SetDefault("stored_responses.database.connection.tls.root_cert", "") 1049 v.SetDefault("stored_responses.database.connection.tls.client_cert", "") 1050 v.SetDefault("stored_responses.database.connection.tls.client_key", "") 1051 v.SetDefault("stored_responses.database.fetcher.query", "") 1052 v.SetDefault("stored_responses.database.fetcher.amp_query", "") 1053 v.SetDefault("stored_responses.database.initialize_caches.timeout_ms", 0) 1054 v.SetDefault("stored_responses.database.initialize_caches.query", "") 1055 v.SetDefault("stored_responses.database.initialize_caches.amp_query", "") 1056 v.SetDefault("stored_responses.database.poll_for_updates.refresh_rate_seconds", 0) 1057 v.SetDefault("stored_responses.database.poll_for_updates.timeout_ms", 0) 1058 v.SetDefault("stored_responses.database.poll_for_updates.query", "") 1059 v.SetDefault("stored_responses.database.poll_for_updates.amp_query", "") 1060 v.SetDefault("stored_responses.filesystem.enabled", false) 1061 v.SetDefault("stored_responses.filesystem.directorypath", "") 1062 v.SetDefault("stored_responses.http.endpoint", "") 1063 v.SetDefault("stored_responses.in_memory_cache.type", "none") 1064 v.SetDefault("stored_responses.in_memory_cache.ttl_seconds", 0) 1065 v.SetDefault("stored_responses.in_memory_cache.request_cache_size_bytes", 0) 1066 v.SetDefault("stored_responses.in_memory_cache.imp_cache_size_bytes", 0) 1067 v.SetDefault("stored_responses.in_memory_cache.resp_cache_size_bytes", 0) 1068 v.SetDefault("stored_responses.cache_events.enabled", false) 1069 v.SetDefault("stored_responses.cache_events.endpoint", "") 1070 v.SetDefault("stored_responses.http_events.endpoint", "") 1071 v.SetDefault("stored_responses.http_events.refresh_rate_seconds", 0) 1072 v.SetDefault("stored_responses.http_events.timeout_ms", 0) 1073 1074 v.SetDefault("vtrack.timeout_ms", 2000) 1075 v.SetDefault("vtrack.allow_unknown_bidder", true) 1076 v.SetDefault("vtrack.enabled", true) 1077 1078 v.SetDefault("event.timeout_ms", 1000) 1079 1080 v.SetDefault("user_sync.priority_groups", [][]string{}) 1081 1082 v.SetDefault("accounts.filesystem.enabled", false) 1083 v.SetDefault("accounts.filesystem.directorypath", "./stored_requests/data/by_id") 1084 v.SetDefault("accounts.in_memory_cache.type", "none") 1085 1086 v.BindEnv("user_sync.external_url") 1087 v.BindEnv("user_sync.coop_sync.default") 1088 1089 // some adapters append the user id to the end of the redirect url instead of using 1090 // macro substitution. it is important for the uid to be the last query parameter. 1091 v.SetDefault("user_sync.redirect_url", "{{.ExternalURL}}/setuid?bidder={{.SyncerKey}}&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&f={{.SyncType}}&uid={{.UserMacro}}") 1092 1093 v.SetDefault("max_request_size", 1024*256) 1094 v.SetDefault("analytics.file.filename", "") 1095 v.SetDefault("analytics.pubstack.endpoint", "https://s2s.pbstck.com/v1") 1096 v.SetDefault("analytics.pubstack.scopeid", "change-me") 1097 v.SetDefault("analytics.pubstack.enabled", false) 1098 v.SetDefault("analytics.pubstack.configuration_refresh_delay", "2h") 1099 v.SetDefault("analytics.pubstack.buffers.size", "2MB") 1100 v.SetDefault("analytics.pubstack.buffers.count", 100) 1101 v.SetDefault("analytics.pubstack.buffers.timeout", "900s") 1102 v.SetDefault("analytics.agma.enabled", false) 1103 v.SetDefault("analytics.agma.endpoint.url", "https://go.pbs.agma-analytics.de/v1/prebid-server") 1104 v.SetDefault("analytics.agma.endpoint.timeout", "2s") 1105 v.SetDefault("analytics.agma.endpoint.gzip", false) 1106 v.SetDefault("analytics.agma.buffers.size", "2MB") 1107 v.SetDefault("analytics.agma.buffers.count", 100) 1108 v.SetDefault("analytics.agma.buffers.timeout", "15m") 1109 v.SetDefault("analytics.agma.accounts", []AgmaAnalyticsAccount{}) 1110 v.SetDefault("amp_timeout_adjustment_ms", 0) 1111 v.BindEnv("gdpr.default_value") 1112 v.SetDefault("gdpr.enabled", true) 1113 v.SetDefault("gdpr.host_vendor_id", 0) 1114 v.SetDefault("gdpr.timeouts_ms.init_vendorlist_fetches", 0) 1115 v.SetDefault("gdpr.timeouts_ms.active_vendorlist_fetch", 0) 1116 v.SetDefault("gdpr.non_standard_publishers", []string{""}) 1117 v.SetDefault("gdpr.tcf2.enabled", true) 1118 v.SetDefault("gdpr.tcf2.purpose1.enforce_vendors", true) 1119 v.SetDefault("gdpr.tcf2.purpose2.enforce_vendors", true) 1120 v.SetDefault("gdpr.tcf2.purpose3.enforce_vendors", true) 1121 v.SetDefault("gdpr.tcf2.purpose4.enforce_vendors", true) 1122 v.SetDefault("gdpr.tcf2.purpose5.enforce_vendors", true) 1123 v.SetDefault("gdpr.tcf2.purpose6.enforce_vendors", true) 1124 v.SetDefault("gdpr.tcf2.purpose7.enforce_vendors", true) 1125 v.SetDefault("gdpr.tcf2.purpose8.enforce_vendors", true) 1126 v.SetDefault("gdpr.tcf2.purpose9.enforce_vendors", true) 1127 v.SetDefault("gdpr.tcf2.purpose10.enforce_vendors", true) 1128 v.SetDefault("gdpr.tcf2.purpose1.vendor_exceptions", []string{}) 1129 v.SetDefault("gdpr.tcf2.purpose2.vendor_exceptions", []string{}) 1130 v.SetDefault("gdpr.tcf2.purpose3.vendor_exceptions", []string{}) 1131 v.SetDefault("gdpr.tcf2.purpose4.vendor_exceptions", []string{}) 1132 v.SetDefault("gdpr.tcf2.purpose5.vendor_exceptions", []string{}) 1133 v.SetDefault("gdpr.tcf2.purpose6.vendor_exceptions", []string{}) 1134 v.SetDefault("gdpr.tcf2.purpose7.vendor_exceptions", []string{}) 1135 v.SetDefault("gdpr.tcf2.purpose8.vendor_exceptions", []string{}) 1136 v.SetDefault("gdpr.tcf2.purpose9.vendor_exceptions", []string{}) 1137 v.SetDefault("gdpr.tcf2.purpose10.vendor_exceptions", []string{}) 1138 v.SetDefault("gdpr.amp_exception", false) 1139 v.SetDefault("gdpr.eea_countries", []string{"ALA", "AUT", "BEL", "BGR", "HRV", "CYP", "CZE", "DNK", "EST", 1140 "FIN", "FRA", "GUF", "DEU", "GIB", "GRC", "GLP", "GGY", "HUN", "ISL", "IRL", "IMN", "ITA", "JEY", "LVA", 1141 "LIE", "LTU", "LUX", "MLT", "MTQ", "MYT", "NLD", "NOR", "POL", "PRT", "REU", "ROU", "BLM", "MAF", "SPM", 1142 "SVK", "SVN", "ESP", "SWE", "GBR"}) 1143 v.SetDefault("ccpa.enforce", false) 1144 v.SetDefault("lmt.enforce", true) 1145 v.SetDefault("currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json") 1146 v.SetDefault("currency_converter.fetch_interval_seconds", 1800) // fetch currency rates every 30 minutes 1147 v.SetDefault("currency_converter.stale_rates_seconds", 0) 1148 v.SetDefault("default_request.type", "") 1149 v.SetDefault("default_request.file.name", "") 1150 v.SetDefault("default_request.alias_info", false) 1151 v.SetDefault("blacklisted_apps", []string{""}) 1152 v.SetDefault("blacklisted_accts", []string{""}) 1153 v.SetDefault("account_required", false) 1154 v.SetDefault("account_defaults.disabled", false) 1155 v.SetDefault("account_defaults.debug_allow", true) 1156 v.SetDefault("account_defaults.price_floors.enabled", false) 1157 v.SetDefault("account_defaults.price_floors.enforce_floors_rate", 100) 1158 v.SetDefault("account_defaults.price_floors.adjust_for_bid_adjustment", true) 1159 v.SetDefault("account_defaults.price_floors.enforce_deal_floors", false) 1160 v.SetDefault("account_defaults.price_floors.use_dynamic_data", false) 1161 v.SetDefault("account_defaults.price_floors.max_rules", 100) 1162 v.SetDefault("account_defaults.price_floors.max_schema_dims", 3) 1163 v.SetDefault("account_defaults.price_floors.fetch.enabled", false) 1164 v.SetDefault("account_defaults.price_floors.fetch.url", "") 1165 v.SetDefault("account_defaults.price_floors.fetch.timeout_ms", 3000) 1166 v.SetDefault("account_defaults.price_floors.fetch.max_file_size_kb", 100) 1167 v.SetDefault("account_defaults.price_floors.fetch.max_rules", 1000) 1168 v.SetDefault("account_defaults.price_floors.fetch.max_age_sec", 86400) 1169 v.SetDefault("account_defaults.price_floors.fetch.period_sec", 3600) 1170 v.SetDefault("account_defaults.price_floors.fetch.max_schema_dims", 0) 1171 v.SetDefault("account_defaults.privacy.privacysandbox.topicsdomain", "") 1172 v.SetDefault("account_defaults.privacy.privacysandbox.cookiedeprecation.enabled", false) 1173 v.SetDefault("account_defaults.privacy.privacysandbox.cookiedeprecation.ttl_sec", 604800) 1174 1175 v.SetDefault("account_defaults.events_enabled", false) 1176 v.BindEnv("account_defaults.privacy.dsa.default") 1177 v.BindEnv("account_defaults.privacy.dsa.gdpr_only") 1178 v.SetDefault("account_defaults.privacy.ipv6.anon_keep_bits", 56) 1179 v.SetDefault("account_defaults.privacy.ipv4.anon_keep_bits", 24) 1180 1181 //Defaults for Price floor fetcher 1182 v.SetDefault("price_floors.fetcher.worker", 20) 1183 v.SetDefault("price_floors.fetcher.capacity", 20000) 1184 v.SetDefault("price_floors.fetcher.cache_size_mb", 64) 1185 v.SetDefault("price_floors.fetcher.http_client.max_connections_per_host", 0) // unlimited 1186 v.SetDefault("price_floors.fetcher.http_client.max_idle_connections", 40) 1187 v.SetDefault("price_floors.fetcher.http_client.max_idle_connections_per_host", 2) 1188 v.SetDefault("price_floors.fetcher.http_client.idle_connection_timeout_seconds", 60) 1189 v.SetDefault("price_floors.fetcher.max_retries", 10) 1190 1191 v.SetDefault("account_defaults.events_enabled", false) 1192 v.SetDefault("compression.response.enable_gzip", false) 1193 v.SetDefault("compression.request.enable_gzip", false) 1194 1195 v.SetDefault("certificates_file", "") 1196 v.SetDefault("auto_gen_source_tid", true) 1197 v.SetDefault("generate_bid_id", false) 1198 v.SetDefault("generate_request_id", false) 1199 1200 v.SetDefault("request_timeout_headers.request_time_in_queue", "") 1201 v.SetDefault("request_timeout_headers.request_timeout_in_queue", "") 1202 1203 v.SetDefault("debug.timeout_notification.log", false) 1204 v.SetDefault("debug.timeout_notification.sampling_rate", 0.0) 1205 v.SetDefault("debug.timeout_notification.fail_only", false) 1206 v.SetDefault("debug.override_token", "") 1207 1208 v.SetDefault("tmax_adjustments.enabled", false) 1209 v.SetDefault("tmax_adjustments.bidder_response_duration_min_ms", 0) 1210 v.SetDefault("tmax_adjustments.bidder_network_latency_buffer_ms", 0) 1211 v.SetDefault("tmax_adjustments.pbs_response_preparation_duration_ms", 0) 1212 1213 /* IPv4 1214 /* Site Local: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 1215 /* Link Local: 169.254.0.0/16 1216 /* Loopback: 127.0.0.0/8 1217 /* 1218 /* IPv6 1219 /* Loopback: ::1/128 1220 /* Documentation: 2001:db8::/32 1221 /* Unique Local: fc00::/7 1222 /* Link Local: fe80::/10 1223 /* Multicast: ff00::/8 1224 */ 1225 v.SetDefault("request_validation.ipv4_private_networks", []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16", "127.0.0.0/8"}) 1226 v.SetDefault("request_validation.ipv6_private_networks", []string{"::1/128", "fc00::/7", "fe80::/10", "ff00::/8", "2001:db8::/32"}) 1227 1228 // Set environment variable support: 1229 v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) 1230 v.SetTypeByDefaultValue(true) 1231 v.SetEnvPrefix("PBS") 1232 v.AutomaticEnv() 1233 v.ReadInConfig() 1234 1235 // These defaults must be set after the migrate functions because those functions look for the presence of these 1236 // config fields and there isn't a way to detect presence of a config field using the viper package if a default 1237 // is set. Viper IsSet and Get functions consider default values. 1238 v.SetDefault("gdpr.tcf2.purpose1.enforce_algo", TCF2EnforceAlgoFull) 1239 v.SetDefault("gdpr.tcf2.purpose2.enforce_algo", TCF2EnforceAlgoFull) 1240 v.SetDefault("gdpr.tcf2.purpose3.enforce_algo", TCF2EnforceAlgoFull) 1241 v.SetDefault("gdpr.tcf2.purpose4.enforce_algo", TCF2EnforceAlgoFull) 1242 v.SetDefault("gdpr.tcf2.purpose5.enforce_algo", TCF2EnforceAlgoFull) 1243 v.SetDefault("gdpr.tcf2.purpose6.enforce_algo", TCF2EnforceAlgoFull) 1244 v.SetDefault("gdpr.tcf2.purpose7.enforce_algo", TCF2EnforceAlgoFull) 1245 v.SetDefault("gdpr.tcf2.purpose8.enforce_algo", TCF2EnforceAlgoFull) 1246 v.SetDefault("gdpr.tcf2.purpose9.enforce_algo", TCF2EnforceAlgoFull) 1247 v.SetDefault("gdpr.tcf2.purpose10.enforce_algo", TCF2EnforceAlgoFull) 1248 v.SetDefault("gdpr.tcf2.purpose1.enforce_purpose", true) 1249 v.SetDefault("gdpr.tcf2.purpose2.enforce_purpose", true) 1250 v.SetDefault("gdpr.tcf2.purpose3.enforce_purpose", true) 1251 v.SetDefault("gdpr.tcf2.purpose4.enforce_purpose", true) 1252 v.SetDefault("gdpr.tcf2.purpose5.enforce_purpose", true) 1253 v.SetDefault("gdpr.tcf2.purpose6.enforce_purpose", true) 1254 v.SetDefault("gdpr.tcf2.purpose7.enforce_purpose", true) 1255 v.SetDefault("gdpr.tcf2.purpose8.enforce_purpose", true) 1256 v.SetDefault("gdpr.tcf2.purpose9.enforce_purpose", true) 1257 v.SetDefault("gdpr.tcf2.purpose10.enforce_purpose", true) 1258 v.SetDefault("gdpr.tcf2.purpose_one_treatment.enabled", true) 1259 v.SetDefault("gdpr.tcf2.purpose_one_treatment.access_allowed", true) 1260 v.SetDefault("gdpr.tcf2.special_feature1.enforce", true) 1261 v.SetDefault("gdpr.tcf2.special_feature1.vendor_exceptions", []openrtb_ext.BidderName{}) 1262 v.SetDefault("price_floors.enabled", false) 1263 1264 // Defaults for account_defaults.events.default_url 1265 v.SetDefault("account_defaults.events.default_url", "https://PBS_HOST/event?t=##PBS-EVENTTYPE##&vtype=##PBS-VASTEVENT##&b=##PBS-BIDID##&f=i&a=##PBS-ACCOUNTID##&ts=##PBS-TIMESTAMP##&bidder=##PBS-BIDDER##&int=##PBS-INTEGRATION##&mt=##PBS-MEDIATYPE##&ch=##PBS-CHANNEL##&aid=##PBS-AUCTIONID##&l=##PBS-LINEID##") 1266 v.SetDefault("account_defaults.events.enabled", false) 1267 1268 v.SetDefault("experiment.adscert.mode", "off") 1269 v.SetDefault("experiment.adscert.inprocess.origin", "") 1270 v.SetDefault("experiment.adscert.inprocess.key", "") 1271 v.SetDefault("experiment.adscert.inprocess.domain_check_interval_seconds", 30) 1272 v.SetDefault("experiment.adscert.inprocess.domain_renewal_interval_seconds", 30) 1273 v.SetDefault("experiment.adscert.remote.url", "") 1274 v.SetDefault("experiment.adscert.remote.signing_timeout_ms", 5) 1275 1276 v.SetDefault("hooks.enabled", false) 1277 1278 for bidderName := range bidderInfos { 1279 setBidderDefaults(v, strings.ToLower(bidderName)) 1280 } 1281 } 1282 1283 func isConfigInfoPresent(v *viper.Viper, prefix string, fields []string) bool { 1284 prefix = prefix + "." 1285 for _, field := range fields { 1286 fieldName := prefix + field 1287 if v.IsSet(fieldName) { 1288 return true 1289 } 1290 } 1291 return false 1292 } 1293 1294 func setBidderDefaults(v *viper.Viper, bidder string) { 1295 adapterCfgPrefix := "adapters." + bidder 1296 v.BindEnv(adapterCfgPrefix + ".disabled") 1297 v.BindEnv(adapterCfgPrefix + ".endpoint") 1298 v.BindEnv(adapterCfgPrefix + ".extra_info") 1299 v.BindEnv(adapterCfgPrefix + ".modifyingVastXmlAllowed") 1300 v.BindEnv(adapterCfgPrefix + ".debug.allow") 1301 v.BindEnv(adapterCfgPrefix + ".gvlVendorID") 1302 v.BindEnv(adapterCfgPrefix + ".usersync_url") 1303 v.BindEnv(adapterCfgPrefix + ".experiment.adsCert.enabled") 1304 v.BindEnv(adapterCfgPrefix + ".platform_id") 1305 v.BindEnv(adapterCfgPrefix + ".app_secret") 1306 v.BindEnv(adapterCfgPrefix + ".xapi.username") 1307 v.BindEnv(adapterCfgPrefix + ".xapi.password") 1308 v.BindEnv(adapterCfgPrefix + ".xapi.tracker") 1309 v.BindEnv(adapterCfgPrefix + ".endpointCompression") 1310 v.BindEnv(adapterCfgPrefix + ".openrtb.version") 1311 v.BindEnv(adapterCfgPrefix + ".openrtb.gpp-supported") 1312 1313 v.BindEnv(adapterCfgPrefix + ".usersync.key") 1314 v.BindEnv(adapterCfgPrefix + ".usersync.default") 1315 v.BindEnv(adapterCfgPrefix + ".usersync.iframe.url") 1316 v.BindEnv(adapterCfgPrefix + ".usersync.iframe.redirect_url") 1317 v.BindEnv(adapterCfgPrefix + ".usersync.iframe.external_url") 1318 v.BindEnv(adapterCfgPrefix + ".usersync.iframe.user_macro") 1319 v.BindEnv(adapterCfgPrefix + ".usersync.redirect.url") 1320 v.BindEnv(adapterCfgPrefix + ".usersync.redirect.redirect_url") 1321 v.BindEnv(adapterCfgPrefix + ".usersync.redirect.external_url") 1322 v.BindEnv(adapterCfgPrefix + ".usersync.redirect.user_macro") 1323 v.BindEnv(adapterCfgPrefix + ".usersync.external_url") 1324 v.BindEnv(adapterCfgPrefix + ".usersync.support_cors") 1325 } 1326 1327 func isValidCookieSize(maxCookieSize int) error { 1328 // If a non-zero-less-than-500-byte "host_cookie.max_cookie_size_bytes" value was specified in the 1329 // environment configuration of prebid-server, default to 500 bytes 1330 if maxCookieSize != 0 && maxCookieSize < MIN_COOKIE_SIZE_BYTES { 1331 return fmt.Errorf("Configured cookie size is less than allowed minimum size of %d \n", MIN_COOKIE_SIZE_BYTES) 1332 } 1333 return nil 1334 } 1335 1336 // Tmax Adjustments enables PBS to estimate the tmax value for bidders, indicating the allotted time for them to respond to a request. 1337 // It's important to note that the calculated tmax is just an estimate and will not be entirely precise. 1338 // PBS will calculate the bidder tmax as follows: 1339 // bidderTmax = request.tmax - reqProcessingTime - BidderNetworkLatencyBuffer - PBSResponsePreparationDuration 1340 // Note that reqProcessingTime is time taken by PBS to process a given request before it is sent to bid adapters and is computed at run time. 1341 type TmaxAdjustments struct { 1342 // Enabled indicates whether bidder tmax should be calculated and passed on to bid adapters 1343 Enabled bool `mapstructure:"enabled"` 1344 // BidderNetworkLatencyBuffer accounts for network delays between PBS and bidder servers. 1345 // A value of 0 indicates no network latency buffer should be accounted for when calculating the bidder tmax. 1346 BidderNetworkLatencyBuffer uint `mapstructure:"bidder_network_latency_buffer_ms"` 1347 // PBSResponsePreparationDuration accounts for amount of time required for PBS to process all bidder responses and generate final response for a request. 1348 // A value of 0 indicates PBS response preparation time shouldn't be accounted for when calculating bidder tmax. 1349 PBSResponsePreparationDuration uint `mapstructure:"pbs_response_preparation_duration_ms"` 1350 // BidderResponseDurationMin is the minimum amount of time expected to get a response from a bidder request. 1351 // PBS won't send a request to the bidder if the bidder tmax calculated is less than the BidderResponseDurationMin value 1352 BidderResponseDurationMin uint `mapstructure:"bidder_response_duration_min_ms"` 1353 }