Classic ExecRuntime to support information responses (1xx)

This commit is contained in:
Oleg Kalnichevski 2024-01-17 16:58:46 +01:00
parent 7cf469c5cc
commit 1111c62dd3
5 changed files with 58 additions and 9 deletions

View File

@ -57,6 +57,7 @@ import org.apache.hc.core5.http.URIScheme;
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
import org.apache.hc.core5.http.io.HttpClientConnection;
import org.apache.hc.core5.http.io.HttpRequestHandler;
import org.apache.hc.core5.http.io.HttpResponseInformationCallback;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.InputStreamEntity;
import org.apache.hc.core5.http.io.entity.StringEntity;
@ -137,8 +138,17 @@ public abstract class TestClientRequestExecution {
final ClassicHttpRequest request,
final HttpClientConnection conn,
final HttpContext context) throws IOException, HttpException {
return execute(request, conn, null, context);
}
final ClassicHttpResponse response = super.execute(request, conn, context);
@Override
public ClassicHttpResponse execute(
final ClassicHttpRequest request,
final HttpClientConnection conn,
final HttpResponseInformationCallback informationCallback,
final HttpContext context) throws IOException, HttpException {
final ClassicHttpResponse response = super.execute(request, conn, informationCallback, context);
final Object marker = context.getAttribute(MARKER);
if (marker == null) {
context.setAttribute(MARKER, Boolean.TRUE);

View File

@ -37,6 +37,7 @@ import org.apache.hc.core5.concurrent.CancellableDependency;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.io.HttpResponseInformationCallback;
import org.apache.hc.core5.util.TimeValue;
/**
@ -141,6 +142,24 @@ public interface ExecRuntime {
ClassicHttpRequest request,
HttpClientContext context) throws IOException, HttpException;
/**
* Executes HTTP request using the given context.
*
* @param id unique operation ID or {@code null}.
* @param request the request message.
* @param informationCallback information (1xx) response handler
* @param context the execution context.
*
* @since 5.4
*/
default ClassicHttpResponse execute(
String id,
ClassicHttpRequest request,
HttpResponseInformationCallback informationCallback,
HttpClientContext context) throws IOException, HttpException {
return execute(id, request, context);
}
/**
* Determines of the connection is considered re-usable.
*

View File

@ -48,6 +48,7 @@ import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
import org.apache.hc.core5.http.io.HttpResponseInformationCallback;
import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.TimeValue;
@ -205,6 +206,15 @@ class InternalExecRuntime implements ExecRuntime, Cancellable {
final String id,
final ClassicHttpRequest request,
final HttpClientContext context) throws IOException, HttpException {
return execute(id, request, null, context);
}
@Override
public ClassicHttpResponse execute(
final String id,
final ClassicHttpRequest request,
final HttpResponseInformationCallback informationCallback,
final HttpClientContext context) throws IOException, HttpException {
final ConnectionEndpoint endpoint = ensureValid();
if (!endpoint.isConnected()) {
connectEndpoint(endpoint, context);
@ -223,7 +233,7 @@ class InternalExecRuntime implements ExecRuntime, Cancellable {
return endpoint.execute(
id,
request,
requestExecutor::execute,
(r, conn, c) -> requestExecutor.execute(r, conn, informationCallback, c),
context);
}

View File

@ -113,7 +113,7 @@ public final class MainClientExec implements ExecChainHandler {
httpProcessor.process(request, request.getEntity(), context);
final ClassicHttpResponse response = execRuntime.execute(exchangeId, request, context);
final ClassicHttpResponse response = execRuntime.execute(exchangeId, request, null, context);
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
httpProcessor.process(response, response.getEntity(), context);

View File

@ -97,13 +97,14 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenReturn(response);
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
Mockito.verify(httpProcessor).process(request, null, context);
Mockito.verify(execRuntime).execute("test", request, context);
Mockito.verify(execRuntime).execute("test", request, null, context);
Mockito.verify(httpProcessor).process(response, responseEntity, context);
Assertions.assertEquals(route, context.getHttpRoute());
@ -124,6 +125,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenReturn(response);
Mockito.when(reuseStrategy.keepAlive(
Mockito.same(request),
@ -132,7 +134,7 @@ public class TestMainClientExec {
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
Mockito.verify(execRuntime).execute("test", request, context);
Mockito.verify(execRuntime).execute("test", request, null, context);
Mockito.verify(execRuntime, Mockito.times(1)).markConnectionNonReusable();
Mockito.verify(execRuntime, Mockito.never()).releaseEndpoint();
@ -152,6 +154,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenReturn(response);
Mockito.when(reuseStrategy.keepAlive(
Mockito.same(request),
@ -161,7 +164,7 @@ public class TestMainClientExec {
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
Mockito.verify(execRuntime).execute("test", request, context);
Mockito.verify(execRuntime).execute("test", request, null, context);
Mockito.verify(execRuntime).markConnectionNonReusable();
Mockito.verify(execRuntime).releaseEndpoint();
@ -184,6 +187,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenReturn(response);
Mockito.when(reuseStrategy.keepAlive(
Mockito.same(request),
@ -196,7 +200,7 @@ public class TestMainClientExec {
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
Mockito.verify(execRuntime).execute("test", request, context);
Mockito.verify(execRuntime).execute("test", request, null, context);
Mockito.verify(execRuntime).markConnectionReusable(null, TimeValue.ofMilliseconds(678L));
Mockito.verify(execRuntime, Mockito.never()).releaseEndpoint();
@ -214,6 +218,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenReturn(response);
Mockito.when(reuseStrategy.keepAlive(
Mockito.same(request),
@ -226,7 +231,7 @@ public class TestMainClientExec {
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
Mockito.verify(execRuntime).execute("test", request, context);
Mockito.verify(execRuntime).execute("test", request, null, context);
Mockito.verify(execRuntime).releaseEndpoint();
Assertions.assertNotNull(finalResponse);
@ -247,6 +252,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenReturn(response);
Mockito.when(reuseStrategy.keepAlive(
Mockito.same(request),
@ -255,7 +261,7 @@ public class TestMainClientExec {
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
Mockito.verify(execRuntime, Mockito.times(1)).execute("test", request, context);
Mockito.verify(execRuntime, Mockito.times(1)).execute("test", request, null, context);
Mockito.verify(execRuntime, Mockito.never()).disconnectEndpoint();
Mockito.verify(execRuntime, Mockito.never()).releaseEndpoint();
@ -276,6 +282,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenThrow(new ConnectionShutdownException());
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
@ -293,6 +300,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenThrow(new RuntimeException("Ka-boom"));
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
@ -310,6 +318,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenThrow(new HttpException("Ka-boom"));
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
@ -327,6 +336,7 @@ public class TestMainClientExec {
Mockito.when(execRuntime.execute(
Mockito.anyString(),
Mockito.same(request),
Mockito.any(),
Mockito.any())).thenThrow(new IOException("Ka-boom"));
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);