Skip to content

Commit

Permalink
Close and release channel upon validation failure (#3855)
Browse files Browse the repository at this point in the history
When content length validation fails when PublisherAdapter#onComplete is
invoked, behave as on PublisherAdapter#onError and also close and release the
channel; otherwise the channel would be left in the leased state forever.
  • Loading branch information
dagnir authored Mar 24, 2023
1 parent 33f6011 commit 0875b58
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changes/next-release/bugfix-NettyNIOHTTPClient-7b511ce.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "bugfix",
"category": "Netty NIO HTTP Client",
"contributor": "",
"description": "Fix a bug where, if validation of of the amount of expected data to be received (HTTP `Content-Length`) fails, the connection would be left dangling, consuming a connection from the pool until the client is shut down."
}
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ public void onComplete() {
}
} catch (IOException e) {
notifyError(e);
runAndLogError(channelContext.channel(), () -> "Could not release channel back to the pool",
() -> closeAndRelease(channelContext));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,56 @@ public void onComplete() {
}
}

@Test
public void contentLengthValidationFails_closesAndReleasesConnection() {
channel.attr(ChannelAttributeKey.RESPONSE_CONTENT_LENGTH).set(1L);
channel.attr(ChannelAttributeKey.RESPONSE_DATA_READ).set(0L);

Publisher<HttpContent> publisher = subscriber -> subscriber.onSubscribe(new Subscription() {
@Override
public void request(long l) {
subscriber.onComplete();
}

@Override
public void cancel() {
}
});

DefaultStreamedHttpResponse streamedResponse = new DefaultStreamedHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK, publisher);

Subscriber<ByteBuffer> subscriber = new Subscriber<ByteBuffer>() {
private Subscription subscription;

@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(Long.MAX_VALUE);
}

@Override
public void onNext(ByteBuffer byteBuffer) {
}

@Override
public void onError(Throwable throwable) {
}

@Override
public void onComplete() {
}
};

ResponseHandler.PublisherAdapter publisherAdapter = new ResponseHandler.PublisherAdapter(streamedResponse, ctx,
requestContext, executeFuture);

publisherAdapter.subscribe(subscriber);

verify(ctx).close();
verify(channelPool).release(channel);
}

static final class TestSubscriber implements Subscriber<ByteBuffer> {

private Subscription subscription;
Expand Down

0 comments on commit 0875b58

Please sign in to comment.