Skip to content

Commit 49bd6fe

Browse files
committed
Fixed a thread safety issue that could cause application to crash in the edge case in AWS CRT HTTP client
1 parent 4aeda8e commit 49bd6fe

File tree

4 files changed

+34
-21
lines changed

4 files changed

+34
-21
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "bugfix",
3+
"category": "AWS CRT HTTP Client",
4+
"contributor": "",
5+
"description": "Fixed a thread safety issue that could cause application to crash in the edge case where the SDK attempted to invoke `incrementWindow` after the stream is closed in AWS CRT HTTP Client."
6+
}

http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/response/CrtResponseAdapter.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,7 @@ public int onResponseBody(HttpStream stream, byte[] bodyBytesIn) {
9595
return;
9696
}
9797

98-
if (!responseHandlerHelper.connectionClosed().get()) {
99-
stream.incrementWindow(bodyBytesIn.length);
100-
}
98+
responseHandlerHelper.incrementWindow(stream, bodyBytesIn.length);
10199
});
102100

103101
return 0;

http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/response/InputStreamAdaptingHttpStreamResponseHandler.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,8 @@ public int onResponseBody(HttpStream stream, byte[] bodyBytesIn) {
101101
failFutureAndCloseConnection(stream, failure);
102102
return;
103103
}
104-
105-
if (!responseHandlerHelper.connectionClosed().get()) {
106-
// increment the window upon buffer consumption.
107-
stream.incrementWindow(bodyBytesIn.length);
108-
}
104+
// increment the window upon buffer consumption.
105+
responseHandlerHelper.incrementWindow(stream, bodyBytesIn.length);
109106
});
110107

111108
// Window will be incremented after the subscriber consumes the data, returning 0 here to disable it.

http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/response/ResponseHandlerHelper.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@
3030
*
3131
* CRT connection will only be closed, i.e., not reused, in one of the following conditions:
3232
* 1. 5xx server error OR
33-
* 2. It fails to read the response.
33+
* 2. It fails to read the response OR
34+
* 3. the response stream is closed/aborted by the caller.
3435
*/
3536
@SdkInternalApi
3637
public class ResponseHandlerHelper {
3738

3839
private final SdkHttpResponse.Builder responseBuilder;
3940
private final HttpClientConnection connection;
40-
private AtomicBoolean connectionClosed = new AtomicBoolean(false);
41+
private boolean connectionClosed;
42+
private final Object lock = new Object();
4143

4244
public ResponseHandlerHelper(SdkHttpResponse.Builder responseBuilder, HttpClientConnection connection) {
4345
this.responseBuilder = responseBuilder;
@@ -57,20 +59,34 @@ public void onResponseHeaders(HttpStream stream, int responseStatusCode, int hea
5759
* Release the connection back to the pool so that it can be reused.
5860
*/
5961
public void releaseConnection(HttpStream stream) {
60-
if (connectionClosed.compareAndSet(false, true)) {
61-
connection.close();
62-
stream.close();
62+
synchronized (lock) {
63+
if (!connectionClosed) {
64+
connectionClosed = true;
65+
connection.close();
66+
stream.close();
67+
}
68+
}
69+
}
70+
71+
public void incrementWindow(HttpStream stream, int windowSize) {
72+
synchronized (lock) {
73+
if (!connectionClosed) {
74+
stream.incrementWindow(windowSize);
75+
}
6376
}
6477
}
6578

6679
/**
6780
* Close the connection completely
6881
*/
6982
public void closeConnection(HttpStream stream) {
70-
if (connectionClosed.compareAndSet(false, true)) {
71-
connection.shutdown();
72-
connection.close();
73-
stream.close();
83+
synchronized (lock) {
84+
if (!connectionClosed) {
85+
connectionClosed = true;
86+
connection.shutdown();
87+
connection.close();
88+
stream.close();
89+
}
7490
}
7591
}
7692

@@ -82,8 +98,4 @@ public void cleanUpConnectionBasedOnStatusCode(HttpStream stream) {
8298
releaseConnection(stream);
8399
}
84100
}
85-
86-
public AtomicBoolean connectionClosed() {
87-
return connectionClosed;
88-
}
89101
}

0 commit comments

Comments
 (0)