I solved the problem by adding a ResponseHandler that clears the headers
(response.getMetadata(),clear()).  Here's what I found while debugging:

JAXRSOutInterceptor puts headers in message from response.getMetadata()

The writer (BinaryDataProvider) copies the inputstream to the
CacheAndWriteOutputStream, with IOUtils.copyAndCloseInput

This adds headers via ServletDestination.copyResponseHeaders:
Transfer-Encoding: chunked and Date, Content-type, Server

Then it writes the contents of the input stream to the servlet output
stream.  During this write Tomcat adds Transfer-Encoding: chunked and Date
headers, so we get duplicates

Phase interceptor closes the conduit, flushing the buffer

When I use a Servlet filter to ignore addHeader requests, I don't get any
duplicate headers.  I'm not sure exactly where the problem lies, as it seems
Tomcat should not allow duplicate headers to be added, however Jetty does
the same.

When I clear response.getMetadata() in a ResponseHandler, CXF adds the Date
header, but Tomcat does not add a duplicate.  I end up with:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Date: Wed, 10 Aug 2011 16:47:43 GMT
Content-Type: application/xml;charset=UTF-8
Transfer-Encoding: chunked

all added by Tomcat.  Thanks for the help.

Andrew

On Tue, Aug 9, 2011 at 2:05 PM, Sergey Beryozkin <sberyoz...@gmail.com>wrote:

> Hi Andrew
>
> On Tue, Aug 9, 2011 at 8:04 PM, Andrew <subo...@gmail.com> wrote:
> > Sergey,
> >
> > Thanks for the suggestions.  Do you mean to use a Servlet filter or CXF
> > filter?  I'm looking at the objects available in the ResponseHandler:
> >
> > public Response handleResponse(Message m, OperationResourceInfo ori,
> > Response response) {
> >
> > but I'm not sure how to manipulate the headers.  Is there an example of
> this
> > somewhere?
> >
> Yes, I meant CXF filter, right now it's about creating another Response
> object:
> ResponseBuilder rb =
> Response.status(response.getStatus()).entity(response.getEntity());
>
> MultivaluedMap<String, Object> headers = response.getMetadata();
> // copy it to rb and block unwanted headers
> // finally
> return rb.build();
>
>
> It's a bit simpler at CXF out interceptor level, you just need to
> extract a Map from the current Message
> using Message.PROTOCOL_HEADERS property, and just call remove on that
> Map for specific headers.
>
> > Next question, is it possible to buffer the XML response from Server 2 to
> > return to the client?  Something like this, but I'm not sure how to
> return
> > the XML as a Response object:
> >
> >                    String s = IOUtils.toString(response.getEntity());
> >                    // How do I create a new Response object to return
> this
> > string?
> >
> > I want to see if I get the duplicate header issue with this approach.
> >
> I think Tomcat reacts to the size of OutputStream so I guess it does
> not matter how it was populated.
> I think the additional buffering will only add to the costs...But
> generally speaking, one just need to specify a
> Content-Type on Response and it will be used to select a writer - this
> Content-Type, if set, will also overwrite @Produces
>
> Cheers, Sergey
>
>
> > Thanks,
> >
> > Andrew
> >
> > On Sun, Aug 7, 2011 at 2:36 PM, Sergey Beryozkin <sberyoz...@gmail.com
> >wrote:
> >
> >> HI
> >>
> >> On Fri, Aug 5, 2011 at 5:30 PM, Andrew <subo...@gmail.com> wrote:
> >> > We have a multi-node REST architecture, using CXF:
> >> >
> >> > Client calls Server 1
> >> > Server 1 looks up the host/url and calls a similar service on Server 2
> >> > Server 1 gets the Response from Server 2 and returns it to the client
> (no
> >> > unmarshalling) For example, this is the call from Server 1 to 2:
> >> >
> >> > public Response testBackup(final Long hostId, final String config) {
> >> >    // create server2Proxy based on hostId
> >> >    return server2Proxy.testBackup(config)
> >> > }
> >> >
> >> > This works and allows us to avoid the unnecessary work of
> >> > unmarshalling/remarshalling the response from Server 2.  First
> question,
> >> is
> >> > this an appropriate CXF implementation?
> >> >
> >> This looks ok. Additionally, you might want to investigate the
> possibility
> >> of
> >> using continuations - that would allow for a thread serving the
> >> current request to Service1 released
> >> immediately and resumed once the response from Server2 is available
> >>
> >> > One problem with this is we see a duplicate Date header from the
> Server 1
> >> > response:
> >> >
> >> > HTTP/1.1 200 OK
> >> > Date: Thu, 04 Aug 2011 23:02:04 GMT
> >> > Date: Thu, 04 Aug 2011 23:02:04 GMT
> >> > Content-Type: application/xml;charset=UTF-8
> >> > Server: Apache-Coyote/1.1
> >> > Content-Length: 8587
> >> >
> >> I'm not quite sure where it's coming from. Response from Server2 would
> >> contain Date - and when processing this Response,
> >> Server1 (JAXRSOutInterceptor) would also set Date - but it must
> >> override the one from Server2 (I double-checked the code).
> >> Can you please confirm Server2 itself does not return 2 Date headers ?
> >> By the way, I don't see 2 Dates in the fragment below...
> >>
> >> Yes, I verified that Server 2 does not return two Date headers.  BTW,
> the
> > duplicate Date header issue only occurs on Jetty.  The response below is
> > when running on Tomcat, it produces duplicate Transfer-Encoding and
> Server
> > headers.
> >
> >
> >> > When I run it on Tomcat, Tomcat chunks the response and duplicates the
> >> > Transfer-Encoding and Server headers:
> >> >
> >> > HTTP/1.1 200 OK
> >> > Server: Apache-Coyote/1.1
> >> > Date: Thu, 04 Aug 2011 22:44:36 GMT
> >> > Transfer-Encoding: chunked
> >> > Server: Apache-Coyote/1.1
> >> > Content-Type: application/xml;charset=UTF-8
> >> > Transfer-Encoding: chunked
> >> >
> >> > This normally could be ignored, however in one of our environments,
> The
> >> > chunked response gets corrupted, not including the chunk size before
> each
> >> > chunk, as required, and the client fails.  Any ideas on this?  We are
> on
> >> CXF
> >> > 2.2.11.  Thanks,
> >> >
> >> I think the only think that can be realistically done is to register
> >> say ResponseHandler filter with Server1 endpoint
> >> and get Transfer-Encoding and Server headers removed. Registering out
> >> CXF interceptor can be even simpler as far as
> >> the headers modification is concerned, but 2.2.11 may have some issues
> >> with this latter option.
> >>
> >> There one other option you might want to consider. In your approach,
> >> Server1 does copy InputStream to OutputStream.
> >> It simply acts as a bridge. If Server 2 is running inside the same
> >> container, then redirecting from the Server1 in chain to Server2
> >> may be prove much more efficient as effectively Server2 will write
> >> directly into Server1's response stream...
> >> Cheers, Sergey
> >>
> >> > Andrew
> >> >
> >>
> >>
> >>
> >> --
> >> Sergey Beryozkin
> >>
> >> http://sberyozkin.blogspot.com
> >> Talend - http://www.talend.com
> >>
> >
>
>
>
> --
> Sergey Beryozkin
>
> http://sberyozkin.blogspot.com
> Talend - http://www.talend.com
>

Reply via email to