commit 633a036ca2450d664bc621ac7fcc3288772b23ed
parent cc3ed8cc3c3adaa4164faa6e99192ec2311676d5
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 20 May 2026 18:59:46 +0200
fix cache control, cookie path
Diffstat:
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/PaivanaCookie.php b/src/PaivanaCookie.php
@@ -56,17 +56,29 @@ class PaivanaCookie {
* now + $lifetime_seconds. Cookie is bound to the request's
* client address.
*
+ * The cookie's Path attribute is scoped to the website's URL path,
+ * so it is only sent back when the browser visits exactly that
+ * resource. This mirrors paivana-httpd's default (per-URL cookie):
+ * other paywalled pages on the same host get their own cookie and
+ * cannot piggy-back on this one. As a side effect, it also keeps
+ * the cookie out of unrelated requests, so the page cache for
+ * other URLs stays warm.
+ *
* @return \Symfony\Component\HttpFoundation\Cookie
*/
public function mint(Request $request, string $website, int $lifetime_seconds): Cookie {
$expires = time() + $lifetime_seconds;
$client_addr = $request->getClientIp() ?? '';
$value = $expires . '-' . $this->hash($expires, $website, $client_addr);
+ $path = parse_url($website, PHP_URL_PATH);
+ if (! is_string($path) || $path === '') {
+ $path = '/';
+ }
return Cookie::create(
self::COOKIE_NAME,
$value,
$expires,
- '/',
+ $path,
NULL,
$request->isSecure(),
TRUE,
diff --git a/taler_turnstile.module b/taler_turnstile.module
@@ -118,6 +118,14 @@ function taler_turnstile_entity_view_alter(array &$build, EntityInterface $entit
if ($cookies->verify($request, $fulfillment_url)) {
\Drupal::logger('taler_turnstile')->debug('Valid Paivana cookie, granting access to @url', ['@url' => $fulfillment_url]);
$build['#cache']['contexts'][] = 'cookies:' . TALER_TURNSTILE_COOKIE;
+ // Vary on Cookie so that when the access cookie expires (or is
+ // cleared) the next navigation to this URL misses the browser
+ // cache and re-reaches the origin to re-evaluate the paywall.
+ // 'private' keeps shared caches from handing one paying
+ // visitor's full-content response to another visitor whose
+ // request happens to lack the cookie.
+ $build['#attached']['http_header'][] = ['Vary', 'Cookie', FALSE];
+ $build['#attached']['http_header'][] = ['Cache-Control', 'private', TRUE];
return;
}