+Url parse_url(const string &str)
+{
+ static Regex r_url("(([a-z]+)://)?([a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*(:[0-9])?)?(/[^?#]*)?(\\?([^#]+))?(#(.*))?");
+ if(RegMatch m=r_url.match(str))
+ {
+ Url url;
+ url.scheme=m[2].str;
+ url.host=m[3].str;
+ url.path=urldecode(m[6].str);
+ url.query=m[8].str;
+ url.fragment=m[10].str;
+ return url;
+ }
+ else
+ throw InvalidParameterValue("Invalid URL");
+}
+
+string build_url(const Url &url)
+{
+ if(!url.path.empty() && url.path[0]!='/')
+ throw InvalidParameterValue("Only absolute paths are supported");
+ string str;
+ if(!url.scheme.empty())
+ str+=url.scheme+"://";
+ str+=url.host;
+ str+=urlencode(url.path);
+ if(!url.query.empty())
+ {
+ str+='?';
+ str+=url.query;
+ }
+ if(!url.fragment.empty())
+ {
+ str+='#';
+ str+=url.fragment;
+ }
+ return str;
+}
+
+Query parse_query(const std::string &str)
+{
+ vector<string> parts=split(str, '&');
+ Query query;
+ for(vector<string>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
+ {
+ unsigned equals=i->find('=');
+ string &value=query[urldecode(i->substr(0, equals))];
+ if(equals!=string::npos)
+ value=urldecode(i->substr(equals+1));
+ }
+ return query;
+}
+
+string build_query(const Query &query)
+{
+ string str;
+ for(Query::const_iterator i=query.begin(); i!=query.end(); ++i)
+ {
+ if(i!=query.begin())
+ str+='&';
+ str+=urlencode_plus(i->first);
+ str+='=';
+ str+=urlencode_plus(i->second);
+ }
+ return str;
+}
+