use of com.hotels.styx.api.LiveHttpResponse in project styx by ExpediaGroup.
the class NettyToStyxResponsePropagator method channelRead0.
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
FlowControllingHttpContentProducer producer = getContentProducer(ctx);
if (msg instanceof io.netty.handler.codec.http.HttpResponse) {
io.netty.handler.codec.http.HttpResponse nettyResponse = (io.netty.handler.codec.http.HttpResponse) msg;
if (!responseReceived.compareAndSet(false, true)) {
LOGGER.warn("Unexpected additional response received: " + nettyResponse);
ctx.channel().close();
return;
}
if (nettyResponse.getDecoderResult().isFailure()) {
emitResponseError(new BadHttpResponseException(origin, nettyResponse.getDecoderResult().cause()));
return;
}
ctx.channel().config().setAutoRead(false);
ctx.channel().read();
// Can be started with flow controlling disabled
EventLoop eventLoop = ctx.channel().eventLoop();
Publisher<Buffer> contentPublisher = new ContentPublisher(eventLoop, producer);
if ("close".equalsIgnoreCase(nettyResponse.headers().get(CONNECTION))) {
toBeClosed = true;
}
LiveHttpResponse response = toStyxResponse(nettyResponse, contentPublisher, origin);
this.sink.next(response);
}
if (msg instanceof HttpContent) {
ByteBuf content = ((ByteBufHolder) msg).content();
if (content.isReadable()) {
producer.newChunk(retain(content));
}
if (msg instanceof LastHttpContent) {
// Note: Netty may send a LastHttpContent as a response to TCP connection close.
// In this case channelReadComplete event will _not_ follow the LastHttpContent.
producer.lastHttpContent();
if (toBeClosed) {
ctx.channel().close();
}
}
}
}
use of com.hotels.styx.api.LiveHttpResponse in project styx by ExpediaGroup.
the class StyxHttpClientTest method sendsSecureStreamingRequests.
/*
* HttpClient.StreamingTransaction
* - Sends LiveHttpRequest messages created from StyxHttpClientTransactions
*/
@Test
public void sendsSecureStreamingRequests() throws ExecutionException, InterruptedException {
LiveHttpResponse response = new StyxHttpClient.Builder().build().secure(true).streaming().send(secureRequest.stream()).get();
assertThat(response.status(), is(OK));
Mono.from(response.aggregate(10000)).block();
server.verify(getRequestedFor(urlEqualTo("/")).withHeader("Host", equalTo(hostString(server.httpsPort()))));
}
use of com.hotels.styx.api.LiveHttpResponse in project styx by ExpediaGroup.
the class StyxHttpClientTest method sendsStreamingRequests.
/*
* HttpClient.StreamingTransaction
* - Sends LiveHttpRequest messages
*/
@Test
public void sendsStreamingRequests() throws ExecutionException, InterruptedException {
LiveHttpResponse response = new StyxHttpClient.Builder().build().streaming().send(httpRequest.stream()).get();
assertThat(response.status(), is(OK));
Mono.from(response.aggregate(10000)).block();
server.verify(getRequestedFor(urlEqualTo("/")).withHeader("Host", equalTo(hostString(server.port()))));
}
use of com.hotels.styx.api.LiveHttpResponse in project styx by ExpediaGroup.
the class StyxHostHttpClientTest method terminatesConnectionDueToUnsubscribedBody.
@Test
public void terminatesConnectionDueToUnsubscribedBody() {
TestPublisher<Buffer> testPublisher = TestPublisher.create();
Connection connection = mockConnection(just(LiveHttpResponse.response(OK).body(new ByteStream(testPublisher)).build()));
ConnectionPool pool = mockPool(connection);
Context context = mockContext();
AtomicReference<LiveHttpResponse> receivedResponse = new AtomicReference<>();
StyxHostHttpClient hostClient = new StyxHostHttpClient(pool);
StepVerifier.create(hostClient.sendRequest(request, context)).consumeNextWith(receivedResponse::set).expectComplete().verify();
StepVerifier.create(receivedResponse.get().body()).thenCancel().verify();
verify(pool).closeConnection(any(Connection.class));
verify(context).add(ORIGINID_CONTEXT_KEY, Id.id("mockorigin"));
}
use of com.hotels.styx.api.LiveHttpResponse in project styx by ExpediaGroup.
the class StyxHostHttpClientTest method ignoresCancelledHeaders.
@Test
public void ignoresCancelledHeaders() {
// Request observable unsubscribe/cancel has to be ignored after "onNext" event.
// This is because Reactor Mono will automatically cancel after an event has
// been published.
Connection connection = mockConnection(just(response));
ConnectionPool pool = mockPool(connection);
Context context = mockContext();
AtomicReference<LiveHttpResponse> transformedResponse = new AtomicReference<>();
StyxHostHttpClient hostClient = new StyxHostHttpClient(pool);
// The StepVerifier consumes the response event and then unsubscribes
// from the response observable.
StepVerifier.create(hostClient.sendRequest(request, context)).consumeNextWith(transformedResponse::set).verifyComplete();
// The response is still alive...
verify(pool, never()).returnConnection(any(Connection.class));
verify(pool, never()).closeConnection(any(Connection.class));
// ... until response body is consumed:
transformedResponse.get().consume();
// Finally, the connection is returned after the response body is fully consumed:
verify(pool).returnConnection(any(Connection.class));
verify(context).add(ORIGINID_CONTEXT_KEY, Id.id("mockorigin"));
}
Aggregations