Search in sources :

Example 1 with HttpStreamResetException

use of org.apache.hc.core5.http.HttpStreamResetException in project httpcomponents-core by apache.

the class ReactiveDataProducer method produce.

@Override
public void produce(final DataStreamChannel channel) throws IOException {
    if (requestChannel.get() == null) {
        requestChannel.set(channel);
        publisher.subscribe(this);
    }
    final Throwable t = exception.get();
    final Subscription s = subscription.get();
    int buffersToReplenish = 0;
    try {
        synchronized (buffers) {
            if (t != null) {
                throw new HttpStreamResetException(t.getMessage(), t);
            } else if (this.complete.get() && buffers.isEmpty()) {
                channel.endStream();
            } else {
                while (!buffers.isEmpty()) {
                    final ByteBuffer nextBuffer = buffers.remove();
                    channel.write(nextBuffer);
                    if (nextBuffer.remaining() > 0) {
                        buffers.push(nextBuffer);
                        break;
                    } else if (s != null) {
                        // We defer the #request call until after we release the buffer lock.
                        buffersToReplenish++;
                    }
                }
            }
        }
    } finally {
        if (s != null && buffersToReplenish > 0) {
            s.request(buffersToReplenish);
        }
    }
}
Also used : Subscription(org.reactivestreams.Subscription) HttpStreamResetException(org.apache.hc.core5.http.HttpStreamResetException) ByteBuffer(java.nio.ByteBuffer)

Example 2 with HttpStreamResetException

use of org.apache.hc.core5.http.HttpStreamResetException in project httpcomponents-core by apache.

the class TestReactiveDataProducer method testStreamThatEndsWithError.

@Test
public void testStreamThatEndsWithError() throws Exception {
    final Flowable<ByteBuffer> publisher = Flowable.concatArray(Flowable.just(ByteBuffer.wrap(new byte[] { '1' }), ByteBuffer.wrap(new byte[] { '2' }), ByteBuffer.wrap(new byte[] { '3' }), ByteBuffer.wrap(new byte[] { '4' }), ByteBuffer.wrap(new byte[] { '5' }), ByteBuffer.wrap(new byte[] { '6' })), Flowable.error(new RuntimeException()));
    final ReactiveDataProducer producer = new ReactiveDataProducer(publisher);
    final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
    final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
    producer.produce(streamChannel);
    Assertions.assertEquals("12345", byteChannel.dump(StandardCharsets.US_ASCII));
    final HttpStreamResetException exception = Assertions.assertThrows(HttpStreamResetException.class, () -> producer.produce(streamChannel));
    Assertions.assertTrue(exception.getCause() instanceof RuntimeException, "Expected published exception to be rethrown");
    Assertions.assertEquals("", byteChannel.dump(StandardCharsets.US_ASCII));
}
Also used : HttpStreamResetException(org.apache.hc.core5.http.HttpStreamResetException) ByteBuffer(java.nio.ByteBuffer) DataStreamChannel(org.apache.hc.core5.http.nio.DataStreamChannel) Test(org.junit.jupiter.api.Test)

Example 3 with HttpStreamResetException

use of org.apache.hc.core5.http.HttpStreamResetException in project httpcomponents-core by apache.

the class TestReactiveEntityProducer method testStreamThatEndsWithError.

@Test
public void testStreamThatEndsWithError() throws Exception {
    final Flowable<ByteBuffer> publisher = Flowable.concatArray(Flowable.just(ByteBuffer.wrap(new byte[] { '1' }), ByteBuffer.wrap(new byte[] { '2' }), ByteBuffer.wrap(new byte[] { '3' }), ByteBuffer.wrap(new byte[] { '4' }), ByteBuffer.wrap(new byte[] { '5' }), ByteBuffer.wrap(new byte[] { '6' })), Flowable.error(new RuntimeException()));
    final ReactiveEntityProducer entityProducer = new ReactiveEntityProducer(publisher, CONTENT_LENGTH, CONTENT_TYPE, GZIP_CONTENT_ENCODING);
    final WritableByteChannelMock byteChannel = new WritableByteChannelMock(1024);
    final DataStreamChannel streamChannel = new BasicDataStreamChannel(byteChannel);
    entityProducer.produce(streamChannel);
    Assertions.assertEquals("12345", byteChannel.dump(StandardCharsets.US_ASCII));
    final HttpStreamResetException exception = Assertions.assertThrows(HttpStreamResetException.class, () -> entityProducer.produce(streamChannel));
    Assertions.assertTrue(exception.getCause() instanceof RuntimeException, "Expected published exception to be rethrown");
    Assertions.assertEquals("", byteChannel.dump(StandardCharsets.US_ASCII));
    entityProducer.failed(exception);
    Assertions.assertEquals(1, entityProducer.available());
    Assertions.assertTrue(byteChannel.isOpen());
    Assertions.assertEquals("", byteChannel.dump(StandardCharsets.US_ASCII));
    Assertions.assertFalse(entityProducer.isChunked());
    Assertions.assertEquals(GZIP_CONTENT_ENCODING, entityProducer.getContentEncoding());
    Assertions.assertNull(entityProducer.getTrailerNames());
    Assertions.assertEquals(CONTENT_LENGTH, entityProducer.getContentLength());
    Assertions.assertEquals(CONTENT_TYPE.toString(), entityProducer.getContentType());
    Assertions.assertFalse(entityProducer.isRepeatable());
    Assertions.assertEquals(1, entityProducer.available());
    entityProducer.releaseResources();
}
Also used : HttpStreamResetException(org.apache.hc.core5.http.HttpStreamResetException) ByteBuffer(java.nio.ByteBuffer) DataStreamChannel(org.apache.hc.core5.http.nio.DataStreamChannel) Test(org.junit.jupiter.api.Test)

Example 4 with HttpStreamResetException

use of org.apache.hc.core5.http.HttpStreamResetException 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;
    }
}
Also used : H2ConnectionException(org.apache.hc.core5.http2.H2ConnectionException) H2StreamResetException(org.apache.hc.core5.http2.H2StreamResetException) ByteBuffer(java.nio.ByteBuffer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AsyncPingHandler(org.apache.hc.core5.http2.nio.AsyncPingHandler) FrameType(org.apache.hc.core5.http2.frame.FrameType) RawFrame(org.apache.hc.core5.http2.frame.RawFrame) Iterator(java.util.Iterator) HttpException(org.apache.hc.core5.http.HttpException) HttpStreamResetException(org.apache.hc.core5.http.HttpStreamResetException) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 5 with HttpStreamResetException

use of org.apache.hc.core5.http.HttpStreamResetException in project httpcomponents-core by apache.

the class ReactiveClientTest method testRequestTimeout.

@Test
public void testRequestTimeout() throws Exception {
    final InetSocketAddress address = startClientAndServer();
    final AtomicBoolean requestPublisherWasCancelled = new AtomicBoolean(false);
    final Publisher<ByteBuffer> publisher = Flowable.<ByteBuffer>never().doOnCancel(() -> requestPublisherWasCancelled.set(true));
    final ReactiveEntityProducer producer = new ReactiveEntityProducer(publisher, -1, null, null);
    final BasicRequestProducer request = getRequestProducer(address, producer);
    final ReactiveResponseConsumer consumer = new ReactiveResponseConsumer();
    final Future<Void> future = requester.execute(request, consumer, Timeout.ofSeconds(1), null);
    final ExecutionException exception = Assertions.assertThrows(ExecutionException.class, () -> future.get(RESULT_TIMEOUT.getDuration(), RESULT_TIMEOUT.getTimeUnit()));
    Assertions.assertTrue(requestPublisherWasCancelled.get());
    final Throwable cause = exception.getCause();
    if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_1) {
        Assertions.assertTrue(cause instanceof SocketTimeoutException, "Expected SocketTimeoutException, but got " + cause.getClass().getName());
    } else if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_2) {
        Assertions.assertTrue(cause instanceof HttpStreamResetException, format("Expected RST_STREAM, but %s was thrown", cause.getClass().getName()));
    } else {
        Assertions.fail("Unknown HttpVersionPolicy: " + versionPolicy);
    }
}
Also used : InetSocketAddress(java.net.InetSocketAddress) BasicRequestProducer(org.apache.hc.core5.http.nio.support.BasicRequestProducer) ByteBuffer(java.nio.ByteBuffer) ReactiveEntityProducer(org.apache.hc.core5.reactive.ReactiveEntityProducer) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SocketTimeoutException(java.net.SocketTimeoutException) ReactiveResponseConsumer(org.apache.hc.core5.reactive.ReactiveResponseConsumer) ExecutionException(java.util.concurrent.ExecutionException) HttpStreamResetException(org.apache.hc.core5.http.HttpStreamResetException) Test(org.junit.Test)

Aggregations

ByteBuffer (java.nio.ByteBuffer)7 HttpStreamResetException (org.apache.hc.core5.http.HttpStreamResetException)7 InetSocketAddress (java.net.InetSocketAddress)3 ExecutionException (java.util.concurrent.ExecutionException)3 BasicRequestProducer (org.apache.hc.core5.http.nio.support.BasicRequestProducer)3 ReactiveEntityProducer (org.apache.hc.core5.reactive.ReactiveEntityProducer)3 ReactiveResponseConsumer (org.apache.hc.core5.reactive.ReactiveResponseConsumer)3 Test (org.junit.Test)3 SocketTimeoutException (java.net.SocketTimeoutException)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 DataStreamChannel (org.apache.hc.core5.http.nio.DataStreamChannel)2 Test (org.junit.jupiter.api.Test)2 Iterator (java.util.Iterator)1 Map (java.util.Map)1 CancellationException (java.util.concurrent.CancellationException)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 HttpException (org.apache.hc.core5.http.HttpException)1 HttpResponse (org.apache.hc.core5.http.HttpResponse)1