url_util_unittest.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/url_matcher/url_util.h"
  5. #include <memory>
  6. #include "base/values.h"
  7. #include "testing/gtest/include/gtest/gtest.h"
  8. #include "url/gurl.h"
  9. namespace url_matcher {
  10. namespace util {
  11. namespace {
  12. GURL GetEmbeddedURL(const std::string& url) {
  13. return url_matcher::util::GetEmbeddedURL(GURL(url));
  14. }
  15. // Parameters for the FilterToComponents test.
  16. struct FilterTestParams {
  17. public:
  18. FilterTestParams(const std::string& filter,
  19. const std::string& scheme,
  20. const std::string& host,
  21. bool match_subdomains,
  22. uint16_t port,
  23. const std::string& path)
  24. : filter_(filter),
  25. scheme_(scheme),
  26. host_(host),
  27. match_subdomains_(match_subdomains),
  28. port_(port),
  29. path_(path) {}
  30. FilterTestParams(const FilterTestParams& params)
  31. : filter_(params.filter_),
  32. scheme_(params.scheme_),
  33. host_(params.host_),
  34. match_subdomains_(params.match_subdomains_),
  35. port_(params.port_),
  36. path_(params.path_) {}
  37. const FilterTestParams& operator=(const FilterTestParams& params) {
  38. filter_ = params.filter_;
  39. scheme_ = params.scheme_;
  40. host_ = params.host_;
  41. match_subdomains_ = params.match_subdomains_;
  42. port_ = params.port_;
  43. path_ = params.path_;
  44. return *this;
  45. }
  46. const std::string& filter() const { return filter_; }
  47. const std::string& scheme() const { return scheme_; }
  48. const std::string& host() const { return host_; }
  49. bool match_subdomains() const { return match_subdomains_; }
  50. uint16_t port() const { return port_; }
  51. const std::string& path() const { return path_; }
  52. private:
  53. std::string filter_;
  54. std::string scheme_;
  55. std::string host_;
  56. bool match_subdomains_;
  57. uint16_t port_;
  58. std::string path_;
  59. };
  60. // Prints better debug information for Valgrind. Without this function, a
  61. // generic one will print the raw bytes in FilterTestParams, which due to some
  62. // likely padding will access uninitialized memory.
  63. void PrintTo(const FilterTestParams& params, std::ostream* os) {
  64. *os << params.filter();
  65. }
  66. bool MatchFilters(const std::vector<std::string>& patterns,
  67. const std::string& url) {
  68. // Add the pattern to the matcher.
  69. URLMatcher matcher;
  70. base::Value::List list;
  71. for (const auto& pattern : patterns)
  72. list.Append(pattern);
  73. AddAllowFilters(&matcher, list);
  74. return !matcher.MatchURL(GURL(url)).empty();
  75. }
  76. class FilterToComponentsTest : public testing::TestWithParam<FilterTestParams> {
  77. public:
  78. FilterToComponentsTest() = default;
  79. FilterToComponentsTest(const FilterToComponentsTest&) = delete;
  80. FilterToComponentsTest& operator=(const FilterToComponentsTest&) = delete;
  81. };
  82. class OnlyWildcardTest
  83. : public testing::TestWithParam<std::tuple<std::string /* scheme */,
  84. std::string /* opt_host */,
  85. std::string /* port */,
  86. std::string /* path */,
  87. std::string /* query*/>> {
  88. public:
  89. OnlyWildcardTest() = default;
  90. OnlyWildcardTest(const OnlyWildcardTest&) = delete;
  91. OnlyWildcardTest& operator=(const OnlyWildcardTest&) = delete;
  92. };
  93. } // namespace
  94. TEST(URLUtilTest, Normalize) {
  95. // Username is cleared.
  96. EXPECT_EQ(Normalize(GURL("http://dino@example/foo")),
  97. GURL("http://example/foo"));
  98. // Username and password are cleared.
  99. EXPECT_EQ(Normalize(GURL("http://dino:hunter2@example/")),
  100. GURL("http://example/"));
  101. // Query string is cleared.
  102. EXPECT_EQ(Normalize(GURL("http://example.com/foo?widgetId=42")),
  103. GURL("http://example.com/foo"));
  104. EXPECT_EQ(Normalize(GURL("https://example.com/?widgetId=42&frobinate=true")),
  105. GURL("https://example.com/"));
  106. // Ref is cleared.
  107. EXPECT_EQ(Normalize(GURL("http://example.com/foo#widgetSection")),
  108. GURL("http://example.com/foo"));
  109. // Port is NOT cleared.
  110. EXPECT_EQ(Normalize(GURL("http://example.com:443/")),
  111. GURL("http://example.com:443/"));
  112. // All together now.
  113. EXPECT_EQ(
  114. Normalize(GURL("https://dino:hunter2@example.com:443/foo?widgetId=42")),
  115. GURL("https://example.com:443/foo"));
  116. }
  117. TEST(URLUtilTest, GetEmbeddedURLAmpCache) {
  118. // Base case.
  119. EXPECT_EQ(GURL("http://example.com"),
  120. GetEmbeddedURL("https://cdn.ampproject.org/c/example.com"));
  121. // "s/" means "use https".
  122. EXPECT_EQ(GURL("https://example.com"),
  123. GetEmbeddedURL("https://cdn.ampproject.org/c/s/example.com"));
  124. // With path and query. Fragment is not extracted.
  125. EXPECT_EQ(GURL("https://example.com/path/to/file.html?q=asdf"),
  126. GetEmbeddedURL("https://cdn.ampproject.org/c/s/example.com/path/to/"
  127. "file.html?q=asdf#baz"));
  128. // Publish subdomain can be included but doesn't affect embedded URL.
  129. EXPECT_EQ(
  130. GURL("http://example.com"),
  131. GetEmbeddedURL("https://example-com.cdn.ampproject.org/c/example.com"));
  132. EXPECT_EQ(
  133. GURL("http://example.com"),
  134. GetEmbeddedURL("https://example-org.cdn.ampproject.org/c/example.com"));
  135. // Different host is not supported.
  136. EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.ampproject.org/c/example.com"));
  137. // Different TLD is not supported.
  138. EXPECT_EQ(GURL(), GetEmbeddedURL("https://cdn.ampproject.com/c/example.com"));
  139. // Content type ("c/") is missing.
  140. EXPECT_EQ(GURL(), GetEmbeddedURL("https://cdn.ampproject.org/example.com"));
  141. // Content type is mis-formatted, must be a single character.
  142. EXPECT_EQ(GURL(),
  143. GetEmbeddedURL("https://cdn.ampproject.org/cd/example.com"));
  144. }
  145. TEST(URLUtilTest, GetEmbeddedURLGoogleAmpViewer) {
  146. // Base case.
  147. EXPECT_EQ(GURL("http://example.com"),
  148. GetEmbeddedURL("https://www.google.com/amp/example.com"));
  149. // "s/" means "use https".
  150. EXPECT_EQ(GURL("https://example.com"),
  151. GetEmbeddedURL("https://www.google.com/amp/s/example.com"));
  152. // Different Google TLDs are supported.
  153. EXPECT_EQ(GURL("http://example.com"),
  154. GetEmbeddedURL("https://www.google.de/amp/example.com"));
  155. EXPECT_EQ(GURL("http://example.com"),
  156. GetEmbeddedURL("https://www.google.co.uk/amp/example.com"));
  157. // With path.
  158. EXPECT_EQ(GURL("http://example.com/path"),
  159. GetEmbeddedURL("https://www.google.com/amp/example.com/path"));
  160. // Query is *not* part of the embedded URL.
  161. EXPECT_EQ(
  162. GURL("http://example.com/path"),
  163. GetEmbeddedURL("https://www.google.com/amp/example.com/path?q=baz"));
  164. // Query and fragment in percent-encoded form *are* part of the embedded URL.
  165. EXPECT_EQ(
  166. GURL("http://example.com/path?q=foo#bar"),
  167. GetEmbeddedURL(
  168. "https://www.google.com/amp/example.com/path%3fq=foo%23bar?q=baz"));
  169. // "/" may also be percent-encoded.
  170. EXPECT_EQ(GURL("http://example.com/path?q=foo#bar"),
  171. GetEmbeddedURL("https://www.google.com/amp/"
  172. "example.com%2fpath%3fq=foo%23bar?q=baz"));
  173. // Missing "amp/".
  174. EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.google.com/example.com"));
  175. // Path component before the "amp/".
  176. EXPECT_EQ(GURL(),
  177. GetEmbeddedURL("https://www.google.com/foo/amp/example.com"));
  178. // Different host.
  179. EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.other.com/amp/example.com"));
  180. // Different subdomain.
  181. EXPECT_EQ(GURL(), GetEmbeddedURL("https://mail.google.com/amp/example.com"));
  182. // Invalid TLD.
  183. EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.google.nope/amp/example.com"));
  184. // Valid TLD that is not considered safe to display to the user by
  185. // UnescapeURLComponent(). Note that when UTF-8 characters appear in a domain
  186. // name, as is the case here, they're replaced by equivalent punycode by the
  187. // GURL constructor.
  188. EXPECT_EQ(GURL("http://www.xn--iv8h.com/"),
  189. GetEmbeddedURL("https://www.google.com/amp/www.%F0%9F%94%8F.com/"));
  190. // Invalid UTF-8 characters.
  191. EXPECT_EQ(GURL("http://example.com/%81%82%83"),
  192. GetEmbeddedURL("https://www.google.com/amp/example.com/%81%82%83"));
  193. }
  194. TEST(URLUtilTest, GetEmbeddedURLGoogleWebCache) {
  195. // Base case.
  196. EXPECT_EQ(GURL("http://example.com"),
  197. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  198. "search?q=cache:ABCDEFGHI-JK:example.com/"));
  199. // With search query.
  200. EXPECT_EQ(
  201. GURL("http://example.com"),
  202. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  203. "search?q=cache:ABCDEFGHI-JK:example.com/+search_query"));
  204. // Without fingerprint.
  205. EXPECT_EQ(GURL("http://example.com"),
  206. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  207. "search?q=cache:example.com/"));
  208. // With search query, without fingerprint.
  209. EXPECT_EQ(GURL("http://example.com"),
  210. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  211. "search?q=cache:example.com/+search_query"));
  212. // Query params other than "q=" don't matter.
  213. EXPECT_EQ(GURL("http://example.com"),
  214. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  215. "search?a=b&q=cache:example.com/&c=d"));
  216. // With scheme.
  217. EXPECT_EQ(GURL("http://example.com"),
  218. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  219. "search?q=cache:http://example.com/"));
  220. // Preserve https.
  221. EXPECT_EQ(GURL("https://example.com"),
  222. GetEmbeddedURL("https://webcache.googleusercontent.com/"
  223. "search?q=cache:https://example.com/"));
  224. // Wrong host.
  225. EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.googleusercontent.com/"
  226. "search?q=cache:example.com/"));
  227. // Wrong path.
  228. EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
  229. "path?q=cache:example.com/"));
  230. EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
  231. "path/search?q=cache:example.com/"));
  232. // Missing "cache:".
  233. EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
  234. "search?q=example.com"));
  235. // Wrong fingerprint.
  236. EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
  237. "search?q=cache:123:example.com/"));
  238. // Wrong query param.
  239. EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
  240. "search?a=cache:example.com/"));
  241. // Invalid scheme.
  242. EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
  243. "search?q=cache:abc://example.com/"));
  244. }
  245. TEST(URLUtilTest, GetEmbeddedURLTranslate) {
  246. // Base case.
  247. EXPECT_EQ(GURL("http://example.com"),
  248. GetEmbeddedURL("https://translate.google.com/path?u=example.com"));
  249. // Different TLD.
  250. EXPECT_EQ(GURL("http://example.com"),
  251. GetEmbeddedURL("https://translate.google.de/path?u=example.com"));
  252. // Alternate base URL.
  253. EXPECT_EQ(GURL("http://example.com"),
  254. GetEmbeddedURL(
  255. "https://translate.googleusercontent.com/path?u=example.com"));
  256. // With scheme.
  257. EXPECT_EQ(
  258. GURL("http://example.com"),
  259. GetEmbeddedURL("https://translate.google.com/path?u=http://example.com"));
  260. // With https scheme.
  261. EXPECT_EQ(GURL("https://example.com"),
  262. GetEmbeddedURL(
  263. "https://translate.google.com/path?u=https://example.com"));
  264. // With other parameters.
  265. EXPECT_EQ(
  266. GURL("http://example.com"),
  267. GetEmbeddedURL(
  268. "https://translate.google.com/path?a=asdf&u=example.com&b=fdsa"));
  269. // Different subdomain is not supported.
  270. EXPECT_EQ(GURL(), GetEmbeddedURL(
  271. "https://translate.foo.google.com/path?u=example.com"));
  272. EXPECT_EQ(GURL(), GetEmbeddedURL(
  273. "https://translate.www.google.com/path?u=example.com"));
  274. EXPECT_EQ(
  275. GURL(),
  276. GetEmbeddedURL("https://translate.google.google.com/path?u=example.com"));
  277. EXPECT_EQ(GURL(), GetEmbeddedURL(
  278. "https://foo.translate.google.com/path?u=example.com"));
  279. EXPECT_EQ(GURL(),
  280. GetEmbeddedURL("https://translate2.google.com/path?u=example.com"));
  281. EXPECT_EQ(GURL(),
  282. GetEmbeddedURL(
  283. "https://translate2.googleusercontent.com/path?u=example.com"));
  284. // Different TLD is not supported for googleusercontent.
  285. EXPECT_EQ(GURL(),
  286. GetEmbeddedURL(
  287. "https://translate.googleusercontent.de/path?u=example.com"));
  288. // Query parameter ("u=...") is missing.
  289. EXPECT_EQ(GURL(),
  290. GetEmbeddedURL("https://translate.google.com/path?t=example.com"));
  291. }
  292. INSTANTIATE_TEST_SUITE_P(URLUtilTest,
  293. OnlyWildcardTest,
  294. testing::Combine(testing::Values("", "https://"),
  295. testing::Values("", "dev."),
  296. testing::Values("", ":1234"),
  297. testing::Values("", "/path"),
  298. testing::Values("", "?query")));
  299. TEST_P(OnlyWildcardTest, OnlyWildcard) {
  300. // Check wildcard filter works on any permutations of format
  301. // [scheme://][.]host[:port][/path][@query]
  302. const std::string scheme = std::get<0>(GetParam());
  303. const std::string opt_host = std::get<1>(GetParam());
  304. const std::string port = std::get<2>(GetParam());
  305. const std::string path = std::get<3>(GetParam());
  306. const std::string query = std::get<4>(GetParam());
  307. const std::string url =
  308. scheme + opt_host + "google.com" + port + path + query;
  309. EXPECT_TRUE(MatchFilters({"*"}, url));
  310. }
  311. TEST(URLUtilTest, SingleFilter) {
  312. // Match domain and all subdomains, for any filtered scheme.
  313. EXPECT_TRUE(MatchFilters({"google.com"}, "http://google.com"));
  314. EXPECT_TRUE(MatchFilters({"google.com"}, "http://google.com/"));
  315. EXPECT_TRUE(MatchFilters({"google.com"}, "http://google.com/whatever"));
  316. EXPECT_TRUE(MatchFilters({"google.com"}, "https://google.com/"));
  317. EXPECT_FALSE(MatchFilters({"google.com"}, "bogus://google.com/"));
  318. EXPECT_FALSE(MatchFilters({"google.com"}, "http://notgoogle.com/"));
  319. EXPECT_TRUE(MatchFilters({"google.com"}, "http://mail.google.com"));
  320. EXPECT_TRUE(MatchFilters({"google.com"}, "http://x.mail.google.com"));
  321. EXPECT_TRUE(MatchFilters({"google.com"}, "https://x.mail.google.com/"));
  322. EXPECT_TRUE(MatchFilters({"google.com"}, "http://x.y.google.com/a/b"));
  323. EXPECT_FALSE(MatchFilters({"google.com"}, "http://youtube.com/"));
  324. // Filter only http, ftp and ws schemes.
  325. EXPECT_TRUE(MatchFilters({"http://secure.com"}, "http://secure.com"));
  326. EXPECT_TRUE(
  327. MatchFilters({"http://secure.com"}, "http://secure.com/whatever"));
  328. EXPECT_TRUE(MatchFilters({"ftp://secure.com"}, "ftp://secure.com/"));
  329. EXPECT_TRUE(MatchFilters({"ws://secure.com"}, "ws://secure.com"));
  330. EXPECT_FALSE(MatchFilters({"http://secure.com"}, "https://secure.com/"));
  331. EXPECT_FALSE(MatchFilters({"ws://secure.com"}, "wss://secure.com"));
  332. EXPECT_TRUE(MatchFilters({"http://secure.com"}, "http://www.secure.com"));
  333. EXPECT_FALSE(MatchFilters({"http://secure.com"}, "https://www.secure.com"));
  334. EXPECT_FALSE(MatchFilters({"ws://secure.com"}, "wss://www.secure.com"));
  335. // Filter only a certain path prefix.
  336. EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://path.to/ruin"));
  337. EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "https://path.to/ruin"));
  338. EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://path.to/ruins"));
  339. EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://path.to/ruin/signup"));
  340. EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://www.path.to/ruin"));
  341. EXPECT_FALSE(MatchFilters({"path.to/ruin"}, "http://path.to/fortune"));
  342. // Filter only a certain path prefix and scheme.
  343. EXPECT_TRUE(
  344. MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/path"));
  345. EXPECT_TRUE(
  346. MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/path/bbb"));
  347. EXPECT_FALSE(
  348. MatchFilters({"https://s.aaa.com/path"}, "http://s.aaa.com/path"));
  349. EXPECT_FALSE(
  350. MatchFilters({"https://s.aaa.com/path"}, "https://aaa.com/path"));
  351. EXPECT_FALSE(
  352. MatchFilters({"https://s.aaa.com/path"}, "https://x.aaa.com/path"));
  353. EXPECT_FALSE(
  354. MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/bbb"));
  355. EXPECT_FALSE(MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/"));
  356. // Filter only ws and wss schemes.
  357. EXPECT_TRUE(MatchFilters({"ws://ws.aaa.com"}, "ws://ws.aaa.com"));
  358. EXPECT_TRUE(MatchFilters({"wss://ws.aaa.com"}, "wss://ws.aaa.com"));
  359. EXPECT_FALSE(MatchFilters({"ws://ws.aaa.com"}, "http://ws.aaa.com"));
  360. EXPECT_FALSE(MatchFilters({"ws://ws.aaa.com"}, "https://ws.aaa.com"));
  361. EXPECT_FALSE(MatchFilters({"ws://ws.aaa.com"}, "ftp://ws.aaa.com"));
  362. // Match an ip address.
  363. EXPECT_TRUE(MatchFilters({"123.123.123.123"}, "http://123.123.123.123/"));
  364. EXPECT_FALSE(MatchFilters({"123.123.123.123"}, "http://123.123.123.124/"));
  365. // Open an exception.
  366. EXPECT_FALSE(MatchFilters({"plus.google.com"}, "http://google.com/"));
  367. EXPECT_FALSE(MatchFilters({"plus.google.com"}, "http://www.google.com/"));
  368. EXPECT_TRUE(MatchFilters({"plus.google.com"}, "http://plus.google.com/"));
  369. // Match exactly "google.com", only for http.
  370. EXPECT_TRUE(MatchFilters({"http://.google.com"}, "http://google.com/"));
  371. EXPECT_FALSE(MatchFilters({"http://.google.com"}, "https://google.com/"));
  372. EXPECT_FALSE(MatchFilters({"http://.google.com"}, "http://www.google.com/"));
  373. }
  374. TEST(URLUtilTest, MultipleFilters) {
  375. // Test exceptions to path prefixes, and most specific matches.
  376. std::vector<std::string> patterns = {"s.xxx.com/a/b",
  377. "https://s.xxx.com/a/b/c/d"};
  378. EXPECT_FALSE(MatchFilters(patterns, "http://s.xxx.com/a"));
  379. EXPECT_FALSE(MatchFilters(patterns, "http://s.xxx.com/a/x"));
  380. EXPECT_FALSE(MatchFilters(patterns, "https://s.xxx.com/a/x"));
  381. EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b"));
  382. EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b"));
  383. EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/x"));
  384. EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/c"));
  385. EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c"));
  386. EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c/x"));
  387. EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c/d"));
  388. EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/c/d"));
  389. EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c/d/x"));
  390. EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/c/d/x"));
  391. EXPECT_FALSE(MatchFilters(patterns, "http://xxx.com/a"));
  392. EXPECT_FALSE(MatchFilters(patterns, "http://xxx.com/a/b"));
  393. // Match queries.
  394. std::vector<std::string> queries = {"*?q=1234", "*?q=5678", "*?a=1&b=2",
  395. "youtube.com?foo=baz",
  396. "youtube.com?foo=bar*"};
  397. EXPECT_TRUE(MatchFilters(queries, "http://google.com?q=1234"));
  398. EXPECT_TRUE(MatchFilters(queries, "http://google.com?q=5678"));
  399. EXPECT_TRUE(MatchFilters(queries, "http://google.com?a=1&b=2"));
  400. EXPECT_TRUE(MatchFilters(queries, "http://google.com?b=2&a=1"));
  401. EXPECT_TRUE(MatchFilters(queries, "http://google.com?a=1&b=4&q=1234"));
  402. EXPECT_TRUE(MatchFilters(queries, "http://youtube.com?foo=baz"));
  403. EXPECT_TRUE(MatchFilters(queries, "http://youtube.com?foo=barbaz"));
  404. EXPECT_TRUE(MatchFilters(queries, "http://youtube.com?a=1&foo=barbaz"));
  405. EXPECT_FALSE(MatchFilters(queries, "http://google.com?r=1234"));
  406. EXPECT_FALSE(MatchFilters(queries, "http://google.com?r=5678"));
  407. EXPECT_FALSE(MatchFilters(queries, "http://google.com?a=2&b=1"));
  408. EXPECT_FALSE(MatchFilters(queries, "http://google.com?b=1&a=2"));
  409. EXPECT_FALSE(MatchFilters(queries, "http://google.com?a=1&b=3"));
  410. EXPECT_FALSE(MatchFilters(queries, "http://youtube.com?foo=meh"));
  411. EXPECT_FALSE(MatchFilters(queries, "http://youtube.com?foo=bazbar"));
  412. EXPECT_FALSE(MatchFilters(queries, "http://youtube.com?foo=ba"));
  413. }
  414. TEST(URLUtilTest, BasicCoverage) {
  415. // Tests to cover the documentation from
  416. // http://www.chromium.org/administrators/url-blocklist-filter-format
  417. // [scheme://][.]host[:port][/path][@query]
  418. // Scheme can be http, https, ftp, chrome, etc. This field is optional, and
  419. // must be followed by '://'.
  420. EXPECT_TRUE(MatchFilters({"file://*"}, "file:///abc.txt"));
  421. EXPECT_TRUE(MatchFilters({"file:*"}, "file:///usr/local/boot.txt"));
  422. EXPECT_TRUE(MatchFilters({"https://*"}, "https:///abc.txt"));
  423. EXPECT_TRUE(MatchFilters({"ftp://*"}, "ftp://ftp.txt"));
  424. EXPECT_TRUE(MatchFilters({"chrome://*"}, "chrome:policy"));
  425. EXPECT_TRUE(MatchFilters({"noscheme"}, "http://noscheme"));
  426. // Filter custom schemes.
  427. EXPECT_TRUE(MatchFilters({"custom://*"}, "custom://example_app"));
  428. EXPECT_TRUE(MatchFilters({"custom:*"}, "custom:example2_app"));
  429. EXPECT_FALSE(MatchFilters({"custom://*"}, "customs://example_apps"));
  430. EXPECT_FALSE(MatchFilters({"custom://*"}, "cust*://example_ap"));
  431. EXPECT_FALSE(MatchFilters({"custom://*"}, "ecustom:example_app"));
  432. EXPECT_TRUE(MatchFilters({"custom://*"}, "custom:///abc.txt"));
  433. // Tests for custom scheme patterns that are not supported.
  434. EXPECT_FALSE(MatchFilters({"wrong://app"}, "wrong://app"));
  435. EXPECT_FALSE(MatchFilters({"wrong ://*"}, "wrong ://app"));
  436. EXPECT_FALSE(MatchFilters({" wrong:*"}, " wrong://app"));
  437. // Omitting the scheme matches most standard schemes.
  438. EXPECT_TRUE(MatchFilters({"example.com"}, "chrome:example.com"));
  439. EXPECT_TRUE(MatchFilters({"example.com"}, "chrome://example.com"));
  440. EXPECT_TRUE(MatchFilters({"example.com"}, "file://example.com/"));
  441. EXPECT_TRUE(MatchFilters({"example.com"}, "ftp://example.com"));
  442. EXPECT_TRUE(MatchFilters({"example.com"}, "http://example.com"));
  443. EXPECT_TRUE(MatchFilters({"example.com"}, "https://example.com"));
  444. EXPECT_TRUE(MatchFilters({"example.com"}, "ws://example.com"));
  445. EXPECT_TRUE(MatchFilters({"example.com"}, "wss://example.com"));
  446. // Some schemes are not matched when the scheme is omitted.
  447. EXPECT_FALSE(MatchFilters({"example.com"}, "about://example.com"));
  448. EXPECT_FALSE(MatchFilters({"example.com"}, "about:example.com"));
  449. EXPECT_FALSE(MatchFilters({"example.com/*"}, "filesystem:///something"));
  450. EXPECT_FALSE(MatchFilters({"example.com"}, "custom://example.com"));
  451. EXPECT_FALSE(MatchFilters({"example"}, "custom://example"));
  452. // An optional '.' (dot) can prefix the host field to disable subdomain
  453. // matching, see below for details.
  454. EXPECT_TRUE(MatchFilters({".example.com"}, "http://example.com/path"));
  455. EXPECT_FALSE(MatchFilters({".example.com"}, "http://mail.example.com/path"));
  456. EXPECT_TRUE(MatchFilters({"example.com"}, "http://mail.example.com/path"));
  457. EXPECT_TRUE(MatchFilters({"ftp://.ftp.file"}, "ftp://ftp.file"));
  458. EXPECT_FALSE(MatchFilters({"ftp://.ftp.file"}, "ftp://sub.ftp.file"));
  459. // The host field is required, and is a valid hostname or an IP address. It
  460. // can also take the special '*' value, see below for details.
  461. EXPECT_TRUE(MatchFilters({"*"}, "http://anything"));
  462. EXPECT_TRUE(MatchFilters({"*"}, "ftp://anything"));
  463. EXPECT_TRUE(MatchFilters({"*"}, "custom://anything"));
  464. EXPECT_TRUE(MatchFilters({"host"}, "http://host:8080"));
  465. EXPECT_FALSE(MatchFilters({"host"}, "file:///host"));
  466. EXPECT_TRUE(MatchFilters({"10.1.2.3"}, "http://10.1.2.3:8080/path"));
  467. // No host, will match nothing.
  468. EXPECT_FALSE(MatchFilters({":8080"}, "http://host:8080"));
  469. EXPECT_FALSE(MatchFilters({":8080"}, "http://:8080"));
  470. // An optional port can come after the host. It must be a valid port value
  471. // from 1 to 65535.
  472. EXPECT_TRUE(MatchFilters({"host:8080"}, "http://host:8080/path"));
  473. EXPECT_TRUE(MatchFilters({"host:1"}, "http://host:1/path"));
  474. // Out of range port.
  475. EXPECT_FALSE(MatchFilters({"host:65536"}, "http://host:65536/path"));
  476. // Star is not allowed in port numbers.
  477. EXPECT_FALSE(MatchFilters({"example.com:*"}, "http://example.com"));
  478. EXPECT_FALSE(MatchFilters({"example.com:*"}, "http://example.com:8888"));
  479. // An optional path can come after port.
  480. EXPECT_TRUE(MatchFilters({"host/path"}, "http://host:8080/path"));
  481. EXPECT_TRUE(MatchFilters({"host/path/path2"}, "http://host/path/path2"));
  482. EXPECT_TRUE(MatchFilters({"host/path"}, "http://host/path/path2"));
  483. // An optional query can come in the end, which is a set of key-value and
  484. // key-only tokens delimited by '&'. The key-value tokens are separated
  485. // by '='. A query token can optionally end with a '*' to indicate prefix
  486. // match. Token order is ignored during matching.
  487. EXPECT_TRUE(MatchFilters({"host?q1=1&q2=2"}, "http://host?q2=2&q1=1"));
  488. EXPECT_FALSE(MatchFilters({"host?q1=1&q2=2"}, "http://host?q2=1&q1=2"));
  489. EXPECT_FALSE(MatchFilters({"host?q1=1&q2=2"}, "http://host?Q2=2&Q1=1"));
  490. EXPECT_TRUE(MatchFilters({"host?q1=1&q2=2"}, "http://host?q2=2&q1=1&q3=3"));
  491. EXPECT_TRUE(MatchFilters({"host?q1=1&q2=2*"}, "http://host?q2=21&q1=1&q3=3"));
  492. // user:pass fields can be included but will be ignored
  493. // (e.g. http://user:pass@ftp.example.com/pub/bigfile.iso).
  494. EXPECT_TRUE(
  495. MatchFilters({"host.com/path"}, "http://user:pass@host.com:8080/path"));
  496. EXPECT_TRUE(MatchFilters({"ftp://host.com/path"},
  497. "ftp://user:pass@host.com:8080/path"));
  498. // Case sensitivity.
  499. // Scheme is case insensitive.
  500. EXPECT_TRUE(MatchFilters({"suPPort://*"}, "support:example"));
  501. EXPECT_TRUE(MatchFilters({"FILE://*"}, "file:example"));
  502. EXPECT_TRUE(MatchFilters({"FILE://*"}, "FILE://example"));
  503. EXPECT_TRUE(MatchFilters({"FtP:*"}, "ftp://example"));
  504. EXPECT_TRUE(MatchFilters({"http://example.com"}, "HTTP://example.com"));
  505. EXPECT_TRUE(MatchFilters({"HTTP://example.com"}, "http://example.com"));
  506. // Host is case insensitive.
  507. EXPECT_TRUE(MatchFilters({"http://EXAMPLE.COM"}, "http://example.com"));
  508. EXPECT_TRUE(MatchFilters({"Example.com"}, "http://examplE.com/Path?Query=1"));
  509. // Path is case sensitive.
  510. EXPECT_FALSE(MatchFilters({"example.com/Path"}, "http://example.com/path"));
  511. EXPECT_TRUE(MatchFilters({"http://example.com/aB"}, "http://example.com/aB"));
  512. EXPECT_FALSE(
  513. MatchFilters({"http://example.com/aB"}, "http://example.com/Ab"));
  514. EXPECT_FALSE(
  515. MatchFilters({"http://example.com/aB"}, "http://example.com/ab"));
  516. EXPECT_FALSE(
  517. MatchFilters({"http://example.com/aB"}, "http://example.com/AB"));
  518. // Query is case sensitive.
  519. EXPECT_FALSE(MatchFilters({"host/path?Query=1"}, "http://host/path?query=1"));
  520. }
  521. INSTANTIATE_TEST_SUITE_P(
  522. URLUtilTest,
  523. FilterToComponentsTest,
  524. testing::Values(
  525. FilterTestParams("google.com",
  526. std::string(),
  527. ".google.com",
  528. true,
  529. 0u,
  530. std::string()),
  531. FilterTestParams(".google.com",
  532. std::string(),
  533. "google.com",
  534. false,
  535. 0u,
  536. std::string()),
  537. FilterTestParams("http://google.com",
  538. "http",
  539. ".google.com",
  540. true,
  541. 0u,
  542. std::string()),
  543. FilterTestParams("google.com/",
  544. std::string(),
  545. ".google.com",
  546. true,
  547. 0u,
  548. "/"),
  549. FilterTestParams("http://google.com:8080/whatever",
  550. "http",
  551. ".google.com",
  552. true,
  553. 8080u,
  554. "/whatever"),
  555. FilterTestParams("http://user:pass@google.com:8080/whatever",
  556. "http",
  557. ".google.com",
  558. true,
  559. 8080u,
  560. "/whatever"),
  561. FilterTestParams("123.123.123.123",
  562. std::string(),
  563. "123.123.123.123",
  564. false,
  565. 0u,
  566. std::string()),
  567. FilterTestParams("https://123.123.123.123",
  568. "https",
  569. "123.123.123.123",
  570. false,
  571. 0u,
  572. std::string()),
  573. FilterTestParams("123.123.123.123/",
  574. std::string(),
  575. "123.123.123.123",
  576. false,
  577. 0u,
  578. "/"),
  579. FilterTestParams("http://123.123.123.123:123/whatever",
  580. "http",
  581. "123.123.123.123",
  582. false,
  583. 123u,
  584. "/whatever"),
  585. FilterTestParams("*",
  586. std::string(),
  587. std::string(),
  588. true,
  589. 0u,
  590. std::string()),
  591. FilterTestParams("ftp://*",
  592. "ftp",
  593. std::string(),
  594. true,
  595. 0u,
  596. std::string()),
  597. FilterTestParams("http://*/whatever",
  598. "http",
  599. std::string(),
  600. true,
  601. 0u,
  602. "/whatever")));
  603. TEST_P(FilterToComponentsTest, FilterToComponents) {
  604. std::string scheme;
  605. std::string host;
  606. bool match_subdomains = true;
  607. uint16_t port = 42;
  608. std::string path;
  609. std::string query;
  610. FilterToComponents(GetParam().filter(), &scheme, &host, &match_subdomains,
  611. &port, &path, &query);
  612. EXPECT_EQ(GetParam().scheme(), scheme);
  613. EXPECT_EQ(GetParam().host(), host);
  614. EXPECT_EQ(GetParam().match_subdomains(), match_subdomains);
  615. EXPECT_EQ(GetParam().port(), port);
  616. EXPECT_EQ(GetParam().path(), path);
  617. }
  618. } // namespace util
  619. } // namespace url_matcher