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

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: Addressed comments. 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 WebContents* web_contents = web_contents_getter.Run();
88 if (!web_contents)
89 return;
77 90
78 ClearSiteDataThrottle::~ClearSiteDataThrottle() { 91 (new UIThreadSiteDataClearer(web_contents, origin, clear_cookies,
79 // At the end of the navigation we finally have access to the correct 92 clear_storage, clear_cache,
80 // RenderFrameHost. Output the cached console messages. Prefix each sequence 93 std::move(callback)))
81 // of messages belonging to the same URL with |kConsoleMessagePrefix|. 94 ->RunAndDestroySelfWhenDone();
95 }
96
97 private:
98 UIThreadSiteDataClearer(const WebContents* web_contents,
99 const url::Origin& origin,
100 bool clear_cookies,
101 bool clear_storage,
102 bool clear_cache,
103 base::OnceClosure callback)
104 : origin_(origin),
105 clear_cookies_(clear_cookies),
106 clear_storage_(clear_storage),
107 clear_cache_(clear_cache),
108 callback_(std::move(callback)),
109 pending_task_count_(0),
110 remover_(nullptr),
111 scoped_observer_(this) {
112 DCHECK_CURRENTLY_ON(BrowserThread::UI);
113
114 remover_ = BrowserContext::GetBrowsingDataRemover(
115 web_contents->GetBrowserContext());
116 DCHECK(remover_);
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 a single |formatted_message| on the UI thread.
198 void OutputFormattedMessage(WebContents* web_contents,
199 ConsoleMessageLevel level,
200 const std::string& formatted_text) {
201 if (web_contents)
202 web_contents->GetMainFrame()->AddMessageToConsole(level, formatted_text);
203 }
204
205 // Outputs |messages| to the console of WebContents retrieved from
206 // |web_contents_getter|. Must be run on the UI thread.
207 void OutputMessagesOnUIThread(
208 const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
209 const std::vector<ClearSiteDataThrottle::ConsoleMessagesDelegate::Message>&
210 messages,
211 const ClearSiteDataThrottle::ConsoleMessagesDelegate ::
212 OutputFormattedMessageFunction& output_formatted_message_function) {
mmenke 2017/05/31 16:25:33 Are those spaces around the :: valid google style?
msramek 2017/06/01 22:02:27 I don't think so. I ran git cl format, but it migh
213 DCHECK_CURRENTLY_ON(BrowserThread::UI);
214
215 WebContents* web_contents =
216 web_contents_getter.is_null() ? nullptr : web_contents_getter.Run();
mmenke 2017/05/31 16:25:33 I guess this is just for tests, but can we instead
msramek 2017/06/01 22:02:27 Done. Yes, this was just for the tests, and it's a
217
218 // Prefix each sequence of messages belonging to the same URL with
219 // |kConsoleMessagePrefix|.
82 GURL last_seen_url; 220 GURL last_seen_url;
83 for (const ConsoleMessage& message : messages_) { 221 for (const auto& message : messages) {
84 if (message.url == last_seen_url) { 222 if (message.url == last_seen_url) {
85 navigation_handle()->GetRenderFrameHost()->AddMessageToConsole( 223 output_formatted_message_function.Run(web_contents, message.level,
86 message.level, message.text); 224 message.text);
mmenke 2017/05/31 16:25:33 Can't remember if I raised this earlier - thought
msramek 2017/06/01 22:02:27 The main reason for this |last_seen_url| was that
mmenke 2017/06/05 21:05:50 I'm not following. Couldn't we do: bool ClearSit
mmenke 2017/06/05 22:39:36 (Note: I'm happy with the current approach)
msramek 2017/06/06 18:20:56 I played a bit with the console, and it doesn't lo
87 } else { 225 } else {
88 navigation_handle()->GetRenderFrameHost()->AddMessageToConsole( 226 output_formatted_message_function.Run(
89 message.level, 227 web_contents, message.level,
90 base::StringPrintf(kConsoleMessagePrefix, message.url.spec().c_str(), 228 base::StringPrintf(kConsoleMessagePrefix, message.url.spec().c_str(),
91 message.text.c_str())); 229 message.text.c_str()));
92 } 230 }
93 231
94 last_seen_url = message.url; 232 last_seen_url = message.url;
95 } 233 }
96 } 234 }
97 235
98 ClearSiteDataThrottle::ThrottleCheckResult 236 } // namespace
99 ClearSiteDataThrottle::WillStartRequest() { 237
100 current_url_ = navigation_handle()->GetURL(); 238 ////////////////////////////////////////////////////////////////////////////////
101 return PROCEED; 239 // ConsoleMessagesDelegate
102 } 240
103 241 ClearSiteDataThrottle::ConsoleMessagesDelegate::ConsoleMessagesDelegate()
104 ClearSiteDataThrottle::ThrottleCheckResult 242 : output_formatted_message_function_(base::Bind(&OutputFormattedMessage)) {}
105 ClearSiteDataThrottle::WillRedirectRequest() { 243
106 // We are processing a redirect from url1 to url2. GetResponseHeaders() 244 ClearSiteDataThrottle::ConsoleMessagesDelegate::~ConsoleMessagesDelegate() {}
107 // contains headers from url1, but GetURL() is already equal to url2. Handle 245
108 // the headers before updating the URL, so that |current_url_| corresponds 246 void ClearSiteDataThrottle::ConsoleMessagesDelegate::AddMessage(
109 // to the URL that sent the headers. 247 const GURL& url,
110 HandleHeader(); 248 const std::string& text,
111 current_url_ = navigation_handle()->GetURL(); 249 ConsoleMessageLevel level) {
112 250 messages_.push_back({url, text, level});
113 return clearing_in_progress_ ? DEFER : PROCEED; 251 }
114 } 252
115 253 void ClearSiteDataThrottle::ConsoleMessagesDelegate::OutputMessages(
116 ClearSiteDataThrottle::ThrottleCheckResult 254 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) {
117 ClearSiteDataThrottle::WillProcessResponse() { 255 if (messages_.empty())
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; 256 return;
133 257
134 // Only accept the header on secure origins. 258 DCHECK_CURRENTLY_ON(BrowserThread::IO);
135 if (!IsOriginSecure(current_url_)) { 259 BrowserThread::PostTask(
136 ConsoleLog(&messages_, current_url_, "Not supported for insecure origins.", 260 BrowserThread::UI, FROM_HERE,
137 CONSOLE_MESSAGE_LEVEL_ERROR); 261 base::BindOnce(&OutputMessagesOnUIThread, web_contents_getter,
138 return; 262 std::move(messages_), output_formatted_message_function_));
139 } 263
264 messages_.clear();
265 }
266
267 void ClearSiteDataThrottle::ConsoleMessagesDelegate::
268 SetOutputFormattedMessageFunctionForTesting(
269 const OutputFormattedMessageFunction& function) {
270 output_formatted_message_function_ = function;
271 }
272
273 ////////////////////////////////////////////////////////////////////////////////
274 // ClearSiteDataThrottle
275
276 // static
277 std::unique_ptr<ResourceThrottle>
278 ClearSiteDataThrottle::MaybeCreateThrottleForRequest(net::URLRequest* request) {
279 // This is an experimental feature.
280 if (!AreExperimentalFeaturesEnabled())
281 return std::unique_ptr<ResourceThrottle>();
282
283 // The throttle has no purpose if the request has no ResourceRequestInfo,
284 // because we won't be able to determine whose data should be deleted.
285 if (!ResourceRequestInfo::ForRequest(request))
286 return std::unique_ptr<ResourceThrottle>();
287
288 return base::WrapUnique(new ClearSiteDataThrottle(
289 request, base::MakeUnique<ConsoleMessagesDelegate>()));
290 }
291
292 ClearSiteDataThrottle::~ClearSiteDataThrottle() {
293 // Output the cached console messages. We output console messages when the
294 // request is finished rather than in real time, since in case of navigations
295 // swapping RenderFrameHost would cause the outputs to disappear.
296 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
297 if (info)
298 delegate_->OutputMessages(info->GetWebContentsGetterForRequest());
299 }
300
301 const char* ClearSiteDataThrottle::GetNameForLogging() const {
302 return kNameForLogging;
303 }
304
305 void ClearSiteDataThrottle::WillRedirectRequest(
306 const net::RedirectInfo& redirect_info,
307 bool* defer) {
308 *defer = HandleHeader();
309 }
310
311 void ClearSiteDataThrottle::WillProcessResponse(bool* defer) {
312 *defer = HandleHeader();
313 }
314
315 // static
316 bool ClearSiteDataThrottle::ParseHeaderForTesting(
317 const std::string& header,
318 bool* clear_cookies,
319 bool* clear_storage,
320 bool* clear_cache,
321 ConsoleMessagesDelegate* delegate,
322 const GURL& current_url) {
323 return ClearSiteDataThrottle::ParseHeader(
324 header, clear_cookies, clear_storage, clear_cache, delegate, current_url);
325 }
326
327 ClearSiteDataThrottle::ClearSiteDataThrottle(
328 net::URLRequest* request,
329 std::unique_ptr<ConsoleMessagesDelegate> delegate)
330 : request_(request),
331 delegate_(std::move(delegate)),
332 weak_ptr_factory_(this) {
333 DCHECK(request_);
334 DCHECK(delegate_);
335 }
336
337 const GURL& ClearSiteDataThrottle::GetCurrentURL() const {
338 return request_->url();
339 }
340
341 const net::HttpResponseHeaders* ClearSiteDataThrottle::GetResponseHeaders()
342 const {
343 return request_->response_headers();
344 }
345
346 bool ClearSiteDataThrottle::HandleHeader() {
347 const net::HttpResponseHeaders* headers = GetResponseHeaders();
140 348
141 std::string header_value; 349 std::string header_value;
142 headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value); 350 if (!headers ||
351 !headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value)) {
352 return false;
353 }
354
355 // Only accept the header on secure non-unique origins.
356 if (!IsOriginSecure(GetCurrentURL())) {
357 delegate_->AddMessage(GetCurrentURL(),
358 "Not supported for insecure origins.",
359 CONSOLE_MESSAGE_LEVEL_ERROR);
360 return false;
361 }
362
363 url::Origin origin(GetCurrentURL());
364 if (origin.unique()) {
365 delegate_->AddMessage(GetCurrentURL(), "Not supported for unique origins.",
366 CONSOLE_MESSAGE_LEVEL_ERROR);
367 return false;
368 }
369
370 // The LOAD_DO_NOT_SAVE_COOKIES flag prohibits the request from doing any
371 // modification to cookies. Clear-Site-Data applies this restriction to other
372 // datatypes as well.
373 // TODO(msramek): Consider showing a blocked icon via
374 // TabSpecificContentSettings and reporting the action in the "Blocked"
375 // section of the cookies dialog in OIB.
376 if (request_->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES) {
377 delegate_->AddMessage(
378 GetCurrentURL(),
379 "The request's credentials mode prohibits modifying cookies "
380 "and other local data.",
381 CONSOLE_MESSAGE_LEVEL_ERROR);
382 return false;
383 }
384
385 // Service workers can handle fetches of third-party resources and inject
386 // arbitrary headers. Ignore responses that came from a service worker,
387 // as supporting Clear-Site-Data would give them the power to delete data from
388 // any website.
389 // See https://w3c.github.io/webappsec-clear-site-data/#service-workers
390 // for more information.
391 const ServiceWorkerResponseInfo* response_info =
392 ServiceWorkerResponseInfo::ForRequest(request_);
393 if (response_info) {
394 ResourceResponseInfo extra_response_info;
395 response_info->GetExtraResponseInfo(&extra_response_info);
396
397 if (extra_response_info.was_fetched_via_service_worker) {
398 delegate_->AddMessage(
399 GetCurrentURL(),
400 "Ignoring, as the response came from a service worker.",
401 CONSOLE_MESSAGE_LEVEL_ERROR);
402 return false;
403 }
404 }
143 405
144 bool clear_cookies; 406 bool clear_cookies;
145 bool clear_storage; 407 bool clear_storage;
146 bool clear_cache; 408 bool clear_cache;
147 409
148 if (!ParseHeader(header_value, &clear_cookies, &clear_storage, &clear_cache, 410 if (!ClearSiteDataThrottle::ParseHeader(header_value, &clear_cookies,
149 &messages_)) { 411 &clear_storage, &clear_cache,
150 return; 412 delegate_.get(), GetCurrentURL())) {
151 } 413 return false;
414 }
415
416 // If the header is valid, clear the data for this browser context and origin.
417 clearing_started_ = base::TimeTicks::Now();
152 418
153 // Record the call parameters. 419 // Record the call parameters.
154 UMA_HISTOGRAM_ENUMERATION( 420 UMA_HISTOGRAM_ENUMERATION(
155 "Navigation.ClearSiteData.Parameters", 421 "Navigation.ClearSiteData.Parameters",
156 ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3)); 422 ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3));
157 423
158 // If the header is valid, clear the data for this browser context and origin. 424 base::WeakPtr<ClearSiteDataThrottle> weak_ptr =
159 BrowserContext* browser_context = 425 weak_ptr_factory_.GetWeakPtr();
160 navigation_handle()->GetWebContents()->GetBrowserContext(); 426
161 url::Origin origin(current_url_); 427 // Immediately bind the weak pointer to the current thread (IO). This will
162 428 // make a potential misuse on the UI thread DCHECK immediately rather than
163 if (origin.unique()) { 429 // later when it's correctly used on the IO thread again.
164 ConsoleLog(&messages_, current_url_, "Not supported for unique origins.", 430 weak_ptr.get();
165 CONSOLE_MESSAGE_LEVEL_ERROR); 431
166 return; 432 ExecuteClearingTask(
167 } 433 origin, clear_cookies, clear_storage, clear_cache,
168 434 base::BindOnce(&ClearSiteDataThrottle::TaskFinished, weak_ptr));
169 clearing_in_progress_ = true; 435
170 clearing_started_ = base::TimeTicks::Now(); 436 return true;
171 GetContentClient()->browser()->ClearSiteData( 437 }
172 browser_context, origin, clear_cookies, clear_storage, clear_cache, 438
173 base::Bind(&ClearSiteDataThrottle::TaskFinished, 439 // static
174 weak_ptr_factory_.GetWeakPtr()));
175 }
176
177 bool ClearSiteDataThrottle::ParseHeader(const std::string& header, 440 bool ClearSiteDataThrottle::ParseHeader(const std::string& header,
178 bool* clear_cookies, 441 bool* clear_cookies,
179 bool* clear_storage, 442 bool* clear_storage,
180 bool* clear_cache, 443 bool* clear_cache,
181 std::vector<ConsoleMessage>* messages) { 444 ConsoleMessagesDelegate* delegate,
445 const GURL& current_url) {
182 if (!base::IsStringASCII(header)) { 446 if (!base::IsStringASCII(header)) {
183 ConsoleLog(messages, current_url_, "Must only contain ASCII characters.", 447 delegate->AddMessage(current_url, "Must only contain ASCII characters.",
184 CONSOLE_MESSAGE_LEVEL_ERROR); 448 CONSOLE_MESSAGE_LEVEL_ERROR);
185 return false; 449 return false;
186 } 450 }
187 451
188 std::unique_ptr<base::Value> parsed_header = base::JSONReader::Read(header); 452 std::unique_ptr<base::Value> parsed_header = base::JSONReader::Read(header);
189 453
190 if (!parsed_header) { 454 if (!parsed_header) {
191 ConsoleLog(messages, current_url_, "Not a valid JSON.", 455 delegate->AddMessage(current_url, "Not a valid JSON.",
192 CONSOLE_MESSAGE_LEVEL_ERROR); 456 CONSOLE_MESSAGE_LEVEL_ERROR);
193 return false; 457 return false;
194 } 458 }
195 459
196 const base::DictionaryValue* dictionary = nullptr; 460 const base::DictionaryValue* dictionary = nullptr;
197 const base::ListValue* types = nullptr; 461 const base::ListValue* types = nullptr;
198 if (!parsed_header->GetAsDictionary(&dictionary) || 462 if (!parsed_header->GetAsDictionary(&dictionary) ||
199 !dictionary->GetListWithoutPathExpansion(kTypesKey, &types)) { 463 !dictionary->GetListWithoutPathExpansion(kTypesKey, &types)) {
200 ConsoleLog(messages, current_url_, 464 delegate->AddMessage(current_url,
201 "Expecting a JSON dictionary with a 'types' field.", 465 "Expecting a JSON dictionary with a 'types' field.",
202 CONSOLE_MESSAGE_LEVEL_ERROR); 466 CONSOLE_MESSAGE_LEVEL_ERROR);
203 return false; 467 return false;
204 } 468 }
205 469
206 DCHECK(types); 470 DCHECK(types);
207 471
208 *clear_cookies = false; 472 *clear_cookies = false;
209 *clear_storage = false; 473 *clear_storage = false;
210 *clear_cache = false; 474 *clear_cache = false;
211 475
212 std::vector<std::string> type_names; 476 std::string type_names;
213 for (const base::Value& value : *types) { 477 for (const base::Value& value : *types) {
214 std::string type; 478 std::string type;
215 value.GetAsString(&type); 479 value.GetAsString(&type);
216 480
217 bool* datatype = nullptr; 481 bool* datatype = nullptr;
218 482
219 if (type == "cookies") { 483 if (type == kDatatypeCookies) {
220 datatype = clear_cookies; 484 datatype = clear_cookies;
221 } else if (type == "storage") { 485 } else if (type == kDatatypeStorage) {
222 datatype = clear_storage; 486 datatype = clear_storage;
223 } else if (type == "cache") { 487 } else if (type == kDatatypeCache) {
224 datatype = clear_cache; 488 datatype = clear_cache;
225 } else { 489 } else {
226 std::string serialized_type; 490 std::string serialized_type;
227 JSONStringValueSerializer serializer(&serialized_type); 491 JSONStringValueSerializer serializer(&serialized_type);
228 serializer.Serialize(value); 492 serializer.Serialize(value);
229 ConsoleLog( 493 delegate->AddMessage(
230 messages, current_url_, 494 current_url,
231 base::StringPrintf("Invalid type: %s.", serialized_type.c_str()), 495 base::StringPrintf("Unrecognized type: %s.", serialized_type.c_str()),
232 CONSOLE_MESSAGE_LEVEL_ERROR); 496 CONSOLE_MESSAGE_LEVEL_ERROR);
233 continue; 497 continue;
234 } 498 }
235 499
500 DCHECK(datatype);
501
236 // Each data type should only be processed once. 502 // Each data type should only be processed once.
237 DCHECK(datatype);
238 if (*datatype) 503 if (*datatype)
239 continue; 504 continue;
240 505
241 *datatype = true; 506 *datatype = true;
242 type_names.push_back(type); 507 if (!type_names.empty())
508 type_names += kConsoleMessageDatatypeSeparator;
509 type_names += type;
243 } 510 }
244 511
245 if (!*clear_cookies && !*clear_storage && !*clear_cache) { 512 if (!*clear_cookies && !*clear_storage && !*clear_cache) {
246 ConsoleLog(messages, current_url_, 513 delegate->AddMessage(current_url,
247 "No valid types specified in the 'types' field.", 514 "No recognized types specified in the 'types' field.",
248 CONSOLE_MESSAGE_LEVEL_ERROR); 515 CONSOLE_MESSAGE_LEVEL_ERROR);
249 return false; 516 return false;
250 } 517 }
251 518
252 // Pretty-print which types are to be cleared. 519 // Pretty-print which types are to be cleared.
253 std::string output; 520 delegate->AddMessage(
254 switch (type_names.size()) { 521 current_url,
255 case 1: 522 base::StringPrintf(kConsoleMessageCleared, type_names.c_str()),
256 output = base::StringPrintf(kClearingOneType, type_names[0].c_str()); 523 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 524
271 return true; 525 return true;
272 } 526 }
273 527
528 void ClearSiteDataThrottle::ExecuteClearingTask(const url::Origin& origin,
529 bool clear_cookies,
530 bool clear_storage,
531 bool clear_cache,
532 base::OnceClosure callback) {
533 DCHECK_CURRENTLY_ON(BrowserThread::IO);
534 BrowserThread::PostTask(
535 BrowserThread::UI, FROM_HERE,
536 base::BindOnce(&UIThreadSiteDataClearer::Run,
537 ResourceRequestInfo::ForRequest(request_)
538 ->GetWebContentsGetterForRequest(),
539 origin, clear_cookies, clear_storage, clear_cache,
540 std::move(callback)));
541 }
542
274 void ClearSiteDataThrottle::TaskFinished() { 543 void ClearSiteDataThrottle::TaskFinished() {
275 DCHECK(clearing_in_progress_); 544 DCHECK_CURRENTLY_ON(BrowserThread::IO);
276 clearing_in_progress_ = false; 545 DCHECK(!clearing_started_.is_null());
277 546
278 UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration", 547 UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration",
279 base::TimeTicks::Now() - clearing_started_, 548 base::TimeTicks::Now() - clearing_started_,
280 base::TimeDelta::FromMilliseconds(1), 549 base::TimeDelta::FromMilliseconds(1),
281 base::TimeDelta::FromSeconds(1), 50); 550 base::TimeDelta::FromSeconds(1), 50);
282 551
283 navigation_handle()->Resume(); 552 Resume();
284 } 553 }
285 554
286 } // namespace content 555 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698