Skip to content

Commit 3d05485

Browse files
authored
Merge branch 'master' into feature/master/synccrtclient
2 parents e4c8164 + 769e98b commit 3d05485

File tree

9 files changed

+150
-13
lines changed

9 files changed

+150
-13
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-based S3 Client",
4+
"contributor": "",
5+
"description": "Make sure all CRT resources are closed when the AWS CRT-based S3 client is closed."
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Bump `aws-crt` version to `0.29.1`."
6+
}

core/aws-core/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
<groupId>software.amazon.awssdk</groupId>
6868
<artifactId>http-auth-aws</artifactId>
6969
<version>${awsjavasdk.version}</version>
70+
<scope>test</scope>
7071
</dependency>
7172
<dependency>
7273
<groupId>software.amazon.awssdk</groupId>

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
<rxjava.version>2.2.21</rxjava.version>
120120
<commons-codec.verion>1.15</commons-codec.verion>
121121
<jmh.version>1.29</jmh.version>
122-
<awscrt.version>0.28.11</awscrt.version>
122+
<awscrt.version>0.29.1</awscrt.version>
123123

124124
<!--Test dependencies -->
125125
<junit5.version>5.10.0</junit5.version>

services/s3/src/it/java/software/amazon/awssdk/services/SelectObjectContentIntegrationTest.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.junit.jupiter.params.provider.MethodSource;
3131
import software.amazon.awssdk.core.async.SdkPublisher;
3232
import software.amazon.awssdk.core.sync.RequestBody;
33+
import software.amazon.awssdk.crt.CrtResource;
3334
import software.amazon.awssdk.services.s3.S3AsyncClient;
3435
import software.amazon.awssdk.services.s3.S3IntegrationTestBase;
3536
import software.amazon.awssdk.services.s3.model.CSVInput;
@@ -54,16 +55,19 @@ public class SelectObjectContentIntegrationTest extends S3IntegrationTestBase {
5455
+ "C,D";
5556
private static final String QUERY = "select s._1 from S3Object s";
5657

58+
private static S3AsyncClient s3CrtClient;
59+
5760
@BeforeAll
5861
public static void setup() throws Exception {
5962
S3IntegrationTestBase.setUp();
6063
s3.createBucket(r -> r.bucket(BUCKET_NAME));
6164
s3.waiter().waitUntilBucketExists(r -> r.bucket(BUCKET_NAME));
6265
s3.putObject(r -> r.bucket(BUCKET_NAME).key(KEY), RequestBody.fromString(CSV_CONTENTS));
66+
s3CrtClient = crtClientBuilder().build();
6367
}
6468

6569
private static Stream<S3AsyncClient> s3AsyncClients() {
66-
return Stream.of(crtClientBuilder().build(), s3AsyncClientBuilder().build());
70+
return Stream.of(s3CrtClient, s3Async);
6771
}
6872

6973
@AfterAll
@@ -73,10 +77,11 @@ public static void teardown() {
7377
} finally {
7478
s3AsyncClients().forEach(SdkAutoCloseable::close);
7579
s3.close();
80+
CrtResource.waitForNoResources();
7681
}
7782
}
7883

79-
@ParameterizedTest
84+
@ParameterizedTest(autoCloseArguments = false)
8085
@MethodSource("s3AsyncClients")
8186
public void selectObjectContent_onResponseInvokedWithResponse(S3AsyncClient client) {
8287
TestHandler handler = new TestHandler();
@@ -85,7 +90,7 @@ public void selectObjectContent_onResponseInvokedWithResponse(S3AsyncClient clie
8590
assertThat(handler.response).isNotNull();
8691
}
8792

88-
@ParameterizedTest
93+
@ParameterizedTest(autoCloseArguments = false)
8994
@MethodSource("s3AsyncClients")
9095
public void selectObjectContent_recordsEventUnmarshalledCorrectly(S3AsyncClient client) {
9196
TestHandler handler = new TestHandler();
@@ -99,7 +104,7 @@ public void selectObjectContent_recordsEventUnmarshalledCorrectly(S3AsyncClient
99104
assertThat(recordsEvent.payload().asUtf8String()).contains("A\nC");
100105
}
101106

102-
@ParameterizedTest
107+
@ParameterizedTest(autoCloseArguments = false)
103108
@MethodSource("s3AsyncClients")
104109
public void selectObjectContent_invalidQuery_unmarshallsErrorResponse(S3AsyncClient client) {
105110
TestHandler handler = new TestHandler();

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3CrtAsyncHttpClient.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public CompletableFuture<Void> execute(AsyncExecuteRequest asyncRequest) {
147147
checksumConfig(httpChecksum, requestType, s3NativeClientConfiguration.checksumValidationEnabled());
148148
URI endpoint = getEndpoint(uri);
149149

150-
AwsSigningConfig defaultS3SigningConfig = awsSigningConfig(signingRegion, httpExecutionAttributes);
150+
AwsSigningConfig signingConfig = awsSigningConfig(signingRegion, httpExecutionAttributes);
151151

152152
S3MetaRequestOptions requestOptions = new S3MetaRequestOptions()
153153
.withHttpRequest(httpRequest)
@@ -157,7 +157,7 @@ public CompletableFuture<Void> execute(AsyncExecuteRequest asyncRequest) {
157157
.withResponseHandler(responseHandler)
158158
.withResumeToken(resumeToken)
159159
.withRequestFilePath(requestFilePath)
160-
.withSigningConfig(defaultS3SigningConfig);
160+
.withSigningConfig(signingConfig);
161161

162162
S3MetaRequest s3MetaRequest = crtS3Client.makeMetaRequest(requestOptions);
163163
S3MetaRequestPauseObservable observable =
@@ -168,7 +168,7 @@ public CompletableFuture<Void> execute(AsyncExecuteRequest asyncRequest) {
168168
if (observable != null) {
169169
observable.subscribe(s3MetaRequest);
170170
}
171-
addCancelCallback(executeFuture, s3MetaRequest, responseHandler);
171+
closeResourceCallback(executeFuture, s3MetaRequest, responseHandler, signingConfig);
172172

173173
return executeFuture;
174174
}
@@ -214,14 +214,19 @@ private static S3MetaRequestOptions.MetaRequestType requestType(AsyncExecuteRequ
214214
return S3MetaRequestOptions.MetaRequestType.DEFAULT;
215215
}
216216

217-
private static void addCancelCallback(CompletableFuture<Void> executeFuture,
218-
S3MetaRequest s3MetaRequest,
219-
S3CrtResponseHandlerAdapter responseHandler) {
217+
private static void closeResourceCallback(CompletableFuture<Void> executeFuture,
218+
S3MetaRequest s3MetaRequest,
219+
S3CrtResponseHandlerAdapter responseHandler,
220+
AwsSigningConfig signingConfig) {
220221
executeFuture.whenComplete((r, t) -> {
221222
if (executeFuture.isCancelled()) {
222223
log.debug(() -> "The request is cancelled, cancelling meta request");
223224
responseHandler.cancelRequest();
224225
s3MetaRequest.cancel();
226+
signingConfig.close();
227+
} else {
228+
s3MetaRequest.close();
229+
signingConfig.close();
225230
}
226231
});
227232
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ public class S3NativeClientConfiguration implements SdkAutoCloseable {
5858
private final URI endpointOverride;
5959
private final boolean checksumValidationEnabled;
6060
private final Long readBufferSizeInBytes;
61-
6261
private final TlsContext tlsContext;
62+
63+
private final TlsContextOptions clientTlsContextOptions;
6364
private final HttpProxyOptions proxyOptions;
6465
private final Duration connectionTimeout;
6566
private final HttpMonitoringOptions httpMonitoringOptions;
@@ -70,7 +71,7 @@ public S3NativeClientConfiguration(Builder builder) {
7071
this.signingRegion = builder.signingRegion == null ? DefaultAwsRegionProviderChain.builder().build().getRegion().id() :
7172
builder.signingRegion;
7273
this.clientBootstrap = new ClientBootstrap(null, null);
73-
TlsContextOptions clientTlsContextOptions =
74+
clientTlsContextOptions =
7475
TlsContextOptions.createDefaultClient()
7576
.withCipherPreference(TlsCipherPreference.TLS_CIPHER_SYSTEM_DEFAULT);
7677

@@ -199,6 +200,7 @@ public Long readBufferSizeInBytes() {
199200
@Override
200201
public void close() {
201202
clientBootstrap.close();
203+
clientTlsContextOptions.close();
202204
tlsContext.close();
203205
credentialProviderAdapter.close();
204206
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.services.s3.internal.crt;
17+
18+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
19+
import static com.github.tomakehurst.wiremock.client.WireMock.any;
20+
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
21+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
24+
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
25+
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
26+
import java.net.URI;
27+
import org.junit.jupiter.api.AfterEach;
28+
import org.junit.jupiter.api.BeforeAll;
29+
import org.junit.jupiter.api.BeforeEach;
30+
import org.junit.jupiter.api.Test;
31+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
32+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
33+
import software.amazon.awssdk.crt.CrtResource;
34+
import software.amazon.awssdk.crt.Log;
35+
import software.amazon.awssdk.regions.Region;
36+
import software.amazon.awssdk.services.s3.S3AsyncClient;
37+
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
38+
39+
/**
40+
* Tests to make sure all CRT resources are cleaned up
41+
*/
42+
@WireMockTest
43+
public class S3CrtClientWiremockTest {
44+
45+
private S3AsyncClient s3AsyncClient;
46+
47+
@BeforeAll
48+
public static void setUpBeforeAll() {
49+
System.setProperty("aws.crt.debugnative", "true");
50+
Log.initLoggingToStdout(Log.LogLevel.Warn);
51+
}
52+
53+
@BeforeEach
54+
public void setup(WireMockRuntimeInfo wiremock) {
55+
s3AsyncClient = S3AsyncClient.crtBuilder()
56+
.region(Region.US_EAST_1)
57+
.endpointOverride(URI.create("http://localhost:" + wiremock.getHttpPort()))
58+
.credentialsProvider(
59+
StaticCredentialsProvider.create(AwsBasicCredentials.create("key", "secret")))
60+
.build();
61+
}
62+
63+
@AfterEach
64+
public void tearDown() {
65+
s3AsyncClient.close();
66+
CrtResource.waitForNoResources();
67+
}
68+
69+
@Test
70+
public void completeMultipartUpload_completeResponse() {
71+
String location = "http://Example-Bucket.s3.amazonaws.com/Example-Object";
72+
String bucket = "Example-Bucket";
73+
String key = "Example-Object";
74+
String eTag = "\"3858f62230ac3c915f300c664312c11f-9\"";
75+
String xmlResponseBody = String.format(
76+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
77+
+ "<CompleteMultipartUploadResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\n"
78+
+ "<Location>%s</Location>\n"
79+
+ "<Bucket>%s</Bucket>\n"
80+
+ "<Key>%s</Key>\n"
81+
+ "<ETag>%s</ETag>\n"
82+
+ "</CompleteMultipartUploadResult>", location, bucket, key, eTag);
83+
84+
stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200).withBody(xmlResponseBody)));
85+
86+
CompleteMultipartUploadResponse response = s3AsyncClient.completeMultipartUpload(
87+
r -> r.bucket(bucket).key(key).uploadId("upload-id")).join();
88+
89+
assertThat(response.location()).isEqualTo(location);
90+
assertThat(response.bucket()).isEqualTo(bucket);
91+
assertThat(response.key()).isEqualTo(key);
92+
assertThat(response.eTag()).isEqualTo(eTag);
93+
}
94+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License").
5+
# You may not use this file except in compliance with the License.
6+
# A copy of the License is located at
7+
#
8+
# http://aws.amazon.com/apache2.0
9+
#
10+
# or in the "license" file accompanying this file. This file is distributed
11+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
# express or implied. See the License for the specific language governing
13+
# permissions and limitations under the License.
14+
#
15+
16+
# Set up logging implementation
17+
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
18+
org.eclipse.jetty.LEVEL=OFF

0 commit comments

Comments
 (0)