]> git.tdb.fi Git - libs/net.git/blobdiff - source/utils.cpp
Don't let exceptions from the socket fall out of Client::data_available
[libs/net.git] / source / utils.cpp
index d550259984f79357ca94449df00a4a53ce8dbdcc..0803c14c74edc980951e50b8c960ebcb94481622 100644 (file)
@@ -1,22 +1,23 @@
-/* $Id$
-
-This file is part of libmsphttp
-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,15 +28,30 @@ 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))
-                       result+=format("%%%02X", *i);
+               if(is_reserved(*i, level))
+                       result += format("%%%02X", *i);
                else
-                       result+=*i;
+                       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;
 }
@@ -45,21 +61,88 @@ string urldecode(const string &str)
        string result;
        for(unsigned i=0; i<str.size(); ++i)
        {
-               char c=str[i];
+               char c = str[i];
                if(c=='%')
                {
                        if(i+3>str.size())
                                throw InvalidParameterValue("Malformed data");
-                       result+=lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
-                       i+=2;
+                       result += lexical_cast<unsigned char>(str.substr(i+1, 2), "x");
+                       i += 2;
                }
                else if(c=='+')
-                       result+=' ';
+                       result += ' ';
                else
-                       result+=c;
+                       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 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