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
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]