[PATCH] Tomcat 4.0.1- Proposed fix for Bugzilla 4609

2001-11-20 Thread Ryan Lubke

Hi,

Thought I'd give a shot at patching a bug (4609) I logged.
The basics of the bug is that an IOException is not thrown
if out.close() is called from within a JSP page and 
subsequent calls to write() or println(), etc. are made.

The solution I have affects two classes:
org.apache.jasper.runtime.JspWriterImpl
org.apache.jasper.compiler.JspParseEventListener

The modification to JspWriterImpl was simple:
  -Added a new boolean instance variable called 'closed'
  -When JspWriter.close() is called, set 'closed' to true.
  -Modified the JspWriter.ensureOpen() method.  If
   'closed' is true, or response is null, throw the IOException.

I felt the modification to JspParseEventListener.generateFooter()
was necessary as the page code generated:

snip
} catch (Throwable t) {
if (out != null  out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
}
/snip

So in this case, now that the IOException is thown, we go into the 
throwable, but the call to out.clearBuffer() generates its own
IOException.  The problem with this is that the stacktrace becomes
inaccurate.  Showing the call to clearBuffer() as the top-most call
on the stack.

So the change I introduced would generate the following code:

snip
if (out != null  out.getBufferSize() != 0)
try {
out.clearBuffer();
} catch (java.io.IOException ioe) {
if (t instanceof java.io.IOException) {
if (!(t.getMessage().equals(ioe.getMessage( {
t = ioe;
}
}
}
/snip

So, here if out.clearBuffer() happens to throw an IOException,
check to see if the throwable that brought us to this point
in the code is an IOException as well.  If it is, see if 
the messages are the same, if they aren't, then there
is a new IO issue and set ioe to the throwable which will
be handled by pageContext.handlePageException.  Otherwise
the catch becomes a no-op and pageContext.handlePageException
will use the original throwable.  Hope that made sense.

Anyway,  comments are definately welcome.  Still getting familiar
with the code.

Thanks,
-rl





Index: JspParseEventListener.java
===
RCS file: 
/home/cvspublic/jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/compiler/JspParseEventListener.java,v
retrieving revision 1.35
diff -u -r1.35 JspParseEventListener.java
--- JspParseEventListener.java  2001/11/02 19:36:09 1.35
+++ JspParseEventListener.java  2001/11/20 22:29:40
@@ -378,7 +378,23 @@
writer.pushIndent();
 writer.println(if (out != null  out.getBufferSize() != 0));
 writer.pushIndent();
+writer.println( try { );
+writer.pushIndent();
writer.println(out.clearBuffer(););
+writer.popIndent();
+writer.println(} catch (java.io.IOException ioe) {);
+writer.pushIndent();
+writer.println(if (t instanceof java.io.IOException) {);
+writer.pushIndent();
+writer.println(if (!(t.getMessage().equals(ioe.getMessage( {);
+writer.pushIndent();
+writer.println(t = ioe;);
+writer.popIndent();
+writer.println(});
+writer.popIndent();
+writer.println(});
+writer.popIndent();
+writer.println(});
writer.popIndent();
writer.println(if (pageContext != null) pageContext.handlePageException(t););
writer.popIndent();


Index: JspWriterImpl.java
===
RCS file: 
/home/cvspublic/jakarta-tomcat-4.0/jasper/src/share/org/apache/jasper/runtime/JspWriterImpl.java,v
retrieving revision 1.1
diff -u -r1.1 JspWriterImpl.java
--- JspWriterImpl.java  2000/08/12 00:52:12 1.1
+++ JspWriterImpl.java  2001/11/20 18:10:11
@@ -99,6 +99,7 @@
 protected static int defaultCharBufferSize = Constants.DEFAULT_BUFFER_SIZE;
 
 protected boolean flushed = false;
+protected boolean closed = false;
 
 public JspWriterImpl() {
super( defaultCharBufferSize, true );
@@ -223,6 +224,7 @@
 if (out != null)
 out.close();
 out = null;
+closed = true;
//cb = null;
 }
 }
@@ -236,7 +238,7 @@
 
 /** check to make sure that the stream has not been closed */
 protected void ensureOpen() throws IOException {
-   if (response == null)
+   if ( closed || response == null)
throw new IOException(Stream closed);
 }
 



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


Re: [PATCH] Tomcat 4.0.1- Proposed fix for Bugzilla 4609

2001-11-20 Thread Kin-Man Chung

The problem is actually deeper than is reported in the bug report.

1. We also need a fix for flush(), since invoking flush after close
   should also throw IOE.
   
2. The fixes should also be applied to BodyContentImpl.java, since it's just
   another JspWriter.
   
However, doing all these fixes leads to another bug in the Jasper runtime.
And this one is nastier.  Suppose we have a jsp:forward somewhere in
the page.  The 'forward' would cause out.close() to be invoked; and then
releasePageContext (generated for every page in 
JspParseEventListener.generateFooter()) would be invoked, which
would cause out.flush() to be invoked, which in term would cause a
IOException!  This all works now because flush called after close does
not cause IOException (a bug).  If fact, if the user explicit closes
a JspWriter, releasePageContext would surely causes a IOE.

I am currently looking at this bug and have essentially the same fix
(except for the generateFooter part), but don't know yet how to fix
the problem I described above.  If you have any ideas, I'd love hearing
from you!


 Date: Tue, 20 Nov 2001 18:19:16 -0500
 From: Ryan Lubke [EMAIL PROTECTED]
 Subject: [PATCH] Tomcat 4.0.1- Proposed fix for Bugzilla 4609
 To: tcdev [EMAIL PROTECTED]
 MIME-version: 1.0
 Delivered-to: mailing list [EMAIL PROTECTED]
 Mailing-List: contact [EMAIL PROTECTED]; run by ezmlm
 X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N
 List-Post: mailto:[EMAIL PROTECTED]
 List-Subscribe: mailto:[EMAIL PROTECTED]
 List-Unsubscribe: mailto:[EMAIL PROTECTED]
 List-Help: mailto:[EMAIL PROTECTED]
 List-Id: Tomcat Developers List tomcat-dev.jakarta.apache.org
 
 Hi,
 
 Thought I'd give a shot at patching a bug (4609) I logged.
 The basics of the bug is that an IOException is not thrown
 if out.close() is called from within a JSP page and 
 subsequent calls to write() or println(), etc. are made.
 
 The solution I have affects two classes:
 org.apache.jasper.runtime.JspWriterImpl
 org.apache.jasper.compiler.JspParseEventListener
 
 The modification to JspWriterImpl was simple:
   -Added a new boolean instance variable called 'closed'
   -When JspWriter.close() is called, set 'closed' to true.
   -Modified the JspWriter.ensureOpen() method.  If
'closed' is true, or response is null, throw the IOException.
 
 I felt the modification to JspParseEventListener.generateFooter()
 was necessary as the page code generated:
 
 snip
 } catch (Throwable t) {
 if (out != null  out.getBufferSize() != 0)
   out.clearBuffer();
 if (pageContext != null) pageContext.handlePageException(t);
 }
 /snip
 
 So in this case, now that the IOException is thown, we go into the 
 throwable, but the call to out.clearBuffer() generates its own
 IOException.  The problem with this is that the stacktrace becomes
 inaccurate.  Showing the call to clearBuffer() as the top-most call
 on the stack.
 
 So the change I introduced would generate the following code:
 
 snip
 if (out != null  out.getBufferSize() != 0)
 try {
 out.clearBuffer();
 } catch (java.io.IOException ioe) {
 if (t instanceof java.io.IOException) {
 if (!(t.getMessage().equals(ioe.getMessage( {
 t = ioe;
 }
 }
 }
 /snip
 
 So, here if out.clearBuffer() happens to throw an IOException,
 check to see if the throwable that brought us to this point
 in the code is an IOException as well.  If it is, see if 
 the messages are the same, if they aren't, then there
 is a new IO issue and set ioe to the throwable which will
 be handled by pageContext.handlePageException.  Otherwise
 the catch becomes a no-op and pageContext.handlePageException
 will use the original throwable.  Hope that made sense.
 
 Anyway,  comments are definately welcome.  Still getting familiar
 with the code.
 
 Thanks,
 -rl
 
 
 


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