Skip to content

Commit 0bd018d

Browse files
Ensure JsonSequenceResponseConsumer completes callback on error responses (#641)
or without issue ID: Fixed callback completion in JsonSequenceResponseConsumer on error responses
1 parent edb6a36 commit 0bd018d

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

httpcore5-jackson2/src/main/java/org/apache/hc/core5/jackson2/http/JsonSequenceResponseConsumer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public void completed(final E result) {
8181
if (errorCallback != null) {
8282
errorCallback.execute(result);
8383
}
84+
if (resultCallback != null) {
85+
// Error content has been fully processed, signal exchange completion.
86+
resultCallback.completed(null);
87+
}
8488
}
8589

8690
});

httpcore5-jackson2/src/test/java/org/apache/hc/core5/jackson2/http/JsonResponseConsumersTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
package org.apache.hc.core5.jackson2.http;
2828

2929
import java.io.InputStream;
30+
import java.net.URI;
3031
import java.net.URL;
3132
import java.nio.ByteBuffer;
3233
import java.nio.charset.StandardCharsets;
3334
import java.util.Collections;
3435
import java.util.LinkedList;
3536
import java.util.List;
37+
import java.util.concurrent.atomic.AtomicBoolean;
3638
import java.util.concurrent.atomic.AtomicReference;
3739

3840
import com.fasterxml.jackson.core.JsonFactory;
@@ -47,6 +49,7 @@
4749
import org.apache.hc.core5.http.UnsupportedMediaTypeException;
4850
import org.apache.hc.core5.http.impl.BasicEntityDetails;
4951
import org.apache.hc.core5.http.message.BasicHttpResponse;
52+
import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
5053
import org.apache.hc.core5.http.nio.AsyncResponseConsumer;
5154
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
5255
import org.apache.hc.core5.http.protocol.HttpCoreContext;
@@ -362,4 +365,53 @@ void testResponseJsonTokenContentCorrectlyProcessed() throws Exception {
362365
Mockito.verifyNoMoreInteractions(mockJsonTokenConsumer);
363366
}
364367

368+
@Test
369+
void testAsyncPipelineErrorResponseInvokesErrorCallbackAndSignalsResultCallback() throws Exception {
370+
final String errorBody = "Unexpected internal failure";
371+
final AtomicReference<String> errorRef = new AtomicReference<>();
372+
final AtomicBoolean completed = new AtomicBoolean();
373+
final AtomicBoolean failed = new AtomicBoolean();
374+
final AtomicBoolean cancelled = new AtomicBoolean();
375+
final AsyncClientExchangeHandler exchangeHandler = AsyncJsonClientPipeline.assemble(objectMapper)
376+
.request()
377+
.get(URI.create("http://localhost/test"))
378+
.response()
379+
.asSequence(
380+
RequestData.class,
381+
response -> {
382+
},
383+
error -> errorRef.set(error != null ? error.asText() : null),
384+
requestData -> {
385+
})
386+
.result(new FutureCallback<Long>() {
387+
@Override
388+
public void completed(final Long result) {
389+
completed.set(true);
390+
}
391+
392+
@Override
393+
public void failed(final Exception ex) {
394+
failed.set(true);
395+
}
396+
397+
@Override
398+
public void cancelled() {
399+
cancelled.set(true);
400+
}
401+
})
402+
.create();
403+
404+
exchangeHandler.consumeResponse(
405+
BasicResponseBuilder.create(500).build(),
406+
new BasicEntityDetails(errorBody.length(), ContentType.TEXT_PLAIN),
407+
HttpCoreContext.create());
408+
exchangeHandler.consume(ByteBuffer.wrap(errorBody.getBytes(StandardCharsets.UTF_8)));
409+
exchangeHandler.streamEnd(Collections.emptyList());
410+
411+
Assertions.assertThat(errorRef.get()).isEqualTo(errorBody);
412+
Assertions.assertThat(completed.get()).isTrue();
413+
Assertions.assertThat(failed.get()).isFalse();
414+
Assertions.assertThat(cancelled.get()).isFalse();
415+
}
416+
365417
}

0 commit comments

Comments
 (0)