use of io.servicetalk.transport.api.ConnectionContext in project servicetalk by apple.
the class GracefulConnectionClosureHandlingTest method setUp.
void setUp(HttpProtocol protocol, boolean initiateClosureFromClient, boolean useUds, boolean viaProxy) throws Exception {
this.protocol = protocol;
this.initiateClosureFromClient = initiateClosureFromClient;
if (useUds) {
Assumptions.assumeTrue(SERVER_CTX.ioExecutor().isUnixDomainSocketSupported(), "Server's IoExecutor does not support UnixDomainSocket");
Assumptions.assumeTrue(CLIENT_CTX.ioExecutor().isUnixDomainSocketSupported(), "Client's IoExecutor does not support UnixDomainSocket");
assumeFalse(viaProxy, "UDS cannot be used via proxy");
}
assumeFalse(protocol == HTTP_2 && viaProxy, "Proxy is not supported with HTTP/2");
HttpServerBuilder serverBuilder = (useUds ? forAddress(newSocketAddress()) : forAddress(localAddress(0))).protocols(protocol.config).ioExecutor(SERVER_CTX.ioExecutor()).executor(SERVER_CTX.executor()).executionStrategy(defaultStrategy()).enableWireLogging("servicetalk-tests-wire-logger", TRACE, () -> true).appendConnectionAcceptorFilter(original -> new DelegatingConnectionAcceptor(original) {
@Override
public Completable accept(final ConnectionContext context) {
if (!initiateClosureFromClient) {
((NettyConnectionContext) context).onClosing().whenFinally(onClosing::countDown).subscribe();
}
context.onClose().whenFinally(serverConnectionClosed::countDown).subscribe();
connectionAccepted.countDown();
return completed();
}
});
HostAndPort proxyAddress = null;
if (viaProxy) {
// Dummy proxy helps to emulate old intermediate systems that do not support half-closed TCP connections
proxyTunnel = new ProxyTunnel();
proxyAddress = proxyTunnel.startProxy();
serverBuilder.sslConfig(new ServerSslConfigBuilder(DefaultTestCerts::loadServerPem, DefaultTestCerts::loadServerKey).build());
} else {
proxyTunnel = null;
}
serverContext = serverBuilder.listenBlockingStreamingAndAwait((ctx, request, response) -> {
serverReceivedRequest.countDown();
response.addHeader(CONTENT_LENGTH, valueOf(RESPONSE_CONTENT.length()));
serverSendResponse.await();
try (HttpPayloadWriter<String> writer = response.sendMetaData(RAW_STRING_SERIALIZER)) {
// Subscribe to the request payload body before response writer closes
BlockingIterator<Buffer> iterator = request.payloadBody().iterator();
// Consume request payload body asynchronously:
ctx.executionContext().executor().submit(() -> {
int receivedSize = 0;
while (iterator.hasNext()) {
Buffer chunk = iterator.next();
assert chunk != null;
receivedSize += chunk.readableBytes();
}
serverReceivedRequestPayload.add(receivedSize);
}).beforeOnError(cause -> {
LOGGER.error("failure while reading request", cause);
serverReceivedRequestPayload.add(-1);
}).toFuture();
serverSendResponsePayload.await();
writer.write(RESPONSE_CONTENT);
}
});
serverContext.onClose().whenFinally(serverContextClosed::countDown).subscribe();
client = (viaProxy ? forSingleAddress(serverHostAndPort(serverContext)).proxyAddress(proxyAddress).sslConfig(new ClientSslConfigBuilder(DefaultTestCerts::loadServerCAPem).peerHost(serverPemHostname()).build()) : forResolvedAddress(serverContext.listenAddress())).protocols(protocol.config).executor(CLIENT_CTX.executor()).ioExecutor(CLIENT_CTX.ioExecutor()).executionStrategy(defaultStrategy()).enableWireLogging("servicetalk-tests-wire-logger", TRACE, Boolean.TRUE::booleanValue).appendConnectionFactoryFilter(ConnectionFactoryFilter.withStrategy(cf -> initiateClosureFromClient ? new OnClosingConnectionFactoryFilter<>(cf, onClosing) : cf, ExecutionStrategy.offloadNone())).buildStreaming();
connection = client.reserveConnection(client.get("/")).toFuture().get();
connection.onClose().whenFinally(clientConnectionClosed::countDown).subscribe();
// wait until server accepts connection
connectionAccepted.await();
toClose = initiateClosureFromClient ? connection : serverContext;
}
use of io.servicetalk.transport.api.ConnectionContext in project servicetalk by apple.
the class H2PriorKnowledgeFeatureParityTest method bindHttpEchoServer.
private InetSocketAddress bindHttpEchoServer(@Nullable StreamingHttpServiceFilterFactory filterFactory, @Nullable CountDownLatch connectionOnClosingLatch) throws Exception {
HttpServerBuilder serverBuilder = HttpServers.forAddress(localAddress(0)).protocols(h2PriorKnowledge ? h2Default() : h1Default());
if (filterFactory != null) {
serverBuilder.appendServiceFilter(filterFactory);
}
if (connectionOnClosingLatch != null) {
serverBuilder.appendConnectionAcceptorFilter(original -> new DelegatingConnectionAcceptor(original) {
@Override
public Completable accept(final ConnectionContext context) {
((NettyConnectionContext) context).onClosing().whenFinally(connectionOnClosingLatch::countDown).subscribe();
return completed();
}
});
}
h1ServerContext = serverBuilder.listenStreaming((ctx, request, responseFactory) -> {
StreamingHttpResponse resp;
if (request.headers().contains(EXPECT, CONTINUE)) {
if (request.headers().contains(EXPECT_FAIL_HEADER)) {
return succeeded(responseFactory.expectationFailed());
} else {
resp = responseFactory.continueResponse();
}
} else {
resp = responseFactory.ok();
}
resp = resp.transformMessageBody(pub -> pub.ignoreElements().merge(request.messageBody())).transform(new StatelessTrailersTransformer<>());
CharSequence contentType = request.headers().get(CONTENT_TYPE);
if (contentType != null) {
resp.setHeader(CONTENT_TYPE, contentType);
}
CharSequence contentLength = request.headers().get(CONTENT_LENGTH);
if (contentLength != null) {
resp.setHeader(CONTENT_LENGTH, contentLength);
}
CharSequence transferEncoding = request.headers().get(TRANSFER_ENCODING);
if (transferEncoding != null) {
resp.setHeader(TRANSFER_ENCODING, transferEncoding);
}
resp.headers().set(COOKIE, request.headers().valuesIterator(COOKIE));
return succeeded(resp);
}).toFuture().get();
return (InetSocketAddress) h1ServerContext.listenAddress();
}
use of io.servicetalk.transport.api.ConnectionContext in project servicetalk by apple.
the class MalformedDataAfterHttpMessageTest method afterResponseNextClientRequestSucceeds.
@ParameterizedTest
@ValueSource(booleans = { true, false })
void afterResponseNextClientRequestSucceeds(boolean doOffloading) throws Exception {
Queue<ConnectionContext> contextQueue = new LinkedBlockingQueue<>();
ServerSocketChannel server = nettyServer(RESPONSE_MSG);
try (BlockingHttpClient client = stClientBuilder(server.localAddress()).executionStrategy(doOffloading ? defaultStrategy() : offloadNever()).appendClientFilter(new RetryingHttpRequesterFilter.Builder().retryOther((req, cause) -> ofConstantBackoffFullJitter(ofNanos(1), MAX_VALUE)).build()).appendConnectionFilter(connection -> new StreamingHttpConnectionFilter(connection) {
@Override
public Single<StreamingHttpResponse> request(final StreamingHttpRequest request) {
contextQueue.add(connectionContext());
return super.request(request);
}
}).buildBlocking()) {
validateClientResponse(client.request(client.get("/1")));
validateClientResponse(client.request(client.get("/2")));
ConnectionContext ctx1 = contextQueue.poll();
assertThat(ctx1, not(nullValue()));
// RetryingHttpRequesterFilter or AutoRetry may re-issue the request if a failure is seen locally. Verify
// the last connection (used for second request) is different from the first.
ConnectionContext ctx2 = null;
ConnectionContext tmp;
while ((tmp = contextQueue.poll()) != null) {
ctx2 = tmp;
}
assertThat(ctx2, not(nullValue()));
assertThat(ctx1, not(equalTo(ctx2)));
assertThat(contextQueue, empty());
} finally {
server.close().sync();
}
}
use of io.servicetalk.transport.api.ConnectionContext in project servicetalk by apple.
the class ConnectionAcceptorFilterTest method testAppend.
@Test
void testAppend() throws Exception {
Deque<Integer> createOrder = new ArrayDeque<>();
Deque<Integer> connectOrder = new ArrayDeque<>();
class AcceptorOrder implements ConnectionAcceptor {
final int order;
ConnectionAcceptor original;
AcceptorOrder(int order, ConnectionAcceptor original) {
this.order = order;
this.original = original;
}
@Override
public Completable accept(ConnectionContext context) {
connectOrder.add(order);
return original.accept(context);
}
@Override
public Completable closeAsync() {
return Completable.completed();
}
}
class FilterOrder implements ConnectionAcceptorFactory {
final int order;
FilterOrder(int order) {
this.order = order;
}
@Override
public ConnectionAcceptor create(ConnectionAcceptor original) {
createOrder.add(order);
return new AcceptorOrder(order, original);
}
}
FilterOrder first = new FilterOrder(1);
FilterOrder second = new FilterOrder(2);
ConnectionAcceptorFactory combined = first.append(second);
ConnectionAcceptor acceptor = combined.create(ConnectionAcceptor.ACCEPT_ALL);
@SuppressWarnings("unused") Void nothing = acceptor.accept(mock(ConnectionContext.class)).toFuture().get();
assertThat(nothing, is(nullValue()));
assertThat(createOrder, is(hasSize(2)));
assertThat(createOrder, is(containsInRelativeOrder(2, 1)));
assertThat(connectOrder, is(hasSize(2)));
assertThat(connectOrder, is(containsInRelativeOrder(1, 2)));
}
use of io.servicetalk.transport.api.ConnectionContext in project servicetalk by apple.
the class DefaultJerseyStreamingHttpRouter method handle0.
private void handle0(final HttpServiceContext serviceCtx, final StreamingHttpRequest req, final StreamingHttpResponseFactory factory, final Subscriber<? super StreamingHttpResponse> subscriber, final DelayedCancellable delayedCancellable) {
final CharSequence baseUri = baseUriFunction.apply(serviceCtx, req);
final CharSequence requestTarget = req.requestTarget();
final StringBuilder requestUriBuilder = new StringBuilder(baseUri.length() + requestTarget.length()).append(baseUri);
// Jersey expects the baseUri ends in a '/' and if not will return 404s
assert baseUri.length() == 0 || baseUri.charAt(baseUri.length() - 1) == '/';
if (requestTarget.length() > 0 && requestTarget.charAt(0) == '/') {
requestUriBuilder.append(requestTarget, 1, requestTarget.length());
} else {
requestUriBuilder.append(requestTarget);
}
final URI baseURI;
final URI requestURI;
try {
baseURI = URI.create(baseUri.toString());
requestURI = URI.create(requestUriBuilder.toString());
} catch (IllegalArgumentException cause) {
Buffer message = serviceCtx.executionContext().bufferAllocator().fromAscii(cause.getMessage());
StreamingHttpResponse response = factory.badRequest().payloadBody(from(message));
response.headers().set(CONTENT_LENGTH, Integer.toString(message.readableBytes()));
response.headers().set(CONTENT_TYPE, TEXT_PLAIN);
subscriber.onSuccess(response);
return;
}
final ContainerRequest containerRequest = new CloseSignalHandoffAbleContainerRequest(baseURI, requestURI, req.method().name(), UNAUTHENTICATED_SECURITY_CONTEXT, new MapPropertiesDelegate(), new ResourceConfig());
req.headers().forEach(h -> containerRequest.getHeaders().add(h.getKey().toString(), h.getValue().toString()));
final BufferPublisherInputStream entityStream = new BufferPublisherInputStream(req.payloadBody(), publisherInputStreamQueueCapacity);
containerRequest.setEntityStream(entityStream);
initRequestProperties(entityStream, containerRequest);
final DefaultContainerResponseWriter responseWriter = new DefaultContainerResponseWriter(containerRequest, req.version(), serviceCtx, factory, subscriber);
containerRequest.setWriter(responseWriter);
containerRequest.setRequestScopedInitializer(injectionManager -> {
injectionManager.<Ref<ConnectionContext>>getInstance(CONNECTION_CONTEXT_REF_TYPE).set(serviceCtx);
injectionManager.<Ref<StreamingHttpRequest>>getInstance(HTTP_REQUEST_REF_TYPE).set(req);
});
delayedCancellable.delayedCancellable(responseWriter::dispose);
applicationHandler.handle(containerRequest);
}
Aggregations