Hi.
I'm using Apache CXF 3.1.5 as a JAX-RS client implementation and recently
encountered
a stream corruption bug when using client side JAX-RS filters.
In my scenario, I use a JAX-RS client side filter to perform response logging
while
using client side JAX-RS proxies.
For that I created a JAX-RS filter implementing ClientRequestFilter and
ClientResponseFilter
and added it as a provider to the JAX-RS/CXF runtime.
Now when I perform e.g. a GET request, the filter is invoked as expected calling
@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext
responseContext) throws IOException {
if (responseContext.hasEntity()) {
// wrap responseContext.getEntityStream() with
LoggingBufferedStream and set it on responseContext
...
}
}
with the current response.
Now from time to time it happened, that the received content missed the first
byte of
the payload leading to an exception in jackson, that it couldn't parse the JSON
content
correctly.
After investigation, this happend most of the time, when the response had
"transfer-encoding: chunked" set. Looking deeper into CXFs
responseContext.hasEntity()
implementation showed, that the lost byte is due to a call to
IOUtils.isEmpty(stream):
https://github.com/apache/cxf/blob/master/core/src/main/java/org/apache/cxf/helpers/IOUtils.java
In there are basically 3 checks:
- is mark supported?
- is available > 0
- if NOT the above, wrap stream with PushbackInputStream, try to read a byte
and unread.
Sadly, in this chunked scenario, it seems that the
responseContext.getEntityStream()
neither supports mark nor is available > 0 (it is 0). So it wraps the stream
with
PushbackInputStream, reads a byte and unreads. But, as the underlying stream
doesn't
support reset/rewind or similar, the read byte is "lost". As the
PushbackInputStream
isn't returned from that method and so there's no way to get that byte back.
Not invoking hasEntity() in the filter at all and just taking the stream and
reading
(buffered) from it, fixes the problem.
It would be great if someone from the CXF team could take a peek at it :).
Thanks!
Veit