Author: remm
Date: Thu Feb 8 21:25:40 2018
New Revision: 1823602
URL: http://svn.apache.org/viewvc?rev=1823602&view=rev
Log:
Refactoring to reduce duplication.
Modified:
tomcat/trunk/java/org/apache/coyote/http2/Http2AsyncParser.java
tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2AsyncParser.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2AsyncParser.java?rev=1823602&r1=1823601&r2=1823602&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2AsyncParser.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2AsyncParser.java Thu Feb 8
21:25:40 2018
@@ -19,10 +19,8 @@ package org.apache.coyote.http2;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
-import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
-import org.apache.tomcat.util.buf.ByteBufferUtils;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.net.SocketWrapperBase.BlockingMode;
@@ -80,378 +78,13 @@ class Http2AsyncParser extends Http2Pars
}
}
- // TODO: see how to refactor to avoid duplication
- private void readDataFrame(int streamId, int flags, int payloadSize,
ByteBuffer buffer)
- throws Http2Exception, IOException {
- // Process the Stream
- int padLength = 0;
-
- boolean endOfStream = Flags.isEndOfStream(flags);
-
- int dataLength;
- if (Flags.hasPadding(flags)) {
- padLength = buffer.get() & 0xFF;
-
- if (padLength >= payloadSize) {
- throw new ConnectionException(
-
sm.getString("http2Parser.processFrame.tooMuchPadding", connectionId,
- Integer.toString(streamId),
Integer.toString(padLength),
- Integer.toString(payloadSize)),
Http2Error.PROTOCOL_ERROR);
- }
- // +1 is for the padding length byte we just read above
- dataLength = payloadSize - (padLength + 1);
- } else {
- dataLength = payloadSize;
- }
-
- if (log.isDebugEnabled()) {
- String padding;
- if (Flags.hasPadding(flags)) {
- padding = Integer.toString(padLength);
- } else {
- padding = "none";
- }
- log.debug(sm.getString("http2Parser.processFrameData.lengths",
connectionId,
- Integer.toString(streamId), Integer.toString(dataLength),
padding));
- }
-
- ByteBuffer dest = output.startRequestBodyFrame(streamId, payloadSize);
- if (dest == null) {
- swallow(streamId, dataLength, false, buffer);
- // Process padding before sending any notifications in case padding
- // is invalid.
- if (padLength > 0) {
- swallow(streamId, padLength, true, buffer);
- }
- if (endOfStream) {
- output.receivedEndOfStream(streamId);
- }
- } else {
- synchronized (dest) {
- if (dest.remaining() < dataLength) {
- swallow(streamId, dataLength, false, buffer);
- // Client has sent more data than permitted by Window size
- throw new StreamException("Client sent more data than
stream window allowed", Http2Error.FLOW_CONTROL_ERROR, streamId);
- }
- int oldLimit = buffer.limit();
- buffer.limit(buffer.position() + dataLength);
- dest.put(buffer);
- buffer.limit(oldLimit);
- // Process padding before sending any notifications in case
- // padding is invalid.
- if (padLength > 0) {
- swallow(streamId, padLength, true, buffer);
- }
- if (endOfStream) {
- output.receivedEndOfStream(streamId);
- }
- output.endRequestBodyFrame(streamId);
- }
- }
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- if (padLength > 0) {
- output.swallowedPadding(streamId, padLength);
- }
- }
-
-
- private void readHeadersFrame(int streamId, int flags, int payloadSize,
ByteBuffer buffer)
- throws Http2Exception, IOException {
-
- headersEndStream = Flags.isEndOfStream(flags);
-
- if (hpackDecoder == null) {
- hpackDecoder = output.getHpackDecoder();
- }
-
- try {
- hpackDecoder.setHeaderEmitter(output.headersStart(streamId,
headersEndStream));
- } catch (StreamException se) {
- swallow(streamId, payloadSize, false, buffer);
- throw se;
- }
-
- int padLength = 0;
- boolean padding = Flags.hasPadding(flags);
- boolean priority = Flags.hasPriority(flags);
- int optionalLen = 0;
- if (padding) {
- optionalLen = 1;
- }
- if (priority) {
- optionalLen += 5;
- }
- if (optionalLen > 0) {
- byte[] optional = new byte[optionalLen];
- buffer.get(optional);
- int optionalPos = 0;
- if (padding) {
- padLength = ByteUtil.getOneByte(optional, optionalPos++);
- if (padLength >= payloadSize) {
- throw new ConnectionException(
-
sm.getString("http2Parser.processFrame.tooMuchPadding", connectionId,
- Integer.toString(streamId),
Integer.toString(padLength),
- Integer.toString(payloadSize)),
Http2Error.PROTOCOL_ERROR);
- }
- }
- if (priority) {
- boolean exclusive = ByteUtil.isBit7Set(optional[optionalPos]);
- int parentStreamId = ByteUtil.get31Bits(optional, optionalPos);
- int weight = ByteUtil.getOneByte(optional, optionalPos + 4) +
1;
- output.reprioritise(streamId, parentStreamId, exclusive,
weight);
- }
-
- payloadSize -= optionalLen;
- payloadSize -= padLength;
- }
-
- readHeaderPayload(streamId, payloadSize, buffer);
-
- swallow(streamId, padLength, true, buffer);
-
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
-
- if (Flags.isEndOfHeaders(flags)) {
- onHeadersComplete(streamId);
- } else {
- headersCurrentStream = streamId;
- }
- }
-
-
- private void readPriorityFrame(int streamId, ByteBuffer buffer) throws
Http2Exception, IOException {
- byte[] payload = new byte[5];
- buffer.get(payload);
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
-
- boolean exclusive = ByteUtil.isBit7Set(payload[0]);
- int parentStreamId = ByteUtil.get31Bits(payload, 0);
- int weight = ByteUtil.getOneByte(payload, 4) + 1;
-
- if (streamId == parentStreamId) {
- throw new
StreamException(sm.getString("http2Parser.processFramePriority.invalidParent",
- connectionId, Integer.valueOf(streamId)),
Http2Error.PROTOCOL_ERROR, streamId);
- }
-
- output.reprioritise(streamId, parentStreamId, exclusive, weight);
- }
-
-
- private void readRstFrame(int streamId, ByteBuffer buffer) throws
Http2Exception, IOException {
- byte[] payload = new byte[4];
- buffer.get(payload);
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
-
- long errorCode = ByteUtil.getFourBytes(payload, 0);
- output.reset(streamId, errorCode);
- headersCurrentStream = -1;
- headersEndStream = false;
- }
-
-
- private void readSettingsFrame(int flags, int payloadSize, ByteBuffer
buffer) throws Http2Exception, IOException {
- boolean ack = Flags.isAck(flags);
- if (payloadSize > 0 && ack) {
- throw new ConnectionException(sm.getString(
- "http2Parser.processFrameSettings.ackWithNonZeroPayload"),
- Http2Error.FRAME_SIZE_ERROR);
- }
-
- if (payloadSize != 0) {
- // Process the settings
- byte[] setting = new byte[6];
- for (int i = 0; i < payloadSize / 6; i++) {
- buffer.get(setting);
- int id = ByteUtil.getTwoBytes(setting, 0);
- long value = ByteUtil.getFourBytes(setting, 2);
- output.setting(Setting.valueOf(id), value);
- }
- }
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- output.settingsEnd(ack);
- }
-
-
- private void readPingFrame(int flags, ByteBuffer buffer) throws
IOException {
- // Read the payload
- byte[] payload = new byte[8];
- buffer.get(payload);
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- output.pingReceive(payload, Flags.isAck(flags));
- }
-
-
- private void readGoawayFrame(int payloadSize, ByteBuffer buffer) throws
IOException {
- byte[] payload = new byte[payloadSize];
- buffer.get(payload);
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- int lastStreamId = ByteUtil.get31Bits(payload, 0);
- long errorCode = ByteUtil.getFourBytes(payload, 4);
- String debugData = null;
- if (payloadSize > 8) {
- debugData = new String(payload, 8, payloadSize - 8,
StandardCharsets.UTF_8);
- }
- output.goaway(lastStreamId, errorCode, debugData);
- }
-
-
- private void readPushPromiseFrame(int streamId, ByteBuffer buffer) throws
Http2Exception {
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- throw new
ConnectionException(sm.getString("http2Parser.processFramePushPromise",
- connectionId, Integer.valueOf(streamId)),
Http2Error.PROTOCOL_ERROR);
- }
-
-
- private void readWindowUpdateFrame(int streamId, ByteBuffer buffer) throws
Http2Exception, IOException {
- byte[] payload = new byte[4];
- buffer.get(payload);
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- 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) {
- if (streamId == 0) {
- throw new ConnectionException(
-
sm.getString("http2Parser.processFrameWindowUpdate.invalidIncrement"),
- Http2Error.PROTOCOL_ERROR);
- } else {
- throw new StreamException(
-
sm.getString("http2Parser.processFrameWindowUpdate.invalidIncrement"),
- Http2Error.PROTOCOL_ERROR, streamId);
- }
- }
-
- output.incrementWindowSize(streamId, windowSizeIncrement);
- }
-
-
- private void readContinuationFrame(int streamId, int flags, int
payloadSize, ByteBuffer buffer)
- throws Http2Exception, IOException {
- if (headersCurrentStream == -1) {
- // No headers to continue
- throw new ConnectionException(sm.getString(
- "http2Parser.processFrameContinuation.notExpected",
connectionId,
- Integer.toString(streamId)), Http2Error.PROTOCOL_ERROR);
- }
-
- readHeaderPayload(streamId, payloadSize, buffer);
- if (buffer.hasRemaining()) {
+ protected void unRead(ByteBuffer buffer) {
+ if (buffer != null && buffer.hasRemaining()) {
socketWrapper.unRead(buffer);
}
-
- if (Flags.isEndOfHeaders(flags)) {
- headersCurrentStream = -1;
- onHeadersComplete(streamId);
- }
}
-
- private void readHeaderPayload(int streamId, int payloadSize, ByteBuffer
buffer)
- throws Http2Exception, IOException {
-
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("http2Parser.processFrameHeaders.payload",
connectionId,
- Integer.valueOf(streamId), Integer.valueOf(payloadSize)));
- }
-
- int remaining = payloadSize;
-
- while (remaining > 0) {
- if (headerReadBuffer.remaining() == 0) {
- // Buffer needs expansion
- int newSize;
- if (headerReadBuffer.capacity() < payloadSize) {
- // First step, expand to the current payload. That should
- // cover most cases.
- newSize = payloadSize;
- } else {
- // Header must be spread over multiple frames. Keep
doubling
- // buffer size until the header can be read.
- newSize = headerReadBuffer.capacity() * 2;
- }
- headerReadBuffer = ByteBufferUtils.expand(headerReadBuffer,
newSize);
- }
- int toRead = Math.min(headerReadBuffer.remaining(), remaining);
- // headerReadBuffer in write mode
- int oldLimit = buffer.limit();
- buffer.limit(buffer.position() + toRead);
- headerReadBuffer.put(buffer);
- buffer.limit(oldLimit);
- // switch to read mode
- headerReadBuffer.flip();
- try {
- hpackDecoder.decode(headerReadBuffer);
- } catch (HpackException hpe) {
- throw new ConnectionException(
-
sm.getString("http2Parser.processFrameHeaders.decodingFailed"),
- Http2Error.COMPRESSION_ERROR, hpe);
- }
-
- // switches to write mode
- headerReadBuffer.compact();
- remaining -= toRead;
-
- if (hpackDecoder.isHeaderCountExceeded()) {
- StreamException headerException = new
StreamException(sm.getString(
- "http2Parser.headerLimitCount", connectionId,
Integer.valueOf(streamId)),
- Http2Error.ENHANCE_YOUR_CALM, streamId);
-
hpackDecoder.getHeaderEmitter().setHeaderException(headerException);
- }
-
- if
(hpackDecoder.isHeaderSizeExceeded(headerReadBuffer.position())) {
- StreamException headerException = new
StreamException(sm.getString(
- "http2Parser.headerLimitSize", connectionId,
Integer.valueOf(streamId)),
- Http2Error.ENHANCE_YOUR_CALM, streamId);
-
hpackDecoder.getHeaderEmitter().setHeaderException(headerException);
- }
-
- if
(hpackDecoder.isHeaderSwallowSizeExceeded(headerReadBuffer.position())) {
- throw new
ConnectionException(sm.getString("http2Parser.headerLimitSize",
- connectionId, Integer.valueOf(streamId)),
Http2Error.ENHANCE_YOUR_CALM);
- }
- }
- }
-
-
- private void readUnknownFrame(int streamId, FrameType frameType, int
flags, int payloadSize, ByteBuffer buffer)
- throws IOException {
- try {
- swallow(streamId, payloadSize, false, buffer);
- } catch (ConnectionException e) {
- // Will never happen because swallow() is called with mustBeZero
set
- // to false
- }
- if (buffer.hasRemaining()) {
- socketWrapper.unRead(buffer);
- }
- output.swallowed(streamId, frameType, flags, payloadSize);
- }
-
-
- private void swallow(int streamId, int len, boolean mustBeZero, ByteBuffer
buffer)
+ protected void swallow(int streamId, int len, boolean mustBeZero,
ByteBuffer buffer)
throws IOException, ConnectionException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http2Parser.swallow.debug", connectionId,
@@ -554,6 +187,7 @@ class Http2AsyncParser extends Http2Pars
try {
if (streamException) {
swallow(streamId, payloadSize, false, buffers[1]);
+ unRead(buffers[1]);
} else {
switch (frameType) {
case DATA:
@@ -591,8 +225,7 @@ class Http2AsyncParser extends Http2Pars
}
}
} catch (Exception e) {
- failed(e, attachment);
- return;
+ error = e;
}
}
if (state == CompletionState.DONE) {
@@ -603,8 +236,8 @@ class Http2AsyncParser extends Http2Pars
}
@Override
- public void failed(Throwable exc, Void attachment) {
- error = exc;
+ public void failed(Throwable e, Void attachment) {
+ error = e;
if (state == CompletionState.DONE) {
// The call was not completed inline, so must start reading
new frames
// or process any error
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=1823602&r1=1823601&r2=1823602&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java Thu Feb 8
21:25:40 2018
@@ -85,50 +85,52 @@ class Http2Parser {
try {
validateFrame(expected, frameType, streamId, flags, payloadSize);
} catch (StreamException se) {
- swallow(streamId, payloadSize, false);
+ swallow(streamId, payloadSize, false, null);
throw se;
}
switch (frameType) {
case DATA:
- readDataFrame(streamId, flags, payloadSize);
+ readDataFrame(streamId, flags, payloadSize, null);
break;
case HEADERS:
- readHeadersFrame(streamId, flags, payloadSize);
+ readHeadersFrame(streamId, flags, payloadSize, null);
break;
case PRIORITY:
- readPriorityFrame(streamId);
+ readPriorityFrame(streamId, null);
break;
case RST:
- readRstFrame(streamId);
+ readRstFrame(streamId, null);
break;
case SETTINGS:
- readSettingsFrame(flags, payloadSize);
+ readSettingsFrame(flags, payloadSize, null);
break;
case PUSH_PROMISE:
- readPushPromiseFrame(streamId);
+ readPushPromiseFrame(streamId, null);
break;
case PING:
- readPingFrame(flags);
+ readPingFrame(flags, null);
break;
case GOAWAY:
- readGoawayFrame(payloadSize);
+ readGoawayFrame(payloadSize, null);
break;
case WINDOW_UPDATE:
- readWindowUpdateFrame(streamId);
+ readWindowUpdateFrame(streamId, null);
break;
case CONTINUATION:
- readContinuationFrame(streamId, flags, payloadSize);
+ readContinuationFrame(streamId, flags, payloadSize, null);
break;
case UNKNOWN:
- readUnknownFrame(streamId, frameType, flags, payloadSize);
+ readUnknownFrame(streamId, frameType, flags, payloadSize, null);
}
return true;
}
+ protected void unRead(ByteBuffer buffer) {
+ }
- private void readDataFrame(int streamId, int flags, int payloadSize)
+ protected void readDataFrame(int streamId, int flags, int payloadSize,
ByteBuffer buffer)
throws Http2Exception, IOException {
// Process the Stream
int padLength = 0;
@@ -137,9 +139,13 @@ class Http2Parser {
int dataLength;
if (Flags.hasPadding(flags)) {
- byte[] b = new byte[1];
- input.fill(true, b);
- padLength = b[0] & 0xFF;
+ if (buffer == null) {
+ byte[] b = new byte[1];
+ input.fill(true, b);
+ padLength = b[0] & 0xFF;
+ } else {
+ padLength = buffer.get() & 0xFF;
+ }
if (padLength >= payloadSize) {
throw new ConnectionException(
@@ -166,11 +172,11 @@ class Http2Parser {
ByteBuffer dest = output.startRequestBodyFrame(streamId, payloadSize);
if (dest == null) {
- swallow(streamId, dataLength, false);
+ swallow(streamId, dataLength, false, buffer);
// Process padding before sending any notifications in case padding
// is invalid.
if (padLength > 0) {
- swallow(streamId, padLength, true);
+ swallow(streamId, padLength, true, buffer);
}
if (endOfStream) {
output.receivedEndOfStream(streamId);
@@ -178,15 +184,23 @@ class Http2Parser {
} else {
synchronized (dest) {
if (dest.remaining() < dataLength) {
- swallow(streamId, dataLength, false);
+ swallow(streamId, dataLength, false, buffer);
+ unRead(buffer);
// Client has sent more data than permitted by Window size
throw new StreamException("Client sent more data than
stream window allowed", Http2Error.FLOW_CONTROL_ERROR, streamId);
}
- input.fill(true, dest, dataLength);
+ if (buffer == null) {
+ input.fill(true, dest, dataLength);
+ } else {
+ int oldLimit = buffer.limit();
+ buffer.limit(buffer.position() + dataLength);
+ dest.put(buffer);
+ buffer.limit(oldLimit);
+ }
// Process padding before sending any notifications in case
// padding is invalid.
if (padLength > 0) {
- swallow(streamId, padLength, true);
+ swallow(streamId, padLength, true, buffer);
}
if (endOfStream) {
output.receivedEndOfStream(streamId);
@@ -194,13 +208,14 @@ class Http2Parser {
output.endRequestBodyFrame(streamId);
}
}
+ unRead(buffer);
if (padLength > 0) {
output.swallowedPadding(streamId, padLength);
}
}
- private void readHeadersFrame(int streamId, int flags, int payloadSize)
+ protected void readHeadersFrame(int streamId, int flags, int payloadSize,
ByteBuffer buffer)
throws Http2Exception, IOException {
headersEndStream = Flags.isEndOfStream(flags);
@@ -211,7 +226,7 @@ class Http2Parser {
try {
hpackDecoder.setHeaderEmitter(output.headersStart(streamId,
headersEndStream));
} catch (StreamException se) {
- swallow(streamId, payloadSize, false);
+ swallow(streamId, payloadSize, false, buffer);
throw se;
}
@@ -227,7 +242,11 @@ class Http2Parser {
}
if (optionalLen > 0) {
byte[] optional = new byte[optionalLen];
- input.fill(true, optional);
+ if (buffer == null) {
+ input.fill(true, optional);
+ } else {
+ buffer.get(optional);
+ }
int optionalPos = 0;
if (padding) {
padLength = ByteUtil.getOneByte(optional, optionalPos++);
@@ -249,9 +268,11 @@ class Http2Parser {
payloadSize -= padLength;
}
- readHeaderPayload(streamId, payloadSize);
+ readHeaderPayload(streamId, payloadSize, buffer);
+
+ swallow(streamId, padLength, true, buffer);
- swallow(streamId, padLength, true);
+ unRead(buffer);
if (Flags.isEndOfHeaders(flags)) {
onHeadersComplete(streamId);
@@ -261,9 +282,14 @@ class Http2Parser {
}
- private void readPriorityFrame(int streamId) throws Http2Exception,
IOException {
+ protected void readPriorityFrame(int streamId, ByteBuffer buffer) throws
Http2Exception, IOException {
byte[] payload = new byte[5];
- input.fill(true, payload);
+ if (buffer == null) {
+ input.fill(true, payload);
+ } else {
+ buffer.get(payload);
+ unRead(buffer);
+ }
boolean exclusive = ByteUtil.isBit7Set(payload[0]);
int parentStreamId = ByteUtil.get31Bits(payload, 0);
@@ -278,9 +304,14 @@ class Http2Parser {
}
- private void readRstFrame(int streamId) throws Http2Exception, IOException
{
+ protected void readRstFrame(int streamId, ByteBuffer buffer) throws
Http2Exception, IOException {
byte[] payload = new byte[4];
- input.fill(true, payload);
+ if (buffer == null) {
+ input.fill(true, payload);
+ } else {
+ buffer.get(payload);
+ unRead(buffer);
+ }
long errorCode = ByteUtil.getFourBytes(payload, 0);
output.reset(streamId, errorCode);
@@ -289,7 +320,7 @@ class Http2Parser {
}
- private void readSettingsFrame(int flags, int payloadSize) throws
Http2Exception, IOException {
+ protected void readSettingsFrame(int flags, int payloadSize, ByteBuffer
buffer) throws Http2Exception, IOException {
boolean ack = Flags.isAck(flags);
if (payloadSize > 0 && ack) {
throw new ConnectionException(sm.getString(
@@ -301,33 +332,49 @@ class Http2Parser {
// Process the settings
byte[] setting = new byte[6];
for (int i = 0; i < payloadSize / 6; i++) {
- input.fill(true, setting);
+ if (buffer == null) {
+ input.fill(true, setting);
+ } else {
+ buffer.get(setting);
+ }
int id = ByteUtil.getTwoBytes(setting, 0);
long value = ByteUtil.getFourBytes(setting, 2);
output.setting(Setting.valueOf(id), value);
}
}
+ unRead(buffer);
output.settingsEnd(ack);
}
- private void readPushPromiseFrame(int streamId) throws Http2Exception {
+ protected void readPushPromiseFrame(int streamId, ByteBuffer buffer)
throws Http2Exception {
+ unRead(buffer);
throw new
ConnectionException(sm.getString("http2Parser.processFramePushPromise",
connectionId, Integer.valueOf(streamId)),
Http2Error.PROTOCOL_ERROR);
}
- private void readPingFrame(int flags) throws IOException {
+ protected void readPingFrame(int flags, ByteBuffer buffer) throws
IOException {
// Read the payload
byte[] payload = new byte[8];
- input.fill(true, payload);
+ if (buffer == null) {
+ input.fill(true, payload);
+ } else {
+ buffer.get(payload);
+ unRead(buffer);
+ }
output.pingReceive(payload, Flags.isAck(flags));
}
- private void readGoawayFrame(int payloadSize) throws IOException {
+ protected void readGoawayFrame(int payloadSize, ByteBuffer buffer) throws
IOException {
byte[] payload = new byte[payloadSize];
- input.fill(true, payload);
+ if (buffer == null) {
+ input.fill(true, payload);
+ } else {
+ buffer.get(payload);
+ unRead(buffer);
+ }
int lastStreamId = ByteUtil.get31Bits(payload, 0);
long errorCode = ByteUtil.getFourBytes(payload, 4);
@@ -339,9 +386,14 @@ class Http2Parser {
}
- private void readWindowUpdateFrame(int streamId) throws Http2Exception,
IOException {
+ protected void readWindowUpdateFrame(int streamId, ByteBuffer buffer)
throws Http2Exception, IOException {
byte[] payload = new byte[4];
- input.fill(true, payload);
+ if (buffer == null) {
+ input.fill(true, payload);
+ } else {
+ buffer.get(payload);
+ unRead(buffer);
+ }
int windowSizeIncrement = ByteUtil.get31Bits(payload, 0);
if (log.isDebugEnabled()) {
@@ -366,7 +418,7 @@ class Http2Parser {
}
- private void readContinuationFrame(int streamId, int flags, int
payloadSize)
+ protected void readContinuationFrame(int streamId, int flags, int
payloadSize, ByteBuffer buffer)
throws Http2Exception, IOException {
if (headersCurrentStream == -1) {
// No headers to continue
@@ -375,7 +427,8 @@ class Http2Parser {
Integer.toString(streamId)), Http2Error.PROTOCOL_ERROR);
}
- readHeaderPayload(streamId, payloadSize);
+ readHeaderPayload(streamId, payloadSize, buffer);
+ unRead(buffer);
if (Flags.isEndOfHeaders(flags)) {
headersCurrentStream = -1;
@@ -384,7 +437,7 @@ class Http2Parser {
}
- private void readHeaderPayload(int streamId, int payloadSize)
+ protected void readHeaderPayload(int streamId, int payloadSize, ByteBuffer
buffer)
throws Http2Exception, IOException {
if (log.isDebugEnabled()) {
@@ -411,7 +464,14 @@ class Http2Parser {
}
int toRead = Math.min(headerReadBuffer.remaining(), remaining);
// headerReadBuffer in write mode
- input.fill(true, headerReadBuffer, toRead);
+ if (buffer == null) {
+ input.fill(true, headerReadBuffer, toRead);
+ } else {
+ int oldLimit = buffer.limit();
+ buffer.limit(buffer.position() + toRead);
+ headerReadBuffer.put(buffer);
+ buffer.limit(oldLimit);
+ }
// switch to read mode
headerReadBuffer.flip();
try {
@@ -448,46 +508,20 @@ class Http2Parser {
}
- protected void onHeadersComplete(int streamId) throws Http2Exception {
- // Any left over data is a compression error
- if (headerReadBuffer.position() > 0) {
- throw new ConnectionException(
-
sm.getString("http2Parser.processFrameHeaders.decodingDataLeft"),
- Http2Error.COMPRESSION_ERROR);
- }
-
- // Delay validation (and triggering any exception) until this point
- // since all the headers still have to be read if a StreamException is
- // going to be thrown.
- hpackDecoder.getHeaderEmitter().validateHeaders();
-
- output.headersEnd(streamId);
-
- if (headersEndStream) {
- output.receivedEndOfStream(streamId);
- headersEndStream = false;
- }
-
- // Reset size for new request if the buffer was previously expanded
- if (headerReadBuffer.capacity() >
Constants.DEFAULT_HEADER_READ_BUFFER_SIZE) {
- headerReadBuffer =
ByteBuffer.allocate(Constants.DEFAULT_HEADER_READ_BUFFER_SIZE);
- }
- }
-
-
- private void readUnknownFrame(int streamId, FrameType frameType, int
flags, int payloadSize)
+ protected void readUnknownFrame(int streamId, FrameType frameType, int
flags, int payloadSize, ByteBuffer buffer)
throws IOException {
try {
- swallow(streamId, payloadSize, false);
+ swallow(streamId, payloadSize, false, buffer);
} catch (ConnectionException e) {
// Will never happen because swallow() is called with mustBeZero
set
// to false
}
+ unRead(buffer);
output.swallowed(streamId, frameType, flags, payloadSize);
}
- private void swallow(int streamId, int len, boolean mustBeZero)
+ protected void swallow(int streamId, int len, boolean mustBeZero,
ByteBuffer byteBuffer)
throws IOException, ConnectionException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http2Parser.swallow.debug", connectionId,
@@ -516,6 +550,33 @@ class Http2Parser {
}
}
+
+ protected void onHeadersComplete(int streamId) throws Http2Exception {
+ // Any left over data is a compression error
+ if (headerReadBuffer.position() > 0) {
+ throw new ConnectionException(
+
sm.getString("http2Parser.processFrameHeaders.decodingDataLeft"),
+ Http2Error.COMPRESSION_ERROR);
+ }
+
+ // Delay validation (and triggering any exception) until this point
+ // since all the headers still have to be read if a StreamException is
+ // going to be thrown.
+ hpackDecoder.getHeaderEmitter().validateHeaders();
+
+ output.headersEnd(streamId);
+
+ if (headersEndStream) {
+ output.receivedEndOfStream(streamId);
+ headersEndStream = false;
+ }
+
+ // Reset size for new request if the buffer was previously expanded
+ if (headerReadBuffer.capacity() >
Constants.DEFAULT_HEADER_READ_BUFFER_SIZE) {
+ headerReadBuffer =
ByteBuffer.allocate(Constants.DEFAULT_HEADER_READ_BUFFER_SIZE);
+ }
+ }
+
/*
* Implementation note:
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]