Skip to content

Expose Fastly geo headers on every response#375

Open
prk-Jr wants to merge 3 commits intomainfrom
feat/geo-response-header
Open

Expose Fastly geo headers on every response#375
prk-Jr wants to merge 3 commits intomainfrom
feat/geo-response-header

Conversation

@prk-Jr
Copy link
Collaborator

@prk-Jr prk-Jr commented Feb 25, 2026

Summary

  • Add GeoInfo::set_response_headers() to set x-geo-* headers on outgoing responses, enabling publishers to access Fastly geolocation data (city, country, continent, coordinates, metro code, region) from every Trusted Server response.
  • Wire geo header injection into the centralized response middleware in main.rs so all routes receive geo headers. When geo data is unavailable (e.g., local dev), sets x-geo-info-available: false.
  • Remove unused get_dma_code() function that was dead code (no callers) and duplicated GeoInfo::from_request() logic.

Changes

File Change
crates/common/src/geo.rs Add set_response_headers() method to GeoInfo; remove dead get_dma_code() function; add 5 unit tests
crates/fastly/src/main.rs Extract GeoInfo before routing; set geo headers on every response in response middleware

Closes

Closes #280

Test plan

  • cargo test --workspace
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check
  • JS tests: cd crates/js/lib && npx vitest run (pre-existing ERR_REQUIRE_ESM failure on main — unrelated)
  • JS format: cd crates/js/lib && npm run format
  • Docs format: cd docs && npm run format
  • WASM build: cargo build --bin trusted-server-fastly --release --target wasm32-wasip1
  • Manual testing via fastly compute serve

Checklist

  • Changes follow CLAUDE.md conventions
  • No unwrap() in production code — use expect("should ...")
  • Uses tracing macros (not println!)
  • New code has tests
  • No secrets or credentials committed

Add GeoInfo::set_response_headers() to set x-geo-* headers on responses
and wire it into the centralized response middleware in main.rs. When geo
data is unavailable, sets x-geo-info-available: false. Remove unused
get_dma_code() function. Add unit tests for the new method.
Resolves #280
@prk-Jr prk-Jr self-assigned this Feb 25, 2026
@prk-Jr prk-Jr requested review from ChristianPavilonis and aram356 and removed request for aram356 February 25, 2026 15:40
Copy link
Collaborator

@ChristianPavilonis ChristianPavilonis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work centralizing the response headers — the finalize_response helper is a solid pattern and the dead get_dma_code cleanup is welcome. Two things to address before merging:


1. Gate x-geo-metro-code on has_metro_code()

In crates/common/src/geo.rs, set_response_headers always emits x-geo-metro-code (line 95), so when Fastly has no DMA data it sends x-geo-metro-code: 0. This is ambiguous — consumers can't distinguish "metro code is actually 0" from "no metro data available."

There's already a has_metro_code() helper (line 81) built for this. Consider gating the header the same way region is handled:

// current (line 95)
response.set_header(HEADER_X_GEO_METRO_CODE, self.metro_code.to_string());

// suggested
if self.has_metro_code() {
    response.set_header(HEADER_X_GEO_METRO_CODE, self.metro_code.to_string());
}

The existing test should also be updated — add a case where metro_code is 0 and assert the header is absent, similar to the set_response_headers_omits_region_when_none test.


2. Header precedence in finalize_response

In crates/fastly/src/main.rs, finalize_response (lines 150-167) writes headers in this order:

  1. Geo headers (x-geo-*)
  2. Version/staging (x-ts-version, x-ts-env)
  3. settings.response_headers (operator-configured)

Since set_header overwrites, an operator who configures x-geo-city or x-ts-version in their settings would silently replace the real values. If this is intentional (operators should be able to override), a short comment in the code documenting the precedence would be enough. If it's not intentional, the operator headers should be written first, or the managed header keys should be skipped when iterating settings.response_headers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

As publisher I want to expose Fastly Geo headers on each response from Trusted Server

2 participants