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 if(!url.query.empty())
114 if(!url.fragment.empty())
122 Query parse_query(const std::string &str)
125 for(const string &p: split(str, '&'))
127 string::size_type equals = p.find('=');
128 string &value = query[urldecode(p.substr(0, equals))];
129 if(equals!=string::npos)
130 value = urldecode(p.substr(equals+1));
135 string build_query(const Query &query)
138 for(const auto &kvp: query)
142 str += urlencode_plus(kvp.first);
144 str += urlencode_plus(kvp.second);