My app server remembered the last visitor, one edit away from a shared cache

by

A two minute check for anyone running a long-lived app server: PHP under RoadRunner or Swoole, Node, anything where one process serves request after request instead of starting fresh each time.

List the values your templates read that middleware sets per request: the signed-in flag, the avatar, the CSRF token, the analytics user id. Then ask what each of them holds on a request where that middleware did not run.

In a process-per-request world the answer is nothing. In a long-lived worker it is whatever the previous request left behind. In my framework those values sit in one shared object for the life of the worker, a plain array that middleware writes into. The next request that skips the middleware reads the values the last one left.

On most of my pages that never shows, because every request runs every middleware and overwrites everything. It matters on the group I built to be cacheable. My public pages run no session and no CSRF on purpose, so a shared cache is allowed to store them, and that means they skip exactly the middleware that would have overwritten the leftovers. A template there that printed the CSRF token would have printed the token of the previous visitor, into a cache entry served to everyone. A check for cookies on cacheable responses does not catch it, because the value never travels as a cookie.

No template printed it. The fix was dull: the cacheable group now sets every one of those values itself, to false or empty, and two tests hold it. One makes a normal request, then a public one, and asserts the token did not carry over. The other reads the middleware groups and fails when a new middleware publishes a value the public group does not reset.

The check for your stack: run one worker on staging, sign in and load any page, then load a cacheable page from a second browser and compare its HTML with the same page served by a freshly started worker. Anything that differs is something the worker remembered.

What else in your stack is per request only because nothing has served two requests in a row yet?

2 views

Add a comment

Replies

Be the first to comment