Background
Spring MVC's RequestContext has had two HTML escape flags since Spring 4.1.2 (see SPR-12350 / #16955):
defaultHtmlEscape — the master switch; controls whether escaping happens at all
responseEncodedHtmlEscape — controls which HtmlUtils.htmlEscape() overload is used when escaping is active
PR #36400 (7.0.6) wired defaultHtmlEscape into WebFlux: WebHttpHandlerBuilder → HttpWebHandlerAdapter → ServerWebExchange.HTML_ESCAPE_ATTRIBUTE → WebFlux RequestContext. That closes half the story. responseEncodedHtmlEscape was not included and remains completely absent from WebFlux.
What responseEncodedHtmlEscape does
When defaultHtmlEscape=true, the two flags combine as follows (from HtmlEscapingAwareTag):
if (isHtmlEscape()) {
if (isResponseEncodedHtmlEscape()) {
out = HtmlUtils.htmlEscape(content, response.getCharacterEncoding()); // encoding-aware
} else {
out = HtmlUtils.htmlEscape(content); // ISO-8859-1, escapes everything
}
}
The difference matters in practice. Given the string "café" with a UTF-8 response:
| Configuration |
Output |
defaultHtmlEscape=false |
café |
defaultHtmlEscape=true, responseEncodedHtmlEscape=false |
café <b> |
defaultHtmlEscape=true, responseEncodedHtmlEscape=true |
café <b> |
With a UTF-8 response, the encoding-aware path only escapes the 5 XML-significant characters and lets native UTF-8 characters pass through unchanged. The one-arg overload converts them to HTML entities unnecessarily. MVC's default for responseEncodedHtmlEscape falls back to true, so MVC apps automatically get the correct behavior. WebFlux apps with defaultHtmlEscape=true currently always take the ISO-8859-1 path because the second flag does not exist.
Proposed solution
Mirror the exact pattern from PR #36400 across the same four files:
-
ServerWebExchange — add constant RESPONSE_ENCODED_HTML_ESCAPE_ATTRIBUTE
-
WebHttpHandlerBuilder — add field and builder method responseEncodedHtmlEscape
-
HttpWebHandlerAdapter — add field, setter, and stamp onto exchange in createExchange()
-
WebFlux RequestContext — add field, read from exchange in constructor, expose isResponseEncodedHtmlEscape() and getResponseEncodedHtmlEscape(), and use an encoding-aware escape helper
The one difference from MVC is how the response charset is resolved. MVC calls response.getCharacterEncoding(). In WebFlux the equivalent is exchange.getResponse().getHeaders().getContentType().getCharset() with a UTF-8 fallback, which is consistent with how charset is resolved elsewhere in the framework. The default for isResponseEncodedHtmlEscape() falls back to true when unset, matching MVC exactly. No breaking change.
I implemented the defaultHtmlEscape wiring in PR #36400 and I'm prepared to open a PR and implement this follow-up across the same files
Background
Spring MVC's RequestContext has had two HTML escape flags since Spring 4.1.2 (see SPR-12350 / #16955):
defaultHtmlEscape— the master switch; controls whether escaping happens at allresponseEncodedHtmlEscape— controls whichHtmlUtils.htmlEscape()overload is used when escaping is activePR #36400 (7.0.6) wired
defaultHtmlEscapeinto WebFlux:WebHttpHandlerBuilder→HttpWebHandlerAdapter→ServerWebExchange.HTML_ESCAPE_ATTRIBUTE→ WebFluxRequestContext. That closes half the story.responseEncodedHtmlEscapewas not included and remains completely absent from WebFlux.What
responseEncodedHtmlEscapedoesWhen defaultHtmlEscape=true, the two flags combine as follows (from
HtmlEscapingAwareTag):The difference matters in practice. Given the string "café" with a UTF-8 response:
defaultHtmlEscape=falsedefaultHtmlEscape=true,responseEncodedHtmlEscape=falsedefaultHtmlEscape=true,responseEncodedHtmlEscape=trueWith a UTF-8 response, the encoding-aware path only escapes the 5 XML-significant characters and lets native UTF-8 characters pass through unchanged. The one-arg overload converts them to HTML entities unnecessarily. MVC's default for responseEncodedHtmlEscape falls back to true, so MVC apps automatically get the correct behavior. WebFlux apps with defaultHtmlEscape=true currently always take the ISO-8859-1 path because the second flag does not exist.
Proposed solution
Mirror the exact pattern from PR #36400 across the same four files:
ServerWebExchange— add constantRESPONSE_ENCODED_HTML_ESCAPE_ATTRIBUTEWebHttpHandlerBuilder— add field and builder methodresponseEncodedHtmlEscapeHttpWebHandlerAdapter— add field, setter, and stamp onto exchange increateExchange()WebFlux
RequestContext— add field, read from exchange in constructor, exposeisResponseEncodedHtmlEscape()andgetResponseEncodedHtmlEscape(), and use an encoding-aware escape helperThe one difference from MVC is how the response charset is resolved. MVC calls
response.getCharacterEncoding(). In WebFlux the equivalent isexchange.getResponse().getHeaders().getContentType().getCharset()with a UTF-8 fallback, which is consistent with how charset is resolved elsewhere in the framework. The default forisResponseEncodedHtmlEscape()falls back to true when unset, matching MVC exactly. No breaking change.I implemented the
defaultHtmlEscapewiring in PR #36400 and I'm prepared to open a PR and implement this follow-up across the same files