fix: avoid redundant locale session writes #30
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/w14-locale-session-writes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes W14 from bugs.md.
SetLocalenow compares the session's stored locale with the freshly resolved one and only callsput_session/3when they differ. Previously every anonymous browser request rewrote the session, forcing aSet-Cookieheader onto responses that would otherwise be cacheable. When the write is skipped the response instead declaresCache-Control: privateandVary: Accept-Language, so a shared cache cannot replay a visitor-specific body.The regression tests seed a real signed session cookie via round-trip so the incoming session is clean (only
SetLocaleitself could dirty it) and assert aftersend_resp: an unchanged locale emits noSet-Cookieand the cache headers above, a changed one still emitsSet-Cookie.Verification: focused tests passed (9), full suite passed (2238; one earlier run hit the known pre-existing PacketConsumerTest flake and passed on re-run),
mix credo --strict, and commit hooks including Dialyzer passed.🤖 Skippy PR review
1 finding — 1 blocking before merge.
lib/aprsme_web/plugs/set_locale.ex:17Reviewed
31259dbc8012. Commentskippy reviewto re-run.@ -16,0 +14,4 @@# Only rewrite the session when the value actually changes: an# unconditional put_session forces a Set-Cookie onto every otherwise# cacheable anonymous response.if get_session(conn, :locale) == locale do🟡 Warning — Cookie-free responses are now cache-eligible, but nothing declares their cache key
Suppressing this write is what makes the response storable by a shared cache (aprs.me is proxied by Cloudflare) — but the body is not visitor-independent. It is Gettext output, so it varies by
Accept-Language, and the LiveView shell embeds a signed per-visitor session:data-phx-sessioncarries the session map, whichlive_session :regular_pagesfills viaregular_pages_session/1(ip_geolocation, read byMapLive.Navigation.determine_map_location/2).Nothing in the app sends
VaryorCache-Controlfor these routes — the only cache header in the repo isNoStore, on the auth pages — so the first response any cache stores is replayed to every visitor: wrong language, and another visitor's IP-derived map centre.If the cacheable-anonymous-response goal is going ahead, declare the key in the same change:
Vary: Accept-Languageplus keeping per-visitor state out of the markup, orCache-Control: privateuntil then. For Cloudflare specifically,Varyother thanAccept-Encodingis ignored, so a cache rule keyed on Accept-Language (or leaving these pages uncached) is the version that actually works.🤖 Skippy PR review
1 finding — none blocking.
test/aprsme_web/plugs/set_locale_test.exs:128Resolved 1 earlier finding: the cookie-free branch now declares its cache key (Cache-Control: private + Vary: Accept-Language), so a shared cache can no longer replay a visitor-specific body. 1 new suggestion, non-blocking.
Reviewed
fa1b2f010a58. Commentskippy reviewto re-run.@ -64,0 +125,4 @@# Set-Cookie — which makes it storable by a shared cache. It must then# declare itself visitor-private: the body varies by Accept-Language and# embeds per-visitor LiveView session data.assert get_resp_header(conn, "set-cookie") == []🔵 Suggestion — The no-Set-Cookie assertion here can never fail
get_resp_header(conn, "set-cookie")is[]for any conn this test could build: the cookie store writes throughPlug.Conn.put_resp_cookie/4, which puts the value inconn.resp_cookies, and Plug only folds cookies intoresp_headersinsiderun_before_send(Plug.Conn, at send time). Nothing here callssend_resp, so the line passes even ifSetLocalestill rewrote the session on every request - that is exactly the regressed case this test is named after, and it guards nothing.The meaningful version already exists in "does not rewrite the session when the locale is unchanged", which
send_resps before asserting. Either pipe|> send_resp(200, "")in before these three assertions, or keep the pre-send shape and assertconn.resp_cookies == %{}(that one does flip when the session is dirtied). Minor, same paragraph: only the older test seeds a signed cookie, so the PR description's "two regression tests seed a real signed session cookie" holds for just one of them.Resolved 1 earlier finding: both no-
Set-Cookietests nowsend_respbefore asserting and both seed a real signed session cookie viarequest_with_seeded_locale/4, so that assertion can actually fail now.Nothing new to flag in
fa1b2f01..93813695(test-only commit).