Skip to content

Commit bd3af79

Browse files
committed
Better terminal state tracking to avoid closing and releasing channel multiple times
1 parent bd3c7b4 commit bd3af79

File tree

1 file changed

+10
-4
lines changed
  • http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal

1 file changed

+10
-4
lines changed

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ResponseHandler.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private static class PublisherAdapter implements Publisher<ByteBuffer> {
179179
private final StreamedHttpResponse response;
180180
private final ChannelHandlerContext channelContext;
181181
private final RequestContext requestContext;
182-
private final AtomicBoolean isCancelled = new AtomicBoolean(false);
182+
private final AtomicBoolean isDone = new AtomicBoolean(false);
183183

184184
private PublisherAdapter(StreamedHttpResponse response, ChannelHandlerContext channelContext,
185185
RequestContext requestContext) {
@@ -209,8 +209,10 @@ private Subscription resolveSubscription(Subscription subscription) {
209209
}
210210

211211
private void onCancel() {
212+
if (!isDone.compareAndSet(false, true)) {
213+
return;
214+
}
212215
try {
213-
isCancelled.set(true);
214216
requestContext.handler().exceptionOccurred(
215217
new SdkCancellationException("Subscriber cancelled before all events were published"));
216218
} finally {
@@ -221,6 +223,10 @@ private void onCancel() {
221223

222224
@Override
223225
public void onNext(HttpContent httpContent) {
226+
// isDone may be true if the subscriber cancelled
227+
if (isDone.get()) {
228+
return;
229+
}
224230
// Needed to prevent use-after-free bug if the subscriber's onNext is asynchronous
225231
ByteBuffer b = copyToByteBuffer(httpContent.content());
226232
httpContent.release();
@@ -230,7 +236,7 @@ public void onNext(HttpContent httpContent) {
230236

231237
@Override
232238
public void onError(Throwable t) {
233-
if (isCancelled.get()) {
239+
if (!isDone.compareAndSet(false, true)) {
234240
return;
235241
}
236242
try {
@@ -247,7 +253,7 @@ public void onError(Throwable t) {
247253
public void onComplete() {
248254
// For HTTP/2 it's possible to get an onComplete after we cancel due to the channel becoming
249255
// inactive. We guard against that here and just ignore the signal (see HandlerPublisher)
250-
if (isCancelled.get()) {
256+
if (!isDone.compareAndSet(false, true)) {
251257
return;
252258
}
253259
try {

0 commit comments

Comments
 (0)