From: Jun LI Date: Fri, 25 Jul 2014 00:07:36 +0000 (-0700) Subject: Add method to parse parameter list in query string to folly::Uri X-Git-Tag: v0.22.0~431 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1e5e33a557fc1f2b7f1322b928566fe71bcf26ad;p=folly.git Add method to parse parameter list in query string to folly::Uri Summary: Add a method to folly::Uri to get parsed query string e.g. http://localhost?key1=foo&key2=bar We can get key value map containing: "key1" => "foo" "key2" => "bar" Test Plan: fbconfig folly/test fbmake runtests_dbg Reviewed By: tudorb@fb.com Subscribers: wormhole-dev@ FB internal diff: D1455158 Tasks: 4768038 --- diff --git a/folly/Uri.cpp b/folly/Uri.cpp index 5b2c155b..f7bf80fa 100644 --- a/folly/Uri.cpp +++ b/folly/Uri.cpp @@ -91,6 +91,26 @@ Uri::Uri(StringPiece str) : port_(0) { } query_ = submatch(match, 3); + if (!query_.empty()) { + // Parse query string + static const boost::regex queryParamRegex( + "(^|&)([^=&]*)=?([^=&]*)(?=(&|$))"); + boost::cregex_iterator paramBeginItr( + match[3].first, + match[3].second, + queryParamRegex); + boost::cregex_iterator paramEndItr; + for(auto itr = paramBeginItr; itr != paramEndItr; itr++) { + if (itr->length(2) == 0) { + // key is empty, ignore it + continue; + } + queryParams_.emplace_back( + fbstring((*itr)[2].first, (*itr)[2].second), // parameter name + fbstring((*itr)[3].first, (*itr)[3].second) // parameter value + ); + } + } fragment_ = submatch(match, 4); } diff --git a/folly/Uri.h b/folly/Uri.h index e7b38615..581307d9 100644 --- a/folly/Uri.h +++ b/folly/Uri.h @@ -18,6 +18,7 @@ #define FOLLY_URI_H_ #include +#include namespace folly { @@ -77,6 +78,26 @@ class Uri { void setPort(uint16_t port) {port_ = port;} + /** + * Get query parameters as key-value pairs. + * e.g. for URI containing query string: key1=foo&key2=&key3&=bar&=bar= + * In returned list, there are 3 entries: + * "key1" => "foo" + * "key2" => "" + * "key3" => "" + * Parts "=bar" and "=bar=" are ignored, as they are not valid query + * parameters. "=bar" is missing parameter name, while "=bar=" has more than + * one equal signs, we don't know which one is the delimiter for key and + * value. + * + * @return query parameter key-value pairs in a vector, each element is a + * pair of which the first element is parameter name and the second + * one is parameter value + */ + const std::vector>& getQueryParams() const { + return queryParams_; + }; + private: fbstring scheme_; fbstring username_; @@ -86,6 +107,7 @@ class Uri { fbstring path_; fbstring query_; fbstring fragment_; + std::vector> queryParams_; }; } // namespace folly diff --git a/folly/test/UriTest.cpp b/folly/test/UriTest.cpp index 7edc84d9..7f8faee8 100644 --- a/folly/test/UriTest.cpp +++ b/folly/test/UriTest.cpp @@ -19,6 +19,7 @@ #include #include #include +#include using namespace folly; @@ -255,6 +256,73 @@ TEST(Uri, Simple) { EXPECT_EQ(s, u.fbstr()); } + { + // test query parameters + fbstring s("http://localhost?&key1=foo&key2=&key3&=bar&=bar=&"); + Uri u(s); + auto paramsList = u.getQueryParams(); + std::map params; + for (auto& param : paramsList) { + params[param.first] = param.second; + } + EXPECT_EQ(3, params.size()); + EXPECT_EQ("foo", params["key1"]); + EXPECT_NE(params.end(), params.find("key2")); + EXPECT_EQ("", params["key2"]); + EXPECT_NE(params.end(), params.find("key3")); + EXPECT_EQ("", params["key3"]); + } + + { + // test query parameters + fbstring s("http://localhost?&&&&&&&&&&&&&&&"); + Uri u(s); + auto params = u.getQueryParams(); + EXPECT_TRUE(params.empty()); + } + + { + // test query parameters + fbstring s("http://localhost?&=invalid_key&key2&key3=foo"); + Uri u(s); + auto paramsList = u.getQueryParams(); + std::map params; + for (auto& param : paramsList) { + params[param.first] = param.second; + } + EXPECT_EQ(2, params.size()); + EXPECT_NE(params.end(), params.find("key2")); + EXPECT_EQ("", params["key2"]); + EXPECT_EQ("foo", params["key3"]); + } + + { + // test query parameters + fbstring s("http://localhost?&key1=====&&=key2&key3="); + Uri u(s); + auto paramsList = u.getQueryParams(); + std::map params; + for (auto& param : paramsList) { + params[param.first] = param.second; + } + EXPECT_EQ(1, params.size()); + EXPECT_NE(params.end(), params.find("key3")); + EXPECT_EQ("", params["key3"]); + } + + { + // test query parameters + fbstring s("http://localhost?key1=foo=bar&key2=foobar&"); + Uri u(s); + auto paramsList = u.getQueryParams(); + std::map params; + for (auto& param : paramsList) { + params[param.first] = param.second; + } + EXPECT_EQ(1, params.size()); + EXPECT_EQ("foobar", params["key2"]); + } + { fbstring s("2http://www.facebook.com");