Skip to content

Commit 9d13cb8

Browse files
authored
Fix to ignore empty strings while marshalling list of strings in header field. (#3165)
1 parent f8e0adb commit 9d13cb8

File tree

5 files changed

+149
-1
lines changed

5 files changed

+149
-1
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"contributor": "",
4+
"type": "bugfix",
5+
"description": "Fix to ignore empty strings while marshalling list of strings in header field."
6+
}

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/HeaderMarshaller.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import software.amazon.awssdk.core.traits.ListTrait;
2828
import software.amazon.awssdk.protocols.core.ValueToStringConverter;
2929
import software.amazon.awssdk.utils.BinaryUtils;
30+
import software.amazon.awssdk.utils.StringUtils;
3031

3132
@SdkInternalApi
3233
public final class HeaderMarshaller {
@@ -51,13 +52,16 @@ public final class HeaderMarshaller {
5152
= new SimpleHeaderMarshaller<>(JsonProtocolMarshaller.INSTANT_VALUE_TO_STRING);
5253

5354
public static final JsonMarshaller<List<?>> LIST = (list, context, paramName, sdkField) -> {
54-
// Null or empty lists cannot be meaningfully (or safely) represented in an HTTP header message since header-fields must
55+
// Null or empty lists cannot be meaningfully (or safely) represented in an HTTP header message since header-fields must
5556
// typically have a non-empty field-value. https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
5657
if (isNullOrEmpty(list)) {
5758
return;
5859
}
5960
SdkField memberFieldInfo = sdkField.getRequiredTrait(ListTrait.class).memberFieldInfo();
6061
for (Object listValue : list) {
62+
if (shouldSkipElement(listValue)) {
63+
continue;
64+
}
6165
JsonMarshaller marshaller = context.marshallerRegistry().getMarshaller(MarshallLocation.HEADER, listValue);
6266
marshaller.marshall(listValue, context, paramName, memberFieldInfo);
6367
}
@@ -66,6 +70,10 @@ public final class HeaderMarshaller {
6670
private HeaderMarshaller() {
6771
}
6872

73+
private static boolean shouldSkipElement(Object element) {
74+
return element instanceof String && StringUtils.isBlank((String) element);
75+
}
76+
6977
private static class SimpleHeaderMarshaller<T> implements JsonMarshaller<T> {
7078

7179
private final ValueToStringConverter.ValueToString<T> converter;

core/protocols/aws-xml-protocol/src/main/java/software/amazon/awssdk/protocols/xml/internal/marshall/HeaderMarshaller.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import software.amazon.awssdk.core.protocol.MarshallLocation;
2626
import software.amazon.awssdk.core.traits.ListTrait;
2727
import software.amazon.awssdk.protocols.core.ValueToStringConverter;
28+
import software.amazon.awssdk.utils.StringUtils;
2829

2930
@SdkInternalApi
3031
public final class HeaderMarshaller {
@@ -78,11 +79,18 @@ public void marshall(List<?> list, XmlMarshallerContext context, String paramNam
7879
}
7980
SdkField memberFieldInfo = sdkField.getRequiredTrait(ListTrait.class).memberFieldInfo();
8081
for (Object listValue : list) {
82+
if (shouldSkipElement(listValue)) {
83+
continue;
84+
}
8185
XmlMarshaller marshaller = context.marshallerRegistry().getMarshaller(MarshallLocation.HEADER, listValue);
8286
marshaller.marshall(listValue, context, paramName, memberFieldInfo);
8387
}
8488
}
8589

90+
private boolean shouldSkipElement(Object element) {
91+
return element instanceof String && StringUtils.isBlank((String) element);
92+
}
93+
8694
@Override
8795
protected boolean shouldEmit(List list) {
8896
// Null or empty lists cannot be meaningfully (or safely) represented in an HTTP header message since header-fields

test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-json-input.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,69 @@
175175
}
176176
}
177177
},
178+
{
179+
"description": "ListOfStrings in header is serialized as multi-valued header with commas, quotes and double quotes",
180+
"given": {
181+
"input": {
182+
"ListOfStringsMember": [
183+
"listValue1,listValue2",
184+
"\"listValueTwo\"",
185+
"\"\"",
186+
"'listValueThree'"
187+
]
188+
}
189+
},
190+
"when": {
191+
"action": "marshall",
192+
"operation": "MembersInHeaders"
193+
},
194+
"then": {
195+
"serializedAs": {
196+
"uri": "/2016-03-11/membersInHeaders",
197+
"headers": {
198+
"contains": {
199+
"x-amz-string-list": [
200+
"listValue1,listValue2",
201+
"\"listValueTwo\"",
202+
"\"\"",
203+
"'listValueThree'"
204+
]
205+
}
206+
}
207+
}
208+
}
209+
},
210+
{
211+
"description": "ListOfStrings in header serializes only non empty Strings",
212+
"given": {
213+
"input": {
214+
"ListOfStringsMember": [
215+
"listValue1",
216+
null,
217+
"",
218+
"",
219+
"listValue6"
220+
]
221+
}
222+
},
223+
"when": {
224+
"action": "marshall",
225+
"operation": "MembersInHeaders"
226+
},
227+
"then": {
228+
"serializedAs": {
229+
"uri": "/2016-03-11/membersInHeaders",
230+
"headers": {
231+
"contains": {
232+
"x-amz-string-list": [
233+
"listValue1",
234+
"listValue6"
235+
]
236+
}
237+
}
238+
}
239+
}
240+
},
178241
{
179242
"description": "Null string header member is not serialized",
180243
"given": {

test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/rest-xml-input.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,69 @@
507507
}
508508
}
509509
}
510+
},
511+
{
512+
"description": "ListOfStrings in header is serialized as multi-valued header with commas, quotes and double quotes",
513+
"given": {
514+
"input": {
515+
"ListOfStringsMember": [
516+
"listValue1,listValue2",
517+
"\"listValueTwo\"",
518+
"\"\"",
519+
"'listValueThree'"
520+
]
521+
}
522+
},
523+
"when": {
524+
"action": "marshall",
525+
"operation": "MembersInHeaders"
526+
},
527+
"then": {
528+
"serializedAs": {
529+
"uri": "/2016-03-11/membersInHeaders",
530+
"headers": {
531+
"contains": {
532+
"x-amz-string-list": [
533+
"listValue1,listValue2",
534+
"\"listValueTwo\"",
535+
"\"\"",
536+
"'listValueThree'"
537+
]
538+
}
539+
}
540+
}
541+
}
542+
},
543+
{
544+
"description": "ListOfStrings in header serializes only non empty Strings",
545+
"given": {
546+
"input": {
547+
"ListOfStringsMember": [
548+
"listValue1",
549+
null,
550+
"",
551+
"",
552+
"listValue6"
553+
]
554+
}
555+
},
556+
"when": {
557+
"action": "marshall",
558+
"operation": "MembersInHeaders"
559+
},
560+
"then": {
561+
"serializedAs": {
562+
"uri": "/2016-03-11/membersInHeaders",
563+
"headers": {
564+
"contains": {
565+
"x-amz-string-list": [
566+
"listValue1",
567+
"listValue6"
568+
]
569+
}
570+
}
571+
}
572+
}
510573
}
511574
// TODO this is not possible, payloads can only be structures or blobs. Only S3 utilizes this
512575
// {

0 commit comments

Comments
 (0)