Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: chrome/browser/policy/url_blacklist_manager.cc

Issue 102973005: Move URLBlacklistManager to components/policy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase, fixed linkage of policy_component Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/policy/url_blacklist_manager.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/location.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/task_runner_util.h"
16 #include "base/values.h"
17 #include "components/policy/core/common/policy_pref_names.h"
18 #include "components/user_prefs/pref_registry_syncable.h"
19 #include "net/base/load_flags.h"
20 #include "net/base/net_util.h"
21 #include "net/url_request/url_request.h"
22
23 using url_matcher::URLMatcher;
24 using url_matcher::URLMatcherCondition;
25 using url_matcher::URLMatcherConditionFactory;
26 using url_matcher::URLMatcherConditionSet;
27 using url_matcher::URLMatcherPortFilter;
28 using url_matcher::URLMatcherSchemeFilter;
29
30 namespace policy {
31
32 namespace {
33
34 const char kFileScheme[] = "file";
35
36 // Maximum filters per policy. Filters over this index are ignored.
37 const size_t kMaxFiltersPerPolicy = 1000;
38
39 // A task that builds the blacklist on a background thread.
40 scoped_ptr<URLBlacklist> BuildBlacklist(
41 scoped_ptr<base::ListValue> block,
42 scoped_ptr<base::ListValue> allow,
43 URLBlacklist::SegmentURLCallback segment_url) {
44 scoped_ptr<URLBlacklist> blacklist(new URLBlacklist(segment_url));
45 blacklist->Block(block.get());
46 blacklist->Allow(allow.get());
47 return blacklist.Pass();
48 }
49
50 } // namespace
51
52 struct URLBlacklist::FilterComponents {
53 FilterComponents() : port(0), match_subdomains(true), allow(true) {}
54 ~FilterComponents() {}
55
56 std::string scheme;
57 std::string host;
58 uint16 port;
59 std::string path;
60 bool match_subdomains;
61 bool allow;
62 };
63
64 URLBlacklist::URLBlacklist(SegmentURLCallback segment_url)
65 : segment_url_(segment_url), id_(0), url_matcher_(new URLMatcher) {}
66
67 URLBlacklist::~URLBlacklist() {}
68
69 void URLBlacklist::AddFilters(bool allow,
70 const base::ListValue* list) {
71 URLMatcherConditionSet::Vector all_conditions;
72 size_t size = std::min(kMaxFiltersPerPolicy, list->GetSize());
73 for (size_t i = 0; i < size; ++i) {
74 std::string pattern;
75 bool success = list->GetString(i, &pattern);
76 DCHECK(success);
77 FilterComponents components;
78 components.allow = allow;
79 if (!FilterToComponents(segment_url_, pattern, &components.scheme,
80 &components.host, &components.match_subdomains,
81 &components.port, &components.path)) {
82 LOG(ERROR) << "Invalid pattern " << pattern;
83 continue;
84 }
85
86 all_conditions.push_back(
87 CreateConditionSet(url_matcher_.get(), ++id_, components.scheme,
88 components.host, components.match_subdomains,
89 components.port, components.path));
90 filters_[id_] = components;
91 }
92 url_matcher_->AddConditionSets(all_conditions);
93 }
94
95 void URLBlacklist::Block(const base::ListValue* filters) {
96 AddFilters(false, filters);
97 }
98
99 void URLBlacklist::Allow(const base::ListValue* filters) {
100 AddFilters(true, filters);
101 }
102
103 bool URLBlacklist::IsURLBlocked(const GURL& url) const {
104 std::set<URLMatcherConditionSet::ID> matching_ids =
105 url_matcher_->MatchURL(url);
106
107 const FilterComponents* max = NULL;
108 for (std::set<URLMatcherConditionSet::ID>::iterator id = matching_ids.begin();
109 id != matching_ids.end(); ++id) {
110 std::map<int, FilterComponents>::const_iterator it = filters_.find(*id);
111 DCHECK(it != filters_.end());
112 const FilterComponents& filter = it->second;
113 if (!max || FilterTakesPrecedence(filter, *max))
114 max = &filter;
115 }
116
117 // Default to allow.
118 if (!max)
119 return false;
120
121 return !max->allow;
122 }
123
124 size_t URLBlacklist::Size() const {
125 return filters_.size();
126 }
127
128 // static
129 bool URLBlacklist::FilterToComponents(SegmentURLCallback segment_url,
130 const std::string& filter,
131 std::string* scheme,
132 std::string* host,
133 bool* match_subdomains,
134 uint16* port,
135 std::string* path) {
136 url_parse::Parsed parsed;
137
138 if (segment_url(filter, &parsed) == kFileScheme) {
139 base::FilePath file_path;
140 if (!net::FileURLToFilePath(GURL(filter), &file_path))
141 return false;
142
143 *scheme = kFileScheme;
144 host->clear();
145 *match_subdomains = true;
146 *port = 0;
147 // Special path when the |filter| is 'file://*'.
148 *path = (filter == "file://*") ? "" : file_path.AsUTF8Unsafe();
149 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
150 // Separators have to be canonicalized on Windows.
151 std::replace(path->begin(), path->end(), '\\', '/');
152 *path = "/" + *path;
153 #endif
154 return true;
155 }
156
157 if (!parsed.host.is_nonempty())
158 return false;
159
160 if (parsed.scheme.is_nonempty())
161 scheme->assign(filter, parsed.scheme.begin, parsed.scheme.len);
162 else
163 scheme->clear();
164
165 host->assign(filter, parsed.host.begin, parsed.host.len);
166 // Special '*' host, matches all hosts.
167 if (*host == "*") {
168 host->clear();
169 *match_subdomains = true;
170 } else if ((*host)[0] == '.') {
171 // A leading dot in the pattern syntax means that we don't want to match
172 // subdomains.
173 host->erase(0, 1);
174 *match_subdomains = false;
175 } else {
176 url_canon::RawCanonOutputT<char> output;
177 url_canon::CanonHostInfo host_info;
178 url_canon::CanonicalizeHostVerbose(filter.c_str(), parsed.host,
179 &output, &host_info);
180 if (host_info.family == url_canon::CanonHostInfo::NEUTRAL) {
181 // We want to match subdomains. Add a dot in front to make sure we only
182 // match at domain component boundaries.
183 *host = "." + *host;
184 *match_subdomains = true;
185 } else {
186 *match_subdomains = false;
187 }
188 }
189
190 if (parsed.port.is_nonempty()) {
191 int int_port;
192 if (!base::StringToInt(filter.substr(parsed.port.begin, parsed.port.len),
193 &int_port)) {
194 return false;
195 }
196 if (int_port <= 0 || int_port > kuint16max)
197 return false;
198 *port = int_port;
199 } else {
200 // Match any port.
201 *port = 0;
202 }
203
204 if (parsed.path.is_nonempty())
205 path->assign(filter, parsed.path.begin, parsed.path.len);
206 else
207 path->clear();
208
209 return true;
210 }
211
212 // static
213 scoped_refptr<URLMatcherConditionSet> URLBlacklist::CreateConditionSet(
214 URLMatcher* url_matcher,
215 int id,
216 const std::string& scheme,
217 const std::string& host,
218 bool match_subdomains,
219 uint16 port,
220 const std::string& path) {
221 URLMatcherConditionFactory* condition_factory =
222 url_matcher->condition_factory();
223 std::set<URLMatcherCondition> conditions;
224 conditions.insert(match_subdomains ?
225 condition_factory->CreateHostSuffixPathPrefixCondition(host, path) :
226 condition_factory->CreateHostEqualsPathPrefixCondition(host, path));
227
228 scoped_ptr<URLMatcherSchemeFilter> scheme_filter;
229 if (!scheme.empty())
230 scheme_filter.reset(new URLMatcherSchemeFilter(scheme));
231
232 scoped_ptr<URLMatcherPortFilter> port_filter;
233 if (port != 0) {
234 std::vector<URLMatcherPortFilter::Range> ranges;
235 ranges.push_back(URLMatcherPortFilter::CreateRange(port));
236 port_filter.reset(new URLMatcherPortFilter(ranges));
237 }
238
239 return new URLMatcherConditionSet(id, conditions,
240 scheme_filter.Pass(), port_filter.Pass());
241 }
242
243 // static
244 bool URLBlacklist::FilterTakesPrecedence(const FilterComponents& lhs,
245 const FilterComponents& rhs) {
246 if (lhs.match_subdomains && !rhs.match_subdomains)
247 return false;
248 if (!lhs.match_subdomains && rhs.match_subdomains)
249 return true;
250
251 size_t host_length = lhs.host.length();
252 size_t other_host_length = rhs.host.length();
253 if (host_length != other_host_length)
254 return host_length > other_host_length;
255
256 size_t path_length = lhs.path.length();
257 size_t other_path_length = rhs.path.length();
258 if (path_length != other_path_length)
259 return path_length > other_path_length;
260
261 if (lhs.allow && !rhs.allow)
262 return true;
263
264 return false;
265 }
266
267 URLBlacklistManager::URLBlacklistManager(
268 PrefService* pref_service,
269 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
270 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
271 URLBlacklist::SegmentURLCallback segment_url,
272 SkipBlacklistCallback skip_blacklist)
273 : ui_weak_ptr_factory_(this),
274 pref_service_(pref_service),
275 background_task_runner_(background_task_runner),
276 io_task_runner_(io_task_runner),
277 segment_url_(segment_url),
278 skip_blacklist_(skip_blacklist),
279 io_weak_ptr_factory_(this),
280 ui_task_runner_(base::MessageLoopProxy::current()),
281 blacklist_(new URLBlacklist(segment_url)) {
282 pref_change_registrar_.Init(pref_service_);
283 base::Closure callback = base::Bind(&URLBlacklistManager::ScheduleUpdate,
284 base::Unretained(this));
285 pref_change_registrar_.Add(policy_prefs::kUrlBlacklist, callback);
286 pref_change_registrar_.Add(policy_prefs::kUrlWhitelist, callback);
287
288 // Start enforcing the policies without a delay when they are present at
289 // startup.
290 if (pref_service_->HasPrefPath(policy_prefs::kUrlBlacklist))
291 Update();
292 }
293
294 void URLBlacklistManager::ShutdownOnUIThread() {
295 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
296 // Cancel any pending updates, and stop listening for pref change updates.
297 ui_weak_ptr_factory_.InvalidateWeakPtrs();
298 pref_change_registrar_.RemoveAll();
299 }
300
301 URLBlacklistManager::~URLBlacklistManager() {
302 }
303
304 void URLBlacklistManager::ScheduleUpdate() {
305 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
306 // Cancel pending updates, if any. This can happen if two preferences that
307 // change the blacklist are updated in one message loop cycle. In those cases,
308 // only rebuild the blacklist after all the preference updates are processed.
309 ui_weak_ptr_factory_.InvalidateWeakPtrs();
310 ui_task_runner_->PostTask(
311 FROM_HERE,
312 base::Bind(&URLBlacklistManager::Update,
313 ui_weak_ptr_factory_.GetWeakPtr()));
314 }
315
316 void URLBlacklistManager::Update() {
317 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
318
319 // The preferences can only be read on the UI thread.
320 scoped_ptr<base::ListValue> block(
321 pref_service_->GetList(policy_prefs::kUrlBlacklist)->DeepCopy());
322 scoped_ptr<base::ListValue> allow(
323 pref_service_->GetList(policy_prefs::kUrlWhitelist)->DeepCopy());
324
325 // Go through the IO thread to grab a WeakPtr to |this|. This is safe from
326 // here, since this task will always execute before a potential deletion of
327 // ProfileIOData on IO.
328 io_task_runner_->PostTask(FROM_HERE,
329 base::Bind(&URLBlacklistManager::UpdateOnIO,
330 base::Unretained(this),
331 base::Passed(&block),
332 base::Passed(&allow)));
333 }
334
335 void URLBlacklistManager::UpdateOnIO(scoped_ptr<base::ListValue> block,
336 scoped_ptr<base::ListValue> allow) {
337 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
338 // The URLBlacklist is built on a worker thread. Once it's ready, it is passed
339 // to the URLBlacklistManager on IO.
340 base::PostTaskAndReplyWithResult(
341 background_task_runner_,
342 FROM_HERE,
343 base::Bind(&BuildBlacklist,
344 base::Passed(&block),
345 base::Passed(&allow),
346 segment_url_),
347 base::Bind(&URLBlacklistManager::SetBlacklist,
348 io_weak_ptr_factory_.GetWeakPtr()));
349 }
350
351 void URLBlacklistManager::SetBlacklist(scoped_ptr<URLBlacklist> blacklist) {
352 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
353 blacklist_ = blacklist.Pass();
354 }
355
356 bool URLBlacklistManager::IsURLBlocked(const GURL& url) const {
357 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
358 return blacklist_->IsURLBlocked(url);
359 }
360
361 bool URLBlacklistManager::IsRequestBlocked(
362 const net::URLRequest& request) const {
363 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
364 int filter_flags = net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME;
365 if ((request.load_flags() & filter_flags) == 0)
366 return false;
367
368 if (skip_blacklist_(request.url()))
369 return false;
370
371 return IsURLBlocked(request.url());
372 }
373
374 // static
375 void URLBlacklistManager::RegisterProfilePrefs(
376 user_prefs::PrefRegistrySyncable* registry) {
377 registry->RegisterListPref(policy_prefs::kUrlBlacklist,
378 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
379 registry->RegisterListPref(policy_prefs::kUrlWhitelist,
380 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
381 }
382
383 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/url_blacklist_manager.h ('k') | chrome/browser/policy/url_blacklist_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698