]> granicus.if.org Git - icinga2/commitdiff
Update url parser
authorJean Flach <jean-marcel.flach@netways.de>
Wed, 29 Jul 2015 11:09:42 +0000 (13:09 +0200)
committerJean Flach <jean-marcel.flach@netways.de>
Wed, 29 Jul 2015 11:14:43 +0000 (13:14 +0200)
fixes #9768

lib/remote/httputility.cpp
lib/remote/url-characters.hpp
lib/remote/url.cpp
lib/remote/url.hpp
test/remote-url.cpp

index 86ddef21f46657d313f78c2eb9f762703d18bc96..a0f0d5f2641339490e11165bd2e70ccb94871157 100644 (file)
@@ -40,9 +40,9 @@ Dictionary::Ptr HttpUtility::FetchRequestParameters(HttpRequest& request)
        if (!result)
                result = new Dictionary();
 
-       typedef std::pair<String, Value> kv_pair;
+       typedef std::pair<String, std::vector<String> > kv_pair;
        BOOST_FOREACH(const kv_pair& kv, request.RequestUrl->GetQuery()) {
-               result->Set(kv.first, kv.second);
+               result->Set(kv.first, Array::FromVector(kv.second));
        }
 
        return result;
index a497655c47ad5ffb41ff79dc847c1a626ed92e49..ab2c9793951c61f0b040b7eebd50a5cb3a3e03ab 100644 (file)
@@ -22,7 +22,7 @@
 #define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 #define NUMERIC "0123456789"
 
-#define UNRESERVED ALPHA NUMERIC "-._~"
+#define UNRESERVED ALPHA NUMERIC "-._~" "%"
 #define GEN_DELIMS ":/?#[]@"
 #define SUB_DELIMS "!$&'()*+,;="
 #define RESERVED GEN_DELIMS SUB-DELIMS
index 581de9befe3b631d70ce0f37cfb277d895d9ccc3..e908d05e72483324fbc3cc6409e0abba139b0c65 100644 (file)
@@ -36,9 +36,7 @@ Url::Url(const String& base_url)
 
        size_t pHelper = url.Find(":");
 
-       if (pHelper == String::NPos) {
-               m_Scheme = "";
-       } else {
+       if (pHelper != String::NPos) {
                if (!ParseScheme(url.SubStr(0, pHelper)))
                        BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid URL Scheme."));
                url = url.SubStr(pHelper + 1);
@@ -51,9 +49,7 @@ Url::Url(const String& base_url)
                return;
        }
 
-       if (*(url.Begin() + 1) != '/')
-               m_Authority = "";
-       else {
+       if (*(url.Begin() + 1) == '/') {
                pHelper = url.Find("/", 2);
 
                if (pHelper == String::NPos)
@@ -105,21 +101,32 @@ const std::vector<String>& Url::GetPath(void) const
        return m_Path;
 }
 
-const std::map<String,Value>& Url::GetQuery(void) const
+const std::map<String, std::vector<String> >& Url::GetQuery(void) const
 {
        return m_Query;
 }
 
-Value Url::GetQueryElement(const String& name) const
+String Url::GetQueryElement(const String& name) const
 {
-       std::map<String, Value>::const_iterator it = m_Query.find(name);
+       std::map<String, std::vector<String> >::const_iterator it = m_Query.find(name);
 
        if (it == m_Query.end())
-               return Empty;
+               return String();
 
-       return it->second;
+       return it->second.back();
 }
 
+const std::vector<String>& Url::GetQueryElements(const String& name) const
+{
+       std::map<String, std::vector<String> >::const_iterator it = m_Query.find(name);
+
+       if (it == m_Query.end()) {
+               static std::vector<String> emptyVector;
+               return emptyVector;
+       }
+
+       return it->second;
+}
 
 String Url::GetFragment(void) const
 {
@@ -128,7 +135,7 @@ String Url::GetFragment(void) const
 
 String Url::Format(void) const
 {
-       String url = "";
+       String url;
 
        if (!m_Scheme.IsEmpty())
                url += m_Scheme + ":";
@@ -145,9 +152,9 @@ String Url::Format(void) const
                }
        }
 
-       String param = "";
+       String param;
        if (!m_Query.empty()) {
-               typedef std::pair<String, Value> kv_pair;
+               typedef std::pair<String, std::vector<String> > kv_pair;
 
                BOOST_FOREACH (const kv_pair& kv, m_Query) {
                        String key = Utility::EscapeString(kv.first, ACQUERY, false);
@@ -155,28 +162,15 @@ String Url::Format(void) const
                                param = "?";
                        else
                                param += "&";
+                       
+                       String temp;
+                       BOOST_FOREACH (const String s, kv.second) {
+                               if (!temp.IsEmpty())
+                                       temp += "&";
 
-                       Value val = kv.second;
-
-                       if (val.IsEmpty())
-                               param += key;
-                       else {
-                               if (val.IsObjectType<Array>()) {
-                                       Array::Ptr arr = val;
-                                       String temp = "";
-
-                                       ObjectLock olock(arr);
-                                       BOOST_FOREACH (const String& sArrIn, arr) {
-                                               if (!temp.IsEmpty())
-                                                       temp += "&";
-
-                                               temp += key + "[]=" + Utility::EscapeString(sArrIn, ACQUERY, false);
-                                       }
-
-                                       param += temp;
-                               } else
-                                       param += key + "=" + Utility::EscapeString(kv.second, ACQUERY, false);
+                               temp += key + "[]=" + Utility::EscapeString(s, ACQUERY, false);
                        }
+                       param += temp;
                }
        }
 
@@ -200,9 +194,9 @@ bool Url::ParseScheme(const String& scheme)
 
 bool Url::ParseAuthority(const String& authority)
 {
-       //TODO parse all Authorities
        m_Authority = authority.SubStr(2);
-       return (ValidateToken(m_Authority, ACHOST));
+       //Just safe the Authority and don't care about the details
+       return (ValidateToken(m_Authority, ACHOST GEN_DELIMS));
 }
 
 bool Url::ParsePath(const String& path)
@@ -236,56 +230,41 @@ bool Url::ParseQuery(const String& query)
        BOOST_FOREACH(const String& token, tokens) {
                size_t pHelper = token.Find("=");
 
+               if (pHelper == 0)
+                       // /?foo=bar&=bar == invalid
+                       return false;
+               
                String key = token.SubStr(0, pHelper);
                String value = Empty;
 
-               if (pHelper != String::NPos) {
-                       if (pHelper == token.GetLength() - 1)
-                               return false;
-
-                       value = token.SubStr(pHelper + 1);
-                       if (!ValidateToken(value, ACQUERY))
-                               return false;
-                       else
-                               value = Utility::UnescapeString(value);
-               } else
-                       String key = token;
+               if (pHelper != token.GetLength()-1)
+                       value = token.SubStr(pHelper+1);
 
-               if (key.IsEmpty())
+               if (!ValidateToken(value, ACQUERY))
                        return false;
+               
+               value = Utility::UnescapeString(value);
 
                pHelper = key.Find("[]");
 
-               if (pHelper != String::NPos) {
-
-                       if (key.GetLength() < 3)
-                               return false;
-
-                       key = key.SubStr(0, key.GetLength() - 2);
-                       key = Utility::UnescapeString(key);
+               if (pHelper == 0 || (pHelper != String::NPos && pHelper != key.GetLength()-2))
+                       return false;
 
-                       if (!ValidateToken(value, ACQUERY))
-                               return false;
+               key = key.SubStr(0, pHelper);
+               
+               if (!ValidateToken(key, ACQUERY))
+                       return false;
 
-                       std::map<String, Value>::iterator it = m_Query.find(key);
+               key = Utility::UnescapeString(key);
 
-                       if (it == m_Query.end()) {
-                               Array::Ptr tmp = new Array();
-                               tmp->Add(Utility::UnescapeString(value));
-                               m_Query[key] = tmp;
-                       } else if (m_Query[key].IsObjectType<Array>()){
-                               Array::Ptr arr = it->second;
-                               arr->Add(Utility::UnescapeString(value));
-                       } else
-                               return false;
-               } else {
-                       key = Utility::UnescapeString(key);
+               std::map<String, std::vector<String> >::iterator it = m_Query.find(key);
 
-                       if (m_Query.find(key) == m_Query.end() && ValidateToken(key, ACQUERY))
-                               m_Query[key] = Utility::UnescapeString(value);
-                       else
-                               return false;
-               }
+               if (it == m_Query.end()) {
+                       m_Query[key] = std::vector<String>();
+                       m_Query[key].push_back(value);
+               } else
+                       m_Query[key].push_back(value);
+               
        }
 
        return true;
index 35bc63dde56593e14660a0dadc280ee551270b05..f5144456825ddf2b02dc638f878da56e0f3003f4 100644 (file)
@@ -23,6 +23,7 @@
 #include "remote/i2-remote.hpp"
 #include "base/object.hpp"
 #include "base/string.hpp"
+#include "base/array.hpp"
 #include "base/value.hpp"
 #include <map>
 #include <vector>
@@ -47,15 +48,16 @@ public:
        String GetScheme(void) const;
        String GetAuthority(void) const;
        const std::vector<String>& GetPath(void) const;
-       const std::map<String,Value>& GetQuery(void) const;
-       Value GetQueryElement(const String& name) 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;
 
 private:
        String m_Scheme;
        String m_Authority;
        std::vector<String> m_Path;
-       std::map<String,Value> m_Query;
+       std::map<String, std::vector<String> > m_Query;
        String m_Fragment;
 
        bool ParseScheme(const String& scheme);
index 158df6dbb94abfbec0f24534a6e5664913414605..1dcc8696c1d56a1ff3700476c60b1ff236e8391b 100644 (file)
@@ -48,10 +48,9 @@ BOOST_AUTO_TEST_CASE(parameters)
 
        BOOST_CHECK(url->GetQueryElement("rair") == "robert");
        BOOST_CHECK(url->GetQueryElement("rain") == "karl");
-       BOOST_CHECK(url->GetQueryElement("foo").IsObjectType<Array>());
-       Array::Ptr test = url->GetQueryElement("foo");
-       BOOST_CHECK(test->GetLength() == 1);
-       BOOST_CHECK(test->Get(0) == "bar");
+       std::vector<String> test = url->GetQueryElements("foo");
+       BOOST_CHECK(test.size() == 1);
+       BOOST_CHECK(test[0] == "bar");
 }
 
 BOOST_AUTO_TEST_CASE(format)
@@ -71,12 +70,13 @@ BOOST_AUTO_TEST_CASE(format)
 
 BOOST_AUTO_TEST_CASE(illegal_legal_strings)
 {
-       BOOST_CHECK_THROW(new Url("/?foo=barr&foo[]=bazz"), std::invalid_argument);
+       BOOST_CHECK(new Url("/?foo=barr&foo[]=bazz"));
        BOOST_CHECK_THROW(new Url("/?]=gar"), std::invalid_argument);
        BOOST_CHECK_THROW(new Url("/#?[]"), std::invalid_argument);
-       BOOST_CHECK_THROW(new Url("/?foo=bar&foo=ba"), std::invalid_argument);
+       BOOST_CHECK(new Url("/?foo=bar&foo=ba"));
        BOOST_CHECK_THROW(new Url("/?foo=bar&[]=d"), std::invalid_argument);
-       BOOST_CHECK_THROW(new Url("/?fo=&bar=garOA"), std::invalid_argument);
+       BOOST_CHECK(new Url("/?fo=&bar=garOA"));
+       BOOST_CHECK(new Url("https://127.0.0.1:5665/demo?type=Service&filter=service.state%3E0"));
        BOOST_CHECK(new Url("/?foo=baz??&\?\?=/?"));
        BOOST_CHECK(new Url("/"));
        BOOST_CHECK(new Url("///////"));