use of org.apache.hc.core5.http2.frame.RawFrame in project httpcomponents-core by apache.
the class AbstractH2StreamMultiplexer method onTimeout.
public final void onTimeout(final Timeout timeout) throws HttpException, IOException {
connState = ConnectionHandshake.SHUTDOWN;
final RawFrame goAway;
if (localSettingState != SettingsHandshake.ACKED) {
goAway = frameFactory.createGoAway(processedRemoteStreamId, H2Error.SETTINGS_TIMEOUT, "Setting timeout (" + timeout + ")");
} else {
goAway = frameFactory.createGoAway(processedRemoteStreamId, H2Error.NO_ERROR, "Timeout due to inactivity (" + timeout + ")");
}
commitFrame(goAway);
for (final Iterator<Map.Entry<Integer, H2Stream>> it = streamMap.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<Integer, H2Stream> entry = it.next();
final H2Stream stream = entry.getValue();
stream.reset(new H2StreamResetException(H2Error.NO_ERROR, "Timeout due to inactivity (" + timeout + ")"));
}
streamMap.clear();
}
use of org.apache.hc.core5.http2.frame.RawFrame in project httpcomponents-core by apache.
the class AbstractH2StreamMultiplexer method consumeFrame.
private void consumeFrame(final RawFrame frame) throws HttpException, IOException {
final FrameType frameType = FrameType.valueOf(frame.getType());
final int streamId = frame.getStreamId();
if (continuation != null && frameType != FrameType.CONTINUATION) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "CONTINUATION frame expected");
}
switch(frameType) {
case DATA:
{
final H2Stream stream = getValidStream(streamId);
try {
consumeDataFrame(frame, stream);
} catch (final H2StreamResetException ex) {
stream.localReset(ex);
} catch (final HttpStreamResetException ex) {
stream.localReset(ex, ex.getCause() != null ? H2Error.INTERNAL_ERROR : H2Error.CANCEL);
}
if (stream.isTerminated()) {
streamMap.remove(streamId);
stream.releaseResources();
requestSessionOutput();
}
}
break;
case HEADERS:
{
if (streamId == 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal stream id: " + streamId);
}
H2Stream stream = streamMap.get(streamId);
if (stream == null) {
acceptHeaderFrame();
if (idGenerator.isSameSide(streamId)) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal stream id: " + streamId);
}
if (goAwayReceived) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "GOAWAY received");
}
updateLastStreamId(streamId);
final H2StreamChannelImpl channel = new H2StreamChannelImpl(streamId, false, initInputWinSize, initOutputWinSize);
final H2StreamHandler streamHandler;
if (connState.compareTo(ConnectionHandshake.ACTIVE) <= 0) {
streamHandler = createRemotelyInitiatedStream(channel, httpProcessor, connMetrics, null);
} else {
streamHandler = NoopH2StreamHandler.INSTANCE;
channel.setLocalEndStream();
}
stream = new H2Stream(channel, streamHandler, true);
if (stream.isOutputReady()) {
stream.produceOutput();
}
streamMap.put(streamId, stream);
}
try {
consumeHeaderFrame(frame, stream);
if (stream.isOutputReady()) {
stream.produceOutput();
}
} catch (final H2StreamResetException ex) {
stream.localReset(ex);
} catch (final HttpStreamResetException ex) {
stream.localReset(ex, ex.getCause() != null ? H2Error.INTERNAL_ERROR : H2Error.CANCEL);
} catch (final HttpException ex) {
stream.handle(ex);
}
if (stream.isTerminated()) {
streamMap.remove(streamId);
stream.releaseResources();
requestSessionOutput();
}
}
break;
case CONTINUATION:
{
if (continuation == null) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Unexpected CONTINUATION frame");
}
if (streamId != continuation.streamId) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Unexpected CONTINUATION stream id: " + streamId);
}
final H2Stream stream = getValidStream(streamId);
try {
consumeContinuationFrame(frame, stream);
} catch (final H2StreamResetException ex) {
stream.localReset(ex);
} catch (final HttpStreamResetException ex) {
stream.localReset(ex, ex.getCause() != null ? H2Error.INTERNAL_ERROR : H2Error.CANCEL);
}
if (stream.isTerminated()) {
streamMap.remove(streamId);
stream.releaseResources();
requestSessionOutput();
}
}
break;
case WINDOW_UPDATE:
{
final ByteBuffer payload = frame.getPayload();
if (payload == null || payload.remaining() != 4) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Invalid WINDOW_UPDATE frame payload");
}
final int delta = payload.getInt();
if (delta <= 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Invalid WINDOW_UPDATE delta");
}
if (streamId == 0) {
try {
updateOutputWindow(0, connOutputWindow, delta);
} catch (final ArithmeticException ex) {
throw new H2ConnectionException(H2Error.FLOW_CONTROL_ERROR, ex.getMessage());
}
} else {
final H2Stream stream = streamMap.get(streamId);
if (stream != null) {
try {
updateOutputWindow(streamId, stream.getOutputWindow(), delta);
} catch (final ArithmeticException ex) {
throw new H2ConnectionException(H2Error.FLOW_CONTROL_ERROR, ex.getMessage());
}
}
}
ioSession.setEvent(SelectionKey.OP_WRITE);
}
break;
case RST_STREAM:
{
if (streamId == 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal stream id: " + streamId);
}
final H2Stream stream = streamMap.get(streamId);
if (stream == null) {
if (streamId > lastStreamId.get()) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Unexpected stream id: " + streamId);
}
} else {
final ByteBuffer payload = frame.getPayload();
if (payload == null || payload.remaining() != 4) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Invalid RST_STREAM frame payload");
}
final int errorCode = payload.getInt();
stream.reset(new H2StreamResetException(errorCode, "Stream reset (" + errorCode + ")"));
streamMap.remove(streamId);
stream.releaseResources();
requestSessionOutput();
}
}
break;
case PING:
{
if (streamId != 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal stream id");
}
final ByteBuffer ping = frame.getPayloadContent();
if (ping == null || ping.remaining() != 8) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Invalid PING frame payload");
}
if (frame.isFlagSet(FrameFlag.ACK)) {
final AsyncPingHandler pingHandler = pingHandlers.poll();
if (pingHandler != null) {
pingHandler.consumeResponse(ping);
}
} else {
final ByteBuffer pong = ByteBuffer.allocate(ping.remaining());
pong.put(ping);
pong.flip();
final RawFrame response = frameFactory.createPingAck(pong);
commitFrame(response);
}
}
break;
case SETTINGS:
{
if (streamId != 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal stream id");
}
if (frame.isFlagSet(FrameFlag.ACK)) {
if (localSettingState == SettingsHandshake.TRANSMITTED) {
localSettingState = SettingsHandshake.ACKED;
ioSession.setEvent(SelectionKey.OP_WRITE);
applyLocalSettings();
}
} else {
final ByteBuffer payload = frame.getPayload();
if (payload != null) {
if ((payload.remaining() % 6) != 0) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Invalid SETTINGS payload");
}
consumeSettingsFrame(payload);
remoteSettingState = SettingsHandshake.TRANSMITTED;
}
// Send ACK
final RawFrame response = frameFactory.createSettingsAck();
commitFrame(response);
remoteSettingState = SettingsHandshake.ACKED;
}
}
break;
case PRIORITY:
// Stream priority not supported
break;
case PUSH_PROMISE:
{
acceptPushFrame();
if (goAwayReceived) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "GOAWAY received");
}
if (!localConfig.isPushEnabled()) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Push is disabled");
}
final H2Stream stream = getValidStream(streamId);
if (stream.isRemoteClosed()) {
stream.localReset(new H2StreamResetException(H2Error.STREAM_CLOSED, "Stream closed"));
break;
}
final ByteBuffer payload = frame.getPayloadContent();
if (payload == null || payload.remaining() < 4) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Invalid PUSH_PROMISE payload");
}
final int promisedStreamId = payload.getInt();
if (promisedStreamId == 0 || idGenerator.isSameSide(promisedStreamId)) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal promised stream id: " + promisedStreamId);
}
if (streamMap.get(promisedStreamId) != null) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Unexpected promised stream id: " + promisedStreamId);
}
updateLastStreamId(promisedStreamId);
final H2StreamChannelImpl channel = new H2StreamChannelImpl(promisedStreamId, false, initInputWinSize, initOutputWinSize);
final H2StreamHandler streamHandler;
if (connState.compareTo(ConnectionHandshake.ACTIVE) <= 0) {
streamHandler = createRemotelyInitiatedStream(channel, httpProcessor, connMetrics, stream.getPushHandlerFactory());
} else {
streamHandler = NoopH2StreamHandler.INSTANCE;
channel.setLocalEndStream();
}
final H2Stream promisedStream = new H2Stream(channel, streamHandler, true);
streamMap.put(promisedStreamId, promisedStream);
try {
consumePushPromiseFrame(frame, payload, promisedStream);
} catch (final H2StreamResetException ex) {
promisedStream.localReset(ex);
} catch (final HttpStreamResetException ex) {
promisedStream.localReset(ex, ex.getCause() != null ? H2Error.INTERNAL_ERROR : H2Error.NO_ERROR);
}
}
break;
case GOAWAY:
{
if (streamId != 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Illegal stream id");
}
final ByteBuffer payload = frame.getPayload();
if (payload == null || payload.remaining() < 8) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Invalid GOAWAY payload");
}
final int processedLocalStreamId = payload.getInt();
final int errorCode = payload.getInt();
goAwayReceived = true;
if (errorCode == H2Error.NO_ERROR.getCode()) {
if (connState.compareTo(ConnectionHandshake.ACTIVE) <= 0) {
for (final Iterator<Map.Entry<Integer, H2Stream>> it = streamMap.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<Integer, H2Stream> entry = it.next();
final int activeStreamId = entry.getKey();
if (!idGenerator.isSameSide(activeStreamId) && activeStreamId > processedLocalStreamId) {
final H2Stream stream = entry.getValue();
stream.cancel();
it.remove();
}
}
}
connState = streamMap.isEmpty() ? ConnectionHandshake.SHUTDOWN : ConnectionHandshake.GRACEFUL_SHUTDOWN;
} else {
for (final Iterator<Map.Entry<Integer, H2Stream>> it = streamMap.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<Integer, H2Stream> entry = it.next();
final H2Stream stream = entry.getValue();
stream.reset(new H2StreamResetException(errorCode, "Connection terminated by the peer (" + errorCode + ")"));
}
streamMap.clear();
connState = ConnectionHandshake.SHUTDOWN;
}
}
ioSession.setEvent(SelectionKey.OP_WRITE);
break;
}
}
use of org.apache.hc.core5.http2.frame.RawFrame in project httpcomponents-core by apache.
the class FrameFactory method createSettings.
public RawFrame createSettings(final H2Setting... settings) {
final ByteBuffer payload = ByteBuffer.allocate(settings.length * 12);
for (final H2Setting setting : settings) {
payload.putShort((short) setting.getCode());
payload.putInt(setting.getValue());
}
payload.flip();
return new RawFrame(FrameType.SETTINGS.getValue(), 0, 0, payload);
}
use of org.apache.hc.core5.http2.frame.RawFrame in project httpcomponents-core by apache.
the class FramePrinter method printPayload.
public void printPayload(final RawFrame frame, final Appendable appendable) throws IOException {
final FrameType type = FrameType.valueOf(frame.getType());
final ByteBuffer buf = frame.getPayloadContent();
if (buf != null) {
switch(type) {
case SETTINGS:
if ((buf.remaining() % 6) == 0) {
while (buf.hasRemaining()) {
final int code = buf.getShort();
final H2Param param = H2Param.valueOf(code);
final int value = buf.getInt();
if (param != null) {
appendable.append(param.name());
} else {
appendable.append("0x").append(Integer.toHexString(code));
}
appendable.append(": ").append(Integer.toString(value)).append("\r\n");
}
} else {
appendable.append("Invalid\r\n");
}
break;
case RST_STREAM:
if (buf.remaining() == 4) {
appendable.append("Code ");
final int code = buf.getInt();
final H2Error error = H2Error.getByCode(code);
if (error != null) {
appendable.append(error.name());
} else {
appendable.append("0x").append(Integer.toHexString(code));
}
appendable.append("\r\n");
} else {
appendable.append("Invalid\r\n");
}
break;
case GOAWAY:
if (buf.remaining() >= 8) {
final int lastStream = buf.getInt();
appendable.append("Last stream ").append(Integer.toString(lastStream)).append("\r\n");
appendable.append("Code ");
final int code2 = buf.getInt();
final H2Error error2 = H2Error.getByCode(code2);
if (error2 != null) {
appendable.append(error2.name());
} else {
appendable.append("0x").append(Integer.toHexString(code2));
}
appendable.append("\r\n");
final byte[] tmp = new byte[buf.remaining()];
buf.get(tmp);
appendable.append(new String(tmp, StandardCharsets.US_ASCII));
appendable.append("\r\n");
} else {
appendable.append("Invalid\r\n");
}
break;
case WINDOW_UPDATE:
if (buf.remaining() == 4) {
final int increment = buf.getInt();
appendable.append("Increment ").append(Integer.toString(increment)).append("\r\n");
} else {
appendable.append("Invalid\r\n");
}
break;
case PUSH_PROMISE:
if (buf.remaining() > 4) {
final int streamId = buf.getInt();
appendable.append("Promised stream ").append(Integer.toString(streamId)).append("\r\n");
printData(buf, appendable);
} else {
appendable.append("Invalid\r\n");
}
break;
default:
printData(frame.getPayload(), appendable);
}
}
}
use of org.apache.hc.core5.http2.frame.RawFrame in project httpcomponents-core by apache.
the class FrameInputBuffer method read.
public RawFrame read(final InputStream inStream) throws IOException {
fillBuffer(inStream, FrameConsts.HEAD_LEN);
final int payloadOff = FrameConsts.HEAD_LEN;
final int payloadLen = (buffer[off] & 0xff) << 16 | (buffer[off + 1] & 0xff) << 8 | (buffer[off + 2] & 0xff);
final int type = buffer[off + 3] & 0xff;
final int flags = buffer[off + 4] & 0xff;
final int streamId = Math.abs(buffer[off + 5] & 0xff) << 24 | (buffer[off + 6] & 0xff << 16) | (buffer[off + 7] & 0xff) << 8 | (buffer[off + 8] & 0xff);
if (payloadLen > maxFramePayloadSize) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Frame size exceeds maximum");
}
final int frameLen = payloadOff + payloadLen;
fillBuffer(inStream, frameLen);
if ((flags & FrameFlag.PADDED.getValue()) > 0) {
if (payloadLen == 0) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Inconsistent padding");
}
final int padding = buffer[off + FrameConsts.HEAD_LEN] & 0xff;
if (payloadLen < padding + 1) {
throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Inconsistent padding");
}
}
final ByteBuffer payload = payloadLen > 0 ? ByteBuffer.wrap(buffer, off + payloadOff, payloadLen) : null;
final RawFrame frame = new RawFrame(type, flags, streamId, payload);
off += frameLen;
dataLen -= frameLen;
this.metrics.incrementFramesTransferred();
return frame;
}
Aggregations