users@jersey.java.net

Re: [Jersey] A bug from Jersey 1.0

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 28 Oct 2008 13:25:59 +0100

HI Matt,

Thanks for taking the time to look into this.

Unfortunately the one line fix you propose will break other behavior.

The committing of the status and headers needs to occur just before
the first byte of the entity is written to the output stream, namely a
message body writer can modify the response meta-data before it writes
out the entity.

I think we require a mechanism such that something can commit status/
headers without writing to the output stream and this mechanism can be
used by JSPTemplateProcessor.

Perhaps we could reuse the OutputStream.flush method to do:

   responseWriter.writeStatusAndHeaders

then the JSPTemplateProcessor can do:

     public void writeTo(String resolvedPath, Object model,
OutputStream out) throws IOException {
         // commit status and headers to servlet response
         out.flush();

         RequestDispatcher d =
servletContext.getRequestDispatcher(resolvedPath);
         if (d == null) {
             throw new ContainerException("No request dispatcher for:
" + resolvedPath);
         }

         d = new RequestDispatcherWrapper(d,
ui.getMatchedResources().get(0), model);

         try {
             d.forward(requestInvoker.get(), responseInvoker.get());
         } catch (Exception e) {
             e.printStackTrace();
             throw new ContainerException(e);
         }
     }

What do you think?

Paul.


On Oct 28, 2008, at 1:00 PM, 马林 wrote:

> Dear all,
>
> I don't know whether this letter will be received, if someone
> read this letter please reply to me. thanks!
>
> I found a bug from Jersey 1.0. if using any method to request a
> resource and that the result will be forward to a JSP file,
> then found that all the value setted to the response object will be
> lost. after check the source code found problem as bellow:
>
> Source code from
> "com.sun.jersey.impl.application.WebApplicationImpl" in
> handleRequest method
>
> public void handleRequest(ContainerRequest request,
> ContainerResponseWriter responseWriter)
> throws IOException {
> final ContainerResponse response = new ContainerResponse(
> this,
> request,
> responseWriter);
> handleRequest(request, response);
> }
>
> as above we see that HttpServletResponse is wrapped by the
> ContainerResponseWriter object. for invoking method of
> " public void handleRequest(ContainerRequest request,
> ContainerResponse response) throws IOException " ContainerResponse
> wraps the
> ContainerResponseWriter again.
> so here I found the problem that the value setted in
> ContainerResponse object not save back to orginal
> HttpServletRequest..
>
> finally it cause to
> com.sun.jersey.impl.container.servlet.JSPTemplateProcessor 's method
> named "writeTo" can only get a unchaged HttpServletResponse instance.
>
>
> public void writeTo(String resolvedPath, Object model,
> OutputStream out) throws IOException {
> RequestDispatcher d =
> servletContext.getRequestDispatcher(resolvedPath);
> if (d == null) {
> throw new ContainerException("No request dispatcher for:
> " + resolvedPath);
> }
>
> d = new RequestDispatcherWrapper(d,
> ui.getMatchedResources().get(0), model);
>
> try {
> // Matt mark here. actually the HttpServletResponse get
> from current thread object is unchanged.
> d.forward(requestInvoker.get(), responseInvoker.get());
> } catch (Exception e) {
> e.printStackTrace();
> throw new ContainerException(e);
> }
> }
>
>
> Here I add one line code to solve this problem
> com.sun.jersey.impl.application.WebApplicationImpl
>
>
> public void handleRequest(ContainerRequest request,
> ContainerResponse response) throws IOException {
> try {
> final WebApplicationContext localContext = new
> WebApplicationContext(this, request, response);
> context.set(localContext);
>
> //...
>
> try {
> for (ContainerResponseFilter f : responseFilters)
> response = f.filter(request, response);
>
>
> } catch (WebApplicationException e) {
> mapWebApplicationException(e, response);
> } catch (RuntimeException e) {
> if (!mapException(e, response)) {
> context.set(null);
> throw e;
> }
> }
> //matt add here
> //before write method save the response header value back to
> store HttpServletResoponse object
>
> response.getContainerResponseWriter().writeStatusAndHeaders(-1,
> response);
>
> try {
> response.write();
> } catch (WebApplicationException e) {
> if (response.isCommitted()) {
> throw e;
> } else {
> mapWebApplicationException(e, response);
> response.write();
> }
> } finally {
> context.set(null);
> }
> }
> Your reply is expecting!
>
>
>
> Yours Matt!
> 2008-10-28 from beijin China.
>
>
>