use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.
the class ClientStrategyInfluencerChainBuilder method add.
void add(StreamingHttpConnectionFilterFactory connectionFilter) {
HttpExecutionStrategy filterOffloads = connectionFilter.requiredOffloads();
if (offloadNever() == filterOffloads) {
LOGGER.warn("{}#requiredOffloads() returns offloadNever(), which is unexpected. " + "offloadNone() should be used instead. " + "Making automatic adjustment, consider updating the filter.", connectionFilter);
filterOffloads = offloadNone();
}
if (defaultStrategy() == filterOffloads) {
LOGGER.warn("{}#requiredOffloads() returns defaultStrategy(), which is unexpected. " + "offloadAll() (safe default) or more appropriate custom strategy should be used instead." + "Making automatic adjustment, consider updating the filter.", connectionFilter);
filterOffloads = offloadAll();
}
if (filterOffloads.hasOffloads()) {
connFilterChain = null != connFilterChain ? connFilterChain.merge(filterOffloads) : filterOffloads;
}
}
use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.
the class DefaultContainerResponseWriter method sendResponse.
private void sendResponse(final long contentLength, @Nullable final Publisher<Buffer> content, final ContainerResponse containerResponse) {
final HttpResponseStatus status = getStatus(containerResponse);
final StreamingHttpResponse response;
if (content != null && !isHeadRequest()) {
final HttpExecutionStrategy executionStrategy = getResponseExecutionStrategy(request);
// TODO(scott): use request factory methods that accept a payload body to avoid overhead of payloadBody.
final Publisher<Buffer> payloadBody = (executionStrategy != null && executionStrategy.isSendOffloaded() ? content.subscribeOn(serviceCtx.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread) : content).beforeCancel(// Cleanup internal state if server cancels response body
this::cancelResponse);
response = responseFactory.newResponse(status).version(protocolVersion).payloadBody(payloadBody);
} else {
response = responseFactory.newResponse(status).version(protocolVersion);
}
final HttpHeaders headers = response.headers();
// If we use HTTP/2 protocol all headers MUST be in lower case
final boolean isH2 = response.version().major() == 2;
containerResponse.getHeaders().forEach((k, vs) -> vs.forEach(v -> {
headers.add(isH2 ? k.toLowerCase() : k, v == null ? emptyAsciiString() : asCharSequence(v));
}));
if (!headers.contains(CONTENT_LENGTH)) {
if (contentLength == UNKNOWN_RESPONSE_LENGTH) {
// We can omit Transfer-Encoding for HEAD per https://tools.ietf.org/html/rfc7231#section-4.3.2
if (!isHeadRequest() && !HTTP_1_0.equals(protocolVersion)) {
headers.set(TRANSFER_ENCODING, CHUNKED);
}
} else {
headers.set(CONTENT_LENGTH, contentLength == 0 ? ZERO : Long.toString(contentLength));
headers.removeIgnoreCase(TRANSFER_ENCODING, CHUNKED);
}
}
responseSubscriber.onSuccess(response);
}
use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.
the class DefaultMultiAddressUrlHttpClientBuilderTest method internalClientsUseDifferentExecutionContextWhenConfigured.
@Test
void internalClientsUseDifferentExecutionContextWhenConfigured() throws Exception {
// Assert prerequisites first.
// Use different strategies, as ExecutionContextExtension shares the same strategy.
HttpExecutionStrategy internalExecutionStrategy = HttpExecutionStrategies.customStrategyBuilder().offloadNone().build();
HttpExecutionStrategy externalExecutionStrategy = HttpExecutionStrategies.customStrategyBuilder().offloadAll().build();
assertThat(internalExecutionStrategy, not(equalTo(externalExecutionStrategy)));
BufferAllocator internalBufferAllocator = BufferAllocators.PREFER_DIRECT_ALLOCATOR;
BufferAllocator externalBufferAllocator = BufferAllocators.PREFER_HEAP_ALLOCATOR;
assertThat(internalBufferAllocator, not(equalTo(externalBufferAllocator)));
assertThat(CTX.executor(), not(equalTo(INTERNAL_CLIENT_CTX.executor())));
assertThat(CTX.ioExecutor(), not(equalTo(INTERNAL_CLIENT_CTX.ioExecutor())));
try (ServerContext serverContext = HttpServers.forAddress(localAddress(0)).executionStrategy(offloadNever()).listenStreamingAndAwait((ctx, request, responseFactory) -> succeeded(responseFactory.ok()))) {
AtomicReference<BufferAllocator> actualInternalBufferAllocator = new AtomicReference<>();
AtomicReference<IoExecutor> actualInternalIoExecutor = new AtomicReference<>();
AtomicReference<Executor> actualInternalExecutor = new AtomicReference<>();
AtomicReference<ExecutionStrategy> actualInternalExecutionStrategy = new AtomicReference<>();
final StreamingHttpClient streamingHttpClient = HttpClients.forMultiAddressUrl().initializer((scheme, address, builder) -> builder.executionStrategy(internalExecutionStrategy).executor(INTERNAL_CLIENT_CTX.executor()).ioExecutor(INTERNAL_CLIENT_CTX.ioExecutor()).bufferAllocator(internalBufferAllocator).executionStrategy(internalExecutionStrategy).appendClientFilter(client -> {
HttpExecutionContext internalContext = client.executionContext();
actualInternalBufferAllocator.set(internalContext.bufferAllocator());
actualInternalExecutor.set(internalContext.executor());
actualInternalIoExecutor.set(internalContext.ioExecutor());
actualInternalExecutionStrategy.set(internalContext.executionStrategy());
return new StreamingHttpClientFilter(client) {
};
})).executor(CTX.executor()).ioExecutor(CTX.ioExecutor()).executionStrategy(externalExecutionStrategy).bufferAllocator(externalBufferAllocator).buildStreaming();
assertNotNull(streamingHttpClient);
// Check external client
final HttpExecutionContext executionContext = streamingHttpClient.executionContext();
assertThat(executionContext.executor(), equalTo(CTX.executor()));
assertThat(executionContext.executionStrategy(), equalTo(externalExecutionStrategy));
assertThat(executionContext.ioExecutor(), equalTo(CTX.ioExecutor()));
assertThat(executionContext.bufferAllocator(), equalTo(CTX.bufferAllocator()));
// Make a request to trigger the filter execution that extracts the execution context.
final HostAndPort address = HostAndPort.of((InetSocketAddress) serverContext.listenAddress());
streamingHttpClient.reserveConnection(streamingHttpClient.get("http://" + address)).toFuture().get();
// Check internal client
assertThat(actualInternalBufferAllocator.get(), equalTo(internalBufferAllocator));
assertThat(actualInternalExecutor.get(), equalTo(INTERNAL_CLIENT_CTX.executor()));
assertThat(actualInternalIoExecutor.get(), equalTo(INTERNAL_CLIENT_CTX.ioExecutor()));
assertThat(actualInternalExecutionStrategy.get(), equalTo(internalExecutionStrategy));
streamingHttpClient.closeAsync().toFuture().get();
}
}
use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.
the class ExecutionStrategyInContextTest method testAsync.
@ParameterizedTest(name = "customStrategy={0}")
@ValueSource(booleans = { false, true })
void testAsync(boolean customStrategy) throws Exception {
HttpClient client = initClientAndServer(builder -> builder.listen((ctx, request, responseFactory) -> {
serviceStrategyRef.set(ctx.executionContext().executionStrategy());
return succeeded(responseFactory.ok());
}), customStrategy).build();
clientAsCloseable = client;
if (!customStrategy) {
assert expectedClientStrategy == null;
expectedClientStrategy = customStrategyBuilder().offloadReceiveData().offloadEvent().build();
assert expectedServerStrategy == null;
expectedServerStrategy = customStrategyBuilder().offloadReceiveData().offloadSend().build();
}
HttpExecutionStrategy clientStrat = client.executionContext().executionStrategy();
assertThat("Unexpected client strategy.", clientStrat, equalStrategies(expectedClientStrategy));
client.request(client.get("/")).toFuture().get();
assertThat("Unexpected service strategy", serviceStrategyRef.get(), equalStrategies(expectedServerStrategy));
ReservedHttpConnection conn = client.reserveConnection(client.get("/")).toFuture().get();
assertThat("Unexpected connection strategy (from execution context).", conn.executionContext().executionStrategy(), equalStrategies(expectedClientStrategy));
assertThat("Unexpected connection strategy (from execution context).", conn.connectionContext().executionContext().executionStrategy(), equalStrategies(expectedClientStrategy));
}
use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.
the class ExecutionStrategyInContextTest method testBlockingStreaming.
@ParameterizedTest(name = "customStrategy={0}")
@ValueSource(booleans = { false, true })
void testBlockingStreaming(boolean customStrategy) throws Exception {
BlockingStreamingHttpClient client = initClientAndServer(builder -> {
if (customStrategy) {
// Ensure we don't deadlock by not offloading receive meta
expectedServerStrategy = customStrategyBuilder().offloadReceiveMetadata().build();
builder.executionStrategy(expectedServerStrategy);
}
return builder.listenBlockingStreaming((ctx, request, response) -> {
serviceStrategyRef.set(ctx.executionContext().executionStrategy());
response.sendMetaData().close();
});
}, customStrategy).buildBlockingStreaming();
clientAsCloseable = client;
if (!customStrategy) {
assert expectedClientStrategy == null;
expectedClientStrategy = customStrategyBuilder().offloadSend().offloadEvent().build();
assert expectedServerStrategy == null;
expectedServerStrategy = customStrategyBuilder().offloadReceiveMetadata().build();
}
HttpExecutionStrategy clientStrat = client.executionContext().executionStrategy();
assertThat("Unexpected client strategy.", clientStrat, equalStrategies(expectedClientStrategy));
client.request(client.get("/"));
assertThat("Unexpected service strategy", serviceStrategyRef.get(), equalStrategies(expectedServerStrategy));
ReservedBlockingStreamingHttpConnection conn = client.reserveConnection(client.get("/"));
assertThat("Unexpected connection strategy (from execution context).", conn.executionContext().executionStrategy(), equalStrategies(expectedClientStrategy));
assertThat("Unexpected connection strategy (from execution context).", conn.connectionContext().executionContext().executionStrategy(), equalStrategies(expectedClientStrategy));
}
Aggregations