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 "extensions/browser/api/declarative_webrequest/webrequest_condition.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/test/values_test_util.h"
12 #include "base/values.h"
13 #include "components/url_matcher/url_matcher_constants.h"
14 #include "content/public/browser/resource_request_info.h"
15 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
16 #include "net/base/request_priority.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using content::ResourceType
;
22 using url_matcher::URLMatcher
;
23 using url_matcher::URLMatcherConditionSet
;
25 namespace extensions
{
27 TEST(WebRequestConditionTest
, CreateCondition
) {
28 // Necessary for TestURLRequest.
29 base::MessageLoopForIO message_loop
;
33 scoped_ptr
<WebRequestCondition
> result
;
35 // Test wrong condition name passed.
37 result
= WebRequestCondition::Create(
39 matcher
.condition_factory(),
40 *base::test::ParseJson(
41 "{ \"invalid\": \"foobar\", \n"
42 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
45 EXPECT_FALSE(error
.empty());
46 EXPECT_FALSE(result
.get());
48 // Test wrong datatype in host_suffix.
50 result
= WebRequestCondition::Create(
52 matcher
.condition_factory(),
53 *base::test::ParseJson(
56 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
59 EXPECT_FALSE(error
.empty());
60 EXPECT_FALSE(result
.get());
62 // Test success (can we support multiple criteria?)
64 result
= WebRequestCondition::Create(
66 matcher
.condition_factory(),
67 *base::test::ParseJson(
69 " \"resourceType\": [\"main_frame\"], \n"
70 " \"url\": { \"hostSuffix\": \"example.com\" }, \n"
71 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
75 ASSERT_TRUE(result
.get());
77 URLMatcherConditionSet::Vector url_matcher_condition_set
;
78 result
->GetURLMatcherConditionSets(&url_matcher_condition_set
);
79 matcher
.AddConditionSets(url_matcher_condition_set
);
81 net::TestURLRequestContext context
;
82 const GURL
http_url("http://www.example.com");
83 scoped_ptr
<net::URLRequest
> match_request(
84 context
.CreateRequest(http_url
, net::DEFAULT_PRIORITY
, NULL
));
85 WebRequestData
data(match_request
.get(), ON_BEFORE_REQUEST
);
86 WebRequestDataWithMatchIds
request_data(&data
);
87 request_data
.url_match_ids
= matcher
.MatchURL(http_url
);
88 EXPECT_EQ(1u, request_data
.url_match_ids
.size());
89 content::ResourceRequestInfo::AllocateForTesting(
91 content::RESOURCE_TYPE_MAIN_FRAME
,
93 -1, // render_process_id
95 -1, // render_frame_id
96 true, // is_main_frame
97 false, // parent_is_main_frame
98 true, // allow_download
100 EXPECT_TRUE(result
->IsFulfilled(request_data
));
102 const GURL
https_url("https://www.example.com");
103 scoped_ptr
<net::URLRequest
> wrong_resource_type(
104 context
.CreateRequest(https_url
, net::DEFAULT_PRIORITY
, NULL
));
105 data
.request
= wrong_resource_type
.get();
106 request_data
.url_match_ids
= matcher
.MatchURL(http_url
);
107 // Make sure IsFulfilled does not fail because of URL matching.
108 EXPECT_EQ(1u, request_data
.url_match_ids
.size());
109 content::ResourceRequestInfo::AllocateForTesting(
110 wrong_resource_type
.get(),
111 content::RESOURCE_TYPE_SUB_FRAME
,
113 -1, // render_process_id
114 -1, // render_view_id
115 -1, // render_frame_id
116 false, // is_main_frame
117 false, // parent_is_main_frame
118 true, // allow_download
120 EXPECT_FALSE(result
->IsFulfilled(request_data
));
123 TEST(WebRequestConditionTest
, CreateConditionFirstPartyForCookies
) {
124 // Necessary for TestURLRequest.
125 base::MessageLoopForIO message_loop
;
129 scoped_ptr
<WebRequestCondition
> result
;
131 result
= WebRequestCondition::Create(
133 matcher
.condition_factory(),
134 *base::test::ParseJson(
136 " \"firstPartyForCookiesUrl\": { \"hostPrefix\": \"fpfc\"}, \n"
137 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
140 EXPECT_EQ("", error
);
141 ASSERT_TRUE(result
.get());
143 URLMatcherConditionSet::Vector url_matcher_condition_set
;
144 result
->GetURLMatcherConditionSets(&url_matcher_condition_set
);
145 matcher
.AddConditionSets(url_matcher_condition_set
);
147 net::TestURLRequestContext context
;
148 const GURL
http_url("http://www.example.com");
149 const GURL
first_party_url("http://fpfc.example.com");
150 scoped_ptr
<net::URLRequest
> match_request(
151 context
.CreateRequest(http_url
, net::DEFAULT_PRIORITY
, NULL
));
152 WebRequestData
data(match_request
.get(), ON_BEFORE_REQUEST
);
153 WebRequestDataWithMatchIds
request_data(&data
);
154 request_data
.url_match_ids
= matcher
.MatchURL(http_url
);
155 EXPECT_EQ(0u, request_data
.url_match_ids
.size());
156 request_data
.first_party_url_match_ids
= matcher
.MatchURL(first_party_url
);
157 EXPECT_EQ(1u, request_data
.first_party_url_match_ids
.size());
158 content::ResourceRequestInfo::AllocateForTesting(
160 content::RESOURCE_TYPE_MAIN_FRAME
,
162 -1, // render_process_id
163 -1, // render_view_id
164 -1, // render_frame_id
165 true, // is_main_frame
166 false, // parent_is_main_frame
167 true, // allow_download
169 EXPECT_TRUE(result
->IsFulfilled(request_data
));
172 // Conditions without UrlFilter attributes need to be independent of URL
173 // matching results. We test here that:
174 // 1. A non-empty condition without UrlFilter attributes is fulfilled iff its
175 // attributes are fulfilled.
176 // 2. An empty condition (in particular, without UrlFilter attributes) is
178 TEST(WebRequestConditionTest
, NoUrlAttributes
) {
179 // Necessary for TestURLRequest.
180 base::MessageLoopForIO message_loop
;
184 // The empty condition.
186 scoped_ptr
<WebRequestCondition
> condition_empty
= WebRequestCondition::Create(
188 matcher
.condition_factory(),
189 *base::test::ParseJson(
191 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
194 EXPECT_EQ("", error
);
195 ASSERT_TRUE(condition_empty
.get());
197 // A condition without a UrlFilter attribute, which is always true.
199 scoped_ptr
<WebRequestCondition
> condition_no_url_true
=
200 WebRequestCondition::Create(
202 matcher
.condition_factory(),
203 *base::test::ParseJson(
205 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
207 // There is no "1st party for cookies" URL in the requests below,
208 // therefore all requests are considered first party for cookies.
209 " \"thirdPartyForCookies\": false, \n"
212 EXPECT_EQ("", error
);
213 ASSERT_TRUE(condition_no_url_true
.get());
215 // A condition without a UrlFilter attribute, which is always false.
217 scoped_ptr
<WebRequestCondition
> condition_no_url_false
=
218 WebRequestCondition::Create(
220 matcher
.condition_factory(),
221 *base::test::ParseJson(
223 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
225 " \"thirdPartyForCookies\": true, \n"
228 EXPECT_EQ("", error
);
229 ASSERT_TRUE(condition_no_url_false
.get());
231 net::TestURLRequestContext context
;
232 scoped_ptr
<net::URLRequest
> https_request(context
.CreateRequest(
233 GURL("https://www.example.com"), net::DEFAULT_PRIORITY
, NULL
));
235 // 1. A non-empty condition without UrlFilter attributes is fulfilled iff its
236 // attributes are fulfilled.
237 WebRequestData
data(https_request
.get(), ON_BEFORE_REQUEST
);
239 condition_no_url_false
->IsFulfilled(WebRequestDataWithMatchIds(&data
)));
241 data
= WebRequestData(https_request
.get(), ON_BEFORE_REQUEST
);
243 condition_no_url_true
->IsFulfilled(WebRequestDataWithMatchIds(&data
)));
245 // 2. An empty condition (in particular, without UrlFilter attributes) is
247 data
= WebRequestData(https_request
.get(), ON_BEFORE_REQUEST
);
248 EXPECT_TRUE(condition_empty
->IsFulfilled(WebRequestDataWithMatchIds(&data
)));
251 TEST(WebRequestConditionTest
, CreateConditionSet
) {
252 // Necessary for TestURLRequest.
253 base::MessageLoopForIO message_loop
;
256 WebRequestConditionSet::Values conditions
;
257 conditions
.push_back(linked_ptr
<base::Value
>(base::test::ParseJson(
259 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
261 " \"hostSuffix\": \"example.com\", \n"
262 " \"schemes\": [\"http\"], \n"
265 conditions
.push_back(linked_ptr
<base::Value
>(base::test::ParseJson(
267 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
269 " \"hostSuffix\": \"example.com\", \n"
270 " \"hostPrefix\": \"www\", \n"
271 " \"schemes\": [\"https\"], \n"
277 scoped_ptr
<WebRequestConditionSet
> result
= WebRequestConditionSet::Create(
278 NULL
, matcher
.condition_factory(), conditions
, &error
);
279 EXPECT_EQ("", error
);
280 ASSERT_TRUE(result
.get());
281 EXPECT_EQ(2u, result
->conditions().size());
283 // Tell the URLMatcher about our shiny new patterns.
284 URLMatcherConditionSet::Vector url_matcher_condition_set
;
285 result
->GetURLMatcherConditionSets(&url_matcher_condition_set
);
286 matcher
.AddConditionSets(url_matcher_condition_set
);
288 // Test that the result is correct and matches http://www.example.com and
289 // https://www.example.com
290 GURL
http_url("http://www.example.com");
291 net::TestURLRequestContext context
;
292 scoped_ptr
<net::URLRequest
> http_request(
293 context
.CreateRequest(http_url
, net::DEFAULT_PRIORITY
, NULL
));
294 WebRequestData
data(http_request
.get(), ON_BEFORE_REQUEST
);
295 WebRequestDataWithMatchIds
request_data(&data
);
296 request_data
.url_match_ids
= matcher
.MatchURL(http_url
);
297 EXPECT_EQ(1u, request_data
.url_match_ids
.size());
298 EXPECT_TRUE(result
->IsFulfilled(*(request_data
.url_match_ids
.begin()),
301 GURL
https_url("https://www.example.com");
302 request_data
.url_match_ids
= matcher
.MatchURL(https_url
);
303 EXPECT_EQ(1u, request_data
.url_match_ids
.size());
304 scoped_ptr
<net::URLRequest
> https_request(
305 context
.CreateRequest(https_url
, net::DEFAULT_PRIORITY
, NULL
));
306 data
.request
= https_request
.get();
307 EXPECT_TRUE(result
->IsFulfilled(*(request_data
.url_match_ids
.begin()),
310 // Check that both, hostPrefix and hostSuffix are evaluated.
311 GURL
https_foo_url("https://foo.example.com");
312 request_data
.url_match_ids
= matcher
.MatchURL(https_foo_url
);
313 EXPECT_EQ(0u, request_data
.url_match_ids
.size());
314 scoped_ptr
<net::URLRequest
> https_foo_request(
315 context
.CreateRequest(https_foo_url
, net::DEFAULT_PRIORITY
, NULL
));
316 data
.request
= https_foo_request
.get();
317 EXPECT_FALSE(result
->IsFulfilled(-1, request_data
));
320 TEST(WebRequestConditionTest
, TestPortFilter
) {
321 // Necessary for TestURLRequest.
322 base::MessageLoopForIO message_loop
;
325 WebRequestConditionSet::Values conditions
;
326 conditions
.push_back(linked_ptr
<base::Value
>(base::test::ParseJson(
328 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
330 " \"ports\": [80, [1000, 1010]], \n" // Allow 80;1000-1010.
331 " \"hostSuffix\": \"example.com\", \n"
337 scoped_ptr
<WebRequestConditionSet
> result
= WebRequestConditionSet::Create(
338 NULL
, matcher
.condition_factory(), conditions
, &error
);
339 EXPECT_EQ("", error
);
340 ASSERT_TRUE(result
.get());
341 EXPECT_EQ(1u, result
->conditions().size());
343 // Tell the URLMatcher about our shiny new patterns.
344 URLMatcherConditionSet::Vector url_matcher_condition_set
;
345 result
->GetURLMatcherConditionSets(&url_matcher_condition_set
);
346 matcher
.AddConditionSets(url_matcher_condition_set
);
348 std::set
<URLMatcherConditionSet::ID
> url_match_ids
;
350 // Test various URLs.
351 GURL
http_url("http://www.example.com");
352 net::TestURLRequestContext context
;
353 scoped_ptr
<net::URLRequest
> http_request(
354 context
.CreateRequest(http_url
, net::DEFAULT_PRIORITY
, NULL
));
355 url_match_ids
= matcher
.MatchURL(http_url
);
356 ASSERT_EQ(1u, url_match_ids
.size());
358 GURL
http_url_80("http://www.example.com:80");
359 scoped_ptr
<net::URLRequest
> http_request_80(
360 context
.CreateRequest(http_url_80
, net::DEFAULT_PRIORITY
, NULL
));
361 url_match_ids
= matcher
.MatchURL(http_url_80
);
362 ASSERT_EQ(1u, url_match_ids
.size());
364 GURL
http_url_1000("http://www.example.com:1000");
365 scoped_ptr
<net::URLRequest
> http_request_1000(
366 context
.CreateRequest(http_url_1000
, net::DEFAULT_PRIORITY
, NULL
));
367 url_match_ids
= matcher
.MatchURL(http_url_1000
);
368 ASSERT_EQ(1u, url_match_ids
.size());
370 GURL
http_url_2000("http://www.example.com:2000");
371 scoped_ptr
<net::URLRequest
> http_request_2000(
372 context
.CreateRequest(http_url_2000
, net::DEFAULT_PRIORITY
, NULL
));
373 url_match_ids
= matcher
.MatchURL(http_url_2000
);
374 ASSERT_EQ(0u, url_match_ids
.size());
377 // Create a condition with two attributes: one on the request header and one on
378 // the response header. The Create() method should fail and complain that it is
379 // impossible that both conditions are fulfilled at the same time.
380 TEST(WebRequestConditionTest
, ConditionsWithConflictingStages
) {
381 // Necessary for TestURLRequest.
382 base::MessageLoopForIO message_loop
;
386 scoped_ptr
<WebRequestCondition
> result
;
388 // Test error on incompatible application stages for involved attributes.
390 result
= WebRequestCondition::Create(
392 matcher
.condition_factory(),
393 *base::test::ParseJson(
395 " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
396 // Pass a JS array with one empty object to each of the header
398 " \"requestHeaders\": [{}], \n"
399 " \"responseHeaders\": [{}], \n"
402 EXPECT_FALSE(error
.empty());
403 EXPECT_FALSE(result
.get());
406 } // namespace extensions