Linton Miller created HTTPCLIENT-2005:
-----------------------------------------
Summary: ContentCompressionExec is not thread-safe
Key: HTTPCLIENT-2005
URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2005
Project: HttpComponents HttpClient
Issue Type: Bug
Components: HttpClient (classic)
Affects Versions: 5.0 Beta5
Reporter: Linton Miller
org.apache.hc.client5.http.impl.classic.ContentCompressionExec is not
thread-safe in its handling of the Accept-Encoding header, which can result in
the header being mangled.
The problem is in its creation of the header by using MessageSupport:
{code:java}
request.addHeader(MessageSupport.format(HttpHeaders.ACCEPT_ENCODING,
acceptEncoding));
{code}
MessageSupport.format is *not* thread-safe, because it sorts its second
argument:
{code:java}
public static Header format(final String name, final String... tokens) {
...
formatTokens(buffer, tokens);
public static void formatTokens(final CharArrayBuffer dst, final String...
tokens) {
Args.notNull(dst, "Destination");
Arrays.sort(tokens); // <--- This is not thread-safe!!!
{code}
The result is that the Accept-Encoding header can end up being any random
combination and subset of the acceptEncoding array elements.
e.g. on the standard acceptEncoding array of new String[] \{"gzip", "x-gzip",
"deflate"}, the request header may read
Accept-Encoding: deflate, deflate, gzip
or
Accept-Encoding: deflate, deflate, deflate
for example.
It won't, however, introduce any elements not previously in the array, or
corrupt any of the individual strings.
It actually seems pretty nasty that MessageSupport isn't thread-safe, but given
that it's not, it would require supplying a separate copy of the acceptEncoding
array for each format call. e.g.
{code:java}
request.addHeader(MessageSupport.format(HttpHeaders.ACCEPT_ENCODING,
acceptEncoding.clone()));
{code}
However, an even better alternative would seem to be to do the MessageFormat in
the ContentCompressionExec constructor, and cache the formatted Header:
{code:java}
this.acceptEncoding = MessageSupport.format(HttpHeaders.ACCEPT_ENCODING,
acceptEncoding != null ? acceptEncoding.toArray(
new String[acceptEncoding.size()]) : new String[] {"gzip",
"x-gzip", "deflate"});
{code}
and then just use it in the execute method:
{code:java}
request.addHeader(acceptEncoding);
{code}
--
This message was sent by Atlassian JIRA
(v7.6.14#76016)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]