use of io.servicetalk.buffer.api.Buffer in project servicetalk by apple.
the class HttpLifecycleObserverTest method testClientCancelsRequestAfterResponse.
@ParameterizedTest(name = "{displayName} [{index}] protocol={0}")
@EnumSource(HttpProtocol.class)
void testClientCancelsRequestAfterResponse(HttpProtocol protocol) throws Exception {
TestPublisher<Buffer> serverResponsePayload = new TestPublisher<>();
serviceFilterFactory(service -> new StreamingHttpServiceFilter(service) {
@Override
public Single<StreamingHttpResponse> handle(HttpServiceContext ctx, StreamingHttpRequest request, StreamingHttpResponseFactory responseFactory) {
return request.payloadBody().ignoreElements().concat(succeeded(responseFactory.ok().payloadBody(serverResponsePayload)));
}
});
setUp(protocol);
StreamingHttpConnection connection = streamingHttpConnection();
StreamingHttpRequest request = connection.post("/").payloadBody(Publisher.from(CONTENT.duplicate())).transform(// adds empty trailers
new StatelessTrailersTransformer<>());
StreamingHttpResponse response = connection.request(request).toFuture().get();
assertResponse(response, protocol.version, OK);
Future<Collection<Buffer>> payload = response.payloadBody().toFuture();
payload.cancel(true);
if (protocol == HttpProtocol.HTTP_1) {
// wait for cancellation to close the connection:
connection.onClose().toFuture().get();
}
// try to write server content to trigger write failure and close the server-side connection:
serverResponsePayload.onNext(CONTENT.duplicate());
bothTerminate.await();
clientInOrder.verify(clientLifecycleObserver).onNewExchange();
clientInOrder.verify(clientExchangeObserver).onConnectionSelected(any(ConnectionInfo.class));
clientInOrder.verify(clientExchangeObserver).onRequest(any(StreamingHttpRequest.class));
clientInOrder.verify(clientExchangeObserver).onResponse(any(StreamingHttpResponse.class));
clientInOrder.verify(clientResponseObserver).onResponseCancel();
clientRequestInOrder.verify(clientRequestObserver).onRequestData(any(Buffer.class));
clientRequestInOrder.verify(clientRequestObserver).onRequestTrailers(any(HttpHeaders.class));
clientRequestInOrder.verify(clientRequestObserver).onRequestComplete();
clientInOrder.verify(clientExchangeObserver).onExchangeFinally();
verifyNoMoreInteractions(clientLifecycleObserver, clientExchangeObserver, clientRequestObserver, clientResponseObserver);
serverInOrder.verify(serverLifecycleObserver).onNewExchange();
serverInOrder.verify(serverExchangeObserver).onConnectionSelected(any(ConnectionInfo.class));
serverInOrder.verify(serverExchangeObserver).onRequest(any(StreamingHttpRequest.class));
serverInOrder.verify(serverExchangeObserver).onResponse(any(StreamingHttpResponse.class));
verify(serverResponseObserver, atMostOnce()).onResponseData(any(Buffer.class));
serverInOrder.verify(serverResponseObserver).onResponseCancel();
serverRequestInOrder.verify(serverRequestObserver).onRequestData(any(Buffer.class));
serverRequestInOrder.verify(serverRequestObserver).onRequestComplete();
serverInOrder.verify(serverExchangeObserver).onExchangeFinally();
verifyNoMoreInteractions(serverLifecycleObserver, serverExchangeObserver, serverRequestObserver, serverResponseObserver);
}
use of io.servicetalk.buffer.api.Buffer in project servicetalk by apple.
the class ContentLengthAndTrailersTest method test.
private void test(Transformer<StreamingHttpRequest> requestTransformer, Transformer<StreamingHttpResponse> responseTransformer, boolean hasContentLength, boolean chunked, boolean hasTrailers) throws Exception {
StreamingHttpRequest preRequest = streamingHttpConnection().post("/");
if (!content.isEmpty()) {
preRequest.payloadBody(from(content), appSerializerUtf8FixLen());
}
StreamingHttpRequest request = requestTransformer.transform(preRequest);
StreamingHttpResponse response = responseTransformer.transform(makeRequest(request));
assertResponse(response, protocol.version, OK);
HttpHeaders headers = response.headers();
assertThat("Unexpected content-length on the response", mergeValues(headers.values(CONTENT_LENGTH)), contentEqualTo(hasContentLength ? valueOf(addFixedLengthFramingOverhead(content.length())) : ""));
assertThat("Unexpected transfer-encoding on the response", mergeValues(headers.values(TRANSFER_ENCODING)), contentEqualTo(chunked ? CHUNKED : ""));
assertThat("Unexpected content-length on the request", headers.get(CLIENT_CONTENT_LENGTH), hasContentLength ? contentEqualTo(valueOf(addFixedLengthFramingOverhead(content.length()))) : nullValue());
assertThat("Unexpected transfer-encoding on the request", headers.get(CLIENT_TRANSFER_ENCODING), chunked ? contentEqualTo(CHUNKED) : nullValue());
if (content.isEmpty()) {
response.transform(new TrailersTransformer<Object, Buffer>() {
@Nullable
@Override
public Integer newState() {
return null;
}
@Override
public Buffer accept(@Nullable final Object o, final Buffer buffer) {
assertThat(buffer.readableBytes(), equalTo(0));
return buffer;
}
@Override
public HttpHeaders payloadComplete(@Nullable final Object o, final HttpHeaders trailers) {
assertThat("Unexpected trailers on the request", trailers.get(TRAILER_NAME), hasTrailers ? contentEqualTo(TRAILER_VALUE) : nullValue());
return trailers;
}
@Override
public HttpHeaders catchPayloadFailure(@Nullable final Object o, final Throwable cause, final HttpHeaders trailers) throws Throwable {
throw cause;
}
}).messageBody().ignoreElements().toFuture().get();
} else {
response.transform(new TrailersTransformer<StringBuilder, String>() {
@Override
public StringBuilder newState() {
return new StringBuilder();
}
@Override
public String accept(final StringBuilder o, final String s) {
o.append(s);
return s;
}
@Override
public HttpHeaders payloadComplete(final StringBuilder o, final HttpHeaders trailers) {
assertThat(o.toString(), equalTo(content));
assertThat("Unexpected trailers on the request", trailers.get(TRAILER_NAME), hasTrailers ? contentEqualTo(TRAILER_VALUE) : nullValue());
return trailers;
}
@Override
public HttpHeaders catchPayloadFailure(@Nullable final StringBuilder o, final Throwable cause, final HttpHeaders trailers) throws Throwable {
throw cause;
}
}, appSerializerUtf8FixLen()).messageBody().ignoreElements().toFuture().get();
}
}
use of io.servicetalk.buffer.api.Buffer in project servicetalk by apple.
the class HttpRequestEncoderTest method contentLengthNoTrailersHeaderWhiteSpaceEncodedWithValidationOff.
@Test
void contentLengthNoTrailersHeaderWhiteSpaceEncodedWithValidationOff() {
EmbeddedChannel channel = newEmbeddedChannel();
byte[] content = new byte[128];
ThreadLocalRandom.current().nextBytes(content);
Buffer buffer = allocator.wrap(content);
HttpRequestMetaData request = newRequestMetaData(HTTP_1_1, GET, "/some/path?foo=bar&baz=yyy", new DefaultHttpHeadersFactory(false, false, false).newHeaders());
request.headers().add(" " + CONNECTION + " ", " " + KEEP_ALIVE).add(" " + USER_AGENT + " ", " unit-test ").add(CONTENT_LENGTH, valueOf(content.length));
channel.writeOutbound(request);
channel.writeOutbound(buffer.duplicate());
ByteBuf byteBuf = channel.readOutbound();
String actualMetaData = byteBuf.toString(US_ASCII);
byteBuf.release();
assertTrue(actualMetaData.contains("GET /some/path?foo=bar&baz=yyy HTTP/1.1" + "\r\n"), () -> "unexpected metadata: " + actualMetaData);
assertTrue(actualMetaData.contains(" " + CONNECTION + " : " + KEEP_ALIVE + "\r\n"), () -> "unexpected metadata: " + actualMetaData);
assertTrue(actualMetaData.contains(" " + USER_AGENT + " : unit-test " + "\r\n"), () -> "unexpected metadata: " + actualMetaData);
assertTrue(actualMetaData.contains(CONTENT_LENGTH + ": " + buffer.readableBytes() + "\r\n"), () -> "unexpected metadata: " + actualMetaData);
assertTrue(actualMetaData.endsWith("\r\n" + "\r\n"), () -> "unexpected metadata: " + actualMetaData);
byteBuf = channel.readOutbound();
assertEquals(buffer.toNioBuffer(), byteBuf.nioBuffer());
byteBuf.release();
assertFalse(channel.finishAndReleaseAll());
}
use of io.servicetalk.buffer.api.Buffer in project servicetalk by apple.
the class HttpRequestEncoderTest method variableNoTrailers.
@Test
void variableNoTrailers() {
EmbeddedChannel channel = newEmbeddedChannel();
byte[] content = new byte[128];
ThreadLocalRandom.current().nextBytes(content);
Buffer buffer = allocator.wrap(content);
HttpRequestMetaData request = newRequestMetaData(HTTP_1_1, GET, "/some/path?foo=bar&baz=yyy", INSTANCE.newHeaders());
request.headers().add(CONNECTION, KEEP_ALIVE).add(USER_AGENT, "unit-test");
channel.writeOutbound(request);
channel.writeOutbound(buffer.duplicate());
channel.writeOutbound(EmptyHttpHeaders.INSTANCE);
verifyHttpRequest(channel, buffer, TransferEncoding.Variable, false);
assertFalse(channel.finishAndReleaseAll());
}
use of io.servicetalk.buffer.api.Buffer in project servicetalk by apple.
the class TcpClient method connectWithFdBlocking.
/**
* Connect using a {@link FileDescriptorSocketAddress} and await for the connection.
*
* @param executionContext {@link ExecutionContext} to use for the connections.
* @param address to connect.
* @return New {@link NettyConnection}.
* @throws ExecutionException If connect failed.
* @throws InterruptedException If interrupted while waiting for connect to complete.
*/
public NettyConnection<Buffer, Buffer> connectWithFdBlocking(ExecutionContext<?> executionContext, SocketAddress address) throws Exception {
assumeTrue(executionContext.ioExecutor().isFileDescriptorSocketAddressSupported());
assumeTrue(Epoll.isAvailable() || KQueue.isAvailable());
final Class<? extends Channel> channelClass;
final EventLoopGroup eventLoopGroup;
if (Epoll.isAvailable()) {
eventLoopGroup = new EpollEventLoopGroup(1);
channelClass = EpollSocketChannel.class;
} else {
eventLoopGroup = new KQueueEventLoopGroup(1);
channelClass = KQueueSocketChannel.class;
}
AtomicBoolean dataReadDirectlyFromNetty = new AtomicBoolean();
// Bootstrap a netty channel to the server so we can access its FD and wrap it later in ST.
Bootstrap bs = new Bootstrap();
UnixChannel channel = (UnixChannel) bs.channel(channelClass).group(eventLoopGroup).handler(new SimpleChannelInboundHandler<Object>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) {
dataReadDirectlyFromNetty.set(true);
}
}).connect(address).sync().channel();
// Unregister it from the netty EventLoop as we want to to handle it via ST.
channel.deregister().sync();
FileDescriptorSocketAddress fd = new FileDescriptorSocketAddress(channel.fd().intValue());
NettyConnection<Buffer, Buffer> connection = connectBlocking(executionContext, fd);
assertThat("Data read on the FileDescriptor from netty pipeline.", dataReadDirectlyFromNetty.get(), is(false));
return connection;
}
Aggregations