]> granicus.if.org Git - icinga2/commitdiff
Update url parser
authorJean Flach <jean-marcel.flach@netways.de>
Tue, 1 Sep 2015 09:11:45 +0000 (11:11 +0200)
committerMichael Friedrich <michael.friedrich@netways.de>
Fri, 4 Sep 2015 12:40:27 +0000 (14:40 +0200)
fixes #10039

lib/remote/url-characters.hpp
lib/remote/url.cpp
lib/remote/url.hpp
test/CMakeLists.txt
test/remote-url.cpp

index ab2c9793951c61f0b040b7eebd50a5cb3a3e03ab..73a098be77e1ed669417701f712aa889ca1db45d 100644 (file)
@@ -31,7 +31,7 @@
 #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
 
index e908d05e72483324fbc3cc6409e0abba139b0c65..6f1e2f2e80f01fb8951b2ccab38d084acbe686cd 100644 (file)
@@ -27,6 +27,8 @@
 
 using namespace icinga;
 
+Url::Url() {}
+
 Url::Url(const String& base_url)
 {
        String url = base_url;
@@ -93,7 +95,43 @@ String Url::GetScheme(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
@@ -132,16 +170,59 @@ String Url::GetFragment(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 += "/";
@@ -194,9 +275,49 @@ bool Url::ParseScheme(const String& scheme)
 
 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)
index f5144456825ddf2b02dc638f878da56e0f3003f4..d2ad7d458938d277c030d848bb8e214c3f15286e 100644 (file)
@@ -41,27 +41,46 @@ class I2_REMOTE_API Url : public Object
 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);
index 53fa3ef8845a7f60f7f6eea9ec92f45ae52e8431..b8cbca6b21f095e8311c51f3ddbb6c0e6b87d863 100644 (file)
@@ -111,6 +111,7 @@ add_boost_test(base
         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
 )
index 1dcc8696c1d56a1ff3700476c60b1ff236e8391b..21cd99c6662be4379d9aa1801c558de7048d911c 100644 (file)
@@ -21,6 +21,7 @@
 #include "remote/url.hpp"
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
+#include <boost/assign/list_of.hpp>
 
 using namespace icinga;
 
@@ -42,6 +43,31 @@ BOOST_AUTO_TEST_CASE(id_and_path)
        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");