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

Side by Side Diff: content/browser/browsing_data/clear_site_data_throttle.cc

Issue 2368923003: Support the Clear-Site-Data header on resource requests (Closed)
Patch Set: Rebase. Created 3 years, 6 months 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/browsing_data/clear_site_data_throttle.h" 5 #include "content/browser/browsing_data/clear_site_data_throttle.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/json/json_string_value_serializer.h" 9 #include "base/json/json_string_value_serializer.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h" 11 #include "base/metrics/histogram_macros.h"
12 #include "base/scoped_observer.h"
12 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h" 14 #include "base/strings/stringprintf.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "content/browser/frame_host/navigation_handle_impl.h" 16 #include "content/browser/service_worker/service_worker_response_info.h"
16 #include "content/public/browser/browser_context.h" 17 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/content_browser_client.h" 18 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/navigation_handle.h" 19 #include "content/public/browser/browsing_data_filter_builder.h"
20 #include "content/public/browser/browsing_data_remover.h"
21 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/content_client.h"
21 #include "content/public/common/content_switches.h" 23 #include "content/public/common/content_switches.h"
22 #include "content/public/common/origin_util.h" 24 #include "content/public/common/origin_util.h"
25 #include "content/public/common/resource_response_info.h"
26 #include "net/base/load_flags.h"
27 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
23 #include "net/http/http_response_headers.h" 28 #include "net/http/http_response_headers.h"
29 #include "net/url_request/redirect_info.h"
24 #include "url/gurl.h" 30 #include "url/gurl.h"
25 #include "url/origin.h" 31 #include "url/origin.h"
26 32
27 namespace content { 33 namespace content {
28 34
29 namespace { 35 namespace {
30 36
31 static const char* kClearSiteDataHeader = "Clear-Site-Data"; 37 const char kNameForLogging[] = "ClearSiteDataThrottle";
32 38
33 static const char* kTypesKey = "types"; 39 const char kClearSiteDataHeader[] = "Clear-Site-Data";
40
41 const char kTypesKey[] = "types";
42
43 // Datatypes.
44 const char kDatatypeCookies[] = "cookies";
45 const char kDatatypeStorage[] = "storage";
46 const char kDatatypeCache[] = "cache";
34 47
35 // Pretty-printed log output. 48 // Pretty-printed log output.
36 static const char* kConsoleMessagePrefix = "Clear-Site-Data header on '%s': %s"; 49 const char kConsoleMessagePrefix[] = "Clear-Site-Data header on '%s': %s";
37 static const char* kClearingOneType = "Clearing %s."; 50 const char kConsoleMessageCleared[] = "Cleared datatypes: %s.";
38 static const char* kClearingTwoTypes = "Clearing %s and %s."; 51 const char kConsoleMessageDatatypeSeparator[] = ", ";
39 static const char* kClearingThreeTypes = "Clearing %s, %s, and %s.";
40
41 // Console logging. Adds a |text| message with |level| to |messages|.
42 void ConsoleLog(std::vector<ClearSiteDataThrottle::ConsoleMessage>* messages,
43 const GURL& url,
44 const std::string& text,
45 ConsoleMessageLevel level) {
46 messages->push_back({url, text, level});
47 }
48 52
49 bool AreExperimentalFeaturesEnabled() { 53 bool AreExperimentalFeaturesEnabled() {
50 return base::CommandLine::ForCurrentProcess()->HasSwitch( 54 return base::CommandLine::ForCurrentProcess()->HasSwitch(
51 switches::kEnableExperimentalWebPlatformFeatures); 55 switches::kEnableExperimentalWebPlatformFeatures);
52 } 56 }
53 57
54 // Represents the parameters as a single number to be recorded in a histogram. 58 // Represents the parameters as a single number to be recorded in a histogram.
55 int ParametersMask(bool clear_cookies, bool clear_storage, bool clear_cache) { 59 int ParametersMask(bool clear_cookies, bool clear_storage, bool clear_cache) {
56 return static_cast<int>(clear_cookies) * (1 << 0) + 60 return static_cast<int>(clear_cookies) * (1 << 0) +
57 static_cast<int>(clear_storage) * (1 << 1) + 61 static_cast<int>(clear_storage) * (1 << 1) +
58 static_cast<int>(clear_cache) * (1 << 2); 62 static_cast<int>(clear_cache) * (1 << 2);
59 } 63 }
60 64
61 } // namespace 65 // A helper function to pass an IO thread callback to a method called on
62 66 // the UI thread.
63 // static 67 void JumpFromUIToIOThread(base::OnceClosure callback) {
64 std::unique_ptr<NavigationThrottle> 68 DCHECK_CURRENTLY_ON(BrowserThread::UI);
65 ClearSiteDataThrottle::CreateThrottleForNavigation(NavigationHandle* handle) { 69 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, std::move(callback));
66 if (AreExperimentalFeaturesEnabled())
67 return base::WrapUnique(new ClearSiteDataThrottle(handle));
68
69 return std::unique_ptr<NavigationThrottle>();
70 } 70 }
71 71
72 ClearSiteDataThrottle::ClearSiteDataThrottle( 72 // Finds the BrowserContext associated with the request and requests
73 NavigationHandle* navigation_handle) 73 // the actual clearing of data for |origin|. The datatypes to be deleted
74 : NavigationThrottle(navigation_handle), 74 // are determined by |clear_cookies|, |clear_storage|, and |clear_cache|.
75 clearing_in_progress_(false), 75 // |web_contents_getter| identifies the WebContents from which the request
76 weak_ptr_factory_(this) {} 76 // originated. Must be run on the UI thread. The |callback| will be executed
77 // on the IO thread.
78 class UIThreadSiteDataClearer : public BrowsingDataRemover::Observer {
79 public:
80 static void Run(
81 const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
82 const url::Origin& origin,
83 bool clear_cookies,
84 bool clear_storage,
85 bool clear_cache,
86 base::OnceClosure callback) {
87 (new UIThreadSiteDataClearer(web_contents_getter, origin, clear_cookies,
88 clear_storage, clear_cache,
89 std::move(callback)))
90 ->RunAndDestroySelfWhenDone();
91 }
77 92
78 ClearSiteDataThrottle::~ClearSiteDataThrottle() { 93 private:
79 // At the end of the navigation we finally have access to the correct 94 UIThreadSiteDataClearer(
80 // RenderFrameHost. Output the cached console messages. Prefix each sequence 95 const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
81 // of messages belonging to the same URL with |kConsoleMessagePrefix|. 96 const url::Origin& origin,
97 bool clear_cookies,
98 bool clear_storage,
99 bool clear_cache,
100 base::OnceClosure callback)
101 : origin_(origin),
102 clear_cookies_(clear_cookies),
103 clear_storage_(clear_storage),
104 clear_cache_(clear_cache),
105 callback_(std::move(callback)),
106 pending_task_count_(0),
107 remover_(nullptr),
108 scoped_observer_(this) {
109 DCHECK_CURRENTLY_ON(BrowserThread::UI);
110
111 WebContents* web_contents = web_contents_getter.Run();
112 if (!web_contents)
113 return;
mmenke 2017/05/25 19:23:09 This isn't handling the case web_contents_getter r
msramek 2017/05/30 21:58:44 Done. Thanks for catching! I fixed this, but I'll
msramek 2017/06/01 22:02:27 Just to follow up on this, we can't test this with
114
115 remover_ = BrowserContext::GetBrowsingDataRemover(
116 web_contents->GetBrowserContext());
117 scoped_observer_.Add(remover_);
118 }
119
120 ~UIThreadSiteDataClearer() override {}
121
122 void RunAndDestroySelfWhenDone() {
123 DCHECK_CURRENTLY_ON(BrowserThread::UI);
124
125 // Cookies and channel IDs are scoped to
126 // a) eTLD+1 of |origin|'s host if |origin|'s host is a registrable domain
127 // or a subdomain thereof
128 // b) |origin|'s host exactly if it is an IP address or an internal hostname
129 // (e.g. "localhost" or "fileserver").
130 // TODO(msramek): What about plugin data?
131 if (clear_cookies_) {
132 std::string domain = GetDomainAndRegistry(
133 origin_.host(),
134 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
135
136 if (domain.empty())
137 domain = origin_.host(); // IP address or internal hostname.
138
139 std::unique_ptr<BrowsingDataFilterBuilder> domain_filter_builder(
140 BrowsingDataFilterBuilder::Create(
141 BrowsingDataFilterBuilder::WHITELIST));
142 domain_filter_builder->AddRegisterableDomain(domain);
143
144 pending_task_count_++;
145 remover_->RemoveWithFilterAndReply(
146 base::Time(), base::Time::Max(),
147 BrowsingDataRemover::DATA_TYPE_COOKIES |
148 BrowsingDataRemover::DATA_TYPE_CHANNEL_IDS,
149 BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
150 BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
151 std::move(domain_filter_builder), this);
152 }
153
154 // Delete origin-scoped data.
155 int remove_mask = 0;
156 if (clear_storage_)
157 remove_mask |= BrowsingDataRemover::DATA_TYPE_DOM_STORAGE;
158 if (clear_cache_)
159 remove_mask |= BrowsingDataRemover::DATA_TYPE_CACHE;
160
161 if (remove_mask) {
162 std::unique_ptr<BrowsingDataFilterBuilder> origin_filter_builder(
163 BrowsingDataFilterBuilder::Create(
164 BrowsingDataFilterBuilder::WHITELIST));
165 origin_filter_builder->AddOrigin(origin_);
166
167 pending_task_count_++;
168 remover_->RemoveWithFilterAndReply(
169 base::Time(), base::Time::Max(), remove_mask,
170 BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
171 BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
172 std::move(origin_filter_builder), this);
173 }
174 }
175
176 // BrowsingDataRemover::Observer;
177 void OnBrowsingDataRemoverDone() override {
178 DCHECK(pending_task_count_);
179 if (--pending_task_count_)
180 return;
181
182 JumpFromUIToIOThread(std::move(callback_));
183 delete this;
184 }
185
186 url::Origin origin_;
187 bool clear_cookies_;
188 bool clear_storage_;
189 bool clear_cache_;
190 base::OnceClosure callback_;
191 int pending_task_count_;
192 BrowsingDataRemover* remover_;
193 ScopedObserver<BrowsingDataRemover, BrowsingDataRemover::Observer>
194 scoped_observer_;
195 };
196
197 // Outputs |messages| to the console of WebContents retrieved from
198 // |web_contents_getter|. Must be run on the UI thread.
199 void OutputMessagesOnUIThread(
200 const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
201 const std::vector<ClearSiteDataThrottle::ConsoleMessagesDelegate::Message>&
202 messages) {
203 DCHECK_CURRENTLY_ON(BrowserThread::UI);
204
205 WebContents* web_contents = web_contents_getter.Run();
206 if (!web_contents)
207 return;
208
209 // Prefix each sequence of messages belonging to the same URL with
210 // |kConsoleMessagePrefix|.
82 GURL last_seen_url; 211 GURL last_seen_url;
83 for (const ConsoleMessage& message : messages_) { 212 for (const auto& message : messages) {
84 if (message.url == last_seen_url) { 213 if (message.url == last_seen_url) {
85 navigation_handle()->GetRenderFrameHost()->AddMessageToConsole( 214 web_contents->GetMainFrame()->AddMessageToConsole(message.level,
86 message.level, message.text); 215 message.text);
87 } else { 216 } else {
88 navigation_handle()->GetRenderFrameHost()->AddMessageToConsole( 217 web_contents->GetMainFrame()->AddMessageToConsole(
89 message.level, 218 message.level,
90 base::StringPrintf(kConsoleMessagePrefix, message.url.spec().c_str(), 219 base::StringPrintf(kConsoleMessagePrefix, message.url.spec().c_str(),
91 message.text.c_str())); 220 message.text.c_str()));
92 } 221 }
93 222
94 last_seen_url = message.url; 223 last_seen_url = message.url;
95 } 224 }
96 } 225 }
97 226
98 ClearSiteDataThrottle::ThrottleCheckResult 227 } // namespace
99 ClearSiteDataThrottle::WillStartRequest() { 228
100 current_url_ = navigation_handle()->GetURL(); 229 ////////////////////////////////////////////////////////////////////////////////
101 return PROCEED; 230 // ConsoleMessagesDelegate
102 } 231
103 232 ClearSiteDataThrottle::ConsoleMessagesDelegate::ConsoleMessagesDelegate() {}
104 ClearSiteDataThrottle::ThrottleCheckResult 233
105 ClearSiteDataThrottle::WillRedirectRequest() { 234 ClearSiteDataThrottle::ConsoleMessagesDelegate::~ConsoleMessagesDelegate() {}
106 // We are processing a redirect from url1 to url2. GetResponseHeaders() 235
107 // contains headers from url1, but GetURL() is already equal to url2. Handle 236 void ClearSiteDataThrottle::ConsoleMessagesDelegate::AddMessage(
108 // the headers before updating the URL, so that |current_url_| corresponds 237 const GURL& url,
109 // to the URL that sent the headers. 238 const std::string& text,
110 HandleHeader(); 239 ConsoleMessageLevel level) {
111 current_url_ = navigation_handle()->GetURL(); 240 messages_.push_back({url, text, level});
112 241 }
113 return clearing_in_progress_ ? DEFER : PROCEED; 242
114 } 243 void ClearSiteDataThrottle::ConsoleMessagesDelegate::OutputMessages(
115 244 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) {
116 ClearSiteDataThrottle::ThrottleCheckResult 245 if (messages_.empty())
117 ClearSiteDataThrottle::WillProcessResponse() {
118 HandleHeader();
119 return clearing_in_progress_ ? DEFER : PROCEED;
120 }
121
122 const char* ClearSiteDataThrottle::GetNameForLogging() {
123 return "ClearSiteDataThrottle";
124 }
125
126 void ClearSiteDataThrottle::HandleHeader() {
127 NavigationHandleImpl* handle =
128 static_cast<NavigationHandleImpl*>(navigation_handle());
129 const net::HttpResponseHeaders* headers = handle->GetResponseHeaders();
130
131 if (!headers || !headers->HasHeader(kClearSiteDataHeader))
132 return; 246 return;
133 247
134 // Only accept the header on secure origins. 248 DCHECK_CURRENTLY_ON(BrowserThread::IO);
135 if (!IsOriginSecure(current_url_)) { 249 BrowserThread::PostTask(
136 ConsoleLog(&messages_, current_url_, "Not supported for insecure origins.", 250 BrowserThread::UI, FROM_HERE,
137 CONSOLE_MESSAGE_LEVEL_ERROR); 251 base::BindOnce(&OutputMessagesOnUIThread, web_contents_getter,
138 return; 252 std::move(messages_)));
139 } 253
254 messages_.clear();
255 }
256
257 ////////////////////////////////////////////////////////////////////////////////
258 // ClearSiteDataThrottle
259
260 // static
261 std::unique_ptr<ResourceThrottle>
262 ClearSiteDataThrottle::MaybeCreateThrottleForRequest(net::URLRequest* request) {
263 // This is an experimental feature.
264 if (!AreExperimentalFeaturesEnabled())
265 return std::unique_ptr<ResourceThrottle>();
266
267 // The throttle has no purpose if the request has no ResourceRequestInfo,
268 // because we won't be able to determine whose data should be deleted.
269 if (!ResourceRequestInfo::ForRequest(request))
270 return std::unique_ptr<ResourceThrottle>();
271
272 return base::WrapUnique(new ClearSiteDataThrottle(
273 request, base::MakeUnique<ConsoleMessagesDelegate>()));
274 }
275
276 ClearSiteDataThrottle::~ClearSiteDataThrottle() {
277 // Output the cached console messages. We output console messages when the
278 // request is finished rather than in real time, since in case of navigations
279 // swapping RenderFrameHost would cause the outputs to disappear.
280 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
281 if (info)
282 delegate_->OutputMessages(info->GetWebContentsGetterForRequest());
283 }
284
285 const char* ClearSiteDataThrottle::GetNameForLogging() const {
286 return kNameForLogging;
287 }
288
289 void ClearSiteDataThrottle::WillRedirectRequest(
290 const net::RedirectInfo& redirect_info,
291 bool* defer) {
292 *defer = HandleHeader();
293 }
294
295 void ClearSiteDataThrottle::WillProcessResponse(bool* defer) {
296 *defer = HandleHeader();
297 }
298
299 // static
300 bool ClearSiteDataThrottle::ParseHeaderForTesting(
301 const std::string& header,
302 bool* clear_cookies,
303 bool* clear_storage,
304 bool* clear_cache,
305 ConsoleMessagesDelegate* delegate,
306 const GURL& current_url) {
307 return ClearSiteDataThrottle::ParseHeader(
308 header, clear_cookies, clear_storage, clear_cache, delegate, current_url);
309 }
310
311 ClearSiteDataThrottle::ClearSiteDataThrottle(
312 net::URLRequest* request,
313 std::unique_ptr<ConsoleMessagesDelegate> delegate)
314 : request_(request),
315 delegate_(std::move(delegate)),
316 weak_ptr_factory_(this) {
317 DCHECK(request_);
318 DCHECK(delegate_);
319 }
320
321 const net::HttpResponseHeaders* ClearSiteDataThrottle::GetResponseHeaders()
322 const {
323 return request_->response_headers();
324 }
325
326 bool ClearSiteDataThrottle::HandleHeader() {
327 const net::HttpResponseHeaders* headers = GetResponseHeaders();
140 328
141 std::string header_value; 329 std::string header_value;
142 headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value); 330 if (!headers ||
331 !headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value)) {
332 return false;
333 }
334
335 // Only accept the header on secure non-unique origins.
336 if (!IsOriginSecure(request_->url())) {
337 delegate_->AddMessage(request_->url(),
338 "Not supported for insecure origins.",
339 CONSOLE_MESSAGE_LEVEL_ERROR);
340 return false;
341 }
342
343 url::Origin origin(request_->url());
344 if (origin.unique()) {
345 delegate_->AddMessage(request_->url(), "Not supported for unique origins.",
346 CONSOLE_MESSAGE_LEVEL_ERROR);
347 return false;
348 }
349
350 // The LOAD_DO_NOT_SAVE_COOKIES flag prohibits the request from doing any
351 // modification to cookies. Clear-Site-Data applies this restriction to other
352 // datatypes as well.
353 // TODO(msramek): Consider showing a blocked icon via
354 // TabSpecificContentSettings and reporting the action in the "Blocked"
355 // section of the cookies dialog in OIB.
356 if (request_->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES) {
357 delegate_->AddMessage(
358 request_->url(),
359 "The request's credentials mode prohibits modifying cookies "
360 "and other local data.",
361 CONSOLE_MESSAGE_LEVEL_ERROR);
362 return false;
363 }
364
365 // Service workers can handle fetches of third-party resources and inject
366 // arbitrary headers. Ignore responses that came from a service worker,
367 // as supporting Clear-Site-Data would give them the power to delete data from
368 // any website.
369 // See https://w3c.github.io/webappsec-clear-site-data/#service-workers
370 // for more information.
371 const ServiceWorkerResponseInfo* response_info =
372 ServiceWorkerResponseInfo::ForRequest(request_);
373 if (response_info) {
374 ResourceResponseInfo extra_response_info;
375 response_info->GetExtraResponseInfo(&extra_response_info);
376
377 if (extra_response_info.was_fetched_via_service_worker) {
378 delegate_->AddMessage(
379 request_->url(),
380 "Ignoring, as the response came from a service worker.",
381 CONSOLE_MESSAGE_LEVEL_ERROR);
382 return false;
383 }
384 }
143 385
144 bool clear_cookies; 386 bool clear_cookies;
145 bool clear_storage; 387 bool clear_storage;
146 bool clear_cache; 388 bool clear_cache;
147 389
148 if (!ParseHeader(header_value, &clear_cookies, &clear_storage, &clear_cache, 390 if (!ClearSiteDataThrottle::ParseHeader(header_value, &clear_cookies,
149 &messages_)) { 391 &clear_storage, &clear_cache,
150 return; 392 delegate_.get(), request_->url())) {
151 } 393 return false;
394 }
395
396 // If the header is valid, clear the data for this browser context and origin.
397 clearing_started_ = base::TimeTicks::Now();
152 398
153 // Record the call parameters. 399 // Record the call parameters.
154 UMA_HISTOGRAM_ENUMERATION( 400 UMA_HISTOGRAM_ENUMERATION(
155 "Navigation.ClearSiteData.Parameters", 401 "Navigation.ClearSiteData.Parameters",
156 ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3)); 402 ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3));
157 403
158 // If the header is valid, clear the data for this browser context and origin. 404 base::WeakPtr<ClearSiteDataThrottle> weak_ptr =
159 BrowserContext* browser_context = 405 weak_ptr_factory_.GetWeakPtr();
160 navigation_handle()->GetWebContents()->GetBrowserContext(); 406
161 url::Origin origin(current_url_); 407 // Immediately bind the weak pointer to the current thread (IO). This will
162 408 // make a potential misuse on the UI thread DCHECK immediately rather than
163 if (origin.unique()) { 409 // later when it's correctly used on the IO thread again.
164 ConsoleLog(&messages_, current_url_, "Not supported for unique origins.", 410 weak_ptr.get();
165 CONSOLE_MESSAGE_LEVEL_ERROR); 411
166 return; 412 ExecuteClearingTask(
167 } 413 origin, clear_cookies, clear_storage, clear_cache,
168 414 base::BindOnce(&ClearSiteDataThrottle::TaskFinished, weak_ptr));
169 clearing_in_progress_ = true; 415
170 clearing_started_ = base::TimeTicks::Now(); 416 return true;
171 GetContentClient()->browser()->ClearSiteData( 417 }
172 browser_context, origin, clear_cookies, clear_storage, clear_cache, 418
173 base::Bind(&ClearSiteDataThrottle::TaskFinished, 419 // static
174 weak_ptr_factory_.GetWeakPtr()));
175 }
176
177 bool ClearSiteDataThrottle::ParseHeader(const std::string& header, 420 bool ClearSiteDataThrottle::ParseHeader(const std::string& header,
178 bool* clear_cookies, 421 bool* clear_cookies,
179 bool* clear_storage, 422 bool* clear_storage,
180 bool* clear_cache, 423 bool* clear_cache,
181 std::vector<ConsoleMessage>* messages) { 424 ConsoleMessagesDelegate* delegate,
425 const GURL& current_url) {
182 if (!base::IsStringASCII(header)) { 426 if (!base::IsStringASCII(header)) {
183 ConsoleLog(messages, current_url_, "Must only contain ASCII characters.", 427 delegate->AddMessage(current_url, "Must only contain ASCII characters.",
184 CONSOLE_MESSAGE_LEVEL_ERROR); 428 CONSOLE_MESSAGE_LEVEL_ERROR);
185 return false; 429 return false;
186 } 430 }
187 431
188 std::unique_ptr<base::Value> parsed_header = base::JSONReader::Read(header); 432 std::unique_ptr<base::Value> parsed_header = base::JSONReader::Read(header);
189 433
190 if (!parsed_header) { 434 if (!parsed_header) {
191 ConsoleLog(messages, current_url_, "Not a valid JSON.", 435 delegate->AddMessage(current_url, "Not a valid JSON.",
192 CONSOLE_MESSAGE_LEVEL_ERROR); 436 CONSOLE_MESSAGE_LEVEL_ERROR);
193 return false; 437 return false;
194 } 438 }
195 439
196 const base::DictionaryValue* dictionary = nullptr; 440 const base::DictionaryValue* dictionary = nullptr;
197 const base::ListValue* types = nullptr; 441 const base::ListValue* types = nullptr;
198 if (!parsed_header->GetAsDictionary(&dictionary) || 442 if (!parsed_header->GetAsDictionary(&dictionary) ||
199 !dictionary->GetListWithoutPathExpansion(kTypesKey, &types)) { 443 !dictionary->GetListWithoutPathExpansion(kTypesKey, &types)) {
200 ConsoleLog(messages, current_url_, 444 delegate->AddMessage(current_url,
201 "Expecting a JSON dictionary with a 'types' field.", 445 "Expecting a JSON dictionary with a 'types' field.",
202 CONSOLE_MESSAGE_LEVEL_ERROR); 446 CONSOLE_MESSAGE_LEVEL_ERROR);
203 return false; 447 return false;
204 } 448 }
205 449
206 DCHECK(types); 450 DCHECK(types);
207 451
208 *clear_cookies = false; 452 *clear_cookies = false;
209 *clear_storage = false; 453 *clear_storage = false;
210 *clear_cache = false; 454 *clear_cache = false;
211 455
212 std::vector<std::string> type_names; 456 std::string type_names;
213 for (const base::Value& value : *types) { 457 for (const base::Value& value : *types) {
214 std::string type; 458 std::string type;
215 value.GetAsString(&type); 459 value.GetAsString(&type);
216 460
217 bool* datatype = nullptr; 461 bool* datatype = nullptr;
218 462
219 if (type == "cookies") { 463 if (type == kDatatypeCookies) {
220 datatype = clear_cookies; 464 datatype = clear_cookies;
221 } else if (type == "storage") { 465 } else if (type == kDatatypeStorage) {
222 datatype = clear_storage; 466 datatype = clear_storage;
223 } else if (type == "cache") { 467 } else if (type == kDatatypeCache) {
224 datatype = clear_cache; 468 datatype = clear_cache;
225 } else { 469 } else {
226 std::string serialized_type; 470 std::string serialized_type;
227 JSONStringValueSerializer serializer(&serialized_type); 471 JSONStringValueSerializer serializer(&serialized_type);
228 serializer.Serialize(value); 472 serializer.Serialize(value);
229 ConsoleLog( 473 delegate->AddMessage(
230 messages, current_url_, 474 current_url,
231 base::StringPrintf("Invalid type: %s.", serialized_type.c_str()), 475 base::StringPrintf("Unrecognized type: %s.", serialized_type.c_str()),
232 CONSOLE_MESSAGE_LEVEL_ERROR); 476 CONSOLE_MESSAGE_LEVEL_ERROR);
233 continue; 477 continue;
234 } 478 }
235 479
480 DCHECK(datatype);
481
236 // Each data type should only be processed once. 482 // Each data type should only be processed once.
237 DCHECK(datatype);
238 if (*datatype) 483 if (*datatype)
239 continue; 484 continue;
240 485
241 *datatype = true; 486 *datatype = true;
242 type_names.push_back(type); 487 if (!type_names.empty())
488 type_names += kConsoleMessageDatatypeSeparator;
489 type_names += type;
243 } 490 }
244 491
245 if (!*clear_cookies && !*clear_storage && !*clear_cache) { 492 if (!*clear_cookies && !*clear_storage && !*clear_cache) {
246 ConsoleLog(messages, current_url_, 493 delegate->AddMessage(current_url,
247 "No valid types specified in the 'types' field.", 494 "No recognized types specified in the 'types' field.",
248 CONSOLE_MESSAGE_LEVEL_ERROR); 495 CONSOLE_MESSAGE_LEVEL_ERROR);
249 return false; 496 return false;
250 } 497 }
251 498
252 // Pretty-print which types are to be cleared. 499 // Pretty-print which types are to be cleared.
253 std::string output; 500 delegate->AddMessage(
254 switch (type_names.size()) { 501 current_url,
255 case 1: 502 base::StringPrintf(kConsoleMessageCleared, type_names.c_str()),
256 output = base::StringPrintf(kClearingOneType, type_names[0].c_str()); 503 CONSOLE_MESSAGE_LEVEL_INFO);
257 break;
258 case 2:
259 output = base::StringPrintf(kClearingTwoTypes, type_names[0].c_str(),
260 type_names[1].c_str());
261 break;
262 case 3:
263 output = base::StringPrintf(kClearingThreeTypes, type_names[0].c_str(),
264 type_names[1].c_str(), type_names[2].c_str());
265 break;
266 default:
267 NOTREACHED();
268 }
269 ConsoleLog(messages, current_url_, output, CONSOLE_MESSAGE_LEVEL_INFO);
270 504
271 return true; 505 return true;
272 } 506 }
273 507
508 void ClearSiteDataThrottle::ExecuteClearingTask(const url::Origin& origin,
509 bool clear_cookies,
510 bool clear_storage,
511 bool clear_cache,
512 base::OnceClosure callback) {
513 DCHECK_CURRENTLY_ON(BrowserThread::IO);
514 BrowserThread::PostTask(
515 BrowserThread::UI, FROM_HERE,
516 base::BindOnce(&UIThreadSiteDataClearer::Run,
517 ResourceRequestInfo::ForRequest(request_)
518 ->GetWebContentsGetterForRequest(),
519 origin, clear_cookies, clear_storage, clear_cache,
520 std::move(callback)));
521 }
522
274 void ClearSiteDataThrottle::TaskFinished() { 523 void ClearSiteDataThrottle::TaskFinished() {
275 DCHECK(clearing_in_progress_); 524 DCHECK(!clearing_started_.is_null());
276 clearing_in_progress_ = false;
277 525
278 UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration", 526 UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration",
279 base::TimeTicks::Now() - clearing_started_, 527 base::TimeTicks::Now() - clearing_started_,
280 base::TimeDelta::FromMilliseconds(1), 528 base::TimeDelta::FromMilliseconds(1),
281 base::TimeDelta::FromSeconds(1), 50); 529 base::TimeDelta::FromSeconds(1), 50);
282 530
283 navigation_handle()->Resume(); 531 Resume();
284 } 532 }
285 533
286 } // namespace content 534 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698