use of io.servicetalk.http.api.StreamingHttpClientFilter 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.StreamingHttpClientFilter in project servicetalk by apple.
the class ClientEffectiveStrategyTest method clientStrategy.
@ParameterizedTest(name = "API={0} builder={1} filter={2} LB={3} CF={4}")
@MethodSource("casesSupplier")
void clientStrategy(ClientType clientType, @Nullable final HttpExecutionStrategy builderStrategy, @Nullable final HttpExecutionStrategy filterStrategy, @Nullable final HttpExecutionStrategy lbStrategy, @Nullable final HttpExecutionStrategy cfStrategy) throws Exception {
HttpExecutionStrategy effectiveStrategy = computeClientExecutionStrategy(builderStrategy, filterStrategy, lbStrategy, cfStrategy);
SingleAddressHttpClientBuilder<HostAndPort, InetSocketAddress> clientBuilder = HttpClients.forSingleAddress(serverHostAndPort(context));
if (builderStrategy != null) {
clientBuilder.executionStrategy(builderStrategy);
}
ClientInvokingThreadRecorder invokingThreadsRecorder = new ClientInvokingThreadRecorder(clientType, effectiveStrategy);
clientBuilder.appendClientFilter(invokingThreadsRecorder);
if (null != filterStrategy) {
clientBuilder.appendClientFilter(new StreamingHttpClientFilterFactory() {
@Override
public StreamingHttpClientFilter create(final FilterableStreamingHttpClient client) {
return new StreamingHttpClientFilter(client) {
};
}
@Override
public HttpExecutionStrategy requiredOffloads() {
return filterStrategy;
}
});
}
if (null != lbStrategy) {
HttpLoadBalancerFactory<InetSocketAddress> lfFactory = DefaultHttpLoadBalancerFactory.Builder.from(new LoadBalancerFactoryImpl() {
@Override
public ExecutionStrategy requiredOffloads() {
return lbStrategy;
}
}).build();
clientBuilder.loadBalancerFactory(lfFactory);
}
if (null != cfStrategy) {
clientBuilder.appendConnectionFilter(new StreamingHttpConnectionFilterFactory() {
@Override
public StreamingHttpConnectionFilter create(final FilterableStreamingHttpConnection connection) {
return new StreamingHttpConnectionFilter(connection) {
};
}
@Override
public HttpExecutionStrategy requiredOffloads() {
return cfStrategy;
}
});
}
// Exercise the client
try (StreamingHttpClient client = clientBuilder.buildStreaming()) {
String responseBody = getResponse(clientType, client);
assertThat(responseBody, is(GREETING));
invokingThreadsRecorder.verifyOffloads();
}
}
use of io.servicetalk.http.api.StreamingHttpClientFilter in project servicetalk by apple.
the class EnforceSequentialModeRequesterFilterTest method responseNeverCompletesIfRequestPayloadBodyNeverCompletes.
@Test
void responseNeverCompletesIfRequestPayloadBodyNeverCompletes() {
StreamingHttpRequest request = REQ_RES_FACTORY.post("/").payloadBody(never());
StreamingHttpClientFilter client = EnforceSequentialModeRequesterFilter.INSTANCE.create(this.client);
AssertionError e = assertThrows(AssertionError.class, () -> StepVerifiers.create(client.request(request)).expectCancellable().expectSuccess().verify(Duration.ofMillis(100)));
assertThat(e.getCause(), instanceOf(TimeoutException.class));
}
use of io.servicetalk.http.api.StreamingHttpClientFilter in project servicetalk by apple.
the class ServiceTalkContentEncodingTest method runTest.
@Override
protected void runTest(final HttpProtocol protocol, final Encoder clientEncoding, final Decoders clientDecoder, final Encoders serverEncoder, final Decoders serverDecoder, boolean valid) throws Throwable {
try (ServerContext serverContext = HttpServers.forAddress(localAddress(0)).protocols(protocol.config).appendServiceFilter(service -> new StreamingHttpServiceFilter(service) {
@Override
public Single<StreamingHttpResponse> handle(final HttpServiceContext ctx, final StreamingHttpRequest request, final StreamingHttpResponseFactory responseFactory) {
return delegate().handle(ctx, request, responseFactory).map(resp -> {
// content encoding should be stripped by the time the decoding is done.
assertThat(resp.headers().get(ACCEPT_ENCODING), nullValue());
CharSequence contentEncoding = resp.headers().get(CONTENT_ENCODING);
boolean found = contentEncoding == null && (serverEncoder.list.isEmpty() || !request.headers().contains(ACCEPT_ENCODING));
for (BufferEncoder be : serverEncoder.list) {
if (contentEncoding == null && contentEqualsIgnoreCase(be.encodingName(), identityEncoder().encodingName()) || contentEncoding != null && contentEqualsIgnoreCase(be.encodingName(), contentEncoding)) {
found = true;
break;
}
}
return found || !valid ? resp : responseFactory.ok().payloadBody(Publisher.from("server error: invalid " + CONTENT_ENCODING + ": " + contentEncoding), appSerializerUtf8FixLen());
}).onErrorReturn(AssertionError.class, cause -> responseFactory.ok().payloadBody(Publisher.from("server error: " + cause.toString()), appSerializerUtf8FixLen()));
}
}).appendServiceFilter(new ContentEncodingHttpServiceFilter(serverEncoder.list, serverDecoder.group)).listenBlockingAndAwait((ctx, request, responseFactory) -> {
String requestPayload = request.payloadBody(textSerializerUtf8());
if (payloadAsString((byte) 'a').equals(requestPayload)) {
return responseFactory.ok().payloadBody(payloadAsString((byte) 'b'), textSerializerUtf8());
} else {
return responseFactory.badRequest().payloadBody(requestPayload, textSerializerUtf8());
}
});
BlockingHttpClient client = HttpClients.forSingleAddress(serverHostAndPort(serverContext)).protocols(protocol.config).appendClientFilter(new ContentEncodingHttpRequesterFilter(clientDecoder.group)).appendClientFilter(c -> new StreamingHttpClientFilter(c) {
@Override
protected Single<StreamingHttpResponse> request(final StreamingHttpRequester delegate, final StreamingHttpRequest request) {
return Single.defer(() -> {
assertHeader(() -> clientEncoding.encoder == null ? null : clientEncoding.encoder.encodingName(), request.headers().get(CONTENT_ENCODING), true);
assertHeader(clientDecoder.group::advertisedMessageEncoding, request.headers().get(ACCEPT_ENCODING), false);
return delegate.request(request).shareContextOnSubscribe();
});
}
}).buildBlocking()) {
HttpResponse response = client.request(client.get("/").contentEncoding(clientEncoding.encoder).payloadBody(payloadAsString((byte) 'a'), textSerializerUtf8()));
if (valid) {
assertThat(response.status(), is(OK));
// content encoding should be stripped by the time the decoding is done.
assertThat(response.headers().get(CONTENT_ENCODING), nullValue());
assertEquals(payloadAsString((byte) 'b'), response.payloadBody(textSerializerUtf8()));
} else {
assertThat(response.status(), is(UNSUPPORTED_MEDIA_TYPE));
}
}
}
Aggregations