1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/test/values_test_util.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
13 #include "components/url_matcher/url_matcher_constants.h"
14 #include "content/public/browser/resource_request_info.h"
15 #include "net/base/request_priority.h"
16 #include "net/url_request/url_request_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 using content::ResourceType;
20 using url_matcher::URLMatcher;
21 using url_matcher::URLMatcherConditionSet;
23 namespace extensions {
25 TEST(WebRequestConditionTest, CreateCondition) {
26 // Necessary for TestURLRequest.
27 base::MessageLoopForIO message_loop;
31 scoped_ptr<WebRequestCondition> result;
33 // Test wrong condition name passed.
35 result = WebRequestCondition::Create(
37 matcher.condition_factory(),
38 *base::test::ParseJson(
39 "{ \"invalid\": \"foobar\", \n"
40 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
43 EXPECT_FALSE(error.empty());
44 EXPECT_FALSE(result.get());
46 // Test wrong datatype in host_suffix.
48 result = WebRequestCondition::Create(
50 matcher.condition_factory(),
51 *base::test::ParseJson(
54 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
57 EXPECT_FALSE(error.empty());
58 EXPECT_FALSE(result.get());
60 // Test success (can we support multiple criteria?)
62 result = WebRequestCondition::Create(
64 matcher.condition_factory(),
65 *base::test::ParseJson(
67 " \"resourceType\": [\"main_frame\"], \n"
68 " \"url\": { \"hostSuffix\": \"example.com\" }, \n"
69 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
73 ASSERT_TRUE(result.get());
75 URLMatcherConditionSet::Vector url_matcher_condition_set;
76 result->GetURLMatcherConditionSets(&url_matcher_condition_set);
77 matcher.AddConditionSets(url_matcher_condition_set);
79 net::TestURLRequestContext context;
80 const GURL http_url("http://www.example.com");
81 net::TestURLRequest match_request(
82 http_url, net::DEFAULT_PRIORITY, NULL, &context);
83 WebRequestData data(&match_request, ON_BEFORE_REQUEST);
84 WebRequestDataWithMatchIds request_data(&data);
85 request_data.url_match_ids = matcher.MatchURL(http_url);
86 EXPECT_EQ(1u, request_data.url_match_ids.size());
87 content::ResourceRequestInfo::AllocateForTesting(
89 content::RESOURCE_TYPE_MAIN_FRAME,
95 EXPECT_TRUE(result->IsFulfilled(request_data));
97 const GURL https_url("https://www.example.com");
98 net::TestURLRequest wrong_resource_type(
99 https_url, net::DEFAULT_PRIORITY, NULL, &context);
100 data.request = &wrong_resource_type;
101 request_data.url_match_ids = matcher.MatchURL(http_url);
102 // Make sure IsFulfilled does not fail because of URL matching.
103 EXPECT_EQ(1u, request_data.url_match_ids.size());
104 content::ResourceRequestInfo::AllocateForTesting(
105 &wrong_resource_type,
106 content::RESOURCE_TYPE_SUB_FRAME,
112 EXPECT_FALSE(result->IsFulfilled(request_data));
115 TEST(WebRequestConditionTest, CreateConditionFirstPartyForCookies) {
116 // Necessary for TestURLRequest.
117 base::MessageLoopForIO message_loop;
121 scoped_ptr<WebRequestCondition> result;
123 result = WebRequestCondition::Create(
125 matcher.condition_factory(),
126 *base::test::ParseJson(
128 " \"firstPartyForCookiesUrl\": { \"hostPrefix\": \"fpfc\"}, \n"
129 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
132 EXPECT_EQ("", error);
133 ASSERT_TRUE(result.get());
135 URLMatcherConditionSet::Vector url_matcher_condition_set;
136 result->GetURLMatcherConditionSets(&url_matcher_condition_set);
137 matcher.AddConditionSets(url_matcher_condition_set);
139 net::TestURLRequestContext context;
140 const GURL http_url("http://www.example.com");
141 const GURL first_party_url("http://fpfc.example.com");
142 net::TestURLRequest match_request(
143 http_url, net::DEFAULT_PRIORITY, NULL, &context);
144 WebRequestData data(&match_request, ON_BEFORE_REQUEST);
145 WebRequestDataWithMatchIds request_data(&data);
146 request_data.url_match_ids = matcher.MatchURL(http_url);
147 EXPECT_EQ(0u, request_data.url_match_ids.size());
148 request_data.first_party_url_match_ids = matcher.MatchURL(first_party_url);
149 EXPECT_EQ(1u, request_data.first_party_url_match_ids.size());
150 content::ResourceRequestInfo::AllocateForTesting(
152 content::RESOURCE_TYPE_MAIN_FRAME,
158 EXPECT_TRUE(result->IsFulfilled(request_data));
161 // Conditions without UrlFilter attributes need to be independent of URL
162 // matching results. We test here that:
163 // 1. A non-empty condition without UrlFilter attributes is fulfilled iff its
164 // attributes are fulfilled.
165 // 2. An empty condition (in particular, without UrlFilter attributes) is
167 TEST(WebRequestConditionTest, NoUrlAttributes) {
168 // Necessary for TestURLRequest.
169 base::MessageLoopForIO message_loop;
173 // The empty condition.
175 scoped_ptr<WebRequestCondition> condition_empty = WebRequestCondition::Create(
177 matcher.condition_factory(),
178 *base::test::ParseJson(
180 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
183 EXPECT_EQ("", error);
184 ASSERT_TRUE(condition_empty.get());
186 // A condition without a UrlFilter attribute, which is always true.
188 scoped_ptr<WebRequestCondition> condition_no_url_true =
189 WebRequestCondition::Create(
191 matcher.condition_factory(),
192 *base::test::ParseJson(
194 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
196 // There is no "1st party for cookies" URL in the requests below,
197 // therefore all requests are considered first party for cookies.
198 " \"thirdPartyForCookies\": false, \n"
201 EXPECT_EQ("", error);
202 ASSERT_TRUE(condition_no_url_true.get());
204 // A condition without a UrlFilter attribute, which is always false.
206 scoped_ptr<WebRequestCondition> condition_no_url_false =
207 WebRequestCondition::Create(
209 matcher.condition_factory(),
210 *base::test::ParseJson(
212 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
214 " \"thirdPartyForCookies\": true, \n"
217 EXPECT_EQ("", error);
218 ASSERT_TRUE(condition_no_url_false.get());
220 net::TestURLRequestContext context;
221 net::TestURLRequest https_request(
222 GURL("https://www.example.com"), net::DEFAULT_PRIORITY, NULL, &context);
224 // 1. A non-empty condition without UrlFilter attributes is fulfilled iff its
225 // attributes are fulfilled.
226 WebRequestData data(&https_request, ON_BEFORE_REQUEST);
228 condition_no_url_false->IsFulfilled(WebRequestDataWithMatchIds(&data)));
230 data = WebRequestData(&https_request, ON_BEFORE_REQUEST);
232 condition_no_url_true->IsFulfilled(WebRequestDataWithMatchIds(&data)));
234 // 2. An empty condition (in particular, without UrlFilter attributes) is
236 data = WebRequestData(&https_request, ON_BEFORE_REQUEST);
237 EXPECT_TRUE(condition_empty->IsFulfilled(WebRequestDataWithMatchIds(&data)));
240 TEST(WebRequestConditionTest, CreateConditionSet) {
241 // Necessary for TestURLRequest.
242 base::MessageLoopForIO message_loop;
245 WebRequestConditionSet::AnyVector conditions;
246 conditions.push_back(linked_ptr<base::Value>(base::test::ParseJson(
248 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
250 " \"hostSuffix\": \"example.com\", \n"
251 " \"schemes\": [\"http\"], \n"
254 conditions.push_back(linked_ptr<base::Value>(base::test::ParseJson(
256 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
258 " \"hostSuffix\": \"example.com\", \n"
259 " \"hostPrefix\": \"www\", \n"
260 " \"schemes\": [\"https\"], \n"
266 scoped_ptr<WebRequestConditionSet> result = WebRequestConditionSet::Create(
267 NULL, matcher.condition_factory(), conditions, &error);
268 EXPECT_EQ("", error);
269 ASSERT_TRUE(result.get());
270 EXPECT_EQ(2u, result->conditions().size());
272 // Tell the URLMatcher about our shiny new patterns.
273 URLMatcherConditionSet::Vector url_matcher_condition_set;
274 result->GetURLMatcherConditionSets(&url_matcher_condition_set);
275 matcher.AddConditionSets(url_matcher_condition_set);
277 // Test that the result is correct and matches http://www.example.com and
278 // https://www.example.com
279 GURL http_url("http://www.example.com");
280 net::TestURLRequestContext context;
281 net::TestURLRequest http_request(
282 http_url, net::DEFAULT_PRIORITY, NULL, &context);
283 WebRequestData data(&http_request, ON_BEFORE_REQUEST);
284 WebRequestDataWithMatchIds request_data(&data);
285 request_data.url_match_ids = matcher.MatchURL(http_url);
286 EXPECT_EQ(1u, request_data.url_match_ids.size());
287 EXPECT_TRUE(result->IsFulfilled(*(request_data.url_match_ids.begin()),
290 GURL https_url("https://www.example.com");
291 request_data.url_match_ids = matcher.MatchURL(https_url);
292 EXPECT_EQ(1u, request_data.url_match_ids.size());
293 net::TestURLRequest https_request(
294 https_url, net::DEFAULT_PRIORITY, NULL, &context);
295 data.request = &https_request;
296 EXPECT_TRUE(result->IsFulfilled(*(request_data.url_match_ids.begin()),
299 // Check that both, hostPrefix and hostSuffix are evaluated.
300 GURL https_foo_url("https://foo.example.com");
301 request_data.url_match_ids = matcher.MatchURL(https_foo_url);
302 EXPECT_EQ(0u, request_data.url_match_ids.size());
303 net::TestURLRequest https_foo_request(
304 https_foo_url, net::DEFAULT_PRIORITY, NULL, &context);
305 data.request = &https_foo_request;
306 EXPECT_FALSE(result->IsFulfilled(-1, request_data));
309 TEST(WebRequestConditionTest, TestPortFilter) {
310 // Necessary for TestURLRequest.
311 base::MessageLoopForIO message_loop;
314 WebRequestConditionSet::AnyVector conditions;
315 conditions.push_back(linked_ptr<base::Value>(base::test::ParseJson(
317 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
319 " \"ports\": [80, [1000, 1010]], \n" // Allow 80;1000-1010.
320 " \"hostSuffix\": \"example.com\", \n"
326 scoped_ptr<WebRequestConditionSet> result = WebRequestConditionSet::Create(
327 NULL, matcher.condition_factory(), conditions, &error);
328 EXPECT_EQ("", error);
329 ASSERT_TRUE(result.get());
330 EXPECT_EQ(1u, result->conditions().size());
332 // Tell the URLMatcher about our shiny new patterns.
333 URLMatcherConditionSet::Vector url_matcher_condition_set;
334 result->GetURLMatcherConditionSets(&url_matcher_condition_set);
335 matcher.AddConditionSets(url_matcher_condition_set);
337 std::set<URLMatcherConditionSet::ID> url_match_ids;
339 // Test various URLs.
340 GURL http_url("http://www.example.com");
341 net::TestURLRequestContext context;
342 net::TestURLRequest http_request(
343 http_url, net::DEFAULT_PRIORITY, NULL, &context);
344 url_match_ids = matcher.MatchURL(http_url);
345 ASSERT_EQ(1u, url_match_ids.size());
347 GURL http_url_80("http://www.example.com:80");
348 net::TestURLRequest http_request_80(
349 http_url_80, net::DEFAULT_PRIORITY, NULL, &context);
350 url_match_ids = matcher.MatchURL(http_url_80);
351 ASSERT_EQ(1u, url_match_ids.size());
353 GURL http_url_1000("http://www.example.com:1000");
354 net::TestURLRequest http_request_1000(
355 http_url_1000, net::DEFAULT_PRIORITY, NULL, &context);
356 url_match_ids = matcher.MatchURL(http_url_1000);
357 ASSERT_EQ(1u, url_match_ids.size());
359 GURL http_url_2000("http://www.example.com:2000");
360 net::TestURLRequest http_request_2000(
361 http_url_2000, net::DEFAULT_PRIORITY, NULL, &context);
362 url_match_ids = matcher.MatchURL(http_url_2000);
363 ASSERT_EQ(0u, url_match_ids.size());
366 // Create a condition with two attributes: one on the request header and one on
367 // the response header. The Create() method should fail and complain that it is
368 // impossible that both conditions are fulfilled at the same time.
369 TEST(WebRequestConditionTest, ConditionsWithConflictingStages) {
370 // Necessary for TestURLRequest.
371 base::MessageLoopForIO message_loop;
375 scoped_ptr<WebRequestCondition> result;
377 // Test error on incompatible application stages for involved attributes.
379 result = WebRequestCondition::Create(
381 matcher.condition_factory(),
382 *base::test::ParseJson(
384 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
385 // Pass a JS array with one empty object to each of the header
387 " \"requestHeaders\": [{}], \n"
388 " \"responseHeaders\": [{}], \n"
391 EXPECT_FALSE(error.empty());
392 EXPECT_FALSE(result.get());
395 } // namespace extensions