diff options
author | Yorick van Pelt <yorick@yorickvanpelt.nl> | 2023-02-07 16:44:37 +0100 |
---|---|---|
committer | Yorick van Pelt <yorick@yorickvanpelt.nl> | 2023-02-27 15:30:00 +0100 |
commit | 0844856c8487e2bdf66a2272622f6bbf6b8b5fb8 (patch) | |
tree | 86de55ef6faa44d877cff937748c1d30ed387e07 /src/libutil/url.cc | |
parent | 92611e6e4c1c5c712ca7d5f9a258640662d006df (diff) |
url: make percentEncode stricter, expose and unit test it
Diffstat (limited to 'src/libutil/url.cc')
-rw-r--r-- | src/libutil/url.cc | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/src/libutil/url.cc b/src/libutil/url.cc index 4e43455e1..9e44241ac 100644 --- a/src/libutil/url.cc +++ b/src/libutil/url.cc @@ -88,17 +88,22 @@ std::map<std::string, std::string> decodeQuery(const std::string & query) return result; } -std::string percentEncode(std::string_view s) +const static std::string allowedInQuery = ":@/?"; +const static std::string allowedInPath = ":@/"; + +std::string percentEncode(std::string_view s, std::string_view keep) { std::string res; for (auto & c : s) + // unreserved + keep if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') - || strchr("-._~!$&'()*+,;=:@", c)) + || strchr("-._~", c) + || keep.find(c) != std::string::npos) res += c; else - res += fmt("%%%02x", (unsigned int) c); + res += fmt("%%%02X", (unsigned int) c); return res; } @@ -109,9 +114,9 @@ std::string encodeQuery(const std::map<std::string, std::string> & ss) for (auto & [name, value] : ss) { if (!first) res += '&'; first = false; - res += percentEncode(name); + res += percentEncode(name, allowedInQuery); res += '='; - res += percentEncode(value); + res += percentEncode(value, allowedInQuery); } return res; } @@ -122,7 +127,7 @@ std::string ParsedURL::to_string() const scheme + ":" + (authority ? "//" + *authority : "") - + path + + percentEncode(path, allowedInPath) + (query.empty() ? "" : "?" + encodeQuery(query)) + (fragment.empty() ? "" : "#" + percentEncode(fragment)); } |