Skip to content

Commit 03ec574

Browse files
committed
Fix deserialization of paths and query params for servers
This decodes potentially-encoded values as early as possible within the deserialization process so that no downstream deserializer needs to reckon with encoding.
1 parent 432b1dd commit 03ec574

File tree

1 file changed

+39
-8
lines changed

1 file changed

+39
-8
lines changed

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,8 +1685,23 @@ private void readDirectQueryBindings(GenerationContext context, List<HttpBinding
16851685
String memberName = context.getSymbolProvider().toMemberName(binding.getMember());
16861686
writer.openBlock("if (query['$L'] !== undefined) {", "}", binding.getLocationName(), () -> {
16871687
Shape target = context.getModel().expectShape(binding.getMember().getTarget());
1688-
String queryValue = getOutputValue(context, binding.getLocation(),
1689-
"query['" + binding.getLocationName() + "'] as string",
1688+
if (target instanceof CollectionShape) {
1689+
writer.write("const decoded = Array.isArray(query['$1L']) ? (query['$1L'] as string[])"
1690+
+ ".map(e => decodeURIComponent(e)) : [decodeURIComponent(query['$1L'] as string)];",
1691+
binding.getLocationName());
1692+
} else {
1693+
writer.addImport("SerializationException",
1694+
"__SerializationException",
1695+
"@aws-smithy/server-common");
1696+
writer.openBlock("if (Array.isArray(query['$1L'])) {", "}",
1697+
binding.getLocationName(),
1698+
() -> {
1699+
writer.write("throw new __SerializationException();");
1700+
});
1701+
writer.write("const decoded = decodeURIComponent(query['$1L'] as string);",
1702+
binding.getLocationName());
1703+
}
1704+
String queryValue = getOutputValue(context, binding.getLocation(), "decoded",
16901705
binding.getMember(), target);
16911706
writer.write("contents.$L = $L;", memberName, queryValue);
16921707
});
@@ -1703,10 +1718,23 @@ private void readMappedQueryBindings(GenerationContext context, HttpBinding mapp
17031718
valueType = "string[]";
17041719
}
17051720
writer.write("let parsedQuery: { [key: string]: $L } = {}", valueType);
1706-
String parsedValue = getOutputValue(context, mappedBinding.getLocation(), "value as string",
1707-
target.getValue(), valueShape);
1721+
String parsedValue = getOutputValue(context, mappedBinding.getLocation(),
1722+
"decoded", target.getValue(), valueShape);
17081723
writer.openBlock("for (const [key, value] of Object.entries(query)) {", "}", () -> {
1709-
writer.write("parsedQuery[key] = $L;", parsedValue);
1724+
if (valueShape instanceof CollectionShape) {
1725+
writer.write("const decoded = Array.isArray(value) ? (value as string[])"
1726+
+ ".map(e => decodeURIComponent(e)) : [decodeURIComponent(value as string)];");
1727+
} else {
1728+
writer.addImport("SerializationException",
1729+
"__SerializationException",
1730+
"@aws-smithy/server-common");
1731+
writer.openBlock("if (Array.isArray(value)) {", "}",
1732+
() -> {
1733+
writer.write("throw new __SerializationException();");
1734+
});
1735+
writer.write("const decoded = decodeURIComponent(value as string);");
1736+
}
1737+
writer.write("parsedQuery[decodeURIComponent(key)] = $L;", parsedValue);
17101738
});
17111739
String memberName = context.getSymbolProvider().toMemberName(mappedBinding.getMember());
17121740
writer.write("contents.$L = parsedQuery;", memberName);
@@ -1745,8 +1773,11 @@ private void readPath(
17451773
for (HttpBinding binding : pathBindings) {
17461774
Shape target = context.getModel().expectShape(binding.getMember().getTarget());
17471775
String memberName = context.getSymbolProvider().toMemberName(binding.getMember());
1776+
// since this is in the path, we should decode early
1777+
String dataSource = String.format("decodeURIComponent(parsedPath.groups.%s)",
1778+
binding.getLocationName());
17481779
String labelValue = getOutputValue(context, binding.getLocation(),
1749-
"parsedPath.groups." + binding.getLocationName(), binding.getMember(), target);
1780+
dataSource, binding.getMember(), target);
17501781
writer.write("contents.$L = $L;", memberName, labelValue);
17511782
}
17521783
});
@@ -2522,11 +2553,11 @@ private String getCollectionOutputParam(
25222553
switch (bindingType) {
25232554
case QUERY_PARAMS:
25242555
case QUERY:
2525-
return String.format("(Array.isArray(%1$s) ? (%1$s[]) : [%1$s]).map(_entry => %2$s)",
2556+
return String.format("%1$s.map(_entry => %2$s)",
25262557
dataSource, collectionTargetValue);
25272558
case LABEL:
25282559
dataSource = "(" + dataSource + " || \"\")";
2529-
// Split these values on commas.
2560+
// Split these values on slashes.
25302561
outputParam = "" + dataSource + ".split('/')";
25312562

25322563
// Iterate over each entry and do deser work.

0 commit comments

Comments
 (0)