Lukasz Lenart created WW-5675:
---------------------------------
Summary: Stop re-parsing OGNL security config on every
SecurityMemberAccess instantiation
Key: WW-5675
URL: https://issues.apache.org/jira/browse/WW-5675
Project: Struts 2
Issue Type: Sub-task
Reporter: Lukasz Lenart
Sub-task of WW-5667.
{{SecurityMemberAccess}} is a {{Scope.PROTOTYPE}} bean
({{StrutsBeanSelectionProvider}}, since WW-5343). Every
{{container.getInstance(SecurityMemberAccess.class)}} therefore constructs a
fresh instance and re-runs all of its {{@Inject}} setters, each of which
re-parses a raw comma-delimited configuration string from scratch.
With the stock {{struts-excluded-classes.xml}}, a single instantiation
re-parses roughly:
* 16 + 16 excluded class names ({{struts.excludedClasses}},
{{struts.devMode.excludedClasses}}) — comma split plus classloader validation
* 29 + 29 excluded package names ({{struts.excludedPackageNames}},
{{struts.devMode.excludedPackageNames}}) — comma split, {{strip}}, and
{{validatePackageNames}}
* the allowlist class and package sets
* any configured excluded-package-name patterns, which are re-compiled via
{{Pattern.compile}}
{{ConfigParseUtil.validatePackageNames}} additionally evaluates
{{Pattern.compile("\\s")}} once per package name rather than once overall, so a
default configuration recompiles that trivial pattern around 58 times per
instance.
New instances are created on the request path from at least:
* {{OgnlValueStackFactory.createValueStack(...)}} — once per value stack;
{{ParametersInterceptor.toNewStack}} creates an additional stack per request
* {{OgnlUtil.createDefaultContext(Object, ClassResolver)}} — reached from
{{setProperties}}, {{copy}}, {{getBeanMap}} and friends
so the full configuration is rebuilt several times per request.
This matches JFR sample 2 on the parent ticket:
{noformat}
HashMap.put / HashSet.add
ConfigParseUtil.toNewPackageNamesSet(Collection, String) :138
SecurityMemberAccess.useExcludedPackageNames(String) :446
{noformat}
Note that the fix proposed on the parent ticket — caching the parsed set in a
{{SecurityMemberAccess}} field — does not address this, because the instance
holding the field is itself discarded and rebuilt each time.
Constraints for any fix: the OGNL allow/deny semantics must not change; the
dev-mode configuration switchover in {{useDevModeConfiguration()}} must keep
working; and per-instance mutable state set at request time by
{{ParametersInterceptor.applyMemberAccessProperties}} ({{useAcceptProperties}}
/ {{useExcludeProperties}}) must stay per-instance.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)