Skip to content

Commit 189c57c

Browse files
committed
Update pr review findings
1 parent 6574790 commit 189c57c

3 files changed

Lines changed: 39 additions & 5 deletions

File tree

crates/trusted-server-adapter-fastly/src/app.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
//! Builds the [`AppState`] once per Wasm instance.
88
//!
99
//! `EdgeZero`'s current Fastly request context exposes client IP but not TLS
10-
//! protocol or cipher metadata. The `EdgeZero` path therefore preserves TLS
11-
//! metadata as `None` until the upstream adapter exposes those fields.
10+
//! protocol or cipher metadata. `edgezero_main` injects a trusted `fastly-ssl`
11+
//! header after stripping client-spoofable headers, so [`detect_request_scheme`]
12+
//! in `http_util` can still derive the correct scheme for HTTPS traffic.
1213
//!
1314
//! # Route inventory
1415
//!
@@ -149,7 +150,8 @@ pub(crate) fn runtime_services_for_consent_route(
149150
///
150151
/// Extracts the client IP address from the [`FastlyRequestContext`] extension
151152
/// inserted by `edgezero_adapter_fastly::dispatch`. TLS metadata is not
152-
/// available through the `EdgeZero` context so those fields are left empty.
153+
/// available through the `EdgeZero` context; scheme detection relies on the
154+
/// trusted `fastly-ssl` header injected by `edgezero_main` after sanitization.
153155
fn build_per_request_services(state: &AppState, ctx: &RequestContext) -> RuntimeServices {
154156
let client_ip = FastlyRequestContext::get(ctx.request()).and_then(|c| c.client_ip);
155157

crates/trusted-server-adapter-fastly/src/main.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,42 @@ fn main() {
160160

161161
/// Handles a request through the `EdgeZero` router path.
162162
fn edgezero_main(mut req: FastlyRequest, config_store: ConfigStoreHandle) {
163+
// Short-circuit the JA4 debug probe before app construction, mirroring
164+
// legacy_main. Must run here because TLS/JA4 accessors are only available
165+
// on FastlyRequest before conversion to edgezero types.
166+
if req.get_method() == FastlyMethod::GET && req.get_path() == "/_ts/debug/ja4" {
167+
match get_settings() {
168+
Ok(settings) if settings.debug.ja4_endpoint_enabled => {
169+
build_ja4_debug_response(&req).send_to_client();
170+
}
171+
Ok(_) => {
172+
FastlyResponse::from_status(fastly::http::StatusCode::NOT_FOUND).send_to_client();
173+
}
174+
Err(e) => {
175+
log::warn!("EdgeZero JA4 endpoint: failed to load settings: {e:?}");
176+
FastlyResponse::from_status(fastly::http::StatusCode::INTERNAL_SERVER_ERROR)
177+
.with_body_text_plain("Internal Server Error")
178+
.send_to_client();
179+
}
180+
}
181+
return;
182+
}
183+
163184
let app = TrustedServerApp::build_app();
164185

165186
// Strip client-spoofable forwarded headers before handing off to the
166187
// EdgeZero dispatcher, mirroring the sanitization done in legacy_main.
167188
compat::sanitize_fastly_forwarded_headers(&mut req);
168189

190+
// Re-inject a trusted TLS scheme signal after sanitization has stripped any
191+
// client-sent fastly-ssl header. Setting it from Fastly's native TLS
192+
// metadata here is authoritative. detect_request_scheme in http_util
193+
// checks this header so scheme-sensitive logic (publisher URL rewriting,
194+
// etc.) produces https URLs on HTTPS traffic, matching legacy path parity.
195+
if req.get_tls_protocol().is_some() || req.get_tls_cipher_openssl_name().is_some() {
196+
req.set_header("fastly-ssl", "1");
197+
}
198+
169199
// Capture client IP before the request is consumed by dispatch.
170200
let client_ip = req.get_client_ip_addr();
171201

crates/trusted-server-core/src/http_util.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ fn normalize_scheme(value: &str) -> Option<String> {
169169
/// 1. `ClientInfo` TLS fields populated at the adapter entry point (most reliable)
170170
/// 2. Forwarded header (RFC 7239)
171171
/// 3. X-Forwarded-Proto header
172-
/// 4. Fastly-SSL header (least reliable, can be spoofed)
172+
/// 4. Fastly-SSL header (trusted on EdgeZero path; can be spoofed on legacy path)
173173
/// 5. Default to HTTP
174174
fn detect_request_scheme(
175175
req: &Request<EdgeBody>,
@@ -210,7 +210,9 @@ fn detect_request_scheme(
210210
}
211211
}
212212

213-
// 4. Check Fastly-SSL header (can be spoofed by clients, use as last resort)
213+
// 4. Check Fastly-SSL header. On the EdgeZero path this is injected from
214+
// authoritative Fastly TLS metadata after spoofable headers are stripped,
215+
// so it is reliable. On direct or legacy paths it can be spoofed by clients.
214216
if let Some(ssl) = req.headers().get("fastly-ssl") {
215217
if let Ok(ssl_str) = ssl.to_str() {
216218
if ssl_str == "1" || ssl_str.to_lowercase() == "true" {

0 commit comments

Comments
 (0)