Skip to content

Commit

Permalink
Copy (untested) ping and window update frame support from Http2Upgrad…
Browse files Browse the repository at this point in the history
…eHandler to Http2Parser

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1683070 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Jun 2, 2015
1 parent d393041 commit 6eb3288
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 9 deletions.
79 changes: 77 additions & 2 deletions java/org/apache/coyote/http2/Http2Parser.java
Expand Up @@ -37,6 +37,8 @@ class Http2Parser implements HeaderEmitter {
private static final int FRAME_TYPE_HEADERS = 1; private static final int FRAME_TYPE_HEADERS = 1;
private static final int FRAME_TYPE_PRIORITY = 2; private static final int FRAME_TYPE_PRIORITY = 2;
private static final int FRAME_TYPE_SETTINGS = 4; private static final int FRAME_TYPE_SETTINGS = 4;
private static final int FRAME_TYPE_PING = 6;
private static final int FRAME_TYPE_WINDOW_UPDATE = 8;


private final String connectionId; private final String connectionId;
private final Input input; private final Input input;
Expand Down Expand Up @@ -93,11 +95,17 @@ boolean readFrame(boolean block) throws IOException {
readHeadersFrame(streamId, flags, payloadSize); readHeadersFrame(streamId, flags, payloadSize);
break; break;
case FRAME_TYPE_PRIORITY: case FRAME_TYPE_PRIORITY:
processFramePriority(streamId, flags, payloadSize); readPriorityFrame(streamId, flags, payloadSize);
break; break;
case FRAME_TYPE_SETTINGS: case FRAME_TYPE_SETTINGS:
readSettingsFrame(streamId, flags, payloadSize); readSettingsFrame(streamId, flags, payloadSize);
break; break;
case FRAME_TYPE_PING:
readPingFrame(streamId, flags, payloadSize);
break;
case FRAME_TYPE_WINDOW_UPDATE:
readWindowUpdateFrame(streamId, flags, payloadSize);
break;
// TODO: Missing types // TODO: Missing types
default: default:
readUnknownFrame(streamId, frameType, flags, payloadSize); readUnknownFrame(streamId, frameType, flags, payloadSize);
Expand Down Expand Up @@ -231,7 +239,7 @@ private void readHeadersFrame(int streamId, int flags, int payloadSize) throws I
} }




private void processFramePriority(int flags, int streamId, int payloadSize) throws IOException { private void readPriorityFrame(int flags, int streamId, int payloadSize) throws IOException {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug(sm.getString("http2Parser.processFrame", connectionId, log.debug(sm.getString("http2Parser.processFrame", connectionId,
Integer.toString(streamId), Integer.toString(flags), Integer.toString(streamId), Integer.toString(flags),
Expand Down Expand Up @@ -297,6 +305,66 @@ private void readSettingsFrame(int streamId, int flags, int payloadSize) throws
} }




private void readPingFrame(int flags, int streamId, int payloadSize)
throws IOException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http2Parser.processFrame", connectionId,
Integer.toString(streamId), Integer.toString(flags),
Integer.toString(payloadSize)));
}
// Validate the frame
if (streamId != 0) {
throw new Http2Exception(sm.getString("http2Parser.processFramePing.invalidStream",
Integer.toString(streamId)), 0, Http2Exception.FRAME_SIZE_ERROR);
}
if (payloadSize != 8) {
throw new Http2Exception(sm.getString("http2Parser.processFramePing.invalidPayloadSize",
Integer.toString(payloadSize)), 0, Http2Exception.FRAME_SIZE_ERROR);
}
if ((flags & 0x1) == 0) {
// Read the payload
byte[] payload = new byte[8];
input.fill(true, payload);
output.pingReceive(payload);
} else {
output.pingAck();
}
}


private void readWindowUpdateFrame(int flags, int streamId, int payloadSize)
throws IOException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http2Parser.processFrame", connectionId,
Integer.toString(streamId), Integer.toString(flags),
Integer.toString(payloadSize)));
}
// Validate the frame
if (payloadSize != 4) {
// Use stream 0 since this is always a connection error
throw new Http2Exception(sm.getString("http2Parser.processFrameWindowUpdate.invalidPayloadSize",
Integer.toString(payloadSize)), 0, Http2Exception.FRAME_SIZE_ERROR);
}

byte[] payload = new byte[4];
input.fill(true, payload);
int windowSizeIncrement = ByteUtil.get31Bits(payload, 0);

if (log.isDebugEnabled()) {
log.debug(sm.getString("http2Parser.processFrameWindowUpdate.debug", connectionId,
Integer.toString(streamId), Integer.toString(windowSizeIncrement)));
}

// Validate the data
if (windowSizeIncrement == 0) {
throw new Http2Exception("http2Parser.processFrameWindowUpdate.invalidIncrement",
streamId, Http2Exception.PROTOCOL_ERROR);
}

output.incrementWindowSize(streamId, windowSizeIncrement);
}


private void readUnknownFrame(int streamId, int frameType, int flags, int payloadSize) private void readUnknownFrame(int streamId, int frameType, int flags, int payloadSize)
throws IOException { throws IOException {
output.swallow(streamId, frameType, flags, payloadSize); output.swallow(streamId, frameType, flags, payloadSize);
Expand Down Expand Up @@ -424,6 +492,13 @@ static interface Output {
void settingsAck(); void settingsAck();
void setting(int identifier, long value) throws IOException; void setting(int identifier, long value) throws IOException;


// Ping frames
void pingReceive(byte[] payload);
void pingAck();

// Window size
void incrementWindowSize(int streamId, int increment);

// Testing // Testing
void swallow(int streamId, int frameType, int flags, int size) throws IOException; void swallow(int streamId, int frameType, int flags, int size) throws IOException;
} }
Expand Down
18 changes: 18 additions & 0 deletions java/org/apache/coyote/http2/Http2UpgradeHandler.java
Expand Up @@ -1169,6 +1169,24 @@ public void setting(int identifier, long value) throws IOException {
} }




@Override
public void pingReceive(byte[] payload) {
// TODO Auto-generated method stub
}


@Override
public void pingAck() {
// TODO Auto-generated method stub
}


@Override
public void incrementWindowSize(int streamId, int increment) {
// TODO Auto-generated method stub
}


@Override @Override
public void swallow(int streamId, int frameType, int flags, int size) throws IOException { public void swallow(int streamId, int frameType, int flags, int size) throws IOException {
swallow(size); swallow(size);
Expand Down
10 changes: 5 additions & 5 deletions java/org/apache/coyote/http2/LocalStrings.properties
Expand Up @@ -40,11 +40,16 @@ http2Parser.processFrameData.invalidStream=Data frame received for stream [0]
http2Parser.processFrameHeaders.invalidStream=Headers frame received for stream [0] http2Parser.processFrameHeaders.invalidStream=Headers frame received for stream [0]
http2Parser.processFrameHeaders.decodingFailed=There was an error during the HPACK decoding of HTTP headers http2Parser.processFrameHeaders.decodingFailed=There was an error during the HPACK decoding of HTTP headers
http2Parser.processFrameHeaders.decodingDataLeft=Data left over after HPACK decoding - it should have been consumed http2Parser.processFrameHeaders.decodingDataLeft=Data left over after HPACK decoding - it should have been consumed
http2Parser.processFramePing.invalidPayloadSize=Settings frame received with an invalid payload size of [{0}] (should be 8)
http2Parser.processFramePing.invalidStream=Ping frame received for stream [{0}]
http2Parser.processFramePriority.invalidPayloadSize=Priority frame received with an invalid payload size of [{0}] (should be 5) http2Parser.processFramePriority.invalidPayloadSize=Priority frame received with an invalid payload size of [{0}] (should be 5)
http2Parser.processFramePriority.invalidStream=Priority frame received for stream [0] http2Parser.processFramePriority.invalidStream=Priority frame received for stream [0]
http2Parser.processFrameSettings.ackWithNonZeroPayload=Settings frame received with the ACK flag set and payload present http2Parser.processFrameSettings.ackWithNonZeroPayload=Settings frame received with the ACK flag set and payload present
http2Parser.processFrameSettings.invalidPayloadSize=Settings frame received with a payload size of [{0}] which is not a multiple of 6 http2Parser.processFrameSettings.invalidPayloadSize=Settings frame received with a payload size of [{0}] which is not a multiple of 6
http2Parser.processFrameSettings.invalidStream=Settings frame received for stream [{0}] http2Parser.processFrameSettings.invalidStream=Settings frame received for stream [{0}]
http2Parser.processFrameWindowUpdate.debug=Connection [{0}], Stream [{1}], Window size increment [{2}]
http2Parser.processFrameWindowUpdate.invalidIncrement=Window update frame received with an invalid increment size of [0]
http2Parser.processFrameWindowUpdate.invalidPayloadSize=Window update frame received with an invalid payload size of [{0}]


stream.header.debug=Connection [{0}], Stream [{1}], HTTP header [{2}], Value [{3}] stream.header.debug=Connection [{0}], Stream [{1}], HTTP header [{2}], Value [{3}]
stream.write=Connection [{0}], Stream [{1}] stream.write=Connection [{0}], Stream [{1}]
Expand All @@ -59,16 +64,11 @@ upgradeHandler.processFrame=Connection [{0}], Stream [{1}], Flags [{2}], Payload
upgradeHandler.processFrameHeaders.invalidStream=Headers frame received for stream [0] upgradeHandler.processFrameHeaders.invalidStream=Headers frame received for stream [0]
upgradeHandler.processFrameHeaders.decodingFailed=There was an error during the HPACK decoding of HTTP headers upgradeHandler.processFrameHeaders.decodingFailed=There was an error during the HPACK decoding of HTTP headers
upgradeHandler.processFrameHeaders.decodingDataLeft=Data left over after HPACK decoding - it should have been consumed upgradeHandler.processFrameHeaders.decodingDataLeft=Data left over after HPACK decoding - it should have been consumed
upgradeHandler.processFramePing.invalidPayloadSize=Settings frame received with an invalid payload size of [{0}] (should be 8)
upgradeHandler.processFramePing.invalidStream=Ping frame received for stream [{0}]
upgradeHandler.processFramePriority.invalidPayloadSize=Priority frame received with an invalid payload size of [{0}] (should be 5) upgradeHandler.processFramePriority.invalidPayloadSize=Priority frame received with an invalid payload size of [{0}] (should be 5)
upgradeHandler.processFramePriority.invalidStream=Priority frame received for stream [0] upgradeHandler.processFramePriority.invalidStream=Priority frame received for stream [0]
upgradeHandler.processFrameSettings.ackWithNonZeroPayload=Settings frame received with the ACK flag set and payload present upgradeHandler.processFrameSettings.ackWithNonZeroPayload=Settings frame received with the ACK flag set and payload present
upgradeHandler.processFrameSettings.invalidPayloadSize=Settings frame received with a payload size of [{0}] which is not a multiple of 6 upgradeHandler.processFrameSettings.invalidPayloadSize=Settings frame received with a payload size of [{0}] which is not a multiple of 6
upgradeHandler.processFrameSettings.invalidStream=Settings frame received for stream [{0}] upgradeHandler.processFrameSettings.invalidStream=Settings frame received for stream [{0}]
upgradeHandler.processFrameWindowUpdate.debug=Connection [{0}], Stream [{1}], Window size increment [{2}]
upgradeHandler.processFrameWindowUpdate.invalidIncrement=Window update frame received with an invalid increment size of [0]
upgradeHandler.processFrameWindowUpdate.invalidPayloadSize=Window update frame received with an invalid payload size of [{0}]
upgradeHandler.receivePrefaceNotSettings=The first frame received from the client was not a settings frame upgradeHandler.receivePrefaceNotSettings=The first frame received from the client was not a settings frame
upgradeHandler.sendPrefaceFail=Failed to send preface to client upgradeHandler.sendPrefaceFail=Failed to send preface to client
upgradeHandler.socketCloseFailed=Error closing socket upgradeHandler.socketCloseFailed=Error closing socket
Expand Down
32 changes: 30 additions & 2 deletions test/org/apache/coyote/http2/Http2TestBase.java
Expand Up @@ -287,17 +287,45 @@ public void headersEnd() {


@Override @Override
public void settingsAck() { public void settingsAck() {
trace.append("0-Settings-Ack"); trace.append("0-Settings-Ack\n");


} }


@Override @Override
public void setting(int identifier, long value) throws IOException { public void setting(int identifier, long value) throws IOException {
trace.append("0-Settings-[" + identifier + "]-[" + value + "]"); trace.append("0-Settings-[" + identifier + "]-[" + value + "]\n");
remoteSettings.set(identifier, value); remoteSettings.set(identifier, value);
} }




@Override
public void pingReceive(byte[] payload) {
trace.append("0-Ping-[");
boolean first = true;
for (byte b : payload) {
if (first) {
first = false;
} else {
trace.append(',');
}
trace.append(b & 0xFF);
}
trace.append("]\n");
}


@Override
public void pingAck() {
trace.append("0-Ping-Ack\n");
}


@Override
public void incrementWindowSize(int streamId, int increment) {
trace.append(streamId + "-WindowSize-[" + increment + "]\n");
}


@Override @Override
public void swallow(int streamId, int frameType, int flags, int size) { public void swallow(int streamId, int frameType, int flags, int size) {
trace.append(streamId); trace.append(streamId);
Expand Down

0 comments on commit 6eb3288

Please sign in to comment.