Commit 7a28452e authored by Harris Hancock's avatar Harris Hancock

Use application/x-www-form-urlencoded format for URL query strings

The main motivation here is to make sure we don't %-escape incoming pluses, but rather interpret them as spaces.
parent 4982c9e8
......@@ -132,6 +132,14 @@ KJ_TEST("parse / stringify URL") {
KJ_EXPECT(KJ_ASSERT_NONNULL(url.fragment) == "garply");
}
{
auto url = parseAndCheck("https://capnproto.org/foo?bar%20baz=qux+quux",
"https://capnproto.org/foo?bar+baz=qux+quux");
KJ_ASSERT(url.query.size() == 1);
KJ_EXPECT(url.query[0].name == "bar baz");
KJ_EXPECT(url.query[0].value == "qux quux");
}
{
auto url = parseAndCheck("https://capnproto.org/foo/bar#garply");
KJ_EXPECT(url.scheme == "https");
......@@ -232,7 +240,7 @@ KJ_TEST("URL percent encoding") {
parseAndCheck(
"https://b b: bcd@capnproto.org/f o?b r=b z#q x",
"https://b%20b:%20bcd@capnproto.org/f%20o?b%20r=b%20z#q%20x");
"https://b%20b:%20bcd@capnproto.org/f%20o?b+r=b+z#q%20x");
}
KJ_TEST("URL relative paths") {
......@@ -340,6 +348,9 @@ KJ_TEST("parse relative URL") {
parseAndCheckRelative("https://capnproto.org/foo/bar?baz=qux#corge",
"?grault",
"https://capnproto.org/foo/bar?grault");
parseAndCheckRelative("https://capnproto.org/foo/bar?baz=qux#corge",
"?grault+garply=waldo",
"https://capnproto.org/foo/bar?grault+garply=waldo");
parseAndCheckRelative("https://capnproto.org/foo/bar?baz=qux#corge",
"grault",
"https://capnproto.org/foo/grault");
......
......@@ -88,6 +88,12 @@ String percentDecode(ArrayPtr<const char> text, bool& hadErrors) {
return kj::mv(result);
}
String percentDecodeQuery(ArrayPtr<const char> text, bool& hadErrors) {
auto result = decodeWwwForm(text);
if (result.hadErrors) hadErrors = true;
return kj::mv(result);
}
} // namespace
Url::~Url() noexcept(false) {}
......@@ -195,9 +201,10 @@ Maybe<Url> Url::tryParse(StringPtr text, Context context) {
if (part.size() > 0) {
KJ_IF_MAYBE(key, trySplit(part, '=')) {
result.query.add(QueryParam { percentDecode(*key, err), percentDecode(part, err) });
result.query.add(QueryParam { percentDecodeQuery(*key, err),
percentDecodeQuery(part, err) });
} else {
result.query.add(QueryParam { percentDecode(part, err), nullptr });
result.query.add(QueryParam { percentDecodeQuery(part, err), nullptr });
}
}
} while (text.startsWith("&"));
......@@ -331,9 +338,10 @@ Maybe<Url> Url::tryParseRelative(StringPtr text) const {
if (part.size() > 0) {
KJ_IF_MAYBE(key, trySplit(part, '=')) {
result.query.add(QueryParam { percentDecode(*key, err), percentDecode(part, err) });
result.query.add(QueryParam { percentDecodeQuery(*key, err),
percentDecodeQuery(part, err) });
} else {
result.query.add(QueryParam { percentDecode(part, err), nullptr });
result.query.add(QueryParam { percentDecodeQuery(part, err), nullptr });
}
}
} while (text.startsWith("&"));
......@@ -407,10 +415,10 @@ String Url::toString(Context context) const {
for (auto& param: query) {
chars.add(first ? '?' : '&');
first = false;
chars.addAll(encodeUriComponent(param.name));
chars.addAll(encodeWwwForm(param.name));
if (param.value.size() > 0) {
chars.add('=');
chars.addAll(encodeUriComponent(param.value));
chars.addAll(encodeWwwForm(param.value));
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment