OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 | |
5 #include "components/subresource_filter/content/common/document_subresource_filt
er.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/callback.h" | |
9 #include "base/files/file.h" | |
10 #include "base/macros.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/strings/string_piece.h" | |
13 #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" | |
14 #include "components/subresource_filter/core/common/test_ruleset_creator.h" | |
15 #include "components/subresource_filter/core/common/test_ruleset_utils.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "third_party/WebKit/public/platform/WebURL.h" | |
18 #include "third_party/WebKit/public/platform/WebURLRequest.h" | |
19 #include "url/gurl.h" | |
20 | |
21 namespace subresource_filter { | |
22 | |
23 namespace { | |
24 | |
25 constexpr auto kDisabled = ActivationLevel::DISABLED; | |
26 constexpr auto kDryRun = ActivationLevel::DRYRUN; | |
27 constexpr auto kEnabled = ActivationLevel::ENABLED; | |
28 | |
29 const char kTestAlphaURL[] = "http://example.com/alpha"; | |
30 const char kTestAlphaDataURI[] = "data:text/plain,alpha"; | |
31 const char kTestBetaURL[] = "http://example.com/beta"; | |
32 | |
33 const char kTestAlphaURLPathSuffix[] = "alpha"; | |
34 | |
35 class TestCallbackReceiver { | |
36 public: | |
37 TestCallbackReceiver() = default; | |
38 base::OnceClosure closure() { | |
39 return base::BindOnce(&TestCallbackReceiver::CallbackMethod, | |
40 base::Unretained(this)); | |
41 } | |
42 size_t callback_count() const { return callback_count_; } | |
43 | |
44 private: | |
45 void CallbackMethod() { ++callback_count_; } | |
46 | |
47 size_t callback_count_ = 0; | |
48 | |
49 DISALLOW_COPY_AND_ASSIGN(TestCallbackReceiver); | |
50 }; | |
51 | |
52 } // namespace | |
53 | |
54 // Tests for DocumentSubresourceFilter class. ---------------------------------- | |
55 | |
56 class DocumentSubresourceFilterTest : public ::testing::Test { | |
57 public: | |
58 DocumentSubresourceFilterTest() {} | |
59 | |
60 protected: | |
61 void SetUp() override { | |
62 ASSERT_NO_FATAL_FAILURE( | |
63 SetTestRulesetToDisallowURLsWithPathSuffix(kTestAlphaURLPathSuffix)); | |
64 } | |
65 | |
66 void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) { | |
67 testing::TestRulesetPair test_ruleset_pair; | |
68 ASSERT_NO_FATAL_FAILURE( | |
69 test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix( | |
70 suffix, &test_ruleset_pair)); | |
71 ruleset_ = new MemoryMappedRuleset( | |
72 testing::TestRuleset::Open(test_ruleset_pair.indexed)); | |
73 } | |
74 | |
75 const MemoryMappedRuleset* ruleset() { return ruleset_.get(); } | |
76 | |
77 private: | |
78 testing::TestRulesetCreator test_ruleset_creator_; | |
79 scoped_refptr<const MemoryMappedRuleset> ruleset_; | |
80 | |
81 DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilterTest); | |
82 }; | |
83 | |
84 TEST_F(DocumentSubresourceFilterTest, DryRun) { | |
85 blink::WebURLRequest::RequestContext request_context = | |
86 blink::WebURLRequest::RequestContextImage; | |
87 TestCallbackReceiver first_disallowed_load_callback_receiver; | |
88 | |
89 ActivationState activation_state(kDryRun); | |
90 activation_state.measure_performance = true; | |
91 DocumentSubresourceFilter filter( | |
92 url::Origin(), activation_state, ruleset(), | |
93 first_disallowed_load_callback_receiver.closure()); | |
94 | |
95 EXPECT_EQ(blink::WebDocumentSubresourceFilter::WouldDisallow, | |
96 filter.getLoadPolicy(GURL(kTestAlphaURL), request_context)); | |
97 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, | |
98 filter.getLoadPolicy(GURL(kTestAlphaDataURI), request_context)); | |
99 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, | |
100 filter.getLoadPolicy(GURL(kTestBetaURL), request_context)); | |
101 EXPECT_EQ(blink::WebDocumentSubresourceFilter::WouldDisallow, | |
102 filter.GetLoadPolicyForSubdocument(GURL(kTestAlphaURL))); | |
103 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, | |
104 filter.GetLoadPolicyForSubdocument(GURL(kTestBetaURL))); | |
105 | |
106 const auto& statistics = filter.statistics(); | |
107 EXPECT_EQ(5, statistics.num_loads_total); | |
108 EXPECT_EQ(4, statistics.num_loads_evaluated); | |
109 EXPECT_EQ(2, statistics.num_loads_matching_rules); | |
110 EXPECT_EQ(0, statistics.num_loads_disallowed); | |
111 | |
112 EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count()); | |
113 } | |
114 | |
115 TEST_F(DocumentSubresourceFilterTest, Enabled) { | |
116 auto test_impl = [this](bool measure_performance) { | |
117 blink::WebURLRequest::RequestContext request_context = | |
118 blink::WebURLRequest::RequestContextImage; | |
119 ActivationState activation_state(kEnabled); | |
120 activation_state.measure_performance = measure_performance; | |
121 DocumentSubresourceFilter filter(url::Origin(), activation_state, ruleset(), | |
122 base::OnceClosure()); | |
123 | |
124 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Disallow, | |
125 filter.getLoadPolicy(GURL(kTestAlphaURL), request_context)); | |
126 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, | |
127 filter.getLoadPolicy(GURL(kTestAlphaDataURI), request_context)); | |
128 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, | |
129 filter.getLoadPolicy(GURL(kTestBetaURL), request_context)); | |
130 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Disallow, | |
131 filter.GetLoadPolicyForSubdocument(GURL(kTestAlphaURL))); | |
132 EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, | |
133 filter.GetLoadPolicyForSubdocument(GURL(kTestBetaURL))); | |
134 | |
135 const auto& statistics = filter.statistics(); | |
136 EXPECT_EQ(5, statistics.num_loads_total); | |
137 EXPECT_EQ(4, statistics.num_loads_evaluated); | |
138 EXPECT_EQ(2, statistics.num_loads_matching_rules); | |
139 EXPECT_EQ(2, statistics.num_loads_disallowed); | |
140 | |
141 if (!measure_performance) { | |
142 EXPECT_TRUE(statistics.evaluation_total_cpu_duration.is_zero()); | |
143 EXPECT_TRUE(statistics.evaluation_total_wall_duration.is_zero()); | |
144 } | |
145 // Otherwise, don't expect |total_duration| to be non-zero, although it | |
146 // practically is (when timer is supported). | |
147 }; | |
148 | |
149 test_impl(true /* measure_performance */); | |
150 test_impl(false /* measure_performance */); | |
151 } | |
152 | |
153 TEST_F(DocumentSubresourceFilterTest, | |
154 CallbackFiredExactlyOnceAfterFirstDisallowedLoad) { | |
155 TestCallbackReceiver first_disallowed_load_callback_receiver; | |
156 | |
157 ActivationState activation_state(kEnabled); | |
158 activation_state.measure_performance = true; | |
159 DocumentSubresourceFilter filter( | |
160 url::Origin(), activation_state, ruleset(), | |
161 first_disallowed_load_callback_receiver.closure()); | |
162 | |
163 EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count()); | |
164 filter.reportDisallowedLoad(); | |
165 EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count()); | |
166 filter.reportDisallowedLoad(); | |
167 EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count()); | |
168 } | |
169 | |
170 // Tests for ComputeActivationState functions. --------------------------------- | |
171 | |
172 class SubresourceFilterComputeActivationStateTest : public ::testing::Test { | |
173 public: | |
174 SubresourceFilterComputeActivationStateTest() {} | |
175 | |
176 protected: | |
177 void SetUp() override { | |
178 constexpr int32_t kDocument = proto::ACTIVATION_TYPE_DOCUMENT; | |
179 constexpr int32_t kGenericBlock = proto::ACTIVATION_TYPE_GENERICBLOCK; | |
180 | |
181 std::vector<proto::UrlRule> rules; | |
182 rules.push_back(testing::CreateWhitelistRuleForDocument( | |
183 "child1.com", kDocument, {"parent1.com", "parent2.com"})); | |
184 rules.push_back(testing::CreateWhitelistRuleForDocument( | |
185 "child2.com", kGenericBlock, {"parent1.com", "parent2.com"})); | |
186 rules.push_back(testing::CreateWhitelistRuleForDocument( | |
187 "child3.com", kDocument | kGenericBlock, | |
188 {"parent1.com", "parent2.com"})); | |
189 | |
190 testing::TestRulesetPair test_ruleset_pair; | |
191 ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules( | |
192 rules, &test_ruleset_pair)); | |
193 ruleset_ = new MemoryMappedRuleset( | |
194 testing::TestRuleset::Open(test_ruleset_pair.indexed)); | |
195 } | |
196 | |
197 static ActivationState MakeState( | |
198 bool filtering_disabled_for_document, | |
199 bool generic_blocking_rules_disabled = false, | |
200 ActivationLevel activation_level = kEnabled) { | |
201 ActivationState activation_state(activation_level); | |
202 activation_state.filtering_disabled_for_document = | |
203 filtering_disabled_for_document; | |
204 activation_state.generic_blocking_rules_disabled = | |
205 generic_blocking_rules_disabled; | |
206 return activation_state; | |
207 }; | |
208 | |
209 const MemoryMappedRuleset* ruleset() { return ruleset_.get(); } | |
210 | |
211 private: | |
212 testing::TestRulesetCreator test_ruleset_creator_; | |
213 scoped_refptr<const MemoryMappedRuleset> ruleset_; | |
214 | |
215 DISALLOW_COPY_AND_ASSIGN(SubresourceFilterComputeActivationStateTest); | |
216 }; | |
217 | |
218 TEST_F(SubresourceFilterComputeActivationStateTest, | |
219 ActivationBitsCorrectlyPropagateToChildDocument) { | |
220 // Make sure that the |generic_blocking_rules_disabled| flag is disregarded | |
221 // when |filtering_disabled_for_document| is true. | |
222 ASSERT_EQ(MakeState(true, false), MakeState(true, true)); | |
223 | |
224 // TODO(pkalinnikov): Find a short way to express all these tests. | |
225 const struct { | |
226 const char* document_url; | |
227 const char* parent_document_origin; | |
228 ActivationState parent_activation; | |
229 ActivationState expected_activation_state; | |
230 } kTestCases[] = { | |
231 {"http://example.com", "http://example.com", MakeState(false, false), | |
232 MakeState(false, false)}, | |
233 {"http://example.com", "http://example.com", MakeState(false, true), | |
234 MakeState(false, true)}, | |
235 {"http://example.com", "http://example.com", MakeState(true, false), | |
236 MakeState(true)}, | |
237 {"http://example.com", "http://example.com", MakeState(true, true), | |
238 MakeState(true)}, | |
239 | |
240 {"http://child1.com", "http://parrrrent1.com", MakeState(false, false), | |
241 MakeState(false, false)}, | |
242 {"http://child1.com", "http://parent1.com", MakeState(false, false), | |
243 MakeState(true, false)}, | |
244 {"http://child1.com", "http://parent2.com", MakeState(false, false), | |
245 MakeState(true, false)}, | |
246 {"http://child1.com", "http://parent2.com", MakeState(true, false), | |
247 MakeState(true)}, | |
248 {"http://child1.com", "http://parent2.com", MakeState(false, true), | |
249 MakeState(true)}, | |
250 | |
251 {"http://child2.com", "http://parent1.com", MakeState(false, false), | |
252 MakeState(false, true)}, | |
253 {"http://child2.com", "http://parent1.com", MakeState(false, true), | |
254 MakeState(false, true)}, | |
255 {"http://child2.com", "http://parent1.com", MakeState(true, false), | |
256 MakeState(true)}, | |
257 {"http://child2.com", "http://parent1.com", MakeState(true, true), | |
258 MakeState(true)}, | |
259 | |
260 {"http://child3.com", "http://parent1.com", MakeState(false, false), | |
261 MakeState(true)}, | |
262 {"http://child3.com", "http://parent1.com", MakeState(false, true), | |
263 MakeState(true)}, | |
264 {"http://child3.com", "http://parent1.com", MakeState(true, false), | |
265 MakeState(true)}, | |
266 {"http://child3.com", "http://parent1.com", MakeState(true, true), | |
267 MakeState(true)}, | |
268 }; | |
269 | |
270 for (size_t i = 0, size = arraysize(kTestCases); i != size; ++i) { | |
271 SCOPED_TRACE(::testing::Message() << "Test number: " << i); | |
272 const auto& test_case = kTestCases[i]; | |
273 | |
274 GURL document_url(test_case.document_url); | |
275 url::Origin parent_document_origin(GURL(test_case.parent_document_origin)); | |
276 ActivationState activation_state = | |
277 ComputeActivationState(document_url, parent_document_origin, | |
278 test_case.parent_activation, ruleset()); | |
279 EXPECT_EQ(test_case.expected_activation_state, activation_state); | |
280 } | |
281 } | |
282 | |
283 TEST_F(SubresourceFilterComputeActivationStateTest, | |
284 ActivationStateCorrectlyPropagatesDownDocumentHierarchy) { | |
285 const struct { | |
286 std::vector<std::string> ancestor_document_urls; | |
287 ActivationLevel activation_level; | |
288 ActivationState expected_activation_state; | |
289 } kTestCases[] = { | |
290 {{"http://example.com"}, kEnabled, MakeState(false)}, | |
291 {std::vector<std::string>(2, "http://example.com"), kEnabled, | |
292 MakeState(false)}, | |
293 {std::vector<std::string>(4, "http://example.com"), kEnabled, | |
294 MakeState(false)}, | |
295 | |
296 {std::vector<std::string>(4, "http://example.com"), kEnabled, | |
297 MakeState(false, false, kEnabled)}, | |
298 {std::vector<std::string>(4, "http://example.com"), kDisabled, | |
299 MakeState(false, false, kDisabled)}, | |
300 {std::vector<std::string>(4, "http://example.com"), kDryRun, | |
301 MakeState(false, false, kDryRun)}, | |
302 | |
303 {{"http://ex.com", "http://child1.com", "http://parent1.com", | |
304 "http://root.com"}, | |
305 kEnabled, | |
306 MakeState(true)}, | |
307 | |
308 {{"http://ex.com", "http://child1.com", "http://parent1.com", | |
309 "http://root.com"}, | |
310 kEnabled, | |
311 MakeState(true)}, | |
312 | |
313 {{"http://ex.com", "http://child2.com", "http://parent1.com", | |
314 "http://root.com"}, | |
315 kEnabled, | |
316 MakeState(false, true)}, | |
317 | |
318 {{"http://ex.com", "http://ex.com", "http://child3.com", | |
319 "http://parent1.com", "http://root.com"}, | |
320 kDryRun, | |
321 MakeState(true, false, kDryRun)}, | |
322 }; | |
323 | |
324 for (size_t i = 0, size = arraysize(kTestCases); i != size; ++i) { | |
325 const auto& test_case = kTestCases[i]; | |
326 SCOPED_TRACE(::testing::Message() << "Test number: " << i); | |
327 | |
328 std::vector<GURL> ancestor_document_urls; | |
329 for (const auto& url_string : test_case.ancestor_document_urls) | |
330 ancestor_document_urls.emplace_back(url_string); | |
331 | |
332 ActivationState activation_state = ComputeActivationState( | |
333 test_case.activation_level, false, ancestor_document_urls, ruleset()); | |
334 EXPECT_EQ(test_case.expected_activation_state, activation_state); | |
335 } | |
336 } | |
337 | |
338 } // namespace subresource_filter | |
OLD | NEW |