You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/06/08 21:45:12 UTC

svn commit: r1684255 - in /tomcat/trunk: java/org/apache/coyote/http2/ test/org/apache/coyote/http2/

Author: markt
Date: Mon Jun  8 19:45:12 2015
New Revision: 1684255

URL: http://svn.apache.org/r1684255
Log:
Introduce separate exceptions for stream errors and connection errors

Added:
    tomcat/trunk/java/org/apache/coyote/http2/ConnectionError.java   (with props)
    tomcat/trunk/java/org/apache/coyote/http2/StreamError.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java
    tomcat/trunk/java/org/apache/coyote/http2/FrameType.java
    tomcat/trunk/java/org/apache/coyote/http2/Http2Exception.java
    tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
    tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
    tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java
    tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java

Added: tomcat/trunk/java/org/apache/coyote/http2/ConnectionError.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/ConnectionError.java?rev=1684255&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/ConnectionError.java (added)
+++ tomcat/trunk/java/org/apache/coyote/http2/ConnectionError.java Mon Jun  8 19:45:12 2015
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.coyote.http2;
+
+public class ConnectionError extends Http2Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    public ConnectionError(String msg, int streamId, Error error) {
+        super(msg, streamId, error);
+    }
+}

Propchange: tomcat/trunk/java/org/apache/coyote/http2/ConnectionError.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java Mon Jun  8 19:45:12 2015
@@ -83,7 +83,7 @@ public class ConnectionSettings {
     public void setHeaderTableSize(long headerTableSize) throws IOException {
         // Need to put a sensible limit on this. Start with 16k (default is 4k)
         if (headerTableSize > (16 * 1024)) {
-            throw new Http2Exception(sm.getString("connectionSettings.headerTableSizeLimit",
+            throw new ConnectionError(sm.getString("connectionSettings.headerTableSizeLimit",
                     Long.toString(headerTableSize)), 0, Error.PROTOCOL_ERROR);
         }
         this.headerTableSize = (int) headerTableSize;
@@ -97,7 +97,7 @@ public class ConnectionSettings {
         // Can't be less than zero since the result of the byte->long conversion
         // will never be negative
         if (enablePush > 1) {
-            throw new Http2Exception(sm.getString("connectionSettings.enablePushInvalid",
+            throw new ConnectionError(sm.getString("connectionSettings.enablePushInvalid",
                     Long.toString(enablePush)), 0, Error.PROTOCOL_ERROR);
         }
         this.enablePush = (enablePush  == 1);
@@ -117,7 +117,7 @@ public class ConnectionSettings {
     }
     public void setInitialWindowSize(long initialWindowSize) throws IOException {
         if (initialWindowSize > MAX_WINDOW_SIZE) {
-            throw new Http2Exception(sm.getString("connectionSettings.windowSizeTooBig",
+            throw new ConnectionError(sm.getString("connectionSettings.windowSizeTooBig",
                     Long.toString(initialWindowSize), Long.toString(MAX_WINDOW_SIZE)),
                     0, Error.PROTOCOL_ERROR);
         }
@@ -130,7 +130,7 @@ public class ConnectionSettings {
     }
     public void setMaxFrameSize(long maxFrameSize) throws IOException {
         if (maxFrameSize < MIN_MAX_FRAME_SIZE || maxFrameSize > MAX_MAX_FRAME_SIZE) {
-            throw new Http2Exception(sm.getString("connectionSettings.maxFrameSizeInvalid",
+            throw new ConnectionError(sm.getString("connectionSettings.maxFrameSizeInvalid",
                     Long.toString(maxFrameSize), Integer.toString(MIN_MAX_FRAME_SIZE),
                     Integer.toString(MAX_MAX_FRAME_SIZE)), 0, Error.PROTOCOL_ERROR);
         }

Modified: tomcat/trunk/java/org/apache/coyote/http2/FrameType.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/FrameType.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/FrameType.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/FrameType.java Mon Jun  8 19:45:12 2015
@@ -58,10 +58,10 @@ public enum FrameType {
 
     public void checkStream(String connectionId, int streamId) throws Http2Exception {
         if (streamId == 0 && !streamZero) {
-            throw new Http2Exception(sm.getString("frameType.checkStream.invalidForZero",
+            throw new ConnectionError(sm.getString("frameType.checkStream.invalidForZero",
                     connectionId, this), 0, Error.PROTOCOL_ERROR);
         } else if (streamId != 0 && !streamNonZero) {
-            throw new Http2Exception(sm.getString("frameType.checkStream.invalidForNonZero",
+            throw new ConnectionError(sm.getString("frameType.checkStream.invalidForNonZero",
                     connectionId, Integer.valueOf(streamId), this), 0, Error.PROTOCOL_ERROR);
         }
     }
@@ -70,7 +70,7 @@ public enum FrameType {
     public void checkPayloadSize(String connectionId, int streamId, int payloadSize)
             throws Http2Exception {
         if (payloadSizeValidator != null && !payloadSizeValidator.test(payloadSize)) {
-            throw new Http2Exception(sm.getString("frameType.checkPayloadSize",
+            throw new ConnectionError(sm.getString("frameType.checkPayloadSize",
                     connectionId, Integer.toString(streamId), this, Integer.toString(payloadSize)),
                     0, Error.FRAME_SIZE_ERROR);
         }

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2Exception.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2Exception.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Exception.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Exception.java Mon Jun  8 19:45:12 2015
@@ -16,9 +16,7 @@
  */
 package org.apache.coyote.http2;
 
-import java.io.IOException;
-
-public class Http2Exception extends IOException {
+public abstract class Http2Exception extends Exception {
 
     private static final long serialVersionUID = 1L;
 

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java Mon Jun  8 19:45:12 2015
@@ -66,12 +66,14 @@ class Http2Parser {
      *
      * @throws IOException If an IO error occurs while trying to read a frame
      */
-    boolean readFrame(boolean block) throws IOException {
+    boolean readFrame(boolean block) throws Http2Exception, IOException {
         return readFrame(block, null);
     }
 
 
-    private boolean readFrame(boolean block, FrameType expected) throws IOException {
+    private boolean readFrame(boolean block, FrameType expected)
+            throws IOException, Http2Exception {
+
         if (!input.fill(block, frameHeaderBuffer)) {
             return false;
         }
@@ -81,7 +83,13 @@ class Http2Parser {
         int flags = ByteUtil.getOneByte(frameHeaderBuffer, 4);
         int streamId = ByteUtil.get31Bits(frameHeaderBuffer, 5);
 
-        validateFrame(expected, frameType, streamId, flags, payloadSize);
+        try {
+            validateFrame(expected, frameType, streamId, flags, payloadSize);
+        } catch (StreamError se) {
+            // TODO debug log
+            swallow(payloadSize);
+            return true;
+        }
 
         switch (frameType) {
         case DATA:
@@ -122,7 +130,8 @@ class Http2Parser {
     }
 
 
-    private void readDataFrame(int streamId, int flags, int payloadSize) throws IOException {
+    private void readDataFrame(int streamId, int flags, int payloadSize)
+            throws Http2Exception, IOException {
         // Process the Stream
         int padLength = 0;
 
@@ -153,7 +162,9 @@ class Http2Parser {
     }
 
 
-    private void readHeadersFrame(int streamId, int flags, int payloadSize) throws IOException {
+    private void readHeadersFrame(int streamId, int flags, int payloadSize)
+            throws Http2Exception, IOException {
+
         if (hpackDecoder == null) {
             hpackDecoder = output.getHpackDecoder();
         }
@@ -208,7 +219,7 @@ class Http2Parser {
     }
 
 
-    private void readPriorityFrame(int streamId) throws IOException {
+    private void readPriorityFrame(int streamId) throws Http2Exception, IOException {
         byte[] payload = new byte[5];
         input.fill(true, payload);
 
@@ -220,7 +231,7 @@ class Http2Parser {
     }
 
 
-    private void readRstFrame(int streamId) throws IOException {
+    private void readRstFrame(int streamId) throws Http2Exception, IOException {
         byte[] payload = new byte[4];
         input.fill(true, payload);
 
@@ -229,10 +240,11 @@ class Http2Parser {
     }
 
 
-    private void readSettingsFrame(int flags, int payloadSize) throws IOException {
+    private void readSettingsFrame(int flags, int payloadSize) throws Http2Exception, IOException {
         boolean ack = Flags.isAck(flags);
         if (payloadSize > 0 && ack) {
-            throw new Http2Exception(sm.getString("http2Parser.processFrameSettings.ackWithNonZeroPayload"),
+            throw new ConnectionError(sm.getString(
+                    "http2Parser.processFrameSettings.ackWithNonZeroPayload"),
                     0, Error.FRAME_SIZE_ERROR);
         }
 
@@ -250,8 +262,8 @@ class Http2Parser {
     }
 
 
-    private void readPushPromiseFrame(int streamId) throws IOException {
-        throw new Http2Exception(sm.getString("http2Parser.processFramePushPromise",
+    private void readPushPromiseFrame(int streamId) throws Http2Exception {
+        throw new ConnectionError(sm.getString("http2Parser.processFramePushPromise",
                 connectionId, Integer.valueOf(streamId)), 0, Error.PROTOCOL_ERROR);
     }
 
@@ -282,7 +294,7 @@ class Http2Parser {
     }
 
 
-    private void readWindowUpdateFrame(int streamId) throws IOException {
+    private void readWindowUpdateFrame(int streamId) throws Http2Exception, IOException {
         byte[] payload = new byte[4];
         input.fill(true,  payload);
         int windowSizeIncrement = ByteUtil.get31Bits(payload, 0);
@@ -294,8 +306,15 @@ class Http2Parser {
 
         // Validate the data
         if (windowSizeIncrement == 0) {
-            throw new Http2Exception("http2Parser.processFrameWindowUpdate.invalidIncrement",
-                    streamId, Error.PROTOCOL_ERROR);
+            if (streamId == 0) {
+                throw new ConnectionError(
+                        sm.getString("http2Parser.processFrameWindowUpdate.invalidIncrement"),
+                        0, Error.PROTOCOL_ERROR);
+            } else {
+                throw new StreamError(
+                        sm.getString("http2Parser.processFrameWindowUpdate.invalidIncrement"),
+                        streamId, Error.PROTOCOL_ERROR);
+            }
         }
 
         output.incrementWindowSize(streamId, windowSizeIncrement);
@@ -303,10 +322,10 @@ class Http2Parser {
 
 
     private void readContinuationFrame(int streamId, int flags, int payloadSize)
-            throws IOException {
+            throws Http2Exception, IOException {
         if (headersCurrentStream == -1) {
             // No headers to continue
-            throw new Http2Exception(sm.getString(
+            throw new ConnectionError(sm.getString(
                     "http2Parser.processFrameContinuation.notExpected", connectionId,
                     Integer.toString(streamId)), 0, Error.PROTOCOL_ERROR);
         }
@@ -325,7 +344,9 @@ class Http2Parser {
     }
 
 
-    private void readHeaderBlock(int payloadSize, boolean endOfHeaders) throws IOException {
+    private void readHeaderBlock(int payloadSize, boolean endOfHeaders)
+            throws Http2Exception, IOException {
+
         while (payloadSize > 0) {
             int toRead = Math.min(headerReadBuffer.remaining(), payloadSize);
             // headerReadBuffer in write mode
@@ -335,7 +356,7 @@ class Http2Parser {
             try {
                 hpackDecoder.decode(headerReadBuffer);
             } catch (HpackException hpe) {
-                throw new Http2Exception(
+                throw new ConnectionError(
                         sm.getString("http2Parser.processFrameHeaders.decodingFailed"),
                         0, Error.COMPRESSION_ERROR);
             }
@@ -345,7 +366,7 @@ class Http2Parser {
         }
 
         if (headerReadBuffer.position() > 0 && endOfHeaders) {
-            throw new Http2Exception(
+            throw new ConnectionError(
                     sm.getString("http2Parser.processFrameHeaders.decodingDataLeft"),
                     0, Error.COMPRESSION_ERROR);
         }
@@ -391,24 +412,24 @@ class Http2Parser {
         }
 
         if (expected != null && frameType != expected) {
-            throw new Http2Exception(sm.getString("http2Parser.processFrame.unexpectedType",
+            throw new StreamError(sm.getString("http2Parser.processFrame.unexpectedType",
                     expected, frameType), streamId, Error.PROTOCOL_ERROR);
         }
 
         if (payloadSize > maxPayloadSize) {
-            throw new Http2Exception(sm.getString("http2Parser.payloadTooBig",
+            throw new ConnectionError(sm.getString("http2Parser.payloadTooBig",
                     Integer.toString(payloadSize), Integer.toString(maxPayloadSize)),
                     streamId, Error.FRAME_SIZE_ERROR);
         }
 
         if (headersCurrentStream != -1) {
             if (headersCurrentStream != streamId) {
-                throw new Http2Exception(sm.getString("http2Parser.headers.wrongStream",
+                throw new ConnectionError(sm.getString("http2Parser.headers.wrongStream",
                         connectionId, Integer.toString(headersCurrentStream),
                         Integer.toString(streamId)), streamId, Error.COMPRESSION_ERROR);
             }
             if (frameType != FrameType.CONTINUATION) {
-                throw new Http2Exception(sm.getString("http2Parser.headers.wrongFrameType",
+                throw new ConnectionError(sm.getString("http2Parser.headers.wrongFrameType",
                         connectionId, Integer.toString(headersCurrentStream),
                         frameType), streamId, Error.COMPRESSION_ERROR);
             }
@@ -422,7 +443,7 @@ class Http2Parser {
     /**
      * Read and validate the connection preface from input using blocking IO.
      */
-    void readConnectionPreface() {
+    void readConnectionPreface() throws Http2Exception {
         byte[] data = new byte[CLIENT_PREFACE_START.length];
         try {
             input.fill(true, data);

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Mon Jun  8 19:45:12 2015
@@ -179,7 +179,7 @@ public class Http2UpgradeHandler extends
                     long value = ByteUtil.getFourBytes(settings, (i * 6) + 2);
                     remoteSettings.set(id, value);
                 }
-            } catch (IOException ioe) {
+            } catch (Http2Exception | IOException ioe) {
                 // TODO i18n
                 throw new ProtocolException();
             }
@@ -195,7 +195,12 @@ public class Http2UpgradeHandler extends
 
         // Make sure the client has sent a valid connection preface before we
         // send the response to the original request over HTTP/2.
-        parser.readConnectionPreface();
+        try {
+            parser.readConnectionPreface();
+        } catch (Http2Exception e) {
+            // TODO i18n
+            throw new ProtocolException();
+        }
 
         if (webConnection != null) {
             // Process the initial request on a container thread
@@ -236,18 +241,16 @@ public class Http2UpgradeHandler extends
             try {
                 while (parser.readFrame(false)) {
                 }
-            } catch (Http2Exception h2e) {
-                if (h2e.getStreamId() == 0) {
-                    if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("upgradeHandler.connectionError"), h2e);
-                    }
-                    closeConnecion(h2e);
-                    break;
-                } else {
-
-                    // Stream error
-                    // TODO Reset stream
+            } catch (StreamError se) {
+                // Stream error
+                // TODO Reset stream
+            } catch (Http2Exception ce) {
+                // This should be a connection error
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("upgradeHandler.connectionError"), ce);
                 }
+                closeConnecion(ce);
+                break;
             } catch (IOException ioe) {
                 if (log.isDebugEnabled()) {
                     log.debug(sm.getString("upgradeHandler.ioerror", connectionId), ioe);
@@ -263,16 +266,6 @@ public class Http2UpgradeHandler extends
         case OPEN_WRITE:
             try {
                 processWrites();
-            } catch (Http2Exception h2e) {
-                if (h2e.getStreamId() == 0) {
-                    // Connection error
-                    log.warn(sm.getString("upgradeHandler.connectionError"), h2e);
-                    closeConnecion(h2e);
-                    break;
-                } else {
-                    // Stream error
-                    // TODO Reset stream
-                }
             } catch (IOException ioe) {
                 if (log.isDebugEnabled()) {
                     log.debug(sm.getString("upgradeHandler.ioerror", connectionId), ioe);
@@ -339,13 +332,13 @@ public class Http2UpgradeHandler extends
     }
 
 
-    private void closeConnecion(Http2Exception h2e) {
+    private void closeConnecion(Http2Exception ce) {
         // Write a GOAWAY frame.
         byte[] fixedPayload = new byte[8];
         // TODO needs to be correct value
         ByteUtil.set31Bits(fixedPayload, 0, (2 << 31) - 1);
-        ByteUtil.setFourBytes(fixedPayload, 4, h2e.getError().getCode());
-        byte[] debugMessage = h2e.getMessage().getBytes(StandardCharsets.UTF_8);
+        ByteUtil.setFourBytes(fixedPayload, 4, ce.getError().getCode());
+        byte[] debugMessage = ce.getMessage().getBytes(StandardCharsets.UTF_8);
         byte[] payloadLength = new byte[3];
         ByteUtil.setThreeBytes(payloadLength, 0, debugMessage.length + 8);
 

Added: tomcat/trunk/java/org/apache/coyote/http2/StreamError.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/StreamError.java?rev=1684255&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/StreamError.java (added)
+++ tomcat/trunk/java/org/apache/coyote/http2/StreamError.java Mon Jun  8 19:45:12 2015
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.coyote.http2;
+
+public class StreamError extends Http2Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    public StreamError(String msg, int streamId, Error error) {
+        super(msg, streamId, error);
+    }
+}

Propchange: tomcat/trunk/java/org/apache/coyote/http2/StreamError.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java Mon Jun  8 19:45:12 2015
@@ -107,15 +107,15 @@ public class StreamStateMachine {
         // No state change. Checks that the frame type is valid for the current
         // state of this stream.
         if (!isFrameTypePermitted(frameType)) {
-            int errorStream;
             if (state.connectionErrorForInvalidFrame) {
-                errorStream = 0;
+                throw new ConnectionError(sm.getString("streamStateMachine.invalidFrame",
+                        stream.getConnectionId(), stream.getIdentifier(), state, frameType),
+                        stream.getIdentifier().intValue(), state.errorCodeForInvalidFrame);
             } else {
-                errorStream = stream.getIdentifier().intValue();
+                throw new StreamError(sm.getString("streamStateMachine.invalidFrame",
+                        stream.getConnectionId(), stream.getIdentifier(), state, frameType),
+                        stream.getIdentifier().intValue(), state.errorCodeForInvalidFrame);
             }
-            throw new Http2Exception(sm.getString("streamStateMachine.invalidFrame",
-                    stream.getConnectionId(), stream.getIdentifier(), state, frameType),
-                    errorStream, state.errorCodeForInvalidFrame);
         }
     }
 

Modified: tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java?rev=1684255&r1=1684254&r2=1684255&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java Mon Jun  8 19:45:12 2015
@@ -179,7 +179,7 @@ public abstract class Http2TestBase exte
     }
 
 
-    protected void readSimpleResponse() throws IOException {
+    protected void readSimpleResponse() throws Http2Exception, IOException {
         // Headers
         parser.readFrame(true);
         // Body



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