You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Lisa Penwall <li...@yahoo.com> on 2000/08/14 05:33:15 UTC

BAD: Flushing ServletOuputStream Commits Response

Hi all,

I'm new to this list and I'm not 100% sure I should be asking about a
potential bug, so please forgive me if this is the wrong group --
better yet, direct me to the right group! I'm not sure who I should
submit this bug to: Sun or the Jakarta folks.

This is definitely an implementation bug I'm seeing. I'm using the
ServletOutputStream in the "servlet.jar" file distributed with Tomcat
v3.1. I've included a simple test servlet below that illustrates the
bug.

Here's the problem: Calling "flush()" on the ServletOutputStream
returned from "HttpServletResponse.getOutputStream()" causes the
response buffer to be committed to the client. This behavior seems
wholly wrong.

If you call "flush()" on the PrintWriter returned from
"HttpServletResponse.getWriter()" the response does *NOT* get committed
to the client. This is the correct behavior and the behavior
ServletOutputStream *should* emulate. Furthermore, there already exists
a method, "ServletResponse.flushBuffer()", specifically designed to
commit the response to the client. It looks to me like somebody forgot
to override ServletOutputStream.flush().

Here's the sample code that shows flushing the ServletOutputStream
returned by "HttpServletResponse.getOutputStream()" causes the response
to be committed.


import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Tester extends HttpServlet implements SingleThreadModel {
   public void doGet(HttpServletRequest req, HttpServletResponse res)
               throws ServletException, IOException {
      res.setContentType("text/html");

      // flushing "out" *does* cause the response buffer
      // to be committed.
      ServletOutputStream out = res.getOutputStream();

      // flushing "out" does *not* cause the response buffer
      // to be committed.
      //PrintWriter out = res.getWriter();

      out.print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0
Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">");
      out.print("<HTML LANG=\"en_US\">");
      out.print("<HEAD><TITLE>Tester Servlet</TITLE><BODY
BGCOLOR=\"#90ccff\"><H2 STYLE=\"color:red\">Tester Servlet</H2><PRE>");
      out.print("Before out.flush(), has response been committed? " +
res.isCommitted() + "<BR>");

      /*----------------------------------------
      Calling flush() on the PrintWriter object returned from
      HttpServletResponse.getWriter() does *not* cause the
      response buffer to be committed -- this is correct.
      On the other hand, calling flush() the OutputStream returned
      from HttpServletResponse.getOutputStream() *does*
      cause the response buffer to be committed -- that's wrong.
      ----------------------------------------*/
      out.flush();

      out.print("After out.flush(), has response been committed? " +
res.isCommitted() + "<BR>");
      res.flushBuffer();
      out.print("After res.flushBuffer(), has response been committed?
" + res.isCommitted() + "<BR>");
      out.print("</PRE></BODY></HTML>");
      out.close();
   } // doget()
} // Tester


__________________________________________________
Do You Yahoo!?
Yahoo! Mail � Free email you can access from anywhere!
http://mail.yahoo.com/

Re: BAD: Flushing ServletOuputStream Commits Response

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Lisa Penwall wrote:

> Hi all,
>
> I'm new to this list and I'm not 100% sure I should be asking about a
> potential bug, so please forgive me if this is the wrong group --
> better yet, direct me to the right group! I'm not sure who I should
> submit this bug to: Sun or the Jakarta folks.
>

Because it is actually a Tomcat issue, this (or TOMCAT-DEV) is the right
place.  The reason for this is that ServletResponse is an interface -- the
ultimate behavior of every method call is determined by the Tomcat-specific
class which implements this interface, which is the behavior you are
observing when you run this test under Tomcat.

>
> This is definitely an implementation bug I'm seeing. I'm using the
> ServletOutputStream in the "servlet.jar" file distributed with Tomcat
> v3.1. I've included a simple test servlet below that illustrates the
> bug.
>
> Here's the problem: Calling "flush()" on the ServletOutputStream
> returned from "HttpServletResponse.getOutputStream()" causes the
> response buffer to be committed to the client. This behavior seems
> wholly wrong.
>
> If you call "flush()" on the PrintWriter returned from
> "HttpServletResponse.getWriter()" the response does *NOT* get committed
> to the client. This is the correct behavior and the behavior
> ServletOutputStream *should* emulate. Furthermore, there already exists
> a method, "ServletResponse.flushBuffer()", specifically designed to
> commit the response to the client. It looks to me like somebody forgot
> to override ServletOutputStream.flush().
>

I agree with you that the behavior of the two output mechanisms should be
the same with regards to whether the response is considered to be
"committed" after a flush.  Where I disagree with you, though, is on which
method is currently incorrect.

When your servlet is communicating via the HTTP protocol (which a large
majority of servlets are doing), one of the protocol requirements is that
the headers are sent *before* any data output that is part of the
response.  Given that restriction, there seems to be only two possible
interpretations for ServletOutputStream.flush() and PrintWriter.flush()
when you call them:

* Ignore the "flush()" call -- which means that servlets who
  deliberately call this method to send a partially completed
  response will not operate as expected.

* Commit the response (i.e. send the headers) followed by the
  data that has been written to date, essentially equivalent
  to ServletResponse.flushBuffer().

My feeling is that most servlet developers would prefer the latter
interpretation, because the reason they are flushing the output at all is
to get partially completed results sent to the client.  Based on that
reasoning, the current ServletOutputStream behavior (which does not
consider the response to be committed) seems to me to be the one that is in
error.

Craig McClanahan