Gouri Sankar A created WW-5832:
----------------------------------

             Summary: FreeMarker template cache is not bounded by default and 
is keyed on the request-derived locale
                 Key: WW-5832
                 URL: https://issues.apache.org/jira/browse/WW-5832
             Project: Struts 2
          Issue Type: Bug
          Components: Core
    Affects Versions: 7.4.0, 7.3.0, 7.0.0, 6.12.0
            Reporter: Gouri Sankar A


With struts.freemarker.mru.max.strong.size=0 (the default in 
default.properties), FreemarkerManager.createConfiguration does not set a cache 
storage, so FreeMarker's template cache uses its default SoftCacheStorage, 
which has no entry limit. The cache key includes the locale. For actions that 
provide a locale (LocaleProvider, for example ActionSupport), FreemarkerResult 
uses the ActionContext locale, which by default comes from the request 
(Accept-Language). Every distinct locale therefore adds template cache entries, 
with no count bound. Same class as WW-5668 (localized-text caches, capped at 
10000) and WW-5716 (Tiles locale caches, capped at 1000).

Reproduction (main, against a running Struts Boot app): an ActionSupport action 
rendering a FreeMarker template, requested with 12,000 distinct Accept-Language 
headers. The template cache (Configuration.getCacheStorage(), a 
DefaultSoftCacheStorage) grew from 1 to 12,001 entries. Repeating the same 
locales added none.

Impact: the entries are soft references, so this alone does not exhaust the 
heap; they are kept until the GC clears them, and each locale re-reads and 
re-parses the template.

Affected versions: the same createConfiguration code (no cache storage is set 
when the value is 0, the default) is present in the 6.12.0, 7.0.0, 7.3.0 and 
7.4.0 tags, by source inspection. The reproduction was only run on main.

Fix: when mru.max.strong.size is 0, use a SoftCacheStorage subclass that 
empties itself at 10000 entries. It stays a ConcurrentCacheStorage, so lookups 
remain lock-free (soft:10000 would create an MruCacheStorage, which 
TemplateCache synchronizes on, see WW-3766). The strong:N path is unchanged. 
The bound is approximate under concurrency.

Tests: FreemarkerManagerTest#testTemplateCacheIsBoundedByDefault (fails without 
the change, passes with it). With the fix, the same 12,000-locale run on a live 
app ends with 2,002 entries instead of 12,001.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to