From a2196bd935e556225723ff1035c634f508a33bb1 Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Mon, 10 Feb 2020 18:16:12 +0300 Subject: [PATCH] [coding] Using url::Params in class Uri instead of plain strings. --- coding/coding_tests/url_tests.cpp | 10 +-- coding/url.cpp | 100 ++++++++++++++++-------------- coding/url.hpp | 46 +++++++------- map/mwm_url.cpp | 49 +++++++-------- 4 files changed, 103 insertions(+), 102 deletions(-) diff --git a/coding/coding_tests/url_tests.cpp b/coding/coding_tests/url_tests.cpp index 0175b7362d..c820f89798 100644 --- a/coding/coding_tests/url_tests.cpp +++ b/coding/coding_tests/url_tests.cpp @@ -31,15 +31,15 @@ public: TEST_EQUAL(uri.GetScheme(), m_scheme, ()); TEST_EQUAL(uri.GetPath(), m_path, ()); TEST(!m_scheme.empty() || !uri.IsValid(), ("Scheme is empty if and only if uri is invalid!")); - uri.ForEachKeyValue(bind(&TestUri::AddTestValue, this, placeholders::_1, placeholders::_2)); + uri.ForEachParam(bind(&TestUri::AddTestValue, this, placeholders::_1)); } private: - bool AddTestValue(string const & key, string const & value) + bool AddTestValue(url::Param const & param) { - TEST(!m_keyValuePairs.empty(), ("Failed for uri = ", m_uri, "Passed KV = ", key, value)); - TEST_EQUAL(m_keyValuePairs.front().first, key, ()); - TEST_EQUAL(m_keyValuePairs.front().second, value, ()); + TEST(!m_keyValuePairs.empty(), ("Failed for uri = ", m_uri, "Passed KV = ", param)); + TEST_EQUAL(m_keyValuePairs.front().first, param.m_name, ()); + TEST_EQUAL(m_keyValuePairs.front().second, param.m_value, ()); m_keyValuePairs.pop(); return true; } diff --git a/coding/url.cpp b/coding/url.cpp index 1d7568ac40..ca1693218d 100644 --- a/coding/url.cpp +++ b/coding/url.cpp @@ -40,30 +40,30 @@ public: return m_latPriority == m_lonPriority && m_latPriority != -1; } - bool operator()(string const & key, string const & value) + bool operator()(url::Param const & param) { - if (key == "z" || key == "zoom") + if (param.m_name == "z" || param.m_name == "zoom") { double x; - if (strings::to_double(value, x)) + if (strings::to_double(param.m_value, x)) m_info.SetZoom(x); return true; } - int const priority = GetCoordinatesPriority(key); + int const priority = GetCoordinatesPriority(param.m_name); if (priority == -1 || priority < m_latPriority || priority < m_lonPriority) return false; if (priority != kLatLonPriority) { - strings::ForEachMatched(value, m_regexp, AssignCoordinates(*this, priority)); + strings::ForEachMatched(param.m_value, m_regexp, AssignCoordinates(*this, priority)); return true; } double x; - if (strings::to_double(value, x)) + if (strings::to_double(param.m_value, x)) { - if (key == "lat") + if (param.m_name == "lat") { if (!m_info.SetLat(x)) return false; @@ -71,7 +71,7 @@ public: } else { - ASSERT_EQUAL(key, "lon", ()); + ASSERT_EQUAL(param.m_name, "lon", ()); if (!m_info.SetLon(x)) return false; m_lonPriority = priority; @@ -148,86 +148,94 @@ private: namespace url { -Uri::Uri(std::string const & uri) : m_url(uri) +std::string DebugPrint(Param const & param) { - if (!Parse()) + return "UrlParam [" + param.m_name + "=" + param.m_value + "]"; +} + +Uri::Uri(std::string const & uri) +{ + if (!Parse(uri)) { ASSERT(m_scheme.empty() && m_path.empty() && !IsValid(), ()); - m_queryStart = m_url.size(); } } -bool Uri::Parse() +bool Uri::Parse(std::string const & uri) { // Get url scheme. - size_t pathStart = m_url.find(':'); + size_t pathStart = uri.find(':'); if (pathStart == string::npos || pathStart == 0) return false; - m_scheme.assign(m_url, 0, pathStart); + m_scheme.assign(uri, 0, pathStart); // Skip slashes. - while (++pathStart < m_url.size() && m_url[pathStart] == '/') + while (++pathStart < uri.size() && uri[pathStart] == '/') { } // Find query starting point for (key, value) parsing. - m_queryStart = m_url.find('?', pathStart); + size_t queryStart = uri.find('?', pathStart); size_t pathLength; - if (m_queryStart == string::npos) + if (queryStart == string::npos) { - m_queryStart = m_url.size(); - pathLength = m_queryStart - pathStart; + queryStart = uri.size(); + pathLength = queryStart - pathStart; } else { - pathLength = m_queryStart - pathStart; - ++m_queryStart; + pathLength = queryStart - pathStart; + ++queryStart; } // Get path (url without query). - m_path.assign(m_url, pathStart, pathLength); + m_path.assign(uri, pathStart, pathLength); - return true; -} - -bool Uri::ForEachKeyValue(Callback const & callback) const -{ // Parse query for keys and values. - size_t const count = m_url.size(); - size_t const queryStart = m_queryStart; - - // Just a URL without parameters. - if (queryStart == count) - return false; - - for (size_t start = queryStart; start < count; ) + for (size_t start = queryStart; start < uri.size();) { - size_t end = m_url.find('&', start); + size_t end = uri.find('&', start); if (end == string::npos) - end = count; + end = uri.size(); // Skip empty keys. if (end != start) { - size_t const eq = m_url.find('=', start); + size_t const eq = uri.find('=', start); - string key, value; + string key; + string value; if (eq != string::npos && eq < end) { - key = UrlDecode(m_url.substr(start, eq - start)); - value = UrlDecode(m_url.substr(eq + 1, end - eq - 1)); + key = UrlDecode(uri.substr(start, eq - start)); + value = UrlDecode(uri.substr(eq + 1, end - eq - 1)); } else { - key = UrlDecode(m_url.substr(start, end - start)); + key = UrlDecode(uri.substr(start, end - start)); } - if (!callback(key, value)) - return false; + m_params.emplace_back(key, value); } start = end + 1; } + + return true; +} + +bool Uri::ForEachParam(Callback const & callback) const +{ + // todo(@m) Looks strange but old code worked this way. + if (m_params.empty()) + return false; + + for (auto const & param : m_params) + { + if (!callback(param)) + return false; + } + return true; } @@ -325,8 +333,8 @@ GeoURLInfo::GeoURLInfo(string const & s) } LatLonParser parser(*this); - parser(string(), uri.GetPath()); - uri.ForEachKeyValue(ref(parser)); + parser(url::Param(string(), uri.GetPath())); + uri.ForEachParam(ref(parser)); if (!parser.IsValid()) { diff --git a/coding/url.hpp b/coding/url.hpp index a6ebf8be25..289a00f858 100644 --- a/coding/url.hpp +++ b/coding/url.hpp @@ -10,29 +10,6 @@ // order to simplify the usage. namespace url { -// Uri in format: 'scheme://path?key1=value1&key2&key3=&key4=value4' -class Uri -{ -public: - using Callback = std::function; - - explicit Uri(std::string const & uri); - - std::string const & GetScheme() const { return m_scheme; } - std::string const & GetPath() const { return m_path; } - bool IsValid() const { return !m_scheme.empty(); } - bool ForEachKeyValue(Callback const & callback) const; - -private: - bool Parse(); - - std::string m_url; - std::string m_scheme; - std::string m_path; - - size_t m_queryStart; -}; - struct Param { Param(std::string const & name, std::string const & value) : m_name(name), m_value(value) {} @@ -41,8 +18,31 @@ struct Param std::string m_value; }; +std::string DebugPrint(Param const & param); + using Params = std::vector; +// Uri in format: 'scheme://path?key1=value1&key2&key3=&key4=value4' +class Uri +{ +public: + using Callback = std::function; + + explicit Uri(std::string const & uri); + + std::string const & GetScheme() const { return m_scheme; } + std::string const & GetPath() const { return m_path; } + bool IsValid() const { return !m_scheme.empty(); } + bool ForEachParam(Callback const & callback) const; + +private: + bool Parse(std::string const & uri); + + std::string m_scheme; + std::string m_path; + std::vector m_params; +}; + // Make URL by using base url and vector of params. std::string Make(std::string const & baseUrl, Params const & params); diff --git a/map/mwm_url.cpp b/map/mwm_url.cpp index 1d1266d8b4..89503eea3a 100644 --- a/map/mwm_url.cpp +++ b/map/mwm_url.cpp @@ -205,10 +205,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) case ApiURLType::Map: { vector points; - auto const result = uri.ForEachKeyValue([&points, this](string const & key, string const & value) - { - return AddKeyValue(key, value, points); - }); + auto const result = uri.ForEachParam([&points, this](url::Param const & param) { + return AddKeyValue(param.m_name, param.m_value, points); + }); if (!result || points.empty()) return ParsingResult::Incorrect; @@ -231,10 +230,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) m_routePoints.clear(); using namespace route; vector pattern{kSourceLatLon, kSourceName, kDestLatLon, kDestName, kRouteType}; - auto const result = uri.ForEachKeyValue([&pattern, this](string const & key, string const & value) - { - return RouteKeyValue(key, value, pattern); - }); + auto const result = uri.ForEachParam([&pattern, this](url::Param const & param) { + return RouteKeyValue(param.m_name, param.m_value, pattern); + }); if (!result || pattern.size() != 0) return ParsingResult::Incorrect; @@ -250,10 +248,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) case ApiURLType::Search: { SearchRequest request; - auto const result = uri.ForEachKeyValue([&request, this](string const & key, string const & value) - { - return SearchKeyValue(key, value, request); - }); + auto const result = uri.ForEachParam([&request, this](url::Param const & param) { + return SearchKeyValue(param.m_name, param.m_value, request); + }); if (!result) return ParsingResult::Incorrect; @@ -263,10 +260,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) case ApiURLType::Lead: { lead::CampaignDescription description; - auto result = uri.ForEachKeyValue([&description, this](string const & key, string const & value) - { - return LeadKeyValue(key, value, description); - }); + auto result = uri.ForEachParam([&description, this](url::Param const & param) { + return LeadKeyValue(param.m_name, param.m_value, description); + }); if (!result || !description.IsValid()) return ParsingResult::Incorrect; @@ -277,10 +273,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) case ApiURLType::Catalogue: { Catalog item; - auto const result = uri.ForEachKeyValue([&item, this](string const & key, string const & value) - { - return CatalogKeyValue(key, value, item); - }); + auto const result = uri.ForEachParam([&item, this](url::Param const & param) { + return CatalogKeyValue(param.m_name, param.m_value, item); + }); if (!result || item.m_id.empty()) return ParsingResult::Incorrect; @@ -291,10 +286,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) case ApiURLType::CataloguePath: { CatalogPath item; - auto const result = uri.ForEachKeyValue([&item, this](string const & key, string const & value) - { - return CatalogPathKeyValue(key, value, item); - }); + auto const result = uri.ForEachParam([&item, this](url::Param const & param) { + return CatalogPathKeyValue(param.m_name, param.m_value, item); + }); if (!result || item.m_url.empty()) return ParsingResult::Incorrect; @@ -305,10 +299,9 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(url::Uri const & uri) case ApiURLType::Subscription: { Subscription item; - auto const result = uri.ForEachKeyValue([&item, this](string const & key, string const & value) - { - return SubscriptionKeyValue(key, value, item); - }); + auto const result = uri.ForEachParam([&item, this](url::Param const & param) { + return SubscriptionKeyValue(param.m_name, param.m_value, item); + }); if (!result || item.m_groups.empty()) return ParsingResult::Incorrect;