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

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

Powered by Google App Engine
This is Rietveld 408576698