You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Jan Luehe <Ja...@Sun.COM> on 2006/01/21 01:25:12 UTC

Re: [Fwd: Re: Response not flushed before RD.forward() returns]


Remy Maucherat wrote On 01/20/06 03:45,:
> I tried to post that to dev, but there's apparently some issue since my 
> message hasn't been posted yet.
> 
> Rémy
> 
> -------- Original Message --------
> Subject: Re: Response not flushed before RD.forward() returns
> Date: Fri, 20 Jan 2006 12:08:30 +0100
> From: Remy Maucherat <re...@apache.org>
> To: Tomcat Developers List <de...@tomcat.apache.org>
> References: <20...@sneezy.wilshire.com> 
> <43...@sun.com>
> 
> Jan Luehe wrote:
> 
>>Bill Barker wrote On 01/19/06 18:11,:
>>
>>> 
>>>
>>>
>>>
>>>>-----Original Message-----
>>>>From: Jan Luehe [mailto:Jan.Luehe@Sun.COM] 
>>>>Sent: Thursday, January 19, 2006 5:57 PM
>>>>To: tomcat-dev@jakarta.apache.org
>>>>Subject: Response not flushed before RD.forward() returns
>>>>
>>>>Consider the following code snippet of a servlet's service() method:
>>>>
>>>> public class DispatcherServlet extends HttpServlet {
>>>>
>>>>   public void service(HttpServletRequest req, 
>>>>HttpServletResponse res)
>>>>       throws IOException, ServletException {
>>>>
>>>>     
>>>>request.getRequestDispatcher("/target").forward(request, response);
>>>>
>>>>     try {
>>>>         Thread.currentThread().sleep(60000);
>>>>     } catch (Exception ex) { }
>>>>   }
>>>>
>>>>where "target" prints some output to the response.
>>>>
>>>>The code currently returns the output printed by "target" only after
>>>>DispatcherServlet's service() method has finished, instead of right
>>>>before RD.forward() returns.
>>>>
>>>>This seems to be in violation of the Servlet Spec, which has this:
>>>>
>>>>SRV.8.4 ("The Forward Method"):
>>>>
>>>> Before the forward() method of the RequestDispatcher interface
>>>> returns, the response content must be sent and committed, and closed
>>>> by the servlet container.
>>>>
>>>>The code at the end of o.a.c.core.ApplicationDispatcher.doForward()
>>>>looks like this:
>>>>
>>>>       // This is not a real close in order to support error 
>>>>processing
>>>>       if ( log.isDebugEnabled() )
>>>>           log.debug(" Disabling the response for futher output");
>>>>
>>>>       if  (response instanceof ResponseFacade) {
>>>>           ((ResponseFacade) response).finish();
>>>>       } else {
>>>>           // Servlet SRV.6.2.2. The Resquest/Response may have been
>>>>wrapped
>>>>           // and may no longer be instance of RequestFacade
>>>>           if (log.isDebugEnabled()){
>>>>               log.debug( " The Response is vehiculed using 
>>>>a wrapper: "
>>>>                          + response.getClass().getName() );
>>>>           }
>>>>
>>>>           // Close anyway
>>>>           try {
>>>>               PrintWriter writer = response.getWriter();
>>>>               writer.close();
>>>>           } catch (IllegalStateException e) {
>>>>               try {
>>>>                   ServletOutputStream stream = 
>>>>response.getOutputStream();
>>>>                   stream.close();
>>>>               } catch (IllegalStateException f) {
>>>>                   ;
>>>>               } catch (IOException f) {
>>>>                   ;
>>>>               }
>>>>           } catch (IOException e) {
>>>>               ;
>>>>           }
>>>>       }
>>>>
>>>>In the above code sample, response will be an instance of
>>>>ResponseFacade, meaning it will be suspended instead of being flushed
>>>>and closed right away.
>>>>
>>>>Does anyone remember why the "response instanceof ResponseFacade"
>>>>check is there? I would have expected the "else" case to always be
>>>>executed.
>>>>
>>>
>>>Without ever actually having looked at ResponseFacade, I'd always assumed
>>>that ResponseFacade.finish called Response.finishResponse.  And I would have
>>>been wrong ;-).  This would have done the commit/send/close properly.
>>>
>>>I don't have time right now to dig through the SVN logs to see why it's this
>>>way, but suspended doesn't really look good enough to satisfy the spec.
>>
>>Yes. I'm afraid it's been like this forever.
> 
> 
> And it has to stay like this forever too: this needs to get some post
> processing done (like error pages, etc). If this person wants to flush,
> let him call flush.

Right, but flush does nothing once the response has been suspended.

In addition, consider the case where a request has been
forward-dispatched into a foreign context. If the target
servlet in the foreign context has set a status code on the response,
and the response is being suspended before returning from the
RD.forward(), the status code will be mapped to an error page
using the mappings of the *origin* context as the response
travels through the origin context's pipeline (and error valve)
on the way out.

The origin and target contexts may map the same status code to
different error pages, or the origin context may not even contain any
mapping for the given status code. In any case, I would find it
confusing for the origin context's mappings to be used, since
a RD.forward() is supposed to transfer control to the target.

I think it is cleaner for the response to be committed before
returning from RD.forward(), at the cost of not being mapped
to any error page. This is better than mapping the response to
a wrong error page. Or we could suspend the response when the
origin and target servlets share the same context, and commit it
when they reside in different contexts? Clearly, this would require
a spec clarification.


Jan


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: [Fwd: Re: Response not flushed before RD.forward() returns]

Posted by Jan Luehe <Ja...@Sun.COM>.

Bill Barker wrote On 01/21/06 17:45,:
> "Remy Maucherat" <re...@apache.org> wrote in message 
> news:43D23B54.60606@apache.org...
> 
>>Bill Barker wrote:
>>
>>>Yeah, it's pretty much a fatal flaw in the Catalina design.  It's 
>>>currently impossible for Catalina to satisfy both the requirements for 
>>>error-pages and forwards.
>>
>>Given the amount of people who have complained about this behavior which 
>>has been present from the beginning of the Catalina architecture, "fatal" 
>>is likely much too strong. However, I don't see any other way to do this 
>>stuff, and I also don't see it as being worth even attempting to fix.
>>
> 
> 
> Yeah, "fatal" is probably too strong (of course, there are five or so years 
> of record that I'm not a big fan of Catalina, so I probably overstated it 
> :).
> 
> To "fix" it (without changing the Catalina architecture) would probably 
> require duplicating the StandardHostValve stuff in ApplicationFilterChain 
> (which would be just too horrible).  And, since as Jan has noted, the spec 
> is grey (or, rather, inconsistant) on this requirement,  I'm +1 to your -1 
> ;-).
> 
> Of course, if this gets clarified against us in the final 2.5 spec, then 
> we'll have to do it for Tomcat 6.

I've filed BZ 38361, so the discussion we're having is archived somewhere.


Jan



> 
> 
>>Rémy 
> 
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: [Fwd: Re: Response not flushed before RD.forward() returns]

Posted by Bill Barker <wb...@wilshire.com>.
"Remy Maucherat" <re...@apache.org> wrote in message 
news:43D23B54.60606@apache.org...
> Bill Barker wrote:
>> Yeah, it's pretty much a fatal flaw in the Catalina design.  It's 
>> currently impossible for Catalina to satisfy both the requirements for 
>> error-pages and forwards.
>
> Given the amount of people who have complained about this behavior which 
> has been present from the beginning of the Catalina architecture, "fatal" 
> is likely much too strong. However, I don't see any other way to do this 
> stuff, and I also don't see it as being worth even attempting to fix.
>

Yeah, "fatal" is probably too strong (of course, there are five or so years 
of record that I'm not a big fan of Catalina, so I probably overstated it 
:).

To "fix" it (without changing the Catalina architecture) would probably 
require duplicating the StandardHostValve stuff in ApplicationFilterChain 
(which would be just too horrible).  And, since as Jan has noted, the spec 
is grey (or, rather, inconsistant) on this requirement,  I'm +1 to your -1 
;-).

Of course, if this gets clarified against us in the final 2.5 spec, then 
we'll have to do it for Tomcat 6.

> R�my 




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: [Fwd: Re: Response not flushed before RD.forward() returns]

Posted by Remy Maucherat <re...@apache.org>.
Bill Barker wrote:
> Yeah, it's pretty much a fatal flaw in the Catalina design.  It's currently 
> impossible for Catalina to satisfy both the requirements for error-pages and 
> forwards.

Given the amount of people who have complained about this behavior which 
has been present from the beginning of the Catalina architecture, 
"fatal" is likely much too strong. However, I don't see any other way to 
do this stuff, and I also don't see it as being worth even attempting to 
fix.

Rémy

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: [Fwd: Re: Response not flushed before RD.forward() returns]

Posted by Bill Barker <wb...@wilshire.com>.
"Remy Maucherat" <re...@apache.org> wrote in message 
news:43D1E86C.4030807@apache.org...
> Jan Luehe wrote:
>> Right, but flush does nothing once the response has been suspended.
>>
>> In addition, consider the case where a request has been
>> forward-dispatched into a foreign context. If the target
>> servlet in the foreign context has set a status code on the response,
>> and the response is being suspended before returning from the
>> RD.forward(), the status code will be mapped to an error page
>> using the mappings of the *origin* context as the response
>> travels through the origin context's pipeline (and error valve)
>> on the way out.
>>
>> The origin and target contexts may map the same status code to
>> different error pages, or the origin context may not even contain any
>> mapping for the given status code. In any case, I would find it
>> confusing for the origin context's mappings to be used, since
>> a RD.forward() is supposed to transfer control to the target.
>>
>> I think it is cleaner for the response to be committed before
>> returning from RD.forward(), at the cost of not being mapped
>> to any error page. This is better than mapping the response to
>> a wrong error page. Or we could suspend the response when the
>> origin and target servlets share the same context, and commit it
>> when they reside in different contexts? Clearly, this would require
>> a spec clarification.
>
> -1
>

Yeah, it's pretty much a fatal flaw in the Catalina design.  It's currently 
impossible for Catalina to satisfy both the requirements for error-pages and 
forwards.

> R�my 




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: [Fwd: Re: Response not flushed before RD.forward() returns]

Posted by Remy Maucherat <re...@apache.org>.
Jan Luehe wrote:
> Right, but flush does nothing once the response has been suspended.
> 
> In addition, consider the case where a request has been
> forward-dispatched into a foreign context. If the target
> servlet in the foreign context has set a status code on the response,
> and the response is being suspended before returning from the
> RD.forward(), the status code will be mapped to an error page
> using the mappings of the *origin* context as the response
> travels through the origin context's pipeline (and error valve)
> on the way out.
> 
> The origin and target contexts may map the same status code to
> different error pages, or the origin context may not even contain any
> mapping for the given status code. In any case, I would find it
> confusing for the origin context's mappings to be used, since
> a RD.forward() is supposed to transfer control to the target.
> 
> I think it is cleaner for the response to be committed before
> returning from RD.forward(), at the cost of not being mapped
> to any error page. This is better than mapping the response to
> a wrong error page. Or we could suspend the response when the
> origin and target servlets share the same context, and commit it
> when they reside in different contexts? Clearly, this would require
> a spec clarification.

-1

Rémy

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org