#include <msp/strings/regex.h>
#include <msp/strings/utils.h>
#include "request.h"
+#include "utils.h"
using namespace std;
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
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;
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;
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
#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