Commit 207795c
authored
* Tidy small review nits across the new auction surface
Addresses review findings on #680:
- P2-18 / price_bucket: reject NaN/Inf cpm up front before the
(x * 100.0).floor() as u64 cast (Rust's NaN-cast behaviour is
only safe by convention, not contract). Add test coverage.
- P2-24 / publisher.rs::write_bids_to_state: drop the per-request
log line from INFO to DEBUG so production logs don't spam a slot
list on every page request.
- P2-25 / publisher.rs::build_bids_script / build_ad_slots_script:
serde_json::to_string of a Map / Vec is infallible -- use
expect("should be infallible") instead of unwrap_or_else with a
silent fallback that would mask any future bug.
- P2-15 / prebid: drop the dead PrebidIntegrationConfig::suppress_nurl
field -- declared but never read anywhere in the codebase. The
no-op test it carried goes with it.
* Extract GPT bootstrap script and guard double enableServices
Addresses review findings on #680:
- P2-2: the inline `__tsAdInit` bootstrap injected at <head> called
googletag.pubads().enableSingleRequest() and googletag.enableServices()
unconditionally. The TS bundle's later-installed version guards both
with a `__tsServicesEnabled` flag — the inline version did not, so
the publisher's own GPT init code (or an upgrade where the bundle
loads before the bids script runs) caused double-enable + duplicate
refresh(), producing duplicate ad requests on every load. Now both
inline and bundle converge on the same flag and only invoke
`refresh(newSlots)` for the slots this pass actually defined, never
the global slot list.
- P2-26: the bootstrap source moves out of a concat!() literal block
in head_inserts() into a syntax-highlighted gpt_bootstrap.js file
pulled in via include_str!. The Rust side keeps a single named
constant, GPT_BOOTSTRAP_JS, so future edits diff cleanly.
Adds a regression test that asserts the guard flag is present and that
unbounded refresh() is gone.
* Harden auction-orchestrator state cleanup
Addresses review findings on #680:
- P2-6: APS provider held its per-request slot_id_map across
request boundaries when the same Wasm instance was reused
(the mock provider already cleared its bid_index, APS did not).
parse_response now `std::mem::take`s the map so it can never
carry over to a subsequent request.
- P2-7: apply_floor_prices used to silently pass bids with
`price=None` through the floor filter. Today both production
callers decode/skip None before calling, so the pass-through
was dead code that would, if revived, cause winning_bids.len()
to overcount what build_bid_map ships to the client. Drop the
None branch and update the existing test to pin the new
contract: callers must decode prices first.
* Harden /__ts/page-bids and creative-opportunities loading
Addresses review findings on #680:
- P2-4: /__ts/page-bids ran the full SSP auction for every request
without gating crawlers or prefetches the way the publisher path
does, exposing partner request quota to client-side spraying.
Apply the same is_bot / is_prefetch gate handle_publisher_request
uses: slots are still returned (so HTML structure is unchanged)
but the auction is short-circuited. New regression tests cover
both gates.
- P2-5 + P2-13: the adapter previously parsed CREATIVE_OPPORTUNITIES_TOML
on every request and `expect("should parse...")` on failure, so a
malformed embedded TOML (CI-bypassed binary patch, future schema
change, anything build.rs didn't catch) would panic every request.
Parse it lazily once per Wasm instance via LazyLock; on parse
failure log an error and fall back to the documented "empty slots
file = feature disabled" state instead of panicking.
* Consolidate HTML stream processor + auction helpers
Addresses review findings on #680:
- P2-3 + P2-16: create_html_stream_processor previously built
HtmlProcessorConfig inline, bypassing HtmlProcessorConfig::from_settings.
A future edit to from_settings (e.g. to read a new flag from Settings)
would silently miss the streaming-with-auction-hold path. Now goes
through from_settings, with a new with_ad_state(...) builder method
that layers the ad_slots_script / ad_bids_state fields on top. The
`_settings` argument on create_html_stream_processor is now actually
used and is no longer underscore-prefixed.
- P2-17: the auction debug-comment prepend logic was duplicated between
one_behind_loop (path=stream) and the BufferedProcessed arm
(path=buffered). Extracted as `prepend_auction_debug_comment(label,
result, state)` so the single source of truth gets one definition
and the only difference between paths is the label string.
- P2-14: build_auction_request was at the project's 7-argument cap.
Bundled (matched_slots, request_path, co_config) into a new
MatchedSlotsContext struct — the three fields always travel together
anyway. The function now takes 5 args, leaving headroom for future
per-request inputs without breaking the project rule.
* Document AuctionContext request contract and pin mediator placeholder
Addresses review finding P2-1 on #680: collect_dispatched_auction and the
publisher-side collectors built fastly::Request::get("https://placeholder.invalid/")
on the fly and stuffed it into AuctionContext.request before invoking the
mediator. That worked today only because the current mediator
(adserver_mock) does not read request headers. A future PBS-as-mediator
change would silently lose DNT, client IP, UA, etc., because the
placeholder has none of them.
The structural fix that surfaces the contract:
- AuctionContext::request now carries a thorough doc-comment that
explicitly distinguishes the dispatch path (real client request, all
headers available) from the collect path (synthetic placeholder, no
client headers — mediators MUST snapshot at dispatch time if they
need them).
- MEDIATOR_PLACEHOLDER_URL is a single named const so the three inline
`"https://placeholder.invalid/"` literals across orchestrator.rs and
publisher.rs converge on one source of truth. Tests / debug-asserts
can compare against it.
- make_collect_context now debug_asserts that the placeholder argument
matches the canonical URL, so any future caller that accidentally
forwards a real client request through the collect path fails loudly
in debug builds instead of triggering an invisible header-loss bug.
A full snapshot-headers refactor (so mediators can read real client
headers across the await) is tracked as follow-up; this PR makes the
existing contract impossible to violate accidentally.
* Apply cargo fmt to fix-up commits
* Forward ts-eids cookie through /auction endpoint
Addresses pass-2 review finding P3-1 on #680: handle_auction read the
request's cookie jar for consent purposes but never threaded it into
the AuctionRequest, so the Extended User IDs from the `ts-eids` cookie
were dropped on the floor. The publisher-page and /__ts/page-bids paths
both call parse_ts_eids_cookie(cookie_jar.as_ref()); the /auction
endpoint now does the same so programmatic callers (slim-Prebid, native
apps, server-to-server integrations) get parity instead of silently
losing identity data.
* Pass-3 review fixes for #680: bot helpers, dead arg, pre-compiled globs
Addresses pass-2 review findings on #680:
- Dedupe the bot-UA and prefetch checks. handle_publisher_request and
handle_page_bids both inlined the same 5-entry crawler list and the
sec-purpose/purpose header check. Promoted to two pub(crate) helpers
in publisher.rs (is_bot_user_agent, is_prefetch_request) backed by a
single BOT_USER_AGENT_FRAGMENTS const, so the two paths can't drift.
- Drop the dead gam_network_id argument on
CreativeOpportunitySlot::to_ad_slot. The parameter was already being
discarded via `let _ = gam_network_id;`. Removing it also drops the
now-unused co_config field from MatchedSlotsContext.
- Pre-compile slot glob patterns once per Wasm instance. Each call to
matches_path previously ran Pattern::new (per pattern, per slot, per
request). The slots live in the adapter's LazyLock-cached
CreativeOpportunitiesFile, so adding a #[serde(skip)] compiled_patterns
cache populated by CreativeOpportunitiesFile::compile() at file-load
time turns matches_path into a Vec<Pattern>::iter().any() lookup on
the hot path. The fallback (compile-per-call) is preserved for
hand-built slots in tests. Two new regression tests pin the cache.
* Address deferred perf findings from PR #680 review
P2-8: Promote STREAM_CHUNK_SIZE (8192) to module scope and use it for
both the brotli Decompressor and CompressorWriter internal buffers,
aligning them with the read buffer in one_behind_loop.
P2-9: Replace RwLock<Option<String>> with Mutex<Option<String>> for
ad_bids_state across publisher.rs and html_processor.rs. Single-threaded
WASM gains no parallelism from RwLock; Mutex is simpler and avoids the
reader-writer bookkeeping the workload cannot use.
P2-10: Rewrite html_escape_for_script as a single-pass char loop with
one pre-allocated String instead of seven sequential String::replace
allocations. All existing escape tests pass unchanged.
1 parent 6c31b66 commit 207795c
12 files changed
Lines changed: 694 additions & 270 deletions
File tree
- crates
- trusted-server-adapter-fastly/src
- trusted-server-core/src
- auction
- integrations
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
45 | 78 | | |
46 | 79 | | |
47 | 80 | | |
| |||
94 | 127 | | |
95 | 128 | | |
96 | 129 | | |
97 | | - | |
98 | | - | |
99 | | - | |
| 130 | + | |
100 | 131 | | |
101 | 132 | | |
102 | 133 | | |
| |||
121 | 152 | | |
122 | 153 | | |
123 | 154 | | |
124 | | - | |
| 155 | + | |
125 | 156 | | |
126 | 157 | | |
127 | 158 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
125 | 125 | | |
126 | 126 | | |
127 | 127 | | |
128 | | - | |
129 | | - | |
| 128 | + | |
| 129 | + | |
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
138 | 142 | | |
139 | 143 | | |
140 | 144 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
540 | 540 | | |
541 | 541 | | |
542 | 542 | | |
543 | | - | |
544 | | - | |
545 | | - | |
546 | | - | |
547 | | - | |
548 | | - | |
549 | | - | |
550 | | - | |
551 | | - | |
552 | | - | |
553 | | - | |
554 | | - | |
555 | | - | |
556 | | - | |
557 | | - | |
558 | | - | |
559 | | - | |
560 | | - | |
561 | | - | |
562 | | - | |
563 | | - | |
564 | | - | |
565 | | - | |
566 | | - | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
567 | 551 | | |
568 | | - | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
569 | 566 | | |
570 | 567 | | |
571 | 568 | | |
| |||
872 | 869 | | |
873 | 870 | | |
874 | 871 | | |
875 | | - | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
876 | 880 | | |
877 | 881 | | |
878 | 882 | | |
| |||
1256 | 1260 | | |
1257 | 1261 | | |
1258 | 1262 | | |
1259 | | - | |
1260 | | - | |
1261 | | - | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
1262 | 1271 | | |
1263 | 1272 | | |
1264 | 1273 | | |
| |||
1268 | 1277 | | |
1269 | 1278 | | |
1270 | 1279 | | |
1271 | | - | |
| 1280 | + | |
1272 | 1281 | | |
1273 | 1282 | | |
1274 | 1283 | | |
| |||
1289 | 1298 | | |
1290 | 1299 | | |
1291 | 1300 | | |
1292 | | - | |
1293 | 1301 | | |
1294 | 1302 | | |
1295 | | - | |
1296 | | - | |
1297 | | - | |
1298 | | - | |
1299 | | - | |
1300 | 1303 | | |
1301 | | - | |
1302 | | - | |
| 1304 | + | |
| 1305 | + | |
1303 | 1306 | | |
1304 | 1307 | | |
1305 | | - | |
1306 | | - | |
1307 | | - | |
1308 | | - | |
1309 | | - | |
1310 | | - | |
| 1308 | + | |
| 1309 | + | |
1311 | 1310 | | |
1312 | 1311 | | |
1313 | 1312 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
118 | 141 | | |
119 | 142 | | |
120 | 143 | | |
| |||
127 | 150 | | |
128 | 151 | | |
129 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
130 | 159 | | |
131 | 160 | | |
132 | 161 | | |
| |||
0 commit comments