3 #include <msp/strings/format.h>
4 #include <msp/strings/regex.h>
5 #include <msp/strings/utils.h>
11 const char *reserved[]=
15 " !#$%&'()*+,/:;=?@[]",
18 bool is_reserved(char c, unsigned level)
20 for(const char *r=reserved[level]; *r; ++r)
31 string urlencode(const string &str, EncodeLevel level)
34 result.reserve(str.size());
37 if(is_reserved(c, level))
38 result += format("%%%02X", c);
45 string urlencode_plus(const string &str, EncodeLevel level)
48 result.reserve(str.size());
53 else if(is_reserved(c, level))
54 result += format("%%%02X", c);
61 string urldecode(const string &str)
64 for(unsigned i=0; i<str.size(); ++i)
70 throw invalid_argument("urldecode");
71 result += lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
82 Url parse_url(const string &str)
84 static Regex r_url("^(([a-z]+)://)?([a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*(:[0-9]+)?)?(/[^?#]*)?(\\?([^#]*))?(#(.*))?$");
85 if(RegMatch m = r_url.match(str))
88 url.scheme = m[2].str;
90 url.path = urldecode(m[6].str);
92 url.fragment = m[10].str;
96 throw invalid_argument("parse_url");
99 string build_url(const Url &url)
101 if(!url.path.empty() && url.path[0]!='/')
102 throw invalid_argument("build_url");
105 if(!url.scheme.empty())
106 str += url.scheme+"://";
108 str += urlencode(url.path);
109 append(str, "?", url.query);
110 append(str, "#", url.fragment);
114 Query parse_query(const std::string &str)
117 for(const string &p: split(str, '&'))
119 string::size_type equals = p.find('=');
120 string &value = query[urldecode(p.substr(0, equals))];
121 if(equals!=string::npos)
122 value = urldecode(p.substr(equals+1));
127 string build_query(const Query &query)
130 for(const auto &kvp: query)
132 append(str, "&", urlencode_plus(kvp.first));
134 str += urlencode_plus(kvp.second);