diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index 445383a38c0..1832ee74e41 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -510,21 +510,12 @@ public class HttpRequest implements Request @Override public Request onResponseContent(final Response.ContentListener listener) { - this.responseListeners.add(new Response.DemandedContentListener() + this.responseListeners.add(new Response.ContentListener() { @Override - public void onContent(Response response, LongConsumer demand, ByteBuffer content, Callback callback) + public void onContent(Response response, ByteBuffer content) { - try - { - listener.onContent(response, content); - callback.succeeded(); - demand.accept(1); - } - catch (Throwable x) - { - callback.failed(x); - } + listener.onContent(response, content); } }); return this; @@ -533,16 +524,12 @@ public class HttpRequest implements Request @Override public Request onResponseContentAsync(final Response.AsyncContentListener listener) { - this.responseListeners.add(new Response.DemandedContentListener() + this.responseListeners.add(new Response.AsyncContentListener() { @Override - public void onContent(Response response, LongConsumer demand, ByteBuffer content, Callback callback) + public void onContent(Response response, ByteBuffer content, Callback callback) { - listener.onContent(response, content, Callback.from(() -> - { - callback.succeeded(); - demand.accept(1); - }, callback::failed)); + listener.onContent(response, content, callback); } }); return this; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java index 31adfc921bb..2f4b87eeb7b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java @@ -85,14 +85,14 @@ public interface Response /** * Common, empty, super-interface for response listeners */ - public interface ResponseListener extends EventListener + interface ResponseListener extends EventListener { } /** * Listener for the response begin event. */ - public interface BeginListener extends ResponseListener + interface BeginListener extends ResponseListener { /** * Callback method invoked when the response line containing HTTP version, @@ -102,13 +102,13 @@ public interface Response * * @param response the response containing the response line data */ - public void onBegin(Response response); + void onBegin(Response response); } /** * Listener for a response header event. */ - public interface HeaderListener extends ResponseListener + interface HeaderListener extends ResponseListener { /** * Callback method invoked when a response header has been received and parsed, @@ -118,20 +118,20 @@ public interface Response * @param field the header received * @return true to process the header, false to skip processing of the header */ - public boolean onHeader(Response response, HttpField field); + boolean onHeader(Response response, HttpField field); } /** * Listener for the response headers event. */ - public interface HeadersListener extends ResponseListener + interface HeadersListener extends ResponseListener { /** * Callback method invoked when all the response headers have been received and parsed. * * @param response the response containing the response line data and the headers */ - public void onHeaders(Response response); + void onHeaders(Response response); } /** @@ -139,7 +139,7 @@ public interface Response * * @see AsyncContentListener */ - public interface ContentListener extends ResponseListener + interface ContentListener extends AsyncContentListener { /** * Callback method invoked when the response content has been received, parsed and there is demand. @@ -149,7 +149,21 @@ public interface Response * @param response the response containing the response line data and the headers * @param content the content bytes received */ - public void onContent(Response response, ByteBuffer content); + void onContent(Response response, ByteBuffer content); + + @Override + default void onContent(Response response, ByteBuffer content, Callback callback) + { + try + { + onContent(response, content); + callback.succeeded(); + } + catch (Throwable x) + { + callback.failed(x); + } + } } /** @@ -157,7 +171,7 @@ public interface Response * * @see DemandedContentListener */ - public interface AsyncContentListener extends ResponseListener + interface AsyncContentListener extends DemandedContentListener { /** * Callback method invoked when the response content has been received, parsed and there is demand. @@ -168,13 +182,23 @@ public interface Response * @param content the content bytes received * @param callback the callback to call when the content is consumed and to demand more content */ - public void onContent(Response response, ByteBuffer content, Callback callback); + void onContent(Response response, ByteBuffer content, Callback callback); + + @Override + default void onContent(Response response, LongConsumer demand, ByteBuffer content, Callback callback) + { + onContent(response, content, Callback.from(() -> + { + callback.succeeded(); + demand.accept(1); + }, callback::failed)); + } } /** * Asynchronous listener for the response content events. */ - public interface DemandedContentListener extends ResponseListener + interface DemandedContentListener extends ResponseListener { /** * Callback method invoked before response content events. @@ -186,7 +210,7 @@ public interface Response * @param response the response containing the response line data and the headers * @param demand the object that allows to demand content buffers */ - public default void onBeforeContent(Response response, LongConsumer demand) + default void onBeforeContent(Response response, LongConsumer demand) { demand.accept(1); } @@ -203,26 +227,26 @@ public interface Response * @param content the content bytes received * @param callback the callback to call when the content is consumed */ - public void onContent(Response response, LongConsumer demand, ByteBuffer content, Callback callback); + void onContent(Response response, LongConsumer demand, ByteBuffer content, Callback callback); } /** * Listener for the response succeeded event. */ - public interface SuccessListener extends ResponseListener + interface SuccessListener extends ResponseListener { /** * Callback method invoked when the whole response has been successfully received. * * @param response the response containing the response line data and the headers */ - public void onSuccess(Response response); + void onSuccess(Response response); } /** * Listener for the response failure event. */ - public interface FailureListener extends ResponseListener + interface FailureListener extends ResponseListener { /** * Callback method invoked when the response has failed in the process of being received @@ -230,13 +254,13 @@ public interface Response * @param response the response containing data up to the point the failure happened * @param failure the failure happened */ - public void onFailure(Response response, Throwable failure); + void onFailure(Response response, Throwable failure); } /** * Listener for the request and response completed event. */ - public interface CompleteListener extends ResponseListener + interface CompleteListener extends ResponseListener { /** * Callback method invoked when the request and the response have been processed, @@ -252,13 +276,13 @@ public interface Response * * @param result the result of the request / response exchange */ - public void onComplete(Result result); + void onComplete(Result result); } /** * Listener for all response events. */ - public interface Listener extends BeginListener, HeaderListener, HeadersListener, ContentListener, AsyncContentListener, DemandedContentListener, SuccessListener, FailureListener, CompleteListener + interface Listener extends BeginListener, HeaderListener, HeadersListener, ContentListener, SuccessListener, FailureListener, CompleteListener { @Override public default void onBegin(Response response) @@ -276,41 +300,11 @@ public interface Response { } - @Override - public default void onBeforeContent(Response response, LongConsumer demand) - { - demand.accept(1); - } - @Override public default void onContent(Response response, ByteBuffer content) { } - @Override - public default void onContent(Response response, ByteBuffer content, Callback callback) - { - try - { - onContent(response, content); - callback.succeeded(); - } - catch (Throwable x) - { - callback.failed(x); - } - } - - @Override - public default void onContent(Response response, LongConsumer demand, ByteBuffer content, Callback callback) - { - onContent(response, content, Callback.from(() -> - { - callback.succeeded(); - demand.accept(1); - }, callback::failed)); - } - @Override public default void onSuccess(Response response) { @@ -329,7 +323,7 @@ public interface Response /** * An empty implementation of {@link Listener} */ - public static class Adapter implements Listener + class Adapter implements Listener { } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index 0330431a0de..f865b884272 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.client; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -84,6 +85,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.Net; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.IO; @@ -1784,6 +1786,57 @@ public class HttpClientTest extends AbstractHttpClientServerTest } } + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testContentListenerAsCompleteListener(Scenario scenario) throws Exception + { + byte[] bytes = new byte[1024]; + new Random().nextBytes(bytes); + start(scenario, new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + ServletOutputStream output = response.getOutputStream(); + output.write(bytes); + } + }); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CountDownLatch latch = new CountDownLatch(1); + class L implements Response.ContentListener, Response.CompleteListener + { + @Override + public void onContent(Response response, ByteBuffer content) + { + try + { + BufferUtil.writeTo(content, baos); + } + catch (IOException x) + { + baos.reset(); + x.printStackTrace(); + } + } + + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + latch.countDown(); + } + } + + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .send(new L()); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertArrayEquals(bytes, baos.toByteArray()); + } + private void assertCopyRequest(Request original) { Request copy = client.copyRequest((HttpRequest)original, original.getURI());