]> git.tdb.fi Git - libs/net.git/blobdiff - source/http/utils.cpp
Prepare for assimilation into mspnet
[libs/net.git] / source / http / utils.cpp
diff --git a/source/http/utils.cpp b/source/http/utils.cpp
new file mode 100644 (file)
index 0000000..5a5dc04
--- /dev/null
@@ -0,0 +1,149 @@
+#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[]=
+{
+       " #%&+=?",
+       " #%&*+:;=?@[]",
+       " !#$%&'()*+,/:;=?@[]",
+};
+
+bool is_reserved(char c, unsigned level)
+{
+       for(const char *r=reserved[level]; *r; ++r)
+               if(c==*r)
+                       return true;
+       return false;
+}
+
+}
+
+namespace Msp {
+namespace Http {
+
+string urlencode(const string &str, EncodeLevel level)
+{
+       string result;
+       for(string::const_iterator i=str.begin(); i!=str.end(); ++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;
+       }
+       return result;
+}
+
+string urldecode(const string &str)
+{
+       string result;
+       for(unsigned i=0; i<str.size(); ++i)
+       {
+               char c = str[i];
+               if(c=='%')
+               {
+                       if(i+3>str.size())
+                               throw invalid_argument("urldecode");
+                       result += lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
+                       i += 2;
+               }
+               else if(c=='+')
+                       result += ' ';
+               else
+                       result += c;
+       }
+       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 invalid_argument("parse_url");
+}
+
+string build_url(const Url &url)
+{
+       if(!url.path.empty() && url.path[0]!='/')
+               throw invalid_argument("build_url");
+
+       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