fix(page-cache): include original request URI in cache key for vanity URL 200-forwards (#35696) - #35704
Conversation
… URL 200-forwards (#35696) When a vanity URL (200 Forward) routes multiple incoming URLs to the same detail page, all requests produced an identical page cache key because FORWARD_REQUEST_URI was not included. The first request warmed the cache and every subsequent request got that cached response regardless of which URL was actually requested. Fix: in VelocityLiveMode.buildCacheParameters(), when VANITY_URL_OBJECT is set and isForward() == true, include RequestDispatcher.FORWARD_REQUEST_URI (the original browser URL set by Tomcat during the CMSFilter→VelocityServlet forward) as an 'originalUri:' component in the PageCacheParameters key. This is a follow-up to #34879, which fixed the same collision for URL-mapped contentlets via WIKI_CONTENTLET_INODE but missed the vanity URL forward path. Closes #35696
|
Claude finished @dsilvam's task in 3m 18s —— View job dotCMS Backend Review — Complete
SummaryThe PR is a tightly scoped fix and the diff holds up well. No security, database, or REST API concerns. Two 🟡 Medium code-quality findings posted in the dedicated review comment:
Neither is blocking. The cache-key fix itself is correct: |
🔍 dotCMS Backend Review[🟡 Medium]
String vanityUrl = request.getAttribute(VANITY_URL_OBJECT) != null
? ((CachedVanityUrl) request.getAttribute(VANITY_URL_OBJECT)).vanityUrlId
: "";
String originalRequestUri = (request.getAttribute(VANITY_URL_OBJECT) != null
&& ((CachedVanityUrl) request.getAttribute(VANITY_URL_OBJECT)).isForward())
? (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)
: null;💡 Suggested fix: final CachedVanityUrl vanity = (CachedVanityUrl) request.getAttribute(VANITY_URL_OBJECT);
final String vanityUrl = vanity != null ? vanity.vanityUrlId : "";
final String originalRequestUri = (vanity != null && vanity.isForward())
? (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)
: null;[🟡 Medium]
@BeforeClass
public static void prepare() throws Exception {
IntegrationTestInitService.getInstance().init();
}
@DataProvider(format = "%m: %p[0]")
public static Object[] configs() throws Exception {
prepare(); // redundant — @BeforeClass already ran💡 Suggested fix: Drop the Next steps
|
What does this PR do?
Fixes a page cache key collision where multiple vanity URL 200-forward requests routed to the same detail page all shared an identical cache key. The first request warmed the cache and every subsequent request — regardless of the actual incoming URL — received that cached response.
Closes #35696
Why is this a problem?
VelocityLiveMode.buildCacheParameters()composed the cache key frompageUrl(the forwarded-to path),pageInode,vanityUrlId, etc. — none of which differ between/store/123/acme/catalog/and/store/456/globex/catalog/when both forward to the same page via the same vanity URL rule.On multi-node clusters with round-robin load balancing, different nodes cached different affiliates' content under the same key, causing wrong content on every other request for the full TTL duration (up to 1 hour).
What is the fix?
When
VANITY_URL_OBJECTis present on the request andisForward() == true, includeRequestDispatcher.FORWARD_REQUEST_URIas anoriginalUri:component in the cache key. This is the original browser URL set by Tomcat when CMSFilter forwards to VelocityServlet viaRequestDispatcher.forward().Non-vanity pages and vanity redirects (301/302) are unaffected —
nullis filtered out of the key byPageCacheParameters.Relation to #34879
PR #34879 fixed the same collision class for URL-mapped contentlets via
WIKI_CONTENTLET_INODE. The vanity URL 200-forward path was not addressed by that fix.Testing
VelocityLiveModeTest#vanityForwardDifferentOriginalUriProducesDifferentCacheKeysChecklist
buildCacheParameters()for testability only)