You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2002/01/14 01:17:59 UTC

cvs commit: jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters ChunkedInputFilter.java

remm        02/01/13 16:17:59

  Modified:    http11/src/java/org/apache/coyote/http11
                        Http11Connector.java
               http11/src/java/org/apache/coyote/http11/filters
                        ChunkedInputFilter.java
  Log:
  - Add input chunking support (last big piece of code for the HTTP connector).
  - Add support for the "no content" status codes: 204, 205 and 304.
  - Add support for HEAD.
  - Add HTTP/0.9 support (untested).
  
  Revision  Changes    Path
  1.12      +43 -14    jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Connector.java
  
  Index: Http11Connector.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Connector.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- Http11Connector.java	10 Jan 2002 16:58:17 -0000	1.11
  +++ Http11Connector.java	14 Jan 2002 00:17:58 -0000	1.12
  @@ -446,6 +446,10 @@
           } else if (protocolMB.equals(Constants.HTTP_10)) {
               http11 = false;
               keepAlive = false;
  +        } else if (protocolMB.equals("")) {
  +            // HTTP/0.9
  +            http11 = false;
  +            keepAlive = false;
           } else {
               // Unsupported protocol
               http11 = false;
  @@ -493,15 +497,6 @@
               inputBuffer.addActiveFilter
                   (inputFilters[Constants.IDENTITY_FILTER]);
               contentDelimitation = true;
  -        } else {
  -            // If method is GET or HEAD, prevent from reading any content
  -            if ((methodMB.equals("GET"))
  -                || (methodMB.equals("HEAD"))
  -                || (methodMB.equals("TRACE"))) {
  -                inputBuffer.addActiveFilter
  -                    (inputFilters[Constants.VOID_FILTER]);
  -                contentDelimitation = true;
  -            }
           }
   
           // Parse transfer-encoding header
  @@ -544,6 +539,17 @@
               response.setStatus(400);
           }
   
  +        if (!contentDelimitation) {
  +            // If method is GET or HEAD, prevent from reading any content
  +            if ((methodMB.equals("GET"))
  +                || (methodMB.equals("HEAD"))
  +                || (methodMB.equals("TRACE"))) {
  +                inputBuffer.addActiveFilter
  +                    (inputFilters[Constants.VOID_FILTER]);
  +                contentDelimitation = true;
  +            }
  +        }
  +
           if (!contentDelimitation)
               keepAlive = false;
   
  @@ -557,18 +563,38 @@
       protected void prepareResponse() {
   
           boolean http09 = false;
  +        boolean entityBody = true;
           contentDelimitation = false;
   
  +        OutputFilter[] outputFilters = outputBuffer.getFilters();
  +
           MessageBytes protocolMB = request.protocol();
           if (protocolMB.equals(Constants.HTTP_11)) {
               http11 = true;
           } else if (protocolMB.equals(Constants.HTTP_10)) {
               http11 = false;
  -        } else {
  -            // FIXME: Check for HTTP/0.9
  +        } else if (protocolMB.equals("")) {
  +            // HTTP/0.9
  +            outputBuffer.addActiveFilter
  +                (outputFilters[Constants.IDENTITY_FILTER]);
  +            return;
           }
   
  -        OutputFilter[] outputFilters = outputBuffer.getFilters();
  +        int statusCode = response.getStatus();
  +        if ((statusCode == 204) || (statusCode == 205) 
  +            || (statusCode == 304)) {
  +            // No entity body
  +            outputBuffer.addActiveFilter
  +                (outputFilters[Constants.VOID_FILTER]);
  +            entityBody = false;
  +        }
  +
  +        MessageBytes methodMB = request.method();
  +        if (methodMB.equals("HEAD")) {
  +            // No entity body
  +            outputBuffer.addActiveFilter
  +                (outputFilters[Constants.VOID_FILTER]);
  +        }
   
           int contentLength = response.getContentLength();
           if (contentLength != -1) {
  @@ -576,7 +602,7 @@
                   (outputFilters[Constants.IDENTITY_FILTER]);
               contentDelimitation = true;
           } else {
  -            if (http11) {
  +            if (entityBody && http11) {
                   outputBuffer.addActiveFilter
                       (outputFilters[Constants.CHUNKED_FILTER]);
                   contentDelimitation = true;
  @@ -593,10 +619,13 @@
           // Add transfer encoding header
           // FIXME
   
  -        if (!contentDelimitation) {
  +        if ((entityBody) && (!contentDelimitation)) {
               // Mark as close the connection after the request, and add the 
               // connection: close header
               keepAlive = false;
  +        }
  +
  +        if (!keepAlive) {
               response.addHeader("Connection", "close");
           }
   
  
  
  
  1.2       +192 -11   jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
  
  Index: ChunkedInputFilter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ChunkedInputFilter.java	24 Dec 2001 20:44:40 -0000	1.1
  +++ ChunkedInputFilter.java	14 Jan 2002 00:17:58 -0000	1.2
  @@ -62,9 +62,11 @@
   import java.io.IOException;
   
   import org.apache.tomcat.util.buf.ByteChunk;
  +import org.apache.tomcat.util.buf.HexUtils;
   
   import org.apache.coyote.InputBuffer;
   import org.apache.coyote.Request;
  +import org.apache.coyote.http11.Constants;
   import org.apache.coyote.http11.InputFilter;
   
   /**
  @@ -94,15 +96,45 @@
   
   
       /**
  -     * Remaining bytes in the current chunk.
  +     * Next buffer in the pipeline.
        */
  -    protected long remaining = -1;
  +    protected InputBuffer buffer;
   
   
       /**
  -     * Next buffer in the pipeline.
  +     * Number of bytes remaining in the current chunk.
        */
  -    protected InputBuffer buffer;
  +    protected int remaining = 0;
  +
  +
  +    /**
  +     * Position in the buffer.
  +     */
  +    protected int pos = 0;
  +
  +
  +    /**
  +     * Last valid byte in the buffer.
  +     */
  +    protected int lastValid = 0;
  +
  +
  +    /**
  +     * Read bytes buffer.
  +     */
  +    protected byte[] buf = null;
  +
  +
  +    /**
  +     * Byte chunk used to read bytes.
  +     */
  +    protected ByteChunk readChunk = new ByteChunk();
  +
  +
  +    /**
  +     * Flag set to true when the end chunk has been read.
  +     */
  +    protected boolean endChunk = false;
   
   
       // ------------------------------------------------------------- Properties
  @@ -123,12 +155,35 @@
       public int doRead(ByteChunk chunk)
           throws IOException {
   
  -        buffer.doRead(chunk);
  +        if (endChunk)
  +            return -1;
  +
  +        if (remaining <= 0) {
  +            if (!parseChunkHeader()) {
  +                throw new IOException("Invalid chunk");
  +            }
  +            if (endChunk) {
  +                parseEndChunk();
  +                return -1;
  +            }
  +        }
   
  -        int result = chunk.getLength();
  +        int result = 0;
   
  -        if (result <= 0) {
  -            return -1;
  +        if (pos >= lastValid) {
  +            readBytes();
  +        }
  +
  +        if (remaining > (lastValid - pos)) {
  +            result = lastValid - pos;
  +            remaining = remaining - result;
  +            chunk.setBytes(buf, pos, result);
  +        } else {
  +            result = remaining;
  +            chunk.setBytes(buf, pos, remaining);
  +            pos = pos + remaining;
  +            remaining = 0;
  +            parseCRLF();
           }
   
           return result;
  @@ -152,9 +207,12 @@
       public long end()
           throws IOException {
   
  -        // FIXME: Consume extra bytes.
  -        // FIXME: If too many bytes were read, return the amount.
  -        return remaining;
  +        // Consume extra bytes : parse the stream until the end chunk is found
  +        while (doRead(readChunk) >= 0) {
  +        }
  +
  +        // Return the number of extra bytes which were consumed
  +        return (lastValid - pos);
   
       }
   
  @@ -172,6 +230,9 @@
        */
       public void recycle() {
           remaining = 0;
  +        pos = 0;
  +        lastValid = 0;
  +        endChunk = false;
       }
   
   
  @@ -181,6 +242,126 @@
        */
       public ByteChunk getEncodingName() {
           return ENCODING;
  +    }
  +
  +
  +    // ------------------------------------------------------ Protected Methods
  +
  +
  +    /**
  +     * Read bytes from the previous buffer.
  +     */
  +    protected int readBytes()
  +        throws IOException {
  +
  +        int nRead = buffer.doRead(readChunk);
  +        pos = readChunk.getStart();
  +        lastValid = readChunk.getEnd();
  +        buf = readChunk.getBytes();
  +
  +        return nRead;
  +
  +    }
  +
  +
  +    /**
  +     * Parse the header of a chunk.
  +     */
  +    protected boolean parseChunkHeader()
  +        throws IOException {
  +
  +        int result = 0;
  +        boolean eol = false;
  +        int begin = pos;
  +        int end = begin;
  +        boolean readDigit = false;
  +
  +        while (!eol) {
  +
  +            if (pos >= lastValid) {
  +                if (readBytes() <= 0)
  +                    return false;
  +            }
  +
  +            if (buf[pos] == Constants.CR) {
  +            } else if (buf[pos] == Constants.LF) {
  +                eol = true;
  +            } else {
  +                if (HexUtils.DEC[buf[pos]] != -1) {
  +                    if (!readDigit) {
  +                        readDigit = true;
  +                        begin = pos;
  +                    }
  +                    end = pos;
  +                }
  +            }
  +
  +            pos++;
  +
  +        }
  +
  +        if (!readDigit)
  +            return false;
  +
  +        int offset = 1;
  +        for (int i = end; i >= begin; i--) {
  +            int val = HexUtils.DEC[buf[i]];
  +            if (val == -1)
  +                return false;
  +            result = result + val * offset;
  +            offset = offset * 16;
  +        }
  +
  +        if (result == 0)
  +            endChunk = true;
  +
  +        remaining = result;
  +
  +        return true;
  +
  +    }
  +
  +
  +    /**
  +     * Parse CRLF at end of chunk.
  +     */
  +    protected boolean parseCRLF()
  +        throws IOException {
  +
  +        boolean eol = false;
  +
  +        while (!eol) {
  +
  +            if (pos >= lastValid) {
  +                if (readBytes() <= 0)
  +                    return false;
  +            }
  +
  +            if (buf[pos] == Constants.CR) {
  +            } else if (buf[pos] == Constants.LF) {
  +                eol = true;
  +            } else {
  +                return false;
  +            }
  +
  +            pos++;
  +
  +        }
  +
  +        return true;
  +
  +    }
  +
  +
  +    /**
  +     * Parse end chunk data.
  +     * FIXME: Handle trailers
  +     */
  +    protected boolean parseEndChunk()
  +        throws IOException {
  +
  +        return parseCRLF(); // FIXME
  +
       }
   
   
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>