I noticed that this bug was marked RESOLVED/LATER and was wondering if there was any way to get this into 3.2.2 since that is the version that is closest to being released. I've already found 2 ways to fix this issue but am willing to abide by the groups decision and concentrate on getting this into the 3.3 release instead. The 2 ways to fix this are: 1. In BufferedServletInputStream, implement an available() method that returns limit - bytesRead or 0 whichever is greater. The limit class variable is set to the value of the Content-Length header and bytesRead is the number of bytes read since limit was set (see the attached diff1.txt). This is the easy fix but doesn't address the feature of available that says it will return the number of bytes that can be read "without blocking". Obviously, if there is a large amount of data, a read will most likely block at some point depending on how much is asked for, however this prevents a condition where one of the adapters returns 0 because a read hasn't actually been requested from the webserver. 2. Update BufferedServletInputStream to call reqA.available and then update the following files to provide this interface: Request.java RequestImpl.java HttpRequestAdapter.java Ajp12ConnectionHandler.java Ajp13ConnectorRequest.java JNIConnectionHandler.java MsgConnector.java TcpConnector.java Each of these classes would need to provide an appropriate available() method. I've also done the work on these files as well (see the attached diff2.txt) but noticed that since some of the protocols (particularly AJP13) actually have to request a read to fill their internal buffer, the adapter (i.e. Ajp13ConnectorRequest.java) will return a 0 if doRead is called and it exactly empties the internal buffer. Also the JNIRequestAdapter (in JNIConnectionHandler.java) makes a native call back into the webserver to do the reads and so available is implemented similar to #1 above; it just returns the max of contentLength - bytesRead or 0. This was because I'm not sure of a way to imp After testing both of these, implementation 1 is actually faster and more reliable. Typically if someone is calling available and they get back a 0, they would block the thread anyways and so it makes some sense to let it block on the read plus it gets around the issue of an adapter requiring one of it's read methods to be called to actually have something available. Any response positive or negative would be appreciated so that I know where to focus my energy (i.e. 3.2.2 or 3.3).
Index: BufferedServletInputStream.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/core/Attic/BufferedServletInputStream.java,v retrieving revision 1.8 diff -u -r1.8 BufferedServletInputStream.java --- BufferedServletInputStream.java 2000/05/26 17:32:04 1.8 +++ BufferedServletInputStream.java 2001/03/21 21:03:59 @@ -151,6 +151,10 @@ } } + public int available() throws IOException { + return Math.max((limit - bytesRead), 0); + } + // /** // * @deprecated Not part of Servlet API, without it we can avoid a lot of GC.
Index: BufferedServletInputStream.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/core/Attic/BufferedServletInputStream.java,v retrieving revision 1.8 diff -u -r1.8 BufferedServletInputStream.java --- BufferedServletInputStream.java 2000/05/26 17:32:04 1.8 +++ BufferedServletInputStream.java 2001/03/21 21:04:23 @@ -151,6 +151,10 @@ } } + public int available() throws IOException { + return reqA.available(); + } + // /** // * @deprecated Not part of Servlet API, without it we can avoid a lot of GC. Index: Request.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java,v retrieving revision 1.46 diff -u -r1.46 Request.java --- Request.java 2000/06/22 19:49:35 1.46 +++ Request.java 2001/03/21 21:05:31 @@ -274,6 +274,9 @@ public int doRead( byte b[], int off, int len ) throws IOException; + // provide a way to overload available from InputStream + public int available() throws IOException; + // -------------------- Internal methods -------------------- /** Support for "pools" */ Index: RequestImpl.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/core/Attic/RequestImpl.java,v retrieving revision 1.52.2.7 diff -u -r1.52.2.7 RequestImpl.java --- RequestImpl.java 2001/03/15 19:00:37 1.52.2.7 +++ RequestImpl.java 2001/03/21 21:05:41 @@ -818,6 +818,11 @@ return -1; } + // provide a way to overload available from InputStream + public int available() throws IOException { + return 0; + } + // -------------------- "cooked" info -------------------- // Hints = return null if you don't know, // and Tom will find the value. You can also use the static Index: HttpRequestAdapter.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/http/Attic/HttpRequestAdapter.java,v retrieving revision 1.16.2.6 diff -u -r1.16.2.6 HttpRequestAdapter.java --- HttpRequestAdapter.java 2001/01/13 18:36:27 1.16.2.6 +++ HttpRequestAdapter.java 2001/03/21 21:10:44 @@ -119,6 +119,11 @@ return sin.read(b, off, len); } + // provide a way to overload available from InputStream + public int available() throws IOException { + return Math.max(sin.available(), 0); + } + public void readNextRequest(Response response) throws IOException { // Odd, but works: we use the ServletInputStream, which uses doRead. Index: Ajp12ConnectionHandler.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp12ConnectionHandler.java,v retrieving revision 1.28.2.2 diff -u -r1.28.2.2 Ajp12ConnectionHandler.java --- Ajp12ConnectionHandler.java 2000/11/10 06:42:51 1.28.2.2 +++ Ajp12ConnectionHandler.java 2001/03/21 21:17:19 @@ -193,6 +193,10 @@ return ajpin.read(b,off,len); } + public int available() throws IOException { + return Math.max(ajpin.available(), 0); + } + void log( String s ) { contextM.log( s ); } Index: Ajp13ConnectorRequest.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp13ConnectorRequest.java,v retrieving revision 1.5.2.5 diff -u -r1.5.2.5 Ajp13ConnectorRequest.java --- Ajp13ConnectorRequest.java 2001/02/14 22:19:55 1.5.2.5 +++ Ajp13ConnectorRequest.java 2001/03/21 21:14:39 @@ -288,6 +288,10 @@ return len - toCopy; } + public int available() throws IOException { + return Math.max((blen - pos) + con.available(), 0); + } + public void recycle() { super.recycle(); Index: JNIConnectionHandler.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/JNIConnectionHandler.java,v retrieving revision 1.9.2.2 diff -u -r1.9.2.2 JNIConnectionHandler.java --- JNIConnectionHandler.java 2000/12/12 09:41:44 1.9.2.2 +++ JNIConnectionHandler.java 2001/03/21 21:15:16 @@ -213,6 +213,7 @@ JNIConnectionHandler h; long s; long l; + int bytesRead; public int doRead() throws IOException { byte []b = new byte[1]; @@ -234,7 +235,16 @@ Thread.currentThread().yield(); } } + + if (contentLength > 0) + bytesRead += rc; + return rc; + } + + // provide a way to overload available from InputStream + public int available() throws IOException { + return Math.max(contentLength - bytesRead, 0); } public JNIRequestAdapter(ContextManager cm, Index: MsgConnector.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/MsgConnector.java,v retrieving revision 1.5.2.1 diff -u -r1.5.2.1 MsgConnector.java --- MsgConnector.java 2000/12/12 09:41:44 1.5.2.1 +++ MsgConnector.java 2001/03/21 21:15:45 @@ -84,4 +84,8 @@ public int receive(MsgBuffer msg) throws IOException; public void close() throws IOException; + + // provide a way to overload available from InputStream + public int available() throws IOException; } + Index: TcpConnector.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/TcpConnector.java,v retrieving revision 1.2.2.2 diff -u -r1.2.2.2 TcpConnector.java --- TcpConnector.java 2000/12/12 09:41:44 1.2.2.2 +++ TcpConnector.java 2001/03/21 21:16:01 @@ -175,4 +175,14 @@ in.close(); } } + + // provide a way to overload available from InputStream + public int available() throws IOException { + if (null != in) { + System.out.println("in.available() = " + in.available()); + return in.available(); + } + else + return 0; + } }