#define ACSCHEME ALPHA NUMERIC ".-+"
//authority = [ userinfo "@" ] host [ ":" port ]
-#define ACUSERINFO UNRESERVED SUB_DELIMS ":"
+#define ACUSERINFO UNRESERVED SUB_DELIMS
#define ACHOST UNRESERVED SUB_DELIMS
#define ACPORT NUMERIC
using namespace icinga;
+Url::Url() {}
+
Url::Url(const String& base_url)
{
String url = base_url;
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
{
return m_Fragment;
}
+void Url::SetScheme(const String& scheme)
+{
+ m_Scheme = scheme;
+}
+
+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;
+}
-String Url::Format(void) const
+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;
if (!m_Scheme.IsEmpty())
url += m_Scheme + ":";
- if (!m_Authority.IsEmpty())
- url += "//" + m_Authority;
+ if (print_credentials && !GetAuthority().IsEmpty())
+ url += "//" + GetAuthority();
+ else if (!GetHost().IsEmpty())
+ url += "//" + GetHost() + (!GetPort().IsEmpty() ? ":" + GetPort() : "");
if (m_Path.empty())
url += "/";
bool Url::ParseAuthority(const String& authority)
{
- m_Authority = authority.SubStr(2);
- //Just safe the Authority and don't care about the details
- return (ValidateToken(m_Authority, ACHOST GEN_DELIMS));
+ String auth = authority.SubStr(2);
+ size_t pos = auth.Find("@");
+ 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)
public:
DECLARE_PTR_TYPEDEFS(Url);
+ Url();
Url(const String& url);
- String Format(void) const;
+ String Format(bool print_credentials = false) const;
String GetScheme(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::map<String, std::vector<String> >& GetQuery(void) const;
String GetQueryElement(const String& name) const;
const std::vector<String>& GetQueryElements(const String& name) 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:
String m_Scheme;
- String m_Authority;
+ String m_Username;
+ String m_Password;
+ String m_Host;
+ String m_Port;
std::vector<String> m_Path;
std::map<String, std::vector<String> > m_Query;
String m_Fragment;
bool ParseScheme(const String& scheme);
bool ParseAuthority(const String& authority);
+ bool ParseUserinfo(const String& userinfo);
+ bool ParsePort(const String& port);
bool ParsePath(const String& path);
bool ParseQuery(const String& query);
bool ParseFragment(const String& fragment);
remote_apiuser/check_password
remote_url/id_and_path
remote_url/parameters
+ remote_url/get_and_set
remote_url/format
remote_url/illegal_legal_strings
)
#include "remote/url.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
+#include <boost/assign/list_of.hpp>
using namespace icinga;
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)
{
Url::Ptr url = new Url("https://icinga.org/hya/?rain=karl&rair=robert&foo[]=bar");