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/20 02:57:19 UTC

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.

Any hints appreciated.

Thanks,


Jan


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


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

Posted by Remy Maucherat <re...@apache.org>.
Bill Barker wrote:
> 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.

It has always been like this: processing for error pages and status 
report pages has to occur later. It's the same for other similarly 
worded mechanisms, such as sendError, sendRedirect, etc.

> 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.

It is the best and only acceptable behavior from a usability standpoint, 
however.

There are other areas where I think implementing the letter of the 
specification turned out completely wrong, such as the charset handling 
that Jan implemented some time before (aka, forcing the addition of a 
charset even if none was specified whenever a writer is being used).

Rémy


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


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

Posted by Remy Maucherat <re...@apache.org>.
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.

Rémy

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


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

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

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.

Does anybody see any problems with removing the
"response instanceof ResponseFacade" check at the end of RD.doForward(),
and unconditionally executing the code in the "else" block, which
commits and closes the response, as requested by the servlet spec?


Jan



> 
>>Any hints appreciated.
>>
>>Thanks,
>>
>>
>>Jan
>>
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
>>For additional commands, e-mail: dev-help@tomcat.apache.org
>>
>>
>>
> 
> 
> 
> 
> This message is intended only for the use of the person(s) listed above as the intended recipient(s), and may contain information that is PRIVILEGED and CONFIDENTIAL.  If you are not an intended recipient, you may not read, copy, or distribute this message or any attachment. If you received this communication in error, please notify us immediately by e-mail and then delete all copies of this message and any attachments.
> 
> In addition you should be aware that ordinary (unencrypted) e-mail sent through the Internet is not secure. Do not send confidential or sensitive information, such as social security numbers, account numbers, personal identification numbers and passwords, to us via ordinary (unencrypted) e-mail.
> 
> 
> ---------------------------------------------------------------------
> 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: Response not flushed before RD.forward() returns

Posted by Bill Barker <wb...@wilshire.com>.
 

> -----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.

> Any hints appreciated.
> 
> Thanks,
> 
> 
> Jan
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
> 
> 
> 



This message is intended only for the use of the person(s) listed above as the intended recipient(s), and may contain information that is PRIVILEGED and CONFIDENTIAL.  If you are not an intended recipient, you may not read, copy, or distribute this message or any attachment. If you received this communication in error, please notify us immediately by e-mail and then delete all copies of this message and any attachments.

In addition you should be aware that ordinary (unencrypted) e-mail sent through the Internet is not secure. Do not send confidential or sensitive information, such as social security numbers, account numbers, personal identification numbers and passwords, to us via ordinary (unencrypted) e-mail.


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