You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by vi...@apache.org on 2016/10/06 11:30:45 UTC

svn commit: r1763559 - in /tomcat/trunk/java/org/apache: catalina/connector/ coyote/ coyote/ajp/ coyote/http11/ coyote/http11/filters/ coyote/http2/ tomcat/util/net/

Author: violetagg
Date: Thu Oct  6 11:30:44 2016
New Revision: 1763559

URL: http://svn.apache.org/viewvc?rev=1763559&view=rev
Log:
Introduce a new method o.a.coyote.InputBuffer.doRead(ApplicationBufferHandler)

Modified:
    tomcat/trunk/java/org/apache/catalina/connector/InputBuffer.java
    tomcat/trunk/java/org/apache/coyote/InputBuffer.java
    tomcat/trunk/java/org/apache/coyote/Request.java
    tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java
    tomcat/trunk/java/org/apache/coyote/http11/filters/BufferedInputFilter.java
    tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
    tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
    tomcat/trunk/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
    tomcat/trunk/java/org/apache/coyote/http11/filters/VoidInputFilter.java
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java
    tomcat/trunk/java/org/apache/tomcat/util/net/ApplicationBufferHandler.java

Modified: tomcat/trunk/java/org/apache/catalina/connector/InputBuffer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/InputBuffer.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/InputBuffer.java (original)
+++ tomcat/trunk/java/org/apache/catalina/connector/InputBuffer.java Thu Oct  6 11:30:44 2016
@@ -36,6 +36,7 @@ import org.apache.tomcat.util.buf.B2CCon
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.CharChunk;
 import org.apache.tomcat.util.collections.SynchronizedStack;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -48,7 +49,7 @@ import org.apache.tomcat.util.res.String
  */
 public class InputBuffer extends Reader
     implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
-               CharChunk.CharOutputChannel {
+               CharChunk.CharOutputChannel, ApplicationBufferHandler {
 
     /**
      * The string manager for this package.
@@ -75,6 +76,7 @@ public class InputBuffer extends Reader
      * The byte buffer.
      */
     private final ByteChunk bb;
+    private ByteBuffer tempRead;
 
 
     /**
@@ -146,6 +148,8 @@ public class InputBuffer extends Reader
     public InputBuffer(int size) {
 
         this.size = size;
+        tempRead = ByteBuffer.allocate(size);
+        tempRead.flip();
         bb = new ByteChunk(size);
         bb.setLimit(size);
         bb.setByteInputChannel(this);
@@ -314,8 +318,10 @@ public class InputBuffer extends Reader
             state = BYTE_STATE;
         }
 
-        int result = coyoteRequest.doRead(bb);
-
+        int result = coyoteRequest.doRead(this);
+        bb.setBytes(tempRead.array(), tempRead.arrayOffset() + tempRead.position(),
+                tempRead.remaining());
+        tempRead.position(0).limit(0);
         return result;
     }
 
@@ -594,4 +600,22 @@ public class InputBuffer extends Reader
         }
 
     }
+
+
+    @Override
+    public void setByteBuffer(ByteBuffer buffer) {
+        tempRead = buffer;
+    }
+
+
+    @Override
+    public ByteBuffer getByteBuffer() {
+        return tempRead;
+    }
+
+
+    @Override
+    public void expand(int size) {
+        // no-op
+    }
 }

Modified: tomcat/trunk/java/org/apache/coyote/InputBuffer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/InputBuffer.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/InputBuffer.java (original)
+++ tomcat/trunk/java/org/apache/coyote/InputBuffer.java Thu Oct  6 11:30:44 2016
@@ -19,6 +19,7 @@ package org.apache.coyote;
 import java.io.IOException;
 
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 
 /**
  * This class is only for internal use in the protocol implementation. All
@@ -40,4 +41,20 @@ public interface InputBuffer {
      * @throws IOException If an I/O error occurs reading from the input stream
      */
     public int doRead(ByteChunk chunk) throws IOException;
+
+    /**
+     * Read from the input stream into the ByteBuffer provided by the
+     * ApplicaitonBufferHandler.
+     * IMPORTANT: the current model assumes that the protocol will 'own' the
+     * ByteBuffer and return a pointer to it.
+     *
+     * @param handler ApplicaitonBufferHandler that provides the buffer to read
+     *                data into.
+     *
+     * @return The number of bytes that have been added to the buffer or -1 for
+     *         end of stream
+     *
+     * @throws IOException If an I/O error occurs reading from the input stream
+     */
+    public int doRead(ApplicationBufferHandler handler) throws IOException;
 }

Modified: tomcat/trunk/java/org/apache/coyote/Request.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/Request.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/Request.java (original)
+++ tomcat/trunk/java/org/apache/coyote/Request.java Thu Oct  6 11:30:44 2016
@@ -29,6 +29,7 @@ import org.apache.tomcat.util.buf.UDecod
 import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.http.Parameters;
 import org.apache.tomcat.util.http.ServerCookies;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -512,6 +513,31 @@ public final class Request {
         if (n > 0) {
             bytesRead+=n;
         }
+        return n;
+    }
+
+
+    /**
+     * Read data from the input buffer and put it into ApplicationBufferHandler.
+     *
+     * The buffer is owned by the protocol implementation - it will be reused on
+     * the next read. The Adapter must either process the data in place or copy
+     * it to a separate buffer if it needs to hold it. In most cases this is
+     * done during byte->char conversions or via InputStream. Unlike
+     * InputStream, this interface allows the app to process data in place,
+     * without copy.
+     *
+     * @param handler The destination to which to copy the data
+     *
+     * @return The number of bytes copied
+     *
+     * @throws IOException If an I/O error occurs during the copy
+     */
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+        int n = inputBuffer.doRead(handler);
+        if (n > 0) {
+            bytesRead+=n;
+        }
         return n;
     }
 

Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java Thu Oct  6 11:30:44 2016
@@ -43,6 +43,7 @@ import org.apache.tomcat.util.buf.Messag
 import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 import org.apache.tomcat.util.net.SSLSupport;
 import org.apache.tomcat.util.net.SocketWrapperBase;
 import org.apache.tomcat.util.res.StringManager;
@@ -1367,6 +1368,23 @@ public class AjpProcessor extends Abstra
             empty = true;
             return chunk.getLength();
         }
+
+        @Override
+        public int doRead(ApplicationBufferHandler handler) throws IOException {
+
+            if (endOfStream) {
+                return -1;
+            }
+            if (empty) {
+                if (!refillReadBuffer(true)) {
+                    return -1;
+                }
+            }
+            ByteChunk bc = bodyBytes.getByteChunk();
+            handler.setByteBuffer(ByteBuffer.wrap(bc.getBuffer(), bc.getStart(), bc.getLength()));
+            empty = true;
+            return handler.getByteBuffer().remaining();
+        }
     }
 
 

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java Thu Oct  6 11:30:44 2016
@@ -292,6 +292,16 @@ public class Http11InputBuffer implement
 
     }
 
+    @Override
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+
+        if (lastActiveFilter == -1)
+            return inputStreamInputBuffer.doRead(handler);
+        else
+            return activeFilters[lastActiveFilter].doRead(handler);
+
+    }
+
 
     // ------------------------------------------------------- Protected Methods
 
@@ -1073,6 +1083,29 @@ public class Http11InputBuffer implement
 
             return length;
         }
+
+        @Override
+        public int doRead(ApplicationBufferHandler handler) throws IOException {
+
+            if (byteBuffer.position() >= byteBuffer.limit()) {
+                // The application is reading the HTTP request body which is
+                // always a blocking operation.
+                if (!fill(true))
+                    return -1;
+            }
+
+            int length = byteBuffer.remaining();
+            handler.setByteBuffer(byteBuffer.duplicate());
+            byteBuffer.position(byteBuffer.limit());
+
+            return length;
+        }
+    }
+
+
+    @Override
+    public void setByteBuffer(ByteBuffer buffer) {
+        byteBuffer = buffer;
     }
 
 

Modified: tomcat/trunk/java/org/apache/coyote/http11/filters/BufferedInputFilter.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/BufferedInputFilter.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/BufferedInputFilter.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/BufferedInputFilter.java Thu Oct  6 11:30:44 2016
@@ -26,12 +26,13 @@ import org.apache.coyote.InputBuffer;
 import org.apache.coyote.Request;
 import org.apache.coyote.http11.InputFilter;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 
 /**
  * Input filter responsible for reading and buffering the request body, so that
  * it does not interfere with client SSL handshake messages.
  */
-public class BufferedInputFilter implements InputFilter {
+public class BufferedInputFilter implements InputFilter, ApplicationBufferHandler {
 
     // -------------------------------------------------------------- Constants
 
@@ -42,7 +43,7 @@ public class BufferedInputFilter impleme
     // ----------------------------------------------------- Instance Variables
 
     private ByteBuffer buffered;
-    private final ByteChunk tempRead = new ByteChunk(1024);
+    private ByteBuffer tempRead;
     private InputBuffer buffer;
     private boolean hasRead = false;
 
@@ -82,11 +83,11 @@ public class BufferedInputFilter impleme
     public void setRequest(Request request) {
         // save off the Request body
         try {
-            while (buffer.doRead(tempRead) >= 0) {
+            while (buffer.doRead(this) >= 0) {
                 buffered.mark().position(buffered.limit()).limit(buffered.capacity());
-                buffered.put(tempRead.getBytes(), tempRead.getStart(), tempRead.getLength());
+                buffered.put(tempRead);
                 buffered.limit(buffered.position()).reset();
-                tempRead.recycle();
+                tempRead = null;
             }
         } catch(IOException | BufferOverflowException ioe) {
             // No need for i18n - this isn't going to get logged anywhere
@@ -110,6 +111,20 @@ public class BufferedInputFilter impleme
         return chunk.getLength();
     }
 
+    /**
+     * Fills the given ByteBuffer with the buffered request body.
+     */
+    @Override
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+        if (isFinished()) {
+            return -1;
+        }
+
+        handler.setByteBuffer(buffered);
+        hasRead = true;
+        return buffered.remaining();
+    }
+
     @Override
     public void setBuffer(InputBuffer buffer) {
         this.buffer = buffer;
@@ -124,7 +139,6 @@ public class BufferedInputFilter impleme
                 buffered.position(0).limit(0);
             }
         }
-        tempRead.recycle();
         hasRead = false;
         buffer = null;
     }
@@ -149,4 +163,22 @@ public class BufferedInputFilter impleme
     public boolean isFinished() {
         return hasRead || buffered.remaining() <= 0;
     }
+
+
+    @Override
+    public void setByteBuffer(ByteBuffer buffer) {
+        tempRead = buffer;
+    }
+
+
+    @Override
+    public ByteBuffer getByteBuffer() {
+        return tempRead;
+    }
+
+
+    @Override
+    public void expand(int size) {
+        // no-op
+    }
 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java Thu Oct  6 11:30:44 2016
@@ -18,6 +18,7 @@ package org.apache.coyote.http11.filters
 
 import java.io.EOFException;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.Set;
@@ -30,6 +31,7 @@ import org.apache.tomcat.util.buf.ByteCh
 import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -38,7 +40,7 @@ import org.apache.tomcat.util.res.String
  *
  * @author Remy Maucherat
  */
-public class ChunkedInputFilter implements InputFilter {
+public class ChunkedInputFilter implements InputFilter, ApplicationBufferHandler {
 
     private static final StringManager sm = StringManager.getManager(
             ChunkedInputFilter.class.getPackage().getName());
@@ -73,27 +75,9 @@ public class ChunkedInputFilter implemen
 
 
     /**
-     * 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 final ByteChunk readChunk = new ByteChunk();
+    protected ByteBuffer readChunk;
 
 
     /**
@@ -189,24 +173,83 @@ public class ChunkedInputFilter implemen
 
         int result = 0;
 
-        if (pos >= lastValid) {
+        if (readChunk == null || readChunk.position() >= readChunk.limit()) {
+            if (readBytes() < 0) {
+                throwIOException(sm.getString("chunkedInputFilter.eos"));
+            }
+        }
+
+        if (remaining > readChunk.remaining()) {
+            result = readChunk.remaining();
+            remaining = remaining - result;
+            chunk.setBytes(readChunk.array(), readChunk.arrayOffset() + readChunk.position(), result);
+            readChunk.position(readChunk.limit());
+        } else {
+            result = remaining;
+            chunk.setBytes(readChunk.array(), readChunk.arrayOffset() + readChunk.position(), remaining);
+            readChunk.position(readChunk.position() + remaining);
+            remaining = 0;
+            //we need a CRLF
+            if ((readChunk.position() + 1) >= readChunk.limit()) {
+                //if we call parseCRLF we overrun the buffer here
+                //so we defer it to the next call BZ 11117
+                needCRLFParse = true;
+            } else {
+                parseCRLF(false); //parse the CRLF immediately
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+        if (endChunk) {
+            return -1;
+        }
+
+        checkError();
+
+        if(needCRLFParse) {
+            needCRLFParse = false;
+            parseCRLF(false);
+        }
+
+        if (remaining <= 0) {
+            if (!parseChunkHeader()) {
+                throwIOException(sm.getString("chunkedInputFilter.invalidHeader"));
+            }
+            if (endChunk) {
+                parseEndChunk();
+                return -1;
+            }
+        }
+
+        int result = 0;
+
+        if (readChunk == null || readChunk.position() >= readChunk.limit()) {
             if (readBytes() < 0) {
                 throwIOException(sm.getString("chunkedInputFilter.eos"));
             }
         }
 
-        if (remaining > (lastValid - pos)) {
-            result = lastValid - pos;
+        if (remaining > readChunk.remaining()) {
+            result = readChunk.remaining();
             remaining = remaining - result;
-            chunk.setBytes(buf, pos, result);
-            pos = lastValid;
+            if (readChunk != handler.getByteBuffer()) {
+                handler.setByteBuffer(readChunk.duplicate());
+            }
+            readChunk.position(readChunk.limit());
         } else {
             result = remaining;
-            chunk.setBytes(buf, pos, remaining);
-            pos = pos + remaining;
+            if (readChunk != handler.getByteBuffer()) {
+                handler.setByteBuffer(readChunk.duplicate());
+                handler.getByteBuffer().limit(readChunk.position() + remaining);
+            }
+            readChunk.position(readChunk.position() + remaining);
             remaining = 0;
             //we need a CRLF
-            if ((pos+1) >= lastValid) {
+            if ((readChunk.position() + 1) >= readChunk.limit()) {
                 //if we call parseCRLF we overrun the buffer here
                 //so we defer it to the next call BZ 11117
                 needCRLFParse = true;
@@ -238,7 +281,7 @@ public class ChunkedInputFilter implemen
         long swallowed = 0;
         int read = 0;
         // Consume extra bytes : parse the stream until the end chunk is found
-        while ((read = doRead(readChunk)) >= 0) {
+        while ((read = doRead(this)) >= 0) {
             swallowed += read;
             if (maxSwallowSize > -1 && swallowed > maxSwallowSize) {
                 throwIOException(sm.getString("inputFilter.maxSwallow"));
@@ -246,7 +289,7 @@ public class ChunkedInputFilter implemen
         }
 
         // Return the number of extra bytes which were consumed
-        return lastValid - pos;
+        return readChunk.remaining();
     }
 
 
@@ -255,7 +298,7 @@ public class ChunkedInputFilter implemen
      */
     @Override
     public int available() {
-        return lastValid - pos;
+        return readChunk != null ? readChunk.remaining() : 0;
     }
 
 
@@ -274,8 +317,9 @@ public class ChunkedInputFilter implemen
     @Override
     public void recycle() {
         remaining = 0;
-        pos = 0;
-        lastValid = 0;
+        if (readChunk != null) {
+            readChunk.position(0).limit(0);
+        }
         endChunk = false;
         needCRLFParse = false;
         trailingHeaders.recycle();
@@ -309,13 +353,7 @@ public class ChunkedInputFilter implemen
      * @throws IOException Read error
      */
     protected int readBytes() throws IOException {
-
-        int nRead = buffer.doRead(readChunk);
-        pos = readChunk.getStart();
-        lastValid = pos + nRead;
-        buf = readChunk.getBytes();
-
-        return nRead;
+        return buffer.doRead(this);
     }
 
 
@@ -342,15 +380,16 @@ public class ChunkedInputFilter implemen
 
         while (!eol) {
 
-            if (pos >= lastValid) {
+            if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                 if (readBytes() <= 0)
                     return false;
             }
 
-            if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
+            byte chr = readChunk.get(readChunk.position());
+            if (chr == Constants.CR || chr == Constants.LF) {
                 parseCRLF(false);
                 eol = true;
-            } else if (buf[pos] == Constants.SEMI_COLON && !extension) {
+            } else if (chr == Constants.SEMI_COLON && !extension) {
                 // First semi-colon marks the start of the extension. Further
                 // semi-colons may appear to separate multiple chunk-extensions.
                 // These need to be processed as part of parsing the extensions.
@@ -358,7 +397,7 @@ public class ChunkedInputFilter implemen
                 extensionSize++;
             } else if (!extension) {
                 //don't read data after the trailer
-                int charValue = HexUtils.getDec(buf[pos]);
+                int charValue = HexUtils.getDec(chr);
                 if (charValue != -1 && readDigit < 8) {
                     readDigit++;
                     result = (result << 4) | charValue;
@@ -379,7 +418,7 @@ public class ChunkedInputFilter implemen
 
             // Parsing the CRLF increments pos
             if (!eol) {
-                pos++;
+                readChunk.position(readChunk.position() + 1);
             }
         }
 
@@ -410,18 +449,19 @@ public class ChunkedInputFilter implemen
         boolean crfound = false;
 
         while (!eol) {
-            if (pos >= lastValid) {
+            if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                 if (readBytes() <= 0) {
                     throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoData"));
                 }
             }
 
-            if (buf[pos] == Constants.CR) {
+            byte chr = readChunk.get(readChunk.position());
+            if (chr == Constants.CR) {
                 if (crfound) {
                     throwIOException(sm.getString("chunkedInputFilter.invalidCrlfCRCR"));
                 }
                 crfound = true;
-            } else if (buf[pos] == Constants.LF) {
+            } else if (chr == Constants.LF) {
                 if (!tolerant && !crfound) {
                     throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoCR"));
                 }
@@ -430,7 +470,7 @@ public class ChunkedInputFilter implemen
                 throwIOException(sm.getString("chunkedInputFilter.invalidCrlf"));
             }
 
-            pos++;
+            readChunk.position(readChunk.position() + 1);
         }
     }
 
@@ -454,13 +494,13 @@ public class ChunkedInputFilter implemen
         byte chr = 0;
 
         // Read new bytes if needed
-        if (pos >= lastValid) {
+        if (readChunk == null || readChunk.position() >= readChunk.limit()) {
             if (readBytes() <0) {
                throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
             }
         }
 
-        chr = buf[pos];
+        chr = readChunk.get(readChunk.position());
 
         // CRLF terminates the request
         if (chr == Constants.CR || chr == Constants.LF) {
@@ -480,13 +520,13 @@ public class ChunkedInputFilter implemen
         while (!colon) {
 
             // Read new bytes if needed
-            if (pos >= lastValid) {
+            if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                 if (readBytes() <0) {
                     throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
                 }
             }
 
-            chr = buf[pos];
+            chr = readChunk.get(readChunk.position());
             if ((chr >= Constants.A) && (chr <= Constants.Z)) {
                 chr = (byte) (chr - Constants.LC_OFFSET);
             }
@@ -497,7 +537,7 @@ public class ChunkedInputFilter implemen
                 trailingHeaders.append(chr);
             }
 
-            pos++;
+            readChunk.position(readChunk.position() + 1);
 
         }
         int colonPos = trailingHeaders.getEnd();
@@ -518,15 +558,15 @@ public class ChunkedInputFilter implemen
             while (space) {
 
                 // Read new bytes if needed
-                if (pos >= lastValid) {
+                if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                     if (readBytes() <0) {
                         throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
                     }
                 }
 
-                chr = buf[pos];
+                chr = readChunk.get(readChunk.position());
                 if ((chr == Constants.SP) || (chr == Constants.HT)) {
-                    pos++;
+                    readChunk.position(readChunk.position() + 1);
                     // If we swallow whitespace, make sure it counts towards the
                     // limit placed on trailing header size
                     int newlimit = trailingHeaders.getLimit() -1;
@@ -544,13 +584,13 @@ public class ChunkedInputFilter implemen
             while (!eol) {
 
                 // Read new bytes if needed
-                if (pos >= lastValid) {
+                if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                     if (readBytes() <0) {
                         throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
                     }
                 }
 
-                chr = buf[pos];
+                chr = readChunk.get(readChunk.position());
                 if (chr == Constants.CR || chr == Constants.LF) {
                     parseCRLF(true);
                     eol = true;
@@ -562,7 +602,7 @@ public class ChunkedInputFilter implemen
                 }
 
                 if (!eol) {
-                    pos++;
+                    readChunk.position(readChunk.position() + 1);
                 }
             }
 
@@ -570,13 +610,13 @@ public class ChunkedInputFilter implemen
             // is a LWS, then it's a multiline header
 
             // Read new bytes if needed
-            if (pos >= lastValid) {
+            if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                 if (readBytes() <0) {
                     throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
                 }
             }
 
-            chr = buf[pos];
+            chr = readChunk.get(readChunk.position());
             if ((chr != Constants.SP) && (chr != Constants.HT)) {
                 validLine = false;
             } else {
@@ -620,4 +660,22 @@ public class ChunkedInputFilter implemen
             throw new IOException(sm.getString("chunkedInputFilter.error"));
         }
     }
+
+
+    @Override
+    public void setByteBuffer(ByteBuffer buffer) {
+        readChunk = buffer;
+    }
+
+
+    @Override
+    public ByteBuffer getByteBuffer() {
+        return readChunk;
+    }
+
+
+    @Override
+    public void expand(int size) {
+        // no-op
+    }
 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityInputFilter.java Thu Oct  6 11:30:44 2016
@@ -24,6 +24,7 @@ import org.apache.coyote.InputBuffer;
 import org.apache.coyote.Request;
 import org.apache.coyote.http11.InputFilter;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -118,6 +119,40 @@ public class IdentityInputFilter impleme
                 result = -1;
             }
         }
+
+        return result;
+
+    }
+
+    @Override
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+
+        int result = -1;
+
+        if (contentLength >= 0) {
+            if (remaining > 0) {
+                int nRead = buffer.doRead(handler);
+                if (nRead > remaining) {
+                    // The chunk is longer than the number of bytes remaining
+                    // in the body; changing the chunk length to the number
+                    // of bytes remaining
+                    handler.getByteBuffer().limit(handler.getByteBuffer().position() + (int) remaining);
+                    result = (int) remaining;
+                } else {
+                    result = nRead;
+                }
+                if (nRead > 0) {
+                    remaining = remaining - nRead;
+                }
+            } else {
+                // No more bytes left to be read : return -1 and clear the
+                // buffer
+                if (handler.getByteBuffer() != null) {
+                    handler.getByteBuffer().position(0).limit(0);
+                }
+                result = -1;
+            }
+        }
 
         return result;
 

Modified: tomcat/trunk/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java Thu Oct  6 11:30:44 2016
@@ -18,10 +18,12 @@
 package org.apache.coyote.http11.filters;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 import org.apache.coyote.InputBuffer;
 import org.apache.coyote.http11.InputFilter;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 
 /**
  * Input filter responsible for replaying the request body when restoring the
@@ -63,6 +65,18 @@ public class SavedRequestInputFilter imp
         return writeLength;
     }
 
+    @Override
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+        if(input.getOffset()>= input.getEnd())
+            return -1;
+
+        ByteBuffer byteBuffer = handler.getByteBuffer();
+        byteBuffer.position(byteBuffer.limit()).limit(byteBuffer.capacity());
+        input.substract(byteBuffer);
+
+        return byteBuffer.remaining();
+    }
+
     /**
      * Set the content length on the request.
      */

Modified: tomcat/trunk/java/org/apache/coyote/http11/filters/VoidInputFilter.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/VoidInputFilter.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/VoidInputFilter.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/VoidInputFilter.java Thu Oct  6 11:30:44 2016
@@ -23,6 +23,7 @@ import org.apache.coyote.InputBuffer;
 import org.apache.coyote.Request;
 import org.apache.coyote.http11.InputFilter;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 
 /**
  * Void input filter, which returns -1 when attempting a read. Used with a GET,
@@ -54,6 +55,11 @@ public class VoidInputFilter implements
         return -1;
     }
 
+    @Override
+    public int doRead(ApplicationBufferHandler handler) throws IOException {
+        return -1;
+    }
+
 
     // ---------------------------------------------------- InputFilter Methods
 

Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Thu Oct  6 11:30:44 2016
@@ -32,6 +32,7 @@ import org.apache.coyote.http2.HpackDeco
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.ApplicationBufferHandler;
 import org.apache.tomcat.util.res.StringManager;
 
 public class Stream extends AbstractStream implements HeaderEmitter {
@@ -655,6 +656,62 @@ public class Stream extends AbstractStre
 
             // Increment client-side flow control windows by the number of bytes
             // read
+            handler.writeWindowUpdate(Stream.this, written, true);
+
+            return written;
+        }
+
+        @Override
+        public int doRead(ApplicationBufferHandler applicationBufferHandler) throws IOException {
+
+            ensureBuffersExist();
+
+            int written = -1;
+
+            // Ensure that only one thread accesses inBuffer at a time
+            synchronized (inBuffer) {
+                while (inBuffer.position() == 0 && !isInputFinished()) {
+                    // Need to block until some data is written
+                    try {
+                        if (log.isDebugEnabled()) {
+                            log.debug(sm.getString("stream.inputBuffer.empty"));
+                        }
+                        inBuffer.wait();
+                        if (reset) {
+                            // TODO: i18n
+                            throw new IOException("HTTP/2 Stream reset");
+                        }
+                    } catch (InterruptedException e) {
+                        // Possible shutdown / rst or similar. Use an
+                        // IOException to signal to the client that further I/O
+                        // isn't possible for this Stream.
+                        throw new IOException(e);
+                    }
+                }
+
+                if (inBuffer.position() > 0) {
+                    // Data is available in the inBuffer. Copy it to the
+                    // outBuffer.
+                    inBuffer.flip();
+                    written = inBuffer.remaining();
+                    if (log.isDebugEnabled()) {
+                        log.debug(sm.getString("stream.inputBuffer.copy",
+                                Integer.toString(written)));
+                    }
+                    inBuffer.get(outBuffer, 0, written);
+                    inBuffer.clear();
+                } else if (isInputFinished()) {
+                    return -1;
+                } else {
+                    // Should never happen
+                    throw new IllegalStateException();
+                }
+            }
+
+            applicationBufferHandler.setByteBuffer(ByteBuffer.wrap(outBuffer, 0,  written));
+
+            // Increment client-side flow control windows by the number of bytes
+            // read
             handler.writeWindowUpdate(Stream.this, written, true);
 
             return written;

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/ApplicationBufferHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/ApplicationBufferHandler.java?rev=1763559&r1=1763558&r2=1763559&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/ApplicationBufferHandler.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/ApplicationBufferHandler.java Thu Oct  6 11:30:44 2016
@@ -20,10 +20,12 @@ import java.nio.ByteBuffer;
 
 /**
  * Callback interface to be able to expand buffers when buffer overflow
- * exceptions happen
+ * exceptions happen or to replace buffers
  */
 public interface ApplicationBufferHandler {
 
+    public void setByteBuffer(ByteBuffer buffer);
+
     public ByteBuffer getByteBuffer();
 
     public void expand(int size);



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org