Skip to content

Commit 918657c

Browse files
authored
Fixed an issue where NPE would be thrown for empty event (#4922)
1 parent 5b85dad commit 918657c

File tree

5 files changed

+101
-1
lines changed

5 files changed

+101
-1
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 SDK for Java v2",
4+
"contributor": "",
5+
"description": "Fixed an issue where NPE would be thrown if there was an empty event in the input for an event streaming operation."
6+
}

core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/handler/AwsClientHandlerUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,15 @@ public static ByteBuffer encodeEventStreamRequestToByteBuffer(SdkHttpFullRequest
4545
Map<String, HeaderValue> headers = new LinkedHashMap<>();
4646
request.forEachHeader((name, value) -> headers.put(name, HeaderValue.fromString(firstIfPresent(value))));
4747

48-
byte[] payload = null;
48+
byte[] payload;
4949
if (request.contentStreamProvider().isPresent()) {
5050
try {
5151
payload = IoUtils.toByteArray(request.contentStreamProvider().get().newStream());
5252
} catch (IOException e) {
5353
throw new UncheckedIOException(e);
5454
}
55+
} else {
56+
payload = new byte[0];
5557
}
5658

5759
return new Message(headers, payload).toByteBuffer();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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.awscore.client.handler;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import java.net.URI;
21+
import java.nio.ByteBuffer;
22+
import org.junit.jupiter.api.Test;
23+
import software.amazon.awssdk.http.SdkHttpFullRequest;
24+
import software.amazon.awssdk.http.SdkHttpMethod;
25+
import software.amazon.awssdk.utils.StringInputStream;
26+
27+
public class AwsClientHandlerUtilsTest {
28+
29+
@Test
30+
void nonNullPayload_shouldEncodeToEmptyMessage() {
31+
SdkHttpFullRequest request = SdkHttpFullRequest.builder()
32+
.method(SdkHttpMethod.GET)
33+
.uri(URI.create("http://localhost"))
34+
.contentStreamProvider(() -> new StringInputStream("test"))
35+
.build();
36+
ByteBuffer buffer = AwsClientHandlerUtils.encodeEventStreamRequestToByteBuffer(request);
37+
assertThat(buffer).isNotNull();
38+
}
39+
40+
@Test
41+
void nullPayload_shouldEncodeToEmptyMessage() {
42+
SdkHttpFullRequest request = SdkHttpFullRequest.builder()
43+
.method(SdkHttpMethod.GET)
44+
.uri(URI.create("http://localhost")).build();
45+
ByteBuffer buffer = AwsClientHandlerUtils.encodeEventStreamRequestToByteBuffer(request);
46+
assertThat(buffer).isNotNull();
47+
}
48+
}

test/protocol-tests/src/main/resources/codegen-resources/restjson/contenttype/service-2.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@
223223
"HeadersOnlyEvent": {
224224
"shape": "HeadersOnlyEvent"
225225
},
226+
"EndEvent": {
227+
"shape": "EndEvent"
228+
},
226229
"ImplicitPayloadAndHeadersEvent": {
227230
"shape": "ImplicitPayloadAndHeadersEvent"
228231
}
@@ -280,6 +283,12 @@
280283
},
281284
"event": true
282285
},
286+
"EndEvent":{
287+
"type":"structure",
288+
"members":{
289+
},
290+
"event":true
291+
},
283292
"BlobPayloadMember":{"type":"blob"},
284293
"EventStream": {
285294
"type": "structure",

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/RestJsonEventStreamProtocolTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,22 @@
1515

1616
package software.amazon.awssdk.protocol.tests;
1717

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.equalTo;
22+
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
23+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
24+
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
1825
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.assertj.core.api.Assertions.in;
1927

28+
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
29+
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
30+
import io.reactivex.Flowable;
2031
import java.net.URI;
2132
import java.nio.charset.StandardCharsets;
33+
import org.junit.jupiter.api.BeforeEach;
2234
import org.junit.jupiter.api.Test;
2335
import software.amazon.awssdk.core.SdkBytes;
2436
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
@@ -27,6 +39,7 @@
2739
import software.amazon.awssdk.http.SdkHttpFullRequest;
2840
import software.amazon.awssdk.protocols.json.AwsJsonProtocol;
2941
import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory;
42+
import software.amazon.awssdk.services.protocolrestjsoncontenttype.ProtocolRestJsonContentTypeAsyncClient;
3043
import software.amazon.awssdk.services.protocolrestjsoncontenttype.model.BlobAndHeadersEvent;
3144
import software.amazon.awssdk.services.protocolrestjsoncontenttype.model.HeadersOnlyEvent;
3245
import software.amazon.awssdk.services.protocolrestjsoncontenttype.model.ImplicitPayloadAndHeadersEvent;
@@ -38,9 +51,19 @@
3851
import software.amazon.awssdk.services.protocolrestjsoncontenttype.transform.ImplicitPayloadAndHeadersEventMarshaller;
3952
import software.amazon.awssdk.services.protocolrestjsoncontenttype.transform.StringAndHeadersEventMarshaller;
4053

54+
@WireMockTest
4155
public class RestJsonEventStreamProtocolTest {
4256
private static final String EVENT_CONTENT_TYPE_HEADER = ":content-type";
4357

58+
private ProtocolRestJsonContentTypeAsyncClient client;
59+
60+
@BeforeEach
61+
void setup(WireMockRuntimeInfo info) {
62+
client = ProtocolRestJsonContentTypeAsyncClient.builder()
63+
.endpointOverride(URI.create("http://localhost:" + info.getHttpPort()))
64+
.build();
65+
}
66+
4467
@Test
4568
public void implicitPayloadAndHeaders_payloadMemberPresent() {
4669
ImplicitPayloadAndHeadersEventMarshaller marshaller = new ImplicitPayloadAndHeadersEventMarshaller(protocolFactory());
@@ -91,6 +114,18 @@ public void blobAndHeadersEvent() {
91114
assertThat(content).isEqualTo("hello rest-json");
92115
}
93116

117+
@Test
118+
public void containsEmptyEvent_shouldEncodeSuccessfully() {
119+
stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200)));
120+
client.testEventStream(b -> {
121+
}, Flowable.fromArray(InputEventStream.stringAndHeadersEventBuilder().stringPayloadMember(
122+
"test").build(),
123+
InputEventStream.endEventBuilder().build())).join();
124+
125+
verify(postRequestedFor(anyUrl())
126+
.withHeader("Content-Type", equalTo("application/vnd.amazon.eventstream")));
127+
}
128+
94129
@Test
95130
public void stringAndHeadersEvent() {
96131
StringAndHeadersEventMarshaller marshaller = new StringAndHeadersEventMarshaller(protocolFactory());

0 commit comments

Comments
 (0)