Bug #18 Details

Project: Jasper
Category: Bug Report
SubCategory: New Bug Report
Class: swbug
State: closed
Priority: high
Severity: serious
Confidence: public
Environment: 
   Release: 3.3
   JVM Release: 1.2.2
   Operating System: Linux
   OS Release: RedHat 6.2
   Platform: i386

Synopsis: 
response.flushBuffer() fails to flush

Description:
Calling response.flushBuffer() doesn't actually flush the buffer.
<p>
>From my posting on the tomcat-dev list:
<p>
Note that in a JSP, out.flush() does the right thing now, but
response.flushBuffer() does not.)
 <p>
The problem comes because Jasper JspWriter has its own buffer --
apparently this was written before Costin added OutputBuffer to the
servlet output stream.  But the Response object used by Jasper is the
exact same one that Tomcat passes it.  Unfortunately, this response
object has no idea of the existence of Jasper's JspWriter buffer.
Thus, its flushBuffer() method just flushes the Tomcat stream, not the
Jasper stream, and characters remain in Jasper until the response is
closed.
 <p>
Possible solutions:
 <p>
1. Remove the buffer from JspWriter.  This would be cleanest, but may
cause problems, since this kind of surgery would require modifying
lots of code throughout JspWriterImpl, possibly leading to odd bugs,
or at least a lot of work.  Also, I haven't thought through the
implications viz the autoFlush attribute, though on first blush I
don't think it would be a problem (we'd just say "Jasper is a
buffering JSP engine" which it actually already is).
 <p>
2. Make Jasper implement a facade over Response (actually over
HttpServletResponse) that correctly implements flushBuffer by calling
jspwriter.flush(); this would have to be done inside _jspService,
meaning inside generated code, which seems flakey to me.  Also, a
trivial implementation of such a facade would lead to performance
issues (making a few new objects per JSP request), unless we use
pooling, which seems also like a lot of work.
<p>
3. Add a private callback method to our HttpServletResponse (in our
facade manager, called from Response.java to make the
HttpServletResponse facade) that calls Jasper when flushBuffer is
called; this would break compatibility with other servlet engines.
<p>
I'm leaning towards #1.  Any doubts?
<p>
Clarification:  flushBuffer is a method on *response*, which was passed
in from Tomcat, which has its own buffer.  Which it flushes.  But
Jasper's buffer is somewhere else (inside JspWriterImpl), that
Response doesn't know about, so it stays full.
<p>
There's a JspWriter whose flush method works fine.  But there's no
"JspResponse" or equivalent (that would be my facade solution).
<p>
This is really the fault of the API; I see no reason for having a
Response.flushBuffer() call when out.flush() should (and does) do the
job perfectly well.  Maybe I should ask the JSR 53 experts why they
added this method to Response.

Title: BugRat Bug # 18

BugRat Bug # 18

Project: Jasper Release: 3.3
Category: Bug Report SubCategory: New Bug Report
Class: swbug State: closed
Priority: high Severity: serious
Confidence: public

Date Opened: Aug 25 2000, 07:29:43 CDT
Date Closed: Aug 27 2000, 05:56:26 CDT
Responsible: Z_Tomcat Alias ( [EMAIL PROTECTED] )

Synopsis:
response.flushBuffer() fails to flush
Environment: (jvm, os, osrel, platform)
1.2.2, Linux, RedHat 6.2, i386

Additional Environment Description:

Report Description:
Calling response.flushBuffer() doesn't actually flush the buffer.

>From my posting on the tomcat-dev list:

Note that in a JSP, out.flush() does the right thing now, but response.flushBuffer() does not.)

The problem comes because Jasper JspWriter has its own buffer -- apparently this was written before Costin added OutputBuffer to the servlet output stream. But the Response object used by Jasper is the exact same one that Tomcat passes it. Unfortunately, this response object has no idea of the existence of Jasper's JspWriter buffer. Thus, its flushBuffer() method just flushes the Tomcat stream, not the Jasper stream, and characters remain in Jasper until the response is closed.

Possible solutions:

1. Remove the buffer from JspWriter. This would be cleanest, but may cause problems, since this kind of surgery would require modifying lots of code throughout JspWriterImpl, possibly leading to odd bugs, or at least a lot of work. Also, I haven't thought through the implications viz the autoFlush attribute, though on first blush I don't think it would be a problem (we'd just say "Jasper is a buffering JSP engine" which it actually already is).

2. Make Jasper implement a facade over Response (actually over HttpServletResponse) that correctly implements flushBuffer by calling jspwriter.flush(); this would have to be done inside _jspService, meaning inside generated code, which seems flakey to me. Also, a trivial implementation of such a facade would lead to performance issues (making a few new objects per JSP request), unless we use pooling, which seems also like a lot of work.

3. Add a private callback method to our HttpServletResponse (in our facade manager, called from Response.java to make the HttpServletResponse facade) that calls Jasper when flushBuffer is called; this would break compatibility with other servlet engines.

I'm leaning towards #1. Any doubts?

Clarification: flushBuffer is a method on *response*, which was passed in from Tomcat, which has its own buffer. Which it flushes. But Jasper's buffer is somewhere else (inside JspWriterImpl), that Response doesn't know about, so it stays full.

There's a JspWriter whose flush method works fine. But there's no "JspResponse" or equivalent (that would be my facade solution).

This is really the fault of the API; I see no reason for having a Response.flushBuffer() call when out.flush() should (and does) do the job perfectly well. Maybe I should ask the JSR 53 experts why they added this method to Response.

How To Reproduce:
Testing flushBuffer <br>
<%
for (int i=0; i<5; ++i) {
  out.println("Flush " + i + "<br>");
  response.flushBuffer();
  long now = System.currentTimeMillis();
  while (System.currentTimeMillis() < now + 1000)
    ;
}
%>
Testing flush <br>
<%
for (int i=0; i<5; ++i) {
  out.println("Flush " + i + "<br>");
  out.flush();
  long now = System.currentTimeMillis();
  while (System.currentTimeMillis() < now + 1000)
    ;
}
%>
Done.

Workaround:
Use out.flush() instead

View this Bug online...



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to