litespeedtech / litespeedtech/lscache_wp
Guest Mode vary cookie never matches when Debug Log is on with Debug URI Includes set
- Dominant language
- PHP
- Stars
- 257
- Forks
- 123
- PR merge metrics
- No merged PRs in 30d
Description
I hit this looking into why first-time visitors were getting a slow second page load. I'm not sure if it's a bug or intended behaviour, so posting it as a question rather than a bug report.
**Setup**
- LSCWP 7.8.1
- OpenLiteSpeed, PHP 8.3
- Guest Mode: on
- Debug Log: on
- Debug URI Includes: two entries, `litespeed_type=activate` and `rest_route=/litespeed`
**What happens**
Guest Mode serves the cached guest page on the first request, the inline script posts to `guest.vary.php`, gets a cookie back and reloads. That reload never hits cache. It's a full PHP render every time, and the response sets `_lscache_vary` to a different value than the one just issued.
**The two values**
`guest.vary.php` hands out the plain string:
```
set-cookie: _lscache_vary=guest_mode%3A1; Max-Age=172800; path=/; secure; HttpOnly
```
The page expects the hashed form, so it resets the cookie and misses:
```
set-cookie: _lscache_vary=<32 char md5>; Max-Age=172800; path=/; secure; HttpOnly
x-litespeed-cache: miss
```
**Where they diverge**
`lib/guest.cls.php`, `update_guest_vary()` checks the debug option directly:
```php
$vary = 'guest_mode:1';
if ( $this->_conf && empty( $this->_conf[ self::O_DEBUG ] ) ) {
$vary = md5( $this->_conf[ self::HASH ] . $vary );
}
```
`src/vary.cls.php`, `finalize_default_vary()` checks `LSCWP_LOG`:
```php
$res = implode( ';', $list );
if ( defined( 'LSCWP_LOG' ) ) {
return $res;
}
// Encrypt in production.
return md5( $this->conf( Base::HASH ) . $res );
```
Those two agree only when debug logging applies to every request. With Debug URI Includes set, `Debug2::init()` returns before defining `LSCWP_LOG` for any front end URL, so the page uses the md5 while `guest.vary.php` is still emitting the plain string.
`guest.cls.php` loads without WordPress and reads `wp-content/.litespeed_conf.dat`, which on my install holds 16 keys and doesn't include `debug-inc`, so it has no way to know logging is scoped.
**Reproduce**
```bash
UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0 Safari/537.36"
curl -s -D- -o /dev/null -X POST -A "$UA" \
https://example.com/wp-content/plugins/litespeed-cache/guest.vary.php
curl -s -D- -o /dev/null -A "$UA" -b "_lscache_vary=guest_mode:1" \
https://example.com/
```
The second one returns `x-litespeed-cache: miss` plus a `Set-Cookie` with a different value, and it does that on every request, not just the first. Repeating it five times gives five misses on a response marked `public,max-age=604800`.
**Effect**
TTFB on our site, three samples each:
| Request | TTFB |
| --- | --- |
| No cookie, guest copy | 0.079 / 0.092 / 0.138 s |
| Plain cookie, the reload | 0.383 / 0.410 / 0.478 s |
| md5 cookie | 0.093 / 0.097 / 0.097 s |
So every first-time visitor gets an uncached render on the reload, once per browser per 48 hours.
**Admin IP Only behaves the same way**
`debug = 2` doesn't avoid it. `empty(2)` is false, so `guest.cls.php` still emits the plain value, and in `Debug2::init()` the admin IP check runs before the Debug URI Includes check, so with includes set `LSCWP_LOG` stays undefined even for an admin IP.
**Question**
Is the check in `guest.cls.php` meant to mirror `LSCWP_LOG` rather than the raw `debug` option? Turning Debug Log off makes both sides agree and the reload becomes a cache hit, so there's an easy workaround, but it took a while to track down because nothing surfaces it. The docs for Debug Log only mention disk usage.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with lib/guest.cls.php:update_guest_vary(), src/vary.cls.php:finalize_default_vary(), and Debug2::init(); reproduce the mismatch with the provided curl requests and Debug URI Includes enabled. Trace how each path determines the vary value, then establish whether they should agree and verify that the reload receives the expected cookie and a cache hit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php, wordpress
- Domain
- backend, performance
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100