url_loader_throttle_unittest.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Copyright 2019 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_rewrite/common/url_loader_throttle.h"
  5. #include <string>
  6. #include <utility>
  7. #include "base/strings/string_piece.h"
  8. #include "base/test/bind.h"
  9. #include "base/test/task_environment.h"
  10. #include "services/network/public/cpp/resource_request.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "third_party/blink/public/common/loader/url_loader_throttle.h"
  13. namespace url_rewrite {
  14. namespace {
  15. constexpr char kMixedCaseCorsExemptHeader[] = "CoRs-ExEmPt";
  16. constexpr char kUpperCaseCorsExemptHeader[] = "CORS-EXEMPT";
  17. constexpr char kMixedCaseCorsExemptHeader2[] = "Another-CoRs-ExEmPt-2";
  18. constexpr char kUpperCaseCorsExemptHeader2[] = "ANOTHER-CORS-EXEMPT-2";
  19. constexpr char kRequiresCorsHeader[] = "requires-cors";
  20. } // namespace
  21. class URLLoaderThrottleTest : public testing::Test {
  22. public:
  23. URLLoaderThrottleTest()
  24. : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
  25. ~URLLoaderThrottleTest() override = default;
  26. URLLoaderThrottle::IsHeaderCorsExemptCallback CreateCorsExemptHeadersCallback(
  27. std::vector<std::string> cors_exempt_headers) {
  28. return base::BindLambdaForTesting(
  29. [cors_exempt_headers](base::StringPiece header) {
  30. LOG(INFO) << "HEADER: " << header;
  31. for (const auto& exempt_header : cors_exempt_headers) {
  32. if (base::EqualsCaseInsensitiveASCII(header, exempt_header)) {
  33. return true;
  34. }
  35. }
  36. return false;
  37. });
  38. }
  39. protected:
  40. base::test::SingleThreadTaskEnvironment task_environment_;
  41. };
  42. // Tests rules are properly applied when wildcard-filtering is used on hosts.
  43. TEST_F(URLLoaderThrottleTest, WildcardHosts) {
  44. mojom::UrlRequestRewriteAddHeadersPtr add_headers =
  45. mojom::UrlRequestRewriteAddHeaders::New();
  46. add_headers->headers.push_back(mojom::UrlHeader::New("Header", "Value"));
  47. mojom::UrlRequestActionPtr rewrite =
  48. mojom::UrlRequestAction::NewAddHeaders(std::move(add_headers));
  49. std::vector<mojom::UrlRequestActionPtr> actions;
  50. actions.push_back(std::move(rewrite));
  51. mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
  52. rule->hosts_filter = absl::optional<std::vector<std::string>>({"*.test.net"});
  53. rule->actions = std::move(actions);
  54. mojom::UrlRequestRewriteRulesPtr rules = mojom::UrlRequestRewriteRules::New();
  55. rules->rules.push_back(std::move(rule));
  56. URLLoaderThrottle throttle(
  57. base::MakeRefCounted<UrlRequestRewriteRules>(std::move(rules)),
  58. CreateCorsExemptHeadersCallback({}));
  59. bool defer = false;
  60. network::ResourceRequest request1;
  61. request1.url = GURL("http://test.net");
  62. throttle.WillStartRequest(&request1, &defer);
  63. EXPECT_TRUE(request1.headers.HasHeader("Header"));
  64. network::ResourceRequest request2;
  65. request2.url = GURL("http://subdomain.test.net");
  66. throttle.WillStartRequest(&request2, &defer);
  67. EXPECT_TRUE(request2.headers.HasHeader("Header"));
  68. network::ResourceRequest request3;
  69. request3.url = GURL("http://domaintest.net");
  70. throttle.WillStartRequest(&request3, &defer);
  71. EXPECT_FALSE(request3.headers.HasHeader("Header"));
  72. network::ResourceRequest request4;
  73. request4.url = GURL("http://otherdomain.net");
  74. throttle.WillStartRequest(&request4, &defer);
  75. EXPECT_FALSE(request4.headers.HasHeader("Header"));
  76. }
  77. // Verifies that injected headers are correctly exempted from CORS checks if
  78. // their names are registered as CORS exempt.
  79. TEST_F(URLLoaderThrottleTest, CorsAwareHeaders) {
  80. mojom::UrlRequestRewriteAddHeadersPtr add_headers =
  81. mojom::UrlRequestRewriteAddHeaders::New();
  82. add_headers->headers.push_back(
  83. mojom::UrlHeader::New(kRequiresCorsHeader, "Value"));
  84. // Inject the uppercased form for CORS exempt header #1, and the mixed case
  85. // form of header #2.
  86. add_headers->headers.push_back(
  87. mojom::UrlHeader::New(kUpperCaseCorsExemptHeader, "Value"));
  88. add_headers->headers.push_back(
  89. mojom::UrlHeader::New(kMixedCaseCorsExemptHeader2, "Value"));
  90. mojom::UrlRequestActionPtr rewrite =
  91. mojom::UrlRequestAction::NewAddHeaders(std::move(add_headers));
  92. std::vector<mojom::UrlRequestActionPtr> actions;
  93. actions.push_back(std::move(rewrite));
  94. mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
  95. rule->hosts_filter = absl::optional<std::vector<std::string>>({"*.test.net"});
  96. rule->actions = std::move(actions);
  97. mojom::UrlRequestRewriteRulesPtr rules = mojom::UrlRequestRewriteRules::New();
  98. rules->rules.push_back(std::move(rule));
  99. // Use the mixed case form for CORS exempt header #1, and the uppercased form
  100. // of header #2.
  101. URLLoaderThrottle throttle(
  102. base::MakeRefCounted<UrlRequestRewriteRules>(std::move(rules)),
  103. CreateCorsExemptHeadersCallback(
  104. {kMixedCaseCorsExemptHeader, kUpperCaseCorsExemptHeader2}));
  105. network::ResourceRequest request;
  106. request.url = GURL("http://test.net");
  107. bool defer = false;
  108. throttle.WillStartRequest(&request, &defer);
  109. EXPECT_FALSE(defer);
  110. // Verify that the cors-exempt and cors-required headers were partitioned into
  111. // the "cors_exempt_headers" and "headers" arrays, respectively.
  112. EXPECT_TRUE(
  113. request.cors_exempt_headers.HasHeader(kUpperCaseCorsExemptHeader));
  114. EXPECT_TRUE(
  115. request.cors_exempt_headers.HasHeader(kMixedCaseCorsExemptHeader2));
  116. EXPECT_TRUE(request.headers.HasHeader(kRequiresCorsHeader));
  117. // Verify that the headers were not also placed in the other array.
  118. EXPECT_FALSE(request.cors_exempt_headers.HasHeader(kRequiresCorsHeader));
  119. EXPECT_FALSE(request.headers.HasHeader(kUpperCaseCorsExemptHeader));
  120. EXPECT_FALSE(request.headers.HasHeader(kMixedCaseCorsExemptHeader2));
  121. }
  122. // Tests URL replacement rules that replace to a data URL do not append query or
  123. // ref from the original URL.
  124. TEST_F(URLLoaderThrottleTest, DataReplacementUrl) {
  125. const char kCssDataURI[] = "data:text/css,";
  126. mojom::UrlRequestRewriteReplaceUrlPtr replace_url =
  127. mojom::UrlRequestRewriteReplaceUrl::New();
  128. replace_url->url_ends_with = ".css";
  129. replace_url->new_url = GURL(kCssDataURI);
  130. mojom::UrlRequestActionPtr rewrite =
  131. mojom::UrlRequestAction::NewReplaceUrl(std::move(replace_url));
  132. std::vector<mojom::UrlRequestActionPtr> actions;
  133. actions.push_back(std::move(rewrite));
  134. mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
  135. rule->hosts_filter = absl::optional<std::vector<std::string>>({"*.test.net"});
  136. rule->actions = std::move(actions);
  137. mojom::UrlRequestRewriteRulesPtr rules = mojom::UrlRequestRewriteRules::New();
  138. rules->rules.push_back(std::move(rule));
  139. URLLoaderThrottle throttle(
  140. base::MakeRefCounted<UrlRequestRewriteRules>(std::move(rules)),
  141. CreateCorsExemptHeadersCallback({}));
  142. bool defer = false;
  143. network::ResourceRequest request;
  144. request.url = GURL("http://test.net/style.css?query#ref");
  145. throttle.WillStartRequest(&request, &defer);
  146. EXPECT_EQ(request.url, base::StringPiece(kCssDataURI));
  147. }
  148. class TestThrottleDelegate : public blink::URLLoaderThrottle::Delegate {
  149. public:
  150. TestThrottleDelegate() = default;
  151. ~TestThrottleDelegate() override = default;
  152. bool canceled() const { return canceled_; }
  153. base::StringPiece cancel_reason() const { return cancel_reason_; }
  154. void Reset() {
  155. canceled_ = false;
  156. cancel_reason_.clear();
  157. }
  158. // URLLoaderThrottle::Delegate implementation.
  159. void CancelWithError(int error_code,
  160. base::StringPiece custom_reason) override {
  161. canceled_ = true;
  162. cancel_reason_ = std::string(custom_reason);
  163. }
  164. void Resume() override {}
  165. private:
  166. bool canceled_ = false;
  167. std::string cancel_reason_;
  168. };
  169. // Tests that resource loads can be allowed or blocked based on the
  170. // UrlRequestAction policy.
  171. TEST_F(URLLoaderThrottleTest, AllowAndDeny) {
  172. mojom::UrlRequestRewriteRulesPtr rules = mojom::UrlRequestRewriteRules::New();
  173. {
  174. mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
  175. rule->hosts_filter = absl::optional<std::vector<std::string>>({"test.net"});
  176. rule->actions.push_back(mojom::UrlRequestAction::NewPolicy(
  177. mojom::UrlRequestAccessPolicy::kAllow));
  178. rules->rules.push_back(std::move(rule));
  179. }
  180. {
  181. mojom::UrlRequestRulePtr rule = mojom::UrlRequestRule::New();
  182. rule->actions.push_back(mojom::UrlRequestAction::NewPolicy(
  183. mojom::UrlRequestAccessPolicy::kDeny));
  184. rules->rules.push_back(std::move(rule));
  185. }
  186. URLLoaderThrottle throttle(
  187. base::MakeRefCounted<UrlRequestRewriteRules>(std::move(rules)),
  188. CreateCorsExemptHeadersCallback({}));
  189. bool defer = false;
  190. TestThrottleDelegate delegate;
  191. throttle.set_delegate(&delegate);
  192. network::ResourceRequest request1;
  193. request1.url = GURL("http://test.net");
  194. throttle.WillStartRequest(&request1, &defer);
  195. EXPECT_FALSE(delegate.canceled());
  196. delegate.Reset();
  197. network::ResourceRequest request2;
  198. request2.url = GURL("http://blocked.net");
  199. throttle.WillStartRequest(&request2, &defer);
  200. EXPECT_TRUE(delegate.canceled());
  201. EXPECT_EQ(delegate.cancel_reason(),
  202. "Resource load blocked by embedder policy.");
  203. }
  204. } // namespace url_rewrite