Lukasz Lenart created WW-5823:
---------------------------------

             Summary: Javatemplates plugin renders dynamic attributes 
differently from the simple theme: values are not HTML-escaped and are 
evaluated a second time
                 Key: WW-5823
                 URL: https://issues.apache.org/jira/browse/WW-5823
             Project: Struts 2
          Issue Type: Bug
          Components: Plugin - Java Templates
            Reporter: Lukasz Lenart
             Fix For: 7.5.0, 6.13.0


The javatemplates plugin is documented as a drop-in replacement for the simple 
theme. {{DynamicAttributesHandler.processDynamicAttributes}} differs from the 
FreeMarker {{dynamic-attributes.ftl}} in two ways.
# Dynamic attribute values are stored with {{Attributes.put}}. Every other 
handler in the plugin goes through {{Attributes.add}} or {{addIfExists}}, which 
apply {{escapeHtml4}}, and the FreeMarker template renders {{${value}}} under 
the configuration's HTML auto-escaping. {{XHTMLTagSerializer.start}} then 
writes the stored value between double quotes as it is.
# {{UIBean.setDynamicAttributes}} already translates {{%{...}}} for every 
component that is not lazily evaluated. The handler tests the resolved value 
with {{ComponentUtils.isExpression}} again and calls {{findString}} on it, so a 
value that resolves to text of the form {{%{...}}} is evaluated a second time. 
The FreeMarker template evaluates only when {{evaluate_dynamic_attributes}} is 
set, which {{radiomap.ftl}} and {{checkboxlist.ftl}} do because {{Radio}} and 
{{CheckboxList}} return {{lazyEvaluation() == true}} and render their dynamic 
attributes per list item.

h2. Observed

{{<s:textfield name="q" data-hint="%{hint}"/>}} with 
{{struts.ui.templateSuffix=java}} and the {{hint}} property bound from the 
request:

{code}hint = a "b" c      java: data-hint="a "b" c"          ftl: data-hint="a 
&quot;b&quot; c"
hint = %{1+1}       java: data-hint="2"                ftl: data-hint="%{1+1}"
{code}

The standard attributes of the same tag ({{value}}, {{title}}) render 
identically under both engines. Every tag wired through 
{{DynamicAttributesHandler}} in {{SimpleTheme}} behaves the same way.

h2. Proposed change
* Store dynamic attribute values through {{Attributes.add}}, in line with the 
other handlers and the FreeMarker templates.
* Evaluate a dynamic attribute in the handler only when the component is lazily 
evaluated. {{UIBean}} already knows this through {{lazyEvaluation()}}; expose 
it as a component parameter so the plugin can read it. {{Radio}} and 
{{CheckboxList}} keep their per-item evaluation in the handler chain, where 
{{RadioHandler}} and {{CheckboxListHandler}} push each item before calling 
{{start}}.

h2. Compatibility

Under the java engine, a dynamic attribute value is now HTML-escaped once, as 
it already is under the FreeMarker themes; a value that already contains 
entities is escaped again, matching the FreeMarker output. A value that 
resolves to text of the form {{%{...}}} is rendered literally instead of being 
evaluated, matching the FreeMarker output. Lazily evaluated components are 
unchanged.

h2. Tests
* A dynamic attribute whose resolved value contains a double quote renders 
escaped under the java engine.
* A dynamic attribute whose resolved value has the form {{%{...}}} renders 
literally on a non-lazy component.
* A dynamic attribute on {{Radio}} is still evaluated per item in the handler.
* The existing dynamic-attribute rendering tests keep passing for every tag in 
{{SimpleTheme}}.

Reported by Claude and Ada Logics.



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

Reply via email to