2 #include <msp/strings/format.h>
3 #include <msp/strings/regex.h>
4 #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)
36 if(is_reserved(c, level))
37 result += format("%%%02X", c);
44 string urlencode_plus(const string &str, EncodeLevel level)
51 else if(is_reserved(c, level))
52 result += format("%%%02X", c);
59 string urldecode(const string &str)
62 for(unsigned i=0; i<str.size(); ++i)
68 throw invalid_argument("urldecode");
69 result += lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
80 Url parse_url(const string &str)
82 static Regex r_url("^(([a-z]+)://)?([a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*(:[0-9]+)?)?(/[^?#]*)?(\\?([^#]*))?(#(.*))?$");
83 if(RegMatch m = r_url.match(str))
86 url.scheme = m[2].str;
88 url.path = urldecode(m[6].str);
90 url.fragment = m[10].str;
94 throw invalid_argument("parse_url");
97 string build_url(const Url &url)
99 if(!url.path.empty() && url.path[0]!='/')
100 throw invalid_argument("build_url");
103 if(!url.scheme.empty())
104 str += url.scheme+"://";
106 str += urlencode(url.path);
107 if(!url.query.empty())
112 if(!url.fragment.empty())
120 Query parse_query(const std::string &str)
123 for(const string &p: split(str, '&'))
125 string::size_type equals = p.find('=');
126 string &value = query[urldecode(p.substr(0, equals))];
127 if(equals!=string::npos)
128 value = urldecode(p.substr(equals+1));
133 string build_query(const Query &query)
136 for(const auto &kvp: query)
140 str += urlencode_plus(kvp.first);
142 str += urlencode_plus(kvp.second);