]> git.tdb.fi Git - libs/net.git/commitdiff
Add functions for parsing and building URIs and query strings
authorMikko Rasa <tdb@tdb.fi>
Sat, 8 Aug 2009 21:41:01 +0000 (21:41 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sat, 8 Aug 2009 21:41:01 +0000 (21:41 +0000)
Use the new parse_url function in Request::from_url
Add urlencode_plus function
Support POST method
Three different encoding levels for urlencode
Add Message::has_header to check for header existence without exceptions

source/message.cpp
source/message.h
source/request.cpp
source/server.cpp
source/utils.cpp
source/utils.h

index 93937c90a71dff3ee8fa65a2fdf973f37e515525..4aaa8bfd26d1fab34302cd6f32e0c583bac133fe 100644 (file)
@@ -26,6 +26,11 @@ void Message::set_header(const string &hdr, const string &val)
        headers[normalize_header_name(hdr)]=val;
 }
 
+bool Message::has_header(const string &hdr) const
+{
+       return headers.count(normalize_header_name(hdr));
+}
+
 const string &Message::get_header(const string &hdr) const
 {
        HeaderMap::const_iterator i=headers.find(normalize_header_name(hdr));
index ae38ffafd9a65dbc1bda16f838da41cb3efa1664..6e139bd283c7ec9b5d942b087c1e33a3a14fe342 100644 (file)
@@ -33,6 +33,7 @@ public:
        virtual ~Message() { }
 
        void set_header(const std::string &, const std::string &);
+       bool has_header(const std::string &) const;
        const std::string &get_header(const std::string &) const;
        void add_content(const std::string &);
        const std::string &get_content() const { return content; }
index bcf36c991f727f5c539a6431304d68691dd5be92..6bad3700681fefdffd40178a88e44cb146442e0b 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #include <msp/strings/regex.h>
 #include <msp/strings/utils.h>
 #include "request.h"
+#include "utils.h"
 
 using namespace std;
 
@@ -45,23 +46,25 @@ Request Request::parse(const string &str)
        return result;
 }
 
-Request Request::from_url(const string &url)
+Request Request::from_url(const string &str)
 {
-       if(RegMatch match=Regex("^http://([a-zA-Z0-9.-]+(:[0-9]+)?)(/[^ #]*)?$").match(url))
+       Url url=parse_url(str);
+       if(url.scheme!="http")
+               throw InvalidParameterValue("Only http scheme is supported");
+       string path=url.path;
+       if(path.empty())
+               path="/";
+       if(!url.query.empty())
        {
-               string host=match[1].str;
-               string path=match[3].str;
-               if(path.empty())
-                       path="/";
+               path+='?';
+               path+=url.query;
+       }
 
-               Request result("GET", path);
-               result.set_header("Host", host);
-               result.set_header("Connection", "close");
+       Request result("GET", path);
+       result.set_header("Host", url.host);
+       result.set_header("Connection", "close");
 
-               return result;
-       }
-       else
-               throw InvalidParameterValue("Invalid URL");
+       return result;
 }
 
 } // namespace Http
index 04eea524ec895637ae34d7c302a2fe5b621d89a0..2e427b974af5ce7a3da4231f596c314235c94463 100644 (file)
@@ -103,7 +103,7 @@ void Server::client_data_available(Client &cl)
                                unsigned colon=addr_str.find(':');
                                cl.request->set_header("-Client-Host", addr_str.substr(0, colon));
 
-                               if(cl.request->get_method()!="GET")
+                               if(cl.request->get_method()!="GET" && cl.request->get_method()!="POST")
                                {
                                        response=new Response(NOT_IMPLEMENTED);
                                        response->add_content("Method not implemented");
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
index 76127a4525845562841c4084d14557f8e948c021..559638a34bf6512e6b289b54efc68ab56c56c889 100644 (file)
@@ -8,13 +8,37 @@ Distributed under the LGPL
 #ifndef MSP_HTTP_UTILS_H_
 #define MSP_HTTP_UTILS_H_
 
+#include <map>
 #include <string>
 
 namespace Msp {
 namespace Http {
 
-std::string urlencode(const std::string &);
+enum EncodeLevel
+{
+       MINIMAL,
+       SAFE,
+       PARANOID
+};
+
+struct Url
+{
+       std::string scheme;
+       std::string host;
+       std::string path;
+       std::string query;
+       std::string fragment;
+};
+
+typedef std::map<std::string, std::string> Query;
+
+std::string urlencode(const std::string &, EncodeLevel =SAFE);
+std::string urlencode_plus(const std::string &, EncodeLevel =SAFE);
 std::string urldecode(const std::string &);
+Url parse_url(const std::string &);
+std::string build_url(const Url &);
+Query parse_query(const std::string &);
+std::string build_query(const Query &);
 
 } // namespace Http
 } // namespace Msp