Skip to content

Commit 28391cd

Browse files
Rename Server Side Cookie (SSC) to Edge Cookie (EC) throughout codebase
Rename the SSC feature to Edge Cookie (EC) to better reflect its purpose as an edge-generated identifier. This is a hard cutover with no backward compatibility — the feature has not been deployed yet. Code changes (18 Rust files): - ssc.rs → ec.rs (module rename + all functions/tests) - Constants: COOKIE_TS_SSC → COOKIE_TS_EC, HEADER_X_TS_SSC → HEADER_X_TS_EC - Settings: struct Ssc → Ec, removed legacy synthetic alias - Error variant: Ssc → Ec - Cookie/header/query-param wire names: ts-ssc → ts-ec, x-ts-ssc → x-ts-ec - OpenRTB field: ssc_fresh → ec_fresh - Extracted upsert_ec_query_param helper in proxy.rs (dedup) Config: [ssc] → [ec] in trusted-server.toml and all test configs KV store test data: synthetic_id → ec_counter JS: Updated GPT integration comments Docs: Renamed server-side-cookies.md → edge-cookies.md, updated 27 doc files Also removed stale nonexistent X-TS-SSC-Trusted-Server header from docs
1 parent 6e51272 commit 28391cd

56 files changed

Lines changed: 471 additions & 491 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
## Project Overview
77

88
Rust-based edge computing application targeting **Fastly Compute**. Handles
9-
privacy-preserving Server Side Cookie (SSC) ID generation, ad serving with GDPR compliance,
9+
privacy-preserving Edge Cookie (EC) ID generation, ad serving with GDPR compliance,
1010
real-time bidding integration, and publisher-side JavaScript injection.
1111

1212
## Workspace Layout
@@ -366,7 +366,7 @@ both runtime behavior and build/tooling changes.
366366
| `crates/common/src/tsjs.rs` | Script tag generation with module IDs |
367367
| `crates/common/src/html_processor.rs` | Injects `<script>` at `<head>` start |
368368
| `crates/common/src/publisher.rs` | `/static/tsjs=` handler, concatenates modules |
369-
| `crates/common/src/ssc.rs` | Server Side Cookie (SSC) ID generation |
369+
| `crates/common/src/ec.rs` | Edge Cookie (EC) ID generation |
370370
| `crates/common/src/cookies.rs` | Cookie handling |
371371
| `crates/common/src/gdpr.rs` | GDPR consent management |
372372
| `crates/common/src/http_wrapper.rs` | HTTP abstractions |

OPTIMIZATION.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ This document presents a performance analysis and optimization plan for the Trus
3535
| ~2% | `IntegrationRegistry` | Route lookup + attribute rewriting + initialization |
3636
| ~0.8% | Memory allocation (`RawVec::reserve`) | Buffer growth during processing |
3737
| ~0.5% | Logging (`fern` / `log_fastly`) | Minimal overhead |
38-
| ~0.5% | Synthetic ID generation | HMAC computation |
38+
| ~0.5% | EC ID generation | HMAC computation |
3939
| ~0.5% | Header extraction | `fastly::http::handle::get_header_values` |
4040

4141
### Key Takeaways
@@ -271,7 +271,7 @@ let settings: Settings = postcard::from_bytes(SETTINGS_DATA)
271271
| `eq_ignore_ascii_case` for compression detection | `streaming_processor.rs:47` | 5 |
272272
| `Cow<str>` for string replacements | `streaming_replacer.rs:120-125` | 5-10 |
273273
| Remove base64 roundtrip in token computation | `http_util.rs:286-294` | 10-15 |
274-
| Replace Handlebars with manual interpolation | `synthetic.rs:82-99` | ~20 |
274+
| Replace Handlebars with manual interpolation | `ec.rs:82-99` | ~20 |
275275
| Cache `origin_host()` result per-request | `settings.rs` | 5-10 |
276276

277277
---

PUBLISHER_IDS_AUDIT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This document lists all publisher-specific IDs and configurations found in the c
1111
- `server_url = "https://securepubads.g.doubleclick.net/gampad/ads"` (line 15)
1212

1313
**Equativ Configuration:**
14-
- `sync_url = "https://adapi-srv-eu.smartadserver.com/ac?pgid=2040327&fmtid=137675&synthetic_id={{synthetic_id}}"` (line 8)
14+
- `sync_url = "https://adapi-srv-eu.smartadserver.com/ac?pgid=2040327&fmtid=137675&ec_id={{ec_id}}"` (line 8)
1515
- Page ID: `2040327`
1616
- Format ID: `137675`
1717

crates/common/README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ JS bundles (served by publisher module):
4747

4848
Behavior is covered by an extensive test suite in `crates/common/src/creative.rs`.
4949

50-
## Server Side Cookie (SSC) Identifier Propagation
51-
52-
- `ssc.rs` generates a server side cookie identifier per user request and exposes helpers:
53-
- `generate_ssc_id` — creates a fresh HMAC-based ID using the client IP address and appends a short random suffix (format: `64hex.6alnum`).
54-
- `get_ssc_id` — extracts an existing ID from the `x-ts-ssc` header or `ts-ssc` cookie.
55-
- `get_or_generate_ssc_id` — reuses the existing ID when present, otherwise creates one.
56-
- `publisher.rs::handle_publisher_request` stamps proxied origin responses with `x-ts-ssc`, and (when absent) issues the `ts-ssc` cookie so the browser keeps the identifier on subsequent requests.
57-
- `proxy.rs::handle_first_party_proxy` replays the identifier to third-party creative origins by appending `ts-ssc=<value>` to the reconstructed target URL, follows redirects (301/302/303/307/308) up to four hops, and keeps downstream fetches linked to the same user scope.
58-
- `proxy.rs::handle_first_party_click` adds `ts-ssc=<value>` to outbound click redirect URLs so analytics endpoints can associate clicks with impressions without third-party cookies.
50+
## Edge Cookie (EC) Identifier Propagation
51+
52+
- `ec.rs` generates an edge cookie identifier per user request and exposes helpers:
53+
- `generate_ec_id` — creates a fresh HMAC-based ID using the client IP address and appends a short random suffix (format: `64hex.6alnum`).
54+
- `get_ec_id` — extracts an existing ID from the `x-ts-ec` header or `ts-ec` cookie.
55+
- `get_or_generate_ec_id` — reuses the existing ID when present, otherwise creates one.
56+
- `publisher.rs::handle_publisher_request` stamps proxied origin responses with `x-ts-ec`, and (when absent) issues the `ts-ec` cookie so the browser keeps the identifier on subsequent requests.
57+
- `proxy.rs::handle_first_party_proxy` replays the identifier to third-party creative origins by appending `ts-ec=<value>` to the reconstructed target URL, follows redirects (301/302/303/307/308) up to four hops, and keeps downstream fetches linked to the same user scope.
58+
- `proxy.rs::handle_first_party_click` adds `ts-ec=<value>` to outbound click redirect URLs so analytics endpoints can associate clicks with impressions without third-party cookies.

crates/common/src/auction/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ When a request arrives at the `/auction` endpoint, it goes through the following
6767
6868
┌──────────────────────────────────────────────────────────────────────┐
6969
│ 4. Generate User IDs (mod.rs:206-214) │
70-
│ - Create/retrieve SSC ID (persistent) │
70+
│ - Create/retrieve EC ID (persistent)
7171
│ - Generate fresh ID (per-request) │
7272
└──────────────────────────────────────────────────────────────────────┘
7373

crates/common/src/auction/formats.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ use std::collections::HashMap;
1313
use uuid::Uuid;
1414

1515
use crate::auction::context::ContextValue;
16-
use crate::constants::{HEADER_X_TS_SSC, HEADER_X_TS_SSC_FRESH};
16+
use crate::constants::{HEADER_X_TS_EC, HEADER_X_TS_EC_FRESH};
1717
use crate::creative;
18+
use crate::ec::{generate_ec_id, get_or_generate_ec_id};
1819
use crate::error::TrustedServerError;
1920
use crate::geo::GeoInfo;
2021
use crate::openrtb::{OpenRtbBid, OpenRtbResponse, ResponseExt, SeatBid};
2122
use crate::settings::Settings;
22-
use crate::ssc::{generate_ssc_id, get_or_generate_ssc_id};
2323

2424
use super::orchestrator::OrchestrationResult;
2525
use super::types::{
@@ -69,20 +69,20 @@ pub struct BannerUnit {
6969
/// # Errors
7070
///
7171
/// Returns an error if:
72-
/// - SSC ID generation fails
72+
/// - EC ID generation fails
7373
/// - Request contains invalid banner sizes (must be [width, height])
7474
pub fn convert_tsjs_to_auction_request(
7575
body: &AdRequest,
7676
settings: &Settings,
7777
req: &Request,
7878
) -> Result<AuctionRequest, Report<TrustedServerError>> {
79-
// Generate SSC ID
80-
let ssc_id =
81-
get_or_generate_ssc_id(settings, req).change_context(TrustedServerError::Auction {
82-
message: "Failed to generate SSC ID".to_string(),
79+
// Generate EC ID
80+
let ec_id =
81+
get_or_generate_ec_id(settings, req).change_context(TrustedServerError::Auction {
82+
message: "Failed to generate EC ID".to_string(),
8383
})?;
84-
let fresh_id = generate_ssc_id(settings, req).change_context(TrustedServerError::Auction {
85-
message: "Failed to generate fresh SSC ID".to_string(),
84+
let fresh_id = generate_ec_id(settings, req).change_context(TrustedServerError::Auction {
85+
message: "Failed to generate fresh EC ID".to_string(),
8686
})?;
8787

8888
// Convert ad units to slots
@@ -176,7 +176,7 @@ pub fn convert_tsjs_to_auction_request(
176176
page_url: Some(format!("https://{}", settings.publisher.domain)),
177177
},
178178
user: UserInfo {
179-
id: ssc_id,
179+
id: ec_id,
180180
fresh_id,
181181
consent: None,
182182
},
@@ -291,7 +291,7 @@ pub fn convert_to_openrtb_response(
291291

292292
Ok(Response::from_status(StatusCode::OK)
293293
.with_header(header::CONTENT_TYPE, "application/json")
294-
.with_header(HEADER_X_TS_SSC, &auction_request.user.id)
295-
.with_header(HEADER_X_TS_SSC_FRESH, &auction_request.user.fresh_id)
294+
.with_header(HEADER_X_TS_EC, &auction_request.user.id)
295+
.with_header(HEADER_X_TS_EC_FRESH, &auction_request.user.fresh_id)
296296
.with_body(body_bytes))
297297
}

crates/common/src/auction/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub struct PublisherInfo {
6969
/// Privacy-preserving user information.
7070
#[derive(Debug, Clone, Serialize, Deserialize)]
7171
pub struct UserInfo {
72-
/// Stable SSC ID (from cookie or freshly generated)
72+
/// Stable EC ID (from cookie or freshly generated)
7373
pub id: String,
7474
/// Fresh ID for this session
7575
pub fresh_id: String,

crates/common/src/constants.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use http::header::HeaderName;
22

3-
pub const COOKIE_TS_SSC: &str = "ts-ssc";
3+
pub const COOKIE_TS_EC: &str = "ts-ec";
44

55
pub const HEADER_X_PUB_USER_ID: HeaderName = HeaderName::from_static("x-pub-user-id");
6-
pub const HEADER_X_TS_SSC: HeaderName = HeaderName::from_static("x-ts-ssc");
7-
pub const HEADER_X_TS_SSC_FRESH: HeaderName = HeaderName::from_static("x-ts-ssc-fresh");
6+
pub const HEADER_X_TS_EC: HeaderName = HeaderName::from_static("x-ts-ec");
7+
pub const HEADER_X_TS_EC_FRESH: HeaderName = HeaderName::from_static("x-ts-ec-fresh");
88
pub const HEADER_X_CONSENT_ADVERTISING: HeaderName =
99
HeaderName::from_static("x-consent-advertising");
1010
pub const HEADER_X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for");
@@ -44,8 +44,8 @@ pub const HEADER_REFERER: HeaderName = HeaderName::from_static("referer");
4444
/// Uses `&str` slices because `HeaderName` has interior mutability and cannot appear
4545
/// in `const` context.
4646
pub const INTERNAL_HEADERS: &[&str] = &[
47-
"x-ts-ssc",
48-
"x-ts-ssc-fresh",
47+
"x-ts-ec",
48+
"x-ts-ec-fresh",
4949
"x-pub-user-id",
5050
"x-subject-id",
5151
"x-consent-advertising",

crates/common/src/cookies.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use error_stack::{Report, ResultExt};
88
use fastly::http::header;
99
use fastly::Request;
1010

11-
use crate::constants::COOKIE_TS_SSC;
11+
use crate::constants::COOKIE_TS_EC;
1212
use crate::error::TrustedServerError;
1313
use crate::settings::Settings;
1414

@@ -59,24 +59,24 @@ pub fn handle_request_cookies(
5959
}
6060
}
6161

62-
/// Creates an SSC cookie string.
62+
/// Creates an EC cookie string.
6363
///
6464
/// Generates a properly formatted cookie with security attributes
65-
/// for storing the SSC ID.
65+
/// for storing the EC ID.
6666
#[must_use]
67-
pub fn create_ssc_cookie(settings: &Settings, ssc_id: &str) -> String {
67+
pub fn create_ec_cookie(settings: &Settings, ec_id: &str) -> String {
6868
format!(
6969
"{}={}; Domain={}; Path=/; Secure; SameSite=Lax; Max-Age={}",
70-
COOKIE_TS_SSC, ssc_id, settings.publisher.cookie_domain, COOKIE_MAX_AGE,
70+
COOKIE_TS_EC, ec_id, settings.publisher.cookie_domain, COOKIE_MAX_AGE,
7171
)
7272
}
7373

74-
/// Sets the SSC ID cookie on the given response.
74+
/// Sets the EC ID cookie on the given response.
7575
///
7676
/// This helper abstracts the logic of creating the cookie string and appending
7777
/// the Set-Cookie header to the response.
78-
pub fn set_ssc_cookie(settings: &Settings, response: &mut fastly::Response, ssc_id: &str) {
79-
response.append_header(header::SET_COOKIE, create_ssc_cookie(settings, ssc_id));
78+
pub fn set_ec_cookie(settings: &Settings, response: &mut fastly::Response, ec_id: &str) {
79+
response.append_header(header::SET_COOKIE, create_ec_cookie(settings, ec_id));
8080
}
8181

8282
#[cfg(test)]
@@ -161,23 +161,23 @@ mod tests {
161161
}
162162

163163
#[test]
164-
fn test_create_ssc_cookie() {
164+
fn test_create_ec_cookie() {
165165
let settings = create_test_settings();
166-
let result = create_ssc_cookie(&settings, "12345");
166+
let result = create_ec_cookie(&settings, "12345");
167167
assert_eq!(
168168
result,
169169
format!(
170170
"{}=12345; Domain={}; Path=/; Secure; SameSite=Lax; Max-Age={}",
171-
COOKIE_TS_SSC, settings.publisher.cookie_domain, COOKIE_MAX_AGE,
171+
COOKIE_TS_EC, settings.publisher.cookie_domain, COOKIE_MAX_AGE,
172172
)
173173
);
174174
}
175175

176176
#[test]
177-
fn test_set_ssc_cookie() {
177+
fn test_set_ec_cookie() {
178178
let settings = create_test_settings();
179179
let mut response = fastly::Response::new();
180-
set_ssc_cookie(&settings, &mut response, "test-id-123");
180+
set_ec_cookie(&settings, &mut response, "test-id-123");
181181

182182
let cookie_header = response
183183
.get_header(header::SET_COOKIE)
@@ -186,10 +186,10 @@ mod tests {
186186
.to_str()
187187
.expect("header should be valid UTF-8");
188188

189-
let expected = create_ssc_cookie(&settings, "test-id-123");
189+
let expected = create_ec_cookie(&settings, "test-id-123");
190190
assert_eq!(
191191
cookie_str, expected,
192-
"Set-Cookie header should match create_ssc_cookie output"
192+
"Set-Cookie header should match create_ec_cookie output"
193193
);
194194
}
195195
}

0 commit comments

Comments
 (0)