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 >