Skip to content

Commit 24f2ead

Browse files
adamthom-amznJordonPhillips
authored andcommitted
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 3c0da62 commit 24f2ead

File tree

1 file changed

+40
-9
lines changed

1 file changed

+40
-9
lines changed

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

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,10 +1683,25 @@ private void readDirectQueryBindings(GenerationContext context, List<HttpBinding
16831683
TypeScriptWriter writer = context.getWriter();
16841684
for (HttpBinding binding : directQueryBindings) {
16851685
String memberName = context.getSymbolProvider().toMemberName(binding.getMember());
1686-
writer.openBlock("if (query['$L'] !== undefined) {", "}", binding.getLocationName(), () -> {
1686+
writer.openBlock("if (query[$S] !== 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[$1S]) ? (query[$1S] as string[])"
1690+
+ ".map(e => decodeURIComponent(e)) : [decodeURIComponent(query[$1S] 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[$1S])) {", "}",
1697+
binding.getLocationName(),
1698+
() -> {
1699+
writer.write("throw new __SerializationException();");
1700+
});
1701+
writer.write("const decoded = decodeURIComponent(query[$1S] 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
});
@@ -2527,11 +2558,11 @@ private String getCollectionOutputParam(
25272558
switch (bindingType) {
25282559
case QUERY_PARAMS:
25292560
case QUERY:
2530-
return String.format("(Array.isArray(%1$s) ? (%1$s[]) : [%1$s]).map(_entry => %2$s)",
2561+
return String.format("%1$s.map(_entry => %2$s)",
25312562
dataSource, collectionTargetValue);
25322563
case LABEL:
25332564
dataSource = "(" + dataSource + " || \"\")";
2534-
// Split these values on commas.
2565+
// Split these values on slashes.
25352566
outputParam = "" + dataSource + ".split('/')";
25362567

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

0 commit comments

Comments
 (0)