jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] Re: Heads Up: Severe problem when rewriting responses! Is our Filter API suitable?

From: Markus KARG <markus_at_headcrashing.eu>
Date: Sat, 13 Oct 2012 16:29:28 +0200

Marek,

> > > On the other hand, it would be interesting to learn what
> > > response context's
> > > setOutputStream() method actually is good for...?
> >
> > If you wrap the output stream returned by getOutputStream(), you need
> > to be able to set the wrapped output stream back, right? That's what
> > the setter is there for.

Understood, but there is a problem with that. I think *transforming* the
result is the only sensible use of getOutputStream(), as simple recording of
the original content can be solved solely by using setOutputStream(),
obviously.

So given this ContainerResponseFilter...

public void filter(ContainerRequestContext request, ContainerResponseContext
response) {
  response.setEntityStream(new
ReplacingFilterStream(response.getEntityStream()));
}

...and assuming ReplacingFilterStream extends java.io.FilterOutputStream to
virtually 'replace' the stream content by writing a transformed variant of
what was written into itself into the original OutputStream passed to its
constructor...

...this effectively replaces the entity representation in the end, without
using a WriterInterceptor, implementing the sole sensible use case as I
noted before.

But, as I have noticed, this does not replace the Content-Length header
automatically set by the JAX-RS implementation (here: RI [Jersey 2.0
M08-1]). As a result, the client will cease reading additional bytes in case
the transformed variant is longer than the original representation, hence
truncating the transformed variant (or, in the reverse case, making the
client hang until timeout, as it expecpects more bytes to come).

As the filter does not know in advance how long the original response will
be, it cannot set the Content-Length in advance of forwarding the request to
next next element in the filter chain. As the ContainerResponseContext is
invalid after leaving the filter() method, the FilterOutputStream cannot
simply store the reference to set the header after its own close(). To sum
up: Neither is the Content-Length automatically corrected, nor is there a
way to manually correct it.

As I do not see any feasible use for getOutputString() besides
transformation (which does not work due to the wrong Content-Length), the
only conclusion I have is that this is a bug in Jersey 2.0 M08-1. But maybe
I oversee something. So I would like to ask you to comment on this use case.
Is this a bug, did I oversee another sensible use case for getOutputString()
besides transformation, or is there another idiom I have to use to complete
the filter-based representation rewriting?

Thanks
Markus