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