Update url parser

fixes #10039
This commit is contained in:
Jean Flach 2015-09-01 11:11:45 +02:00 committed by Michael Friedrich
parent 50cd694142
commit 6571ffc2c8
5 changed files with 177 additions and 10 deletions

View File

@ -31,7 +31,7 @@
#define ACSCHEME ALPHA NUMERIC ".-+" #define ACSCHEME ALPHA NUMERIC ".-+"
//authority = [ userinfo "@" ] host [ ":" port ] //authority = [ userinfo "@" ] host [ ":" port ]
#define ACUSERINFO UNRESERVED SUB_DELIMS ":" #define ACUSERINFO UNRESERVED SUB_DELIMS
#define ACHOST UNRESERVED SUB_DELIMS #define ACHOST UNRESERVED SUB_DELIMS
#define ACPORT NUMERIC #define ACPORT NUMERIC

View File

@ -27,6 +27,8 @@
using namespace icinga; using namespace icinga;
Url::Url() {}
Url::Url(const String& base_url) Url::Url(const String& base_url)
{ {
String url = base_url; String url = base_url;
@ -93,7 +95,43 @@ String Url::GetScheme(void) const
String Url::GetAuthority(void) const String Url::GetAuthority(void) const
{ {
return m_Authority; if (m_Host.IsEmpty())
return "";
String auth;
if (!m_Username.IsEmpty()) {
auth = m_Username;
if (!m_Password.IsEmpty())
auth += ":" + m_Password;
auth += "@";
}
auth += m_Host;
if (!m_Port.IsEmpty())
auth += ":" + m_Port;
return auth;
}
String Url::GetUsername(void) const
{
return m_Username;
}
String Url::GetPassword(void) const
{
return m_Password;
}
String Url::GetHost(void) const
{
return m_Host;
}
String Url::GetPort(void) const
{
return m_Port;
} }
const std::vector<String>& Url::GetPath(void) const const std::vector<String>& Url::GetPath(void) const
@ -132,16 +170,59 @@ String Url::GetFragment(void) const
{ {
return m_Fragment; return m_Fragment;
} }
void Url::SetScheme(const String& scheme)
{
m_Scheme = scheme;
}
String Url::Format(void) const void Url::SetAuthority(const String& username, const String& password, const String& host, const String& port)
{
m_Username = username;
m_Password = password;
m_Host = host;
m_Port = port;
}
void Url::SetPath(const std::vector<String>& path)
{
m_Path = path;
}
void Url::SetQuery(const std::map<String, std::vector<String> >& query)
{
m_Query = query;
}
void Url::AddQueryElement(const String& name, const String& value)
{
std::map<String, std::vector<String> >::iterator it = m_Query.find(name);
if (it == m_Query.end()) {
m_Query[name] = std::vector<String>();
m_Query[name].push_back(value);
} else
m_Query[name].push_back(value);
}
void Url::SetQueryElements(const String& name, const std::vector<String>& values)
{
m_Query[name] = values;
}
void Url::SetFragment(const String& fragment) {
m_Fragment = fragment;
}
String Url::Format(bool print_credentials) const
{ {
String url; String url;
if (!m_Scheme.IsEmpty()) if (!m_Scheme.IsEmpty())
url += m_Scheme + ":"; url += m_Scheme + ":";
if (!m_Authority.IsEmpty()) if (print_credentials && !GetAuthority().IsEmpty())
url += "//" + m_Authority; url += "//" + GetAuthority();
else if (!GetHost().IsEmpty())
url += "//" + GetHost() + (!GetPort().IsEmpty() ? ":" + GetPort() : "");
if (m_Path.empty()) if (m_Path.empty())
url += "/"; url += "/";
@ -194,9 +275,49 @@ bool Url::ParseScheme(const String& scheme)
bool Url::ParseAuthority(const String& authority) bool Url::ParseAuthority(const String& authority)
{ {
m_Authority = authority.SubStr(2); String auth = authority.SubStr(2);
//Just safe the Authority and don't care about the details size_t pos = auth.Find("@");
return (ValidateToken(m_Authority, ACHOST GEN_DELIMS)); if (pos != String::NPos && pos != 0) {
if (!Url::ParseUserinfo(auth.SubStr(0, pos)))
return false;
auth = auth.SubStr(pos+1);
}
pos = auth.Find(":");
if (pos != String::NPos) {
if (pos == 0 || pos == auth.GetLength() - 1 || !Url::ParsePort(auth.SubStr(pos+1)))
return false;
}
m_Host = auth.SubStr(0, pos-1);
return ValidateToken(m_Host, ACHOST);
}
bool Url::ParseUserinfo(const String& userinfo)
{
size_t pos = userinfo.Find(":");
m_Username = userinfo.SubStr(0, pos-1);
if (!ValidateToken(m_Username, ACUSERINFO))
return false;
m_Username = Utility::UnescapeString(m_Username);
if (pos != String::NPos && pos != userinfo.GetLength() - 1) {
//Password
m_Password = userinfo.SubStr(pos+1);
if (!ValidateToken(m_Username, ACUSERINFO))
return false;
m_Password = Utility::UnescapeString(m_Password);
} else
m_Password = "";
return true;
}
bool Url::ParsePort(const String& port)
{
m_Port = Utility::UnescapeString(m_Port);
if (!ValidateToken(m_Port, ACPORT))
return false;
return true;
} }
bool Url::ParsePath(const String& path) bool Url::ParsePath(const String& path)

View File

@ -41,27 +41,46 @@ class I2_REMOTE_API Url : public Object
public: public:
DECLARE_PTR_TYPEDEFS(Url); DECLARE_PTR_TYPEDEFS(Url);
Url();
Url(const String& url); Url(const String& url);
String Format(void) const; String Format(bool print_credentials = false) const;
String GetScheme(void) const; String GetScheme(void) const;
String GetAuthority(void) const; String GetAuthority(void) const;
String GetUsername(void) const;
String GetPassword(void) const;
String GetHost(void) const;
String GetPort(void) const;
const std::vector<String>& GetPath(void) const; const std::vector<String>& GetPath(void) const;
const std::map<String, std::vector<String> >& GetQuery(void) const; const std::map<String, std::vector<String> >& GetQuery(void) const;
String GetQueryElement(const String& name) const; String GetQueryElement(const String& name) const;
const std::vector<String>& GetQueryElements(const String& name) const; const std::vector<String>& GetQueryElements(const String& name) const;
String GetFragment(void) const; String GetFragment(void) const;
void SetScheme(const String& scheme);
void SetAuthority(const String& username, const String& password,
const String& host, const String& port);
void SetPath(const std::vector<String>& path);
void SetQuery(const std::map<String, std::vector<String> >& query);
void AddQueryElement(const String& name, const String& query);
void SetQueryElements(const String& name, const std::vector<String>& query);
void SetFragment(const String& fragment);
private: private:
String m_Scheme; String m_Scheme;
String m_Authority; String m_Username;
String m_Password;
String m_Host;
String m_Port;
std::vector<String> m_Path; std::vector<String> m_Path;
std::map<String, std::vector<String> > m_Query; std::map<String, std::vector<String> > m_Query;
String m_Fragment; String m_Fragment;
bool ParseScheme(const String& scheme); bool ParseScheme(const String& scheme);
bool ParseAuthority(const String& authority); bool ParseAuthority(const String& authority);
bool ParseUserinfo(const String& userinfo);
bool ParsePort(const String& port);
bool ParsePath(const String& path); bool ParsePath(const String& path);
bool ParseQuery(const String& query); bool ParseQuery(const String& query);
bool ParseFragment(const String& fragment); bool ParseFragment(const String& fragment);

View File

@ -111,6 +111,7 @@ add_boost_test(base
remote_apiuser/check_password remote_apiuser/check_password
remote_url/id_and_path remote_url/id_and_path
remote_url/parameters remote_url/parameters
remote_url/get_and_set
remote_url/format remote_url/format
remote_url/illegal_legal_strings remote_url/illegal_legal_strings
) )

View File

@ -21,6 +21,7 @@
#include "remote/url.hpp" #include "remote/url.hpp"
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
using namespace icinga; using namespace icinga;
@ -42,6 +43,31 @@ BOOST_AUTO_TEST_CASE(id_and_path)
BOOST_CHECK(url->GetPath() == PathCorrect); BOOST_CHECK(url->GetPath() == PathCorrect);
} }
BOOST_AUTO_TEST_CASE(get_and_set)
{
Url::Ptr url = new Url();
url->SetScheme("ftp");
url->SetAuthority("Horst", "Seehofer", "koenigreich.bayern", "1918");
std::vector<String> p = boost::assign::list_of("path")("to")("münchen");
url->SetPath(p);
BOOST_CHECK(url->Format(true) == "ftp://Horst:Seehofer@koenigreich.bayern:1918/path/to/m%C3%BCnchen");
std::map<String, std::vector<String> > m;
std::vector<String> v1 = boost::assign::list_of("hip")("hip")("hurra");
std::vector<String> v2 = boost::assign::list_of("äü^ä+#ül-");
std::vector<String> v3 = boost::assign::list_of("1")("2");
m.insert(std::pair<String, std::vector<String> >("shout", v1));
m.insert(std::pair<String, std::vector<String> >("sonderzeichen", v2));
url->SetQuery(m);
url->SetQueryElements("count", v3);
url->AddQueryElement("count", "3");
std::map<String, std::vector<String> > mn = url->GetQuery();
BOOST_CHECK(mn["shout"][0] == v1[0]);
BOOST_CHECK(mn["sonderzeichen"][0] == v2[0]);
BOOST_CHECK(mn["count"][2] == "3");
}
BOOST_AUTO_TEST_CASE(parameters) BOOST_AUTO_TEST_CASE(parameters)
{ {
Url::Ptr url = new Url("https://icinga.org/hya/?rain=karl&rair=robert&foo[]=bar"); Url::Ptr url = new Url("https://icinga.org/hya/?rain=karl&rair=robert&foo[]=bar");