]> git.tdb.fi Git - libs/net.git/blobdiff - source/utils.cpp
Add functions for parsing and building URIs and query strings
[libs/net.git] / source / utils.cpp
index d550259984f79357ca94449df00a4a53ce8dbdcc..b6340db7dfd2da87a9abc6c9cbb8baabb6fba999 100644 (file)
@@ -5,18 +5,26 @@ Copyright © 2009  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
 
+#include <algorithm>
 #include <msp/strings/formatter.h>
+#include <msp/strings/regex.h>
+#include <msp/strings/utils.h>
 #include "utils.h"
 
 using namespace std;
 
 namespace {
 
-const char reserved[]=" :/?#[]@!$&'()*+,;=%";
+const char *reserved[]=
+{
+       " #%&+=?",
+       " #%&*+:;=?@[]",
+       " !#$%&'()*+,/:;=?@[]",
+};
 
-bool is_reserved(char c)
+bool is_reserved(char c, unsigned level)
 {
-       for(const char *r=reserved; *r; ++r)
+       for(const char *r=reserved[level]; *r; ++r)
                if(c==*r)
                        return true;
        return false;
@@ -27,12 +35,27 @@ bool is_reserved(char c)
 namespace Msp {
 namespace Http {
 
-string urlencode(const string &str)
+string urlencode(const string &str, EncodeLevel level)
 {
        string result;
        for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
        {
-               if(is_reserved(*i))
+               if(is_reserved(*i, level))
+                       result+=format("%%%02X", *i);
+               else
+                       result+=*i;
+       }
+       return result;
+}
+
+string urlencode_plus(const string &str, EncodeLevel level)
+{
+       string result;
+       for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
+       {
+               if(*i==' ')
+                       result+='+';
+               else if(is_reserved(*i, level))
                        result+=format("%%%02X", *i);
                else
                        result+=*i;
@@ -61,5 +84,72 @@ string urldecode(const string &str)
        return result;
 }
 
+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;
+}
+
 } // namespace Http
 } // namespace Msp