diff --git a/.changes/next-release/bugfix-AWSQueryProtocol-1398d13.json b/.changes/next-release/bugfix-AWSQueryProtocol-1398d13.json new file mode 100644 index 000000000000..e715db44639b --- /dev/null +++ b/.changes/next-release/bugfix-AWSQueryProtocol-1398d13.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS Query Protocol", + "contributor": "", + "description": "Fixed EC2 DescribeInstances query failure in non-ASCII digit locales by using ROOT locale when formatting query paths to ensure ASCII digits are always used." +} diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java index 971dbb96f953..995e07172f85 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java @@ -29,9 +29,9 @@ public class ListQueryMarshaller implements QueryMarshaller> { private static final PathResolver AWS_QUERY_PATH_RESOLVER = (path, i, listTrait) -> listTrait.isFlattened() ? - String.format("%s.%d", path, i + 1) : - String.format("%s.%s.%d", path, listTrait.memberFieldInfo().locationName(), i + 1); - private static final PathResolver EC2_QUERY_PATH_RESOLVER = (path, i, listTrait) -> String.format("%s.%d", path, i + 1); + path + "." + (i + 1) : + path + "." + listTrait.memberFieldInfo().locationName() + "." + (i + 1); + private static final PathResolver EC2_QUERY_PATH_RESOLVER = (path, i, listTrait) -> path + "." + (i + 1); private static final EmptyListMarshaller AWS_QUERY_EMPTY_LIST_MARSHALLER = (context, path) -> context.request().putRawQueryParameter(path, ""); diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java index 195125e027c6..1bf915e647a3 100644 --- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java +++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/MapQueryMarshaller.java @@ -46,7 +46,7 @@ public void marshall(QueryMarshallerContext context, String path, Map private static String resolveMapPath(String path, MapTrait mapTrait, AtomicInteger entryNum, String s) { return mapTrait.isFlattened() ? - String.format("%s.%d.%s", path, entryNum.get(), s) : - String.format("%s.entry.%d.%s", path, entryNum.get(), s); + path + "." + entryNum.get() + "." + s : + path + ".entry." + entryNum.get() + "." + s; } } diff --git a/core/protocols/aws-query-protocol/src/test/java/software/amazon/awssdk/protocols/query/ListQueryMarshallerTest.java b/core/protocols/aws-query-protocol/src/test/java/software/amazon/awssdk/protocols/query/ListQueryMarshallerTest.java new file mode 100644 index 000000000000..3050c6d01eb2 --- /dev/null +++ b/core/protocols/aws-query-protocol/src/test/java/software/amazon/awssdk/protocols/query/ListQueryMarshallerTest.java @@ -0,0 +1,100 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.protocols.query; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.SdkField; +import software.amazon.awssdk.core.protocol.MarshallLocation; +import software.amazon.awssdk.core.protocol.MarshallingType; +import software.amazon.awssdk.core.traits.ListTrait; +import software.amazon.awssdk.core.traits.LocationTrait; +import software.amazon.awssdk.http.SdkHttpFullRequest; +import software.amazon.awssdk.protocols.query.internal.marshall.ListQueryMarshaller; +import software.amazon.awssdk.protocols.query.internal.marshall.QueryMarshaller; +import software.amazon.awssdk.protocols.query.internal.marshall.QueryMarshallerContext; +import software.amazon.awssdk.protocols.query.internal.marshall.QueryMarshallerRegistry; + + +public class ListQueryMarshallerTest { + + @Test + public void localeSetAsNe_ParsedCorrectly() { + Locale defaultLocale = Locale.getDefault(); + Locale.setDefault(new Locale("ne")); + + ListQueryMarshaller marshaller = ListQueryMarshaller.ec2Query(); + + QueryMarshallerContext context = createTestContext(); + List testList = Arrays.asList("value1", "value2"); + SdkField> field = createTestField(); + + marshaller.marshall(context, "TestParam", testList, field); + + Map> params = context.request().rawQueryParameters(); + + assertEquals(Collections.singletonList("value1"), params.get("TestParam.1")); + assertEquals(Collections.singletonList("value2"), params.get("TestParam.2")); + Locale.setDefault(defaultLocale); + } + + private QueryMarshallerContext createTestContext() { + + QueryMarshaller stringMarshaller = (context, path, val, field) -> + context.request().putRawQueryParameter(path, val); + + QueryMarshallerRegistry registry = QueryMarshallerRegistry.builder() + .marshaller(MarshallingType.STRING, stringMarshaller) + .build(); + + return QueryMarshallerContext.builder() + .request(SdkHttpFullRequest.builder()) + .marshallerRegistry(registry) + .build(); + } + + + + private SdkField> createTestField() { + SdkField memberField = SdkField.builder(MarshallingType.STRING) + .memberName("item") + .traits(LocationTrait.builder() + .location(MarshallLocation.PAYLOAD) + .locationName("item") + .build()) + .build(); + + ListTrait listTrait = ListTrait.builder() + .memberFieldInfo(memberField) + .memberLocationName("item") + .isFlattened(true) + .build(); + + return SdkField.builder(MarshallingType.LIST) + .memberName("TestParam") + .traits(LocationTrait.builder() + .location(MarshallLocation.QUERY_PARAM) + .locationName("TestParam") + .build(),listTrait) + .build(); + } +}