aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/url.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/url.cc')
-rw-r--r--src/libutil/url.cc17
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));
}