remm 00/12/13 23:49:16 Modified: catalina/src/share/org/apache/catalina/connector RequestStream.java catalina/src/share/org/apache/catalina/connector/http HttpRequestStream.java Log: - Fix two overlapping problems in input chunking. - Fix for a serious logic bug (apparently, I had forgotten to port back another fix from the HTTP client library :((((). - Removed buffering in RequestStream, since it was causing problems with chunking in some cases. The request was double buffered anyway, so the performance impact, if any, shouldn't be too big. Doing a buffered stream which would also transparently handle chunks could be tricky, so I prefer keeping those two things separate : at the bottom is the buffered stream, and the chunk handling is done at a higher level. Also, an all in one approach wouldn't work for more that one transfer encoding. In the future a layered approach could be used to transparently do successive decodings / encodings. Revision Changes Path 1.4 +21 -246 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/RequestStream.java Index: RequestStream.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/RequestStream.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- RequestStream.java 2000/10/28 01:39:44 1.3 +++ RequestStream.java 2000/12/14 07:49:15 1.4 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/RequestStream.java,v 1.3 2000/10/28 01:39:44 craigmcc Exp $ - * $Revision: 1.3 $ - * $Date: 2000/10/28 01:39:44 $ + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/RequestStream.java,v 1.4 2000/12/14 07:49:15 remm Exp $ + * $Revision: 1.4 $ + * $Date: 2000/12/14 07:49:15 $ * * ==================================================================== * @@ -79,7 +79,7 @@ * not reading more than that many bytes on the underlying stream. * * @author Craig R. McClanahan - * @version $Revision: 1.3 $ $Date: 2000/10/28 01:39:44 $ + * @version $Revision: 1.4 $ $Date: 2000/12/14 07:49:15 $ */ public class RequestStream @@ -109,31 +109,6 @@ /** - * The default buffer size for our input buffer. - */ - protected static final int BUFFER_SIZE = 512; - - - /** - * The input buffer for our stream. - */ - protected byte buffer[] = new byte[BUFFER_SIZE]; - - - /** - * The current number of bytes in the buffer. - */ - protected int bufferCount = 0; - - - /** - * The current position in the buffer. - */ - protected int bufferPosition = 0; - - - - /** * Has this stream been closed? */ protected boolean closed = false; @@ -169,48 +144,21 @@ /** - * Return the number of bytes that can be read (or skipped over) from this - * input stream without blocking by the next caller of a method on this - * input stream. - * - * @exception IOException if an input/output error occurs - */ - public int available() throws IOException { - - // Has this stream been closed? - if (closed) - throw new IOException(sm.getString("requestStream.read.closed")); - - // Calculate the number of bytes that are available - int available = (bufferCount - bufferPosition) + stream.available(); - if ((length > 0) && ((count + available) > length)) - available = length - count; - return (available); - - } - - - /** * Close this input stream. No physical level I-O is performed, but * any further attempt to read from this stream will throw an IOException. * If a content length has been set but not all of the bytes have yet been * consumed, the remaining bytes will be swallowed. - * - * @exception IOException if an input/output error occurs */ public void close() throws IOException { if (closed) throw new IOException(sm.getString("requestStream.close.closed")); - if ((length > 0) && (count < length)) { - long remaining = length - count; - while (remaining > 0) { - long skipped = skip(remaining); - if (skipped == 0L) - throw new IOException - (sm.getString("requestStream.close.skip")); - remaining -= skipped; + if (length > 0) { + while (count < length) { + int b = read(); + if (b < 0) + break; } } @@ -235,17 +183,11 @@ // Have we read the specified content length already? if ((length >= 0) && (count >= length)) return (-1); // End of file indicator - - // Refill the buffer if needed - if (bufferPosition >= bufferCount) { - fill(); - if (bufferPosition >= bufferCount) - return (-1); - } - // Grab and return the next byte from the buffer - int b = buffer[bufferPosition++]; - count++; + // Read and count the next byte, then return it + int b = stream.read(); + if (b >= 0) + count++; return (b); } @@ -284,183 +226,16 @@ * @exception IOException if an input/output error occurs */ public int read(byte b[], int off, int len) throws IOException { - - // Has this stream been closed? - if (closed) - throw new IOException(sm.getString("requestStream.read.closed")); - - // Have we read the specified content length already? - if ((length >= 0) && (count >= length)) - return (-1); // End of file indicator - - // Refill the buffer if needed - int available = bufferCount - bufferPosition; - if (available <= 0) { - fill(); - available = bufferCount - bufferPosition; - if (available <= 0) - return (-1); - } - - // Copy as many bytes as we can from the buffer - if (available < len) - len = available; - System.arraycopy(buffer, bufferPosition, b, off, len); - bufferPosition += len; - count += len; - return (len); - - } - - - /** - * Read into an array of bytes until all requested bytes have been - * read or a '\n' is encountered, in which case the '\n' is read into - * the array as well. - * - * @param b The buffer where data is stored - * @param off The start offset into the buffer - * @param len The maximum number of bytes to be returned - * - * @return The actual number of bytes read, or -1 if the end of the - * stream is reached or the byte limit has been exceeded - * - * @exception IOException if an input/output error occurs - */ - public int readLine(byte b[], int off, int len) throws IOException { - - // Has this stream been closed? - if (closed) - throw new IOException(sm.getString("requestStream.read.closed")); - - // Have we read the specified content length already? - if ((length >= 0) && (count >= length)) - return (-1); // End of file indicator - - int available; // Bytes available in buffer - int readlen; // Amount to be read by copyLine() - int remain = len; // Amount remaining to be read - int newlen; // Amount read by copyLine() - int totalread; // Total amount read so far - - // Refill the buffer if needed - available = bufferCount - bufferPosition; - if (available <= 0) { - fill(); - available = bufferCount - bufferPosition; - if (available <= 0) - return (-1); - } - - // Determine how many bytes we should try to read - if (available < len) - readlen = available; - else - readlen = len; - - // Copy the initial portion of this line - newlen = copyLine(buffer, bufferPosition, b, off, readlen); - bufferPosition += newlen; - count += newlen; - remain -= newlen; - totalread = newlen; - if (totalread == 0) // Cannot happen - return (-1); - - // Copy additional chunks until a newline is encountered - while ((remain > 0) && (b[off + totalread - 1] != '\n')) { - fill(); - available = bufferCount - bufferPosition; - if (available <= 0) - return (totalread); // The stream is finished - if (available < remain) - readlen = available; - else - readlen = remain; - newlen = copyLine(buffer, bufferPosition, b, off, readlen); - bufferPosition += newlen; - count += newlen; - remain -= newlen; - totalread += newlen; - } - - return (totalread); - - } - - - /** - * Skip the specified number of bytes of input, and return the actual - * number of bytes skipped. - * - * @param n The number of bytes to be skipped - * - * @exception IOException if an input/output error occurs - */ - public long skip(long n) throws IOException { - - if ((length > 0) && (count >= length)) - return (0); - - long remaining = n; - if (length > 0) - remaining = Math.min(remaining, (length - count)); - long skipped = 0; - while (remaining > 0) { - int available = bufferCount - bufferPosition; - if (available <= 0) { - fill(); - available = bufferCount - bufferPosition; - if (available <= 0) - return (skipped); - } - if (remaining < available) - available = (int) remaining; - skipped += available; - remaining -= available; - bufferPosition += available; - count += available; - } - return (skipped); - - } - - - // ------------------------------------------------- Protected Methods - - - /** - * Copy up to a line of data from source to destination buffer. - */ - protected int copyLine(byte source[], int srcOff, - byte dest[], int destOff, int len) { - - int off = srcOff; - while ((len-- > 0) && (source[off++] != '\n')) - ; - System.arraycopy(source, srcOff, dest, destOff, off - srcOff); - return (off - srcOff); - - } - - - /** - * Refill the buffer from the underlying stream. - * - * @exception IOException if an input/output error occurs - */ - protected void fill() throws IOException { - bufferPosition = 0; - bufferCount = 0; - int len = buffer.length; - if (length > 0) - len = Math.min(len, (length - count)); - if (len > 0) { - len = stream.read(buffer, 0, len); - if (len > 0) - bufferCount = len; + int toRead = len; + if (length > 0) { + if (count >= length) + return (-1); + if ((count + len) > length) + toRead = length - count; } + int actuallyRead = super.read(b, off, toRead); + return (actuallyRead); } 1.6 +12 -13 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java Index: HttpRequestStream.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- HttpRequestStream.java 2000/12/06 06:46:39 1.5 +++ HttpRequestStream.java 2000/12/14 07:49:16 1.6 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.5 2000/12/06 06:46:39 remm Exp $ - * $Revision: 1.5 $ - * $Date: 2000/12/06 06:46:39 $ + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.6 2000/12/14 07:49:16 remm Exp $ + * $Revision: 1.6 $ + * $Date: 2000/12/14 07:49:16 $ * * ==================================================================== * @@ -91,6 +91,7 @@ super(request); String transferEncoding = request.getHeader("Transfer-Encoding"); + http11 = request.getProtocol().equals("HTTP/1.1"); chunk = ((transferEncoding != null) && (transferEncoding.indexOf("chunked") != -1)); @@ -99,8 +100,6 @@ response.addHeader("Connection", "close"); } - http11 = request.getProtocol().equals("HTTP/1.1"); - } @@ -202,12 +201,13 @@ return (-1); if ((chunkBuffer == null) - || (chunkPos == chunkLength)) { + || (chunkPos >= chunkLength)) { chunkPos = 0; try { - chunkLength = Integer.parseInt(readLine().trim(), 16); + chunkLength = + Integer.parseInt(readLineFromStream().trim(), 16); } catch (NumberFormatException e) { // Critical error, unable to parse the chunk length chunkLength = 0; @@ -219,9 +219,9 @@ if (chunkLength == 0) { // Skipping trailing headers, if any - String trailingLine = readLine(); + String trailingLine = readLineFromStream(); while (!trailingLine.equals("")) - trailingLine = readLine(); + trailingLine = readLineFromStream(); endChunk = true; return (-1); // TODO : Should the stream be automatically closed ? @@ -239,7 +239,7 @@ while (nbRead < chunkLength) { currentRead = - super.read(chunkBuffer, nbRead, + stream.read(chunkBuffer, nbRead, chunkLength - nbRead); if (currentRead == -1) throw new IOException @@ -248,8 +248,7 @@ } // Skipping the CRLF - super.read(); - super.read(); + readLineFromStream(); } @@ -279,7 +278,7 @@ * was encountered * @exception IOException if an input or output exception has occurred */ - private String readLine() + private String readLineFromStream() throws IOException { StringBuffer sb = new StringBuffer();