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