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

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, added some debug outputs. Created 3 years, 7 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/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/content_switches.h"
22 #include "content/public/common/origin_util.h" 23 #include "content/public/common/origin_util.h"
24 #include "content/public/common/resource_response_info.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
36 static const char* kNameForLogging = "ClearSiteDataThrottle";
37
31 static const char* kClearSiteDataHeader = "Clear-Site-Data"; 38 static const char* kClearSiteDataHeader = "Clear-Site-Data";
32 39
33 static const char* kTypesKey = "types"; 40 static const char* kTypesKey = "types";
34 41
35 // Pretty-printed log output. 42 // Pretty-printed log output.
36 static const char* kConsoleMessagePrefix = "Clear-Site-Data header on '%s': %s"; 43 static const char* kConsoleMessagePrefix = "Clear-Site-Data header on '%s': %s";
37 static const char* kClearingOneType = "Clearing %s."; 44 static const char* kClearingOneType = "Clearing %s.";
38 static const char* kClearingTwoTypes = "Clearing %s and %s."; 45 static const char* kClearingTwoTypes = "Clearing %s and %s.";
39 static const char* kClearingThreeTypes = "Clearing %s, %s, and %s."; 46 static const char* kClearingThreeTypes = "Clearing %s, %s, and %s.";
40 47
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
49 bool AreExperimentalFeaturesEnabled() { 48 bool AreExperimentalFeaturesEnabled() {
50 return base::CommandLine::ForCurrentProcess()->HasSwitch( 49 return base::CommandLine::ForCurrentProcess()->HasSwitch(
51 switches::kEnableExperimentalWebPlatformFeatures); 50 switches::kEnableExperimentalWebPlatformFeatures);
52 } 51 }
53 52
54 // Represents the parameters as a single number to be recorded in a histogram. 53 // 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) { 54 int ParametersMask(bool clear_cookies, bool clear_storage, bool clear_cache) {
56 return static_cast<int>(clear_cookies) * (1 << 0) + 55 return static_cast<int>(clear_cookies) * (1 << 0) +
57 static_cast<int>(clear_storage) * (1 << 1) + 56 static_cast<int>(clear_storage) * (1 << 1) +
58 static_cast<int>(clear_cache) * (1 << 2); 57 static_cast<int>(clear_cache) * (1 << 2);
59 } 58 }
60 59
61 } // namespace 60 // A helper function to pass an IO thread callback to a method called on
62 61 // the UI thread.
63 // static 62 void JumpFromUIToIOThread(const base::Closure& callback) {
64 std::unique_ptr<NavigationThrottle> 63 DCHECK_CURRENTLY_ON(BrowserThread::UI);
65 ClearSiteDataThrottle::CreateThrottleForNavigation(NavigationHandle* handle) { 64 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
66 if (AreExperimentalFeaturesEnabled())
67 return base::WrapUnique(new ClearSiteDataThrottle(handle));
68
69 return std::unique_ptr<NavigationThrottle>();
70 } 65 }
71 66
72 ClearSiteDataThrottle::ClearSiteDataThrottle( 67 // A BrowsingDataRemover::Observer that waits for |count|
73 NavigationHandle* navigation_handle) 68 // OnBrowsingDataRemoverDone() callbacks, translates them into
74 : NavigationThrottle(navigation_handle), 69 // one base::Closure, and then destroys itself.
75 clearing_in_progress_(false), 70 class ClearSiteDataObserver : public BrowsingDataRemover::Observer {
76 weak_ptr_factory_(this) {} 71 public:
72 explicit ClearSiteDataObserver(BrowsingDataRemover* remover,
73 const base::Closure& callback,
74 int count)
mmenke 2017/05/22 18:35:35 count seems too ambiguous here. expected_completi
msramek 2017/05/24 22:59:51 Done - merged ClearSiteDataOnUIThread() and this O
75 : remover_(remover), callback_(callback), count_(count) {
76 remover_->AddObserver(this);
77 }
77 78
78 ClearSiteDataThrottle::~ClearSiteDataThrottle() { 79 ~ClearSiteDataObserver() override { remover_->RemoveObserver(this); }
79 // At the end of the navigation we finally have access to the correct 80
80 // RenderFrameHost. Output the cached console messages. Prefix each sequence 81 // BrowsingDataRemover::Observer.
81 // of messages belonging to the same URL with |kConsoleMessagePrefix|. 82 void OnBrowsingDataRemoverDone() override {
83 DCHECK(count_);
84 if (--count_)
85 return;
86
87 JumpFromUIToIOThread(callback_);
88 delete this;
89 }
90
91 private:
92 BrowsingDataRemover* remover_;
93 base::Closure callback_;
94 int count_;
95 };
96
97 // Finds the BrowserContext associated with the request and requests
98 // the actual clearing of data for |origin|. The datatypes to be deleted
99 // are determined by |clear_cookies|, |clear_storage|, and |clear_cache|.
100 // |web_contents_getter| identifies the WebContents from which the request
101 // originated. Must be run on the UI thread. The |callback| will be executed
102 // on the IO thread.
103 void ClearSiteDataOnUIThread(
104 const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
105 url::Origin origin,
106 bool clear_cookies,
107 bool clear_storage,
108 bool clear_cache,
109 const base::Closure& callback) {
110 DCHECK_CURRENTLY_ON(BrowserThread::UI);
111
112 WebContents* web_contents = web_contents_getter.Run();
113 if (!web_contents)
114 return;
115
116 BrowsingDataRemover* remover =
117 BrowserContext::GetBrowsingDataRemover(web_contents->GetBrowserContext());
118
119 // ClearSiteDataObserver deletes itself when callbacks from both removal
120 // tasks are received.
121 ClearSiteDataObserver* observer =
122 new ClearSiteDataObserver(remover, callback, 2 /* number of tasks */);
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 remover->RemoveWithFilterAndReply(
144 base::Time(), base::Time::Max(),
145 BrowsingDataRemover::DATA_TYPE_COOKIES |
146 BrowsingDataRemover::DATA_TYPE_CHANNEL_IDS,
147 BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
148 BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
149 std::move(domain_filter_builder), observer);
150 } else {
151 // The first removal task is a no-op.
152 observer->OnBrowsingDataRemoverDone();
153 }
154
155 // Delete origin-scoped data.
156 int remove_mask = 0;
157 if (clear_storage)
158 remove_mask |= BrowsingDataRemover::DATA_TYPE_DOM_STORAGE;
159 if (clear_cache)
160 remove_mask |= BrowsingDataRemover::DATA_TYPE_CACHE;
161
162 if (remove_mask) {
163 std::unique_ptr<BrowsingDataFilterBuilder> origin_filter_builder(
164 BrowsingDataFilterBuilder::Create(
165 BrowsingDataFilterBuilder::WHITELIST));
166 origin_filter_builder->AddOrigin(origin);
167
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), observer);
173 } else {
174 // The second removal task is a no-op.
175 observer->OnBrowsingDataRemoverDone();
176 }
177 }
178
179 // Outputs |messages| to the console of WebContents retrieved from
180 // |web_contents_getter|. Must be run on the UI thread.
181 void OutputMessagesOnUIThread(
182 const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
183 const std::vector<ClearSiteDataThrottle::ConsoleMessagesDelegate::Message>&
184 messages) {
185 DCHECK_CURRENTLY_ON(BrowserThread::UI);
186
187 WebContents* web_contents = web_contents_getter.Run();
188 if (!web_contents)
189 return;
190
191 // Prefix each sequence of messages belonging to the same URL with
192 // |kConsoleMessagePrefix|.
82 GURL last_seen_url; 193 GURL last_seen_url;
83 for (const ConsoleMessage& message : messages_) { 194 for (const auto& message : messages) {
84 if (message.url == last_seen_url) { 195 if (message.url == last_seen_url) {
mmenke 2017/05/22 18:35:35 Any reason to do these all at the end, instead of
msramek 2017/05/24 22:59:51 That's a good point - changed "Clearing..." To "Cl
mmenke 2017/05/25 15:19:01 Hrm....But for subresources, clearing will affect
msramek 2017/05/30 21:58:44 But we're not delaying the clearing itself, just t
mmenke 2017/05/30 22:58:35 My main concern is subresources - events will be l
msramek 2017/06/01 22:02:27 Fair enough. For the record, of course, please do
85 navigation_handle()->GetRenderFrameHost()->AddMessageToConsole( 196 web_contents->GetMainFrame()->AddMessageToConsole(message.level,
86 message.level, message.text); 197 message.text);
87 } else { 198 } else {
88 navigation_handle()->GetRenderFrameHost()->AddMessageToConsole( 199 web_contents->GetMainFrame()->AddMessageToConsole(
89 message.level, 200 message.level,
90 base::StringPrintf(kConsoleMessagePrefix, message.url.spec().c_str(), 201 base::StringPrintf(kConsoleMessagePrefix, message.url.spec().c_str(),
91 message.text.c_str())); 202 message.text.c_str()));
92 } 203 }
93 204
94 last_seen_url = message.url; 205 last_seen_url = message.url;
95 } 206 }
96 } 207 }
97 208
98 ClearSiteDataThrottle::ThrottleCheckResult 209 } // namespace
99 ClearSiteDataThrottle::WillStartRequest() { 210
100 current_url_ = navigation_handle()->GetURL(); 211 ////////////////////////////////////////////////////////////////////////////////
101 return PROCEED; 212 // ConsoleMessagesDelegate
213
214 ClearSiteDataThrottle::ConsoleMessagesDelegate::ConsoleMessagesDelegate() {}
215
216 ClearSiteDataThrottle::ConsoleMessagesDelegate::~ConsoleMessagesDelegate() {}
217
218 void ClearSiteDataThrottle::ConsoleMessagesDelegate::AddMessage(
219 const GURL& url,
220 const std::string& text,
221 ConsoleMessageLevel level) {
222 messages_.push_back({url, text, level});
102 } 223 }
103 224
104 ClearSiteDataThrottle::ThrottleCheckResult 225 void ClearSiteDataThrottle::ConsoleMessagesDelegate::OutputMessages(
105 ClearSiteDataThrottle::WillRedirectRequest() { 226 const ResourceRequestInfo::WebContentsGetter& web_contents_getter) {
106 // We are processing a redirect from url1 to url2. GetResponseHeaders() 227 if (messages_.empty())
107 // contains headers from url1, but GetURL() is already equal to url2. Handle 228 return;
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 229
113 return clearing_in_progress_ ? DEFER : PROCEED; 230 DCHECK_CURRENTLY_ON(BrowserThread::IO);
231 BrowserThread::PostTask(
232 BrowserThread::UI, FROM_HERE,
233 base::Bind(&OutputMessagesOnUIThread, web_contents_getter,
234 std::move(messages_)));
235
236 messages_.clear();
mmenke 2017/05/22 18:35:34 Is this needed, or is std::move guaranteed to clea
msramek 2017/05/24 22:59:51 I'm not sure that std::vector<> is safe to use aft
mmenke 2017/05/25 15:19:01 Googling for an answer, looks like it may not be g
msramek 2017/05/30 21:58:44 Acknowledged.
114 } 237 }
115 238
116 ClearSiteDataThrottle::ThrottleCheckResult 239 ////////////////////////////////////////////////////////////////////////////////
117 ClearSiteDataThrottle::WillProcessResponse() { 240 // ClearSiteDataThrottle
118 HandleHeader(); 241
119 return clearing_in_progress_ ? DEFER : PROCEED; 242 // static
243 std::unique_ptr<ResourceThrottle>
244 ClearSiteDataThrottle::CreateThrottleForRequest(net::URLRequest* request) {
245 // This is an experimental feature.
246 if (!AreExperimentalFeaturesEnabled())
247 return std::unique_ptr<ResourceThrottle>();
248
249 // The throttle has no purpose if the request has no ResourceRequestInfo,
250 // because we won't be able to determine whose data should be deleted.
251 if (!ResourceRequestInfo::ForRequest(request))
252 return std::unique_ptr<ResourceThrottle>();
253
254 return base::WrapUnique(new ClearSiteDataThrottle(
255 request, base::MakeUnique<ConsoleMessagesDelegate>()));
120 } 256 }
121 257
122 const char* ClearSiteDataThrottle::GetNameForLogging() { 258 ClearSiteDataThrottle::ClearSiteDataThrottle(
123 return "ClearSiteDataThrottle"; 259 net::URLRequest* request,
260 std::unique_ptr<ConsoleMessagesDelegate> delegate)
261 : request_(request),
262 delegate_(std::move(delegate)),
263 weak_ptr_factory_(this) {
264 DCHECK(request_);
265 DCHECK(delegate_);
124 } 266 }
125 267
126 void ClearSiteDataThrottle::HandleHeader() { 268 ClearSiteDataThrottle::~ClearSiteDataThrottle() {
127 NavigationHandleImpl* handle = 269 // Output the cached console messages. We output console messages when the
128 static_cast<NavigationHandleImpl*>(navigation_handle()); 270 // request is finished rather than in real time, since in case of navigations
129 const net::HttpResponseHeaders* headers = handle->GetResponseHeaders(); 271 // swapping RenderFrameHost would cause the outputs to disappear.
272 LOG(ERROR) << "*** DEBUG OUTPUT FOR TRYBOTS *** Destructor " << this;
273 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
274 if (info)
275 delegate_->OutputMessages(info->GetWebContentsGetterForRequest());
276 }
130 277
131 if (!headers || !headers->HasHeader(kClearSiteDataHeader)) 278 void ClearSiteDataThrottle::WillRedirectRequest(
132 return; 279 const net::RedirectInfo& redirect_info,
280 bool* defer) {
281 *defer = HandleHeader();
282 }
133 283
134 // Only accept the header on secure origins. 284 void ClearSiteDataThrottle::WillProcessResponse(bool* defer) {
135 if (!IsOriginSecure(current_url_)) { 285 *defer = HandleHeader();
136 ConsoleLog(&messages_, current_url_, "Not supported for insecure origins.", 286 }
137 CONSOLE_MESSAGE_LEVEL_ERROR); 287
138 return; 288 const char* ClearSiteDataThrottle::GetNameForLogging() const {
289 return kNameForLogging;
290 }
291
292 bool ClearSiteDataThrottle::HandleHeader() {
293 const net::HttpResponseHeaders* headers = GetResponseHeaders();
294
295 std::string header_value;
296 if (!headers ||
297 !headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value)) {
298 return false;
139 } 299 }
140 300
141 std::string header_value; 301 // Only accept the header on secure non-unique origins.
142 headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value); 302 if (!IsOriginSecure(request_->url())) {
mmenke 2017/05/22 18:35:35 Hrm....bizarrely, we don't have a version of IsOri
msramek 2017/05/24 22:59:51 Acknowledged. I'd expect that we can just move it
303 delegate_->AddMessage(request_->url(),
304 "Not supported for insecure origins.",
305 CONSOLE_MESSAGE_LEVEL_ERROR);
306 return false;
307 }
308
309 url::Origin origin(request_->url());
310 if (origin.unique()) {
311 delegate_->AddMessage(request_->url(), "Not supported for unique origins.",
312 CONSOLE_MESSAGE_LEVEL_ERROR);
313 return false;
314 }
315
316 // The LOAD_DO_NOT_SAVE_COOKIES flag prohibits the request from doing any
317 // modification to cookies. Clear-Site-Data applies this restriction to other
318 // datatypes as well.
319 if (request_->load_flags() & net::LOAD_DO_NOT_SAVE_COOKIES) {
320 delegate_->AddMessage(
321 request_->url(),
322 "The request's credentials mode prohibits modifying cookies "
323 "and other local data.",
324 CONSOLE_MESSAGE_LEVEL_ERROR);
mmenke 2017/05/22 18:35:34 Hrm...We don't log this for normal requests with S
msramek 2017/05/24 22:59:51 We wouldn't log anything to the console, but I thi
325 return false;
326 }
327
328 // Service workers can handle fetches of third-party resources and inject
329 // arbitrary headers. Ignore responses that came from a service worker,
330 // as supporting Clear-Site-Data would give them the power to delete data from
331 // any website.
332 // See https://w3c.github.io/webappsec-clear-site-data/#service-workers
333 // for more information.
334 const ServiceWorkerResponseInfo* response_info =
335 ServiceWorkerResponseInfo::ForRequest(request_);
336 if (response_info) {
337 ResourceResponseInfo extra_response_info;
338 response_info->GetExtraResponseInfo(&extra_response_info);
339
340 if (extra_response_info.was_fetched_via_service_worker) {
341 delegate_->AddMessage(
342 request_->url(),
343 "Ignoring, as the response came from a service worker.",
344 CONSOLE_MESSAGE_LEVEL_ERROR);
345 return false;
346 }
347 }
143 348
144 bool clear_cookies; 349 bool clear_cookies;
145 bool clear_storage; 350 bool clear_storage;
146 bool clear_cache; 351 bool clear_cache;
147 352
148 if (!ParseHeader(header_value, &clear_cookies, &clear_storage, &clear_cache, 353 if (!ParseHeader(header_value, &clear_cookies, &clear_storage, &clear_cache,
mmenke 2017/05/22 18:35:34 Know this is old code, but can we use a less gener
msramek 2017/05/24 22:59:51 How about simply prefixing it with the class name
149 &messages_)) { 354 delegate_.get(), request_->url())) {
150 return; 355 return false;
151 } 356 }
152 357
358 // If the header is valid, clear the data for this browser context and origin.
359 clearing_started_ = base::TimeTicks::Now();
360
153 // Record the call parameters. 361 // Record the call parameters.
154 UMA_HISTOGRAM_ENUMERATION( 362 UMA_HISTOGRAM_ENUMERATION(
155 "Navigation.ClearSiteData.Parameters", 363 "Navigation.ClearSiteData.Parameters",
156 ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3)); 364 ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3));
157 365
158 // If the header is valid, clear the data for this browser context and origin. 366 base::WeakPtr<ClearSiteDataThrottle> weak_ptr =
159 BrowserContext* browser_context = 367 weak_ptr_factory_.GetWeakPtr();
160 navigation_handle()->GetWebContents()->GetBrowserContext();
161 url::Origin origin(current_url_);
162 368
163 if (origin.unique()) { 369 // Immediately bind the weak pointer to the current thread (IO). This will
164 ConsoleLog(&messages_, current_url_, "Not supported for unique origins.", 370 // make a potential misuse on the UI thread DCHECK immediately rather than
165 CONSOLE_MESSAGE_LEVEL_ERROR); 371 // later when it's correctly used on the IO thread again.
166 return; 372 weak_ptr.get();
mmenke 2017/05/22 18:35:34 I don't think this is needed - GetWeakPtr already
msramek 2017/05/24 22:59:51 But there is also this: // To ensure correct use,
167 }
168 373
169 clearing_in_progress_ = true; 374 ExecuteClearingTask(
170 clearing_started_ = base::TimeTicks::Now(); 375 origin, clear_cookies, clear_storage, clear_cache,
171 GetContentClient()->browser()->ClearSiteData( 376 base::Bind(&ClearSiteDataThrottle::TaskFinished, weak_ptr));
mmenke 2017/05/22 18:35:34 base::BindOnce + use std::move everywhere to pass
msramek 2017/05/24 22:59:51 Done. Yes, I think so too. Changed here and in tes
172 browser_context, origin, clear_cookies, clear_storage, clear_cache, 377
173 base::Bind(&ClearSiteDataThrottle::TaskFinished, 378 return true;
174 weak_ptr_factory_.GetWeakPtr()));
175 } 379 }
176 380
381 // static
177 bool ClearSiteDataThrottle::ParseHeader(const std::string& header, 382 bool ClearSiteDataThrottle::ParseHeader(const std::string& header,
mmenke 2017/05/22 18:35:34 This should be in the same order it's declared in
msramek 2017/05/24 22:59:51 Done. Reordered.
178 bool* clear_cookies, 383 bool* clear_cookies,
179 bool* clear_storage, 384 bool* clear_storage,
180 bool* clear_cache, 385 bool* clear_cache,
181 std::vector<ConsoleMessage>* messages) { 386 ConsoleMessagesDelegate* delegate,
387 const GURL& current_url) {
182 if (!base::IsStringASCII(header)) { 388 if (!base::IsStringASCII(header)) {
183 ConsoleLog(messages, current_url_, "Must only contain ASCII characters.", 389 delegate->AddMessage(current_url, "Must only contain ASCII characters.",
184 CONSOLE_MESSAGE_LEVEL_ERROR); 390 CONSOLE_MESSAGE_LEVEL_ERROR);
185 return false; 391 return false;
186 } 392 }
187 393
188 std::unique_ptr<base::Value> parsed_header = base::JSONReader::Read(header); 394 std::unique_ptr<base::Value> parsed_header = base::JSONReader::Read(header);
189 395
190 if (!parsed_header) { 396 if (!parsed_header) {
191 ConsoleLog(messages, current_url_, "Not a valid JSON.", 397 delegate->AddMessage(current_url, "Not a valid JSON.",
192 CONSOLE_MESSAGE_LEVEL_ERROR); 398 CONSOLE_MESSAGE_LEVEL_ERROR);
193 return false; 399 return false;
194 } 400 }
195 401
196 const base::DictionaryValue* dictionary = nullptr; 402 const base::DictionaryValue* dictionary = nullptr;
197 const base::ListValue* types = nullptr; 403 const base::ListValue* types = nullptr;
198 if (!parsed_header->GetAsDictionary(&dictionary) || 404 if (!parsed_header->GetAsDictionary(&dictionary) ||
199 !dictionary->GetListWithoutPathExpansion(kTypesKey, &types)) { 405 !dictionary->GetListWithoutPathExpansion(kTypesKey, &types)) {
200 ConsoleLog(messages, current_url_, 406 delegate->AddMessage(current_url,
201 "Expecting a JSON dictionary with a 'types' field.", 407 "Expecting a JSON dictionary with a 'types' field.",
202 CONSOLE_MESSAGE_LEVEL_ERROR); 408 CONSOLE_MESSAGE_LEVEL_ERROR);
203 return false; 409 return false;
204 } 410 }
205 411
206 DCHECK(types); 412 DCHECK(types);
207 413
208 *clear_cookies = false; 414 *clear_cookies = false;
209 *clear_storage = false; 415 *clear_storage = false;
210 *clear_cache = false; 416 *clear_cache = false;
211 417
212 std::vector<std::string> type_names; 418 std::vector<std::string> type_names;
213 for (const base::Value& value : *types) { 419 for (const base::Value& value : *types) {
214 std::string type; 420 std::string type;
215 value.GetAsString(&type); 421 value.GetAsString(&type);
mmenke 2017/05/22 18:35:35 if (!value.GetAsString(&type)) continue; (With m
msramek 2017/05/24 22:59:51 This is handled in the "} else {" branch below, to
216 422
217 bool* datatype = nullptr; 423 bool* datatype = nullptr;
218 424
219 if (type == "cookies") { 425 if (type == "cookies") {
220 datatype = clear_cookies; 426 datatype = clear_cookies;
221 } else if (type == "storage") { 427 } else if (type == "storage") {
222 datatype = clear_storage; 428 datatype = clear_storage;
223 } else if (type == "cache") { 429 } else if (type == "cache") {
mmenke 2017/05/22 18:35:35 optional: Suggest making these 3 constants up top
msramek 2017/05/24 22:59:52 Done.
224 datatype = clear_cache; 430 datatype = clear_cache;
225 } else { 431 } else {
226 std::string serialized_type; 432 std::string serialized_type;
227 JSONStringValueSerializer serializer(&serialized_type); 433 JSONStringValueSerializer serializer(&serialized_type);
228 serializer.Serialize(value); 434 serializer.Serialize(value);
229 ConsoleLog( 435 delegate->AddMessage(
230 messages, current_url_, 436 current_url,
231 base::StringPrintf("Invalid type: %s.", serialized_type.c_str()), 437 base::StringPrintf("Unrecognized type: %s.", serialized_type.c_str()),
232 CONSOLE_MESSAGE_LEVEL_ERROR); 438 CONSOLE_MESSAGE_LEVEL_ERROR);
233 continue; 439 continue;
234 } 440 }
235 441
236 // Each data type should only be processed once. 442 // Each data type should only be processed once.
237 DCHECK(datatype); 443 DCHECK(datatype);
mmenke 2017/05/22 18:35:34 This seems wrong - we shouldn't DCHECK if a site s
msramek 2017/05/24 22:59:51 I moved the comment one line below, where it's hop
238 if (*datatype) 444 if (*datatype)
239 continue; 445 continue;
240 446
241 *datatype = true; 447 *datatype = true;
242 type_names.push_back(type); 448 type_names.push_back(type);
243 } 449 }
244 450
245 if (!*clear_cookies && !*clear_storage && !*clear_cache) { 451 if (!*clear_cookies && !*clear_storage && !*clear_cache) {
246 ConsoleLog(messages, current_url_, 452 delegate->AddMessage(current_url,
247 "No valid types specified in the 'types' field.", 453 "No recognized types specified in the 'types' field.",
248 CONSOLE_MESSAGE_LEVEL_ERROR); 454 CONSOLE_MESSAGE_LEVEL_ERROR);
249 return false; 455 return false;
250 } 456 }
251 457
252 // Pretty-print which types are to be cleared. 458 // Pretty-print which types are to be cleared.
253 std::string output; 459 std::string output;
254 switch (type_names.size()) { 460 switch (type_names.size()) {
255 case 1: 461 case 1:
256 output = base::StringPrintf(kClearingOneType, type_names[0].c_str()); 462 output = base::StringPrintf(kClearingOneType, type_names[0].c_str());
257 break; 463 break;
258 case 2: 464 case 2:
259 output = base::StringPrintf(kClearingTwoTypes, type_names[0].c_str(), 465 output = base::StringPrintf(kClearingTwoTypes, type_names[0].c_str(),
260 type_names[1].c_str()); 466 type_names[1].c_str());
261 break; 467 break;
262 case 3: 468 case 3:
263 output = base::StringPrintf(kClearingThreeTypes, type_names[0].c_str(), 469 output = base::StringPrintf(kClearingThreeTypes, type_names[0].c_str(),
264 type_names[1].c_str(), type_names[2].c_str()); 470 type_names[1].c_str(), type_names[2].c_str());
mmenke 2017/05/22 18:35:35 Since this isn't internationalized (I assume nothi
msramek 2017/05/24 22:59:52 Done.
265 break; 471 break;
266 default: 472 default:
267 NOTREACHED(); 473 NOTREACHED();
268 } 474 }
269 ConsoleLog(messages, current_url_, output, CONSOLE_MESSAGE_LEVEL_INFO); 475 delegate->AddMessage(current_url, output, CONSOLE_MESSAGE_LEVEL_INFO);
270 476
271 return true; 477 return true;
272 } 478 }
273 479
480 const net::HttpResponseHeaders* ClearSiteDataThrottle::GetResponseHeaders()
481 const {
482 return request_->response_headers();
483 }
484
485 void ClearSiteDataThrottle::ExecuteClearingTask(const url::Origin& origin,
486 bool clear_cookies,
487 bool clear_storage,
488 bool clear_cache,
489 const base::Closure& callback) {
490 DCHECK_CURRENTLY_ON(BrowserThread::IO);
491 BrowserThread::PostTask(
492 BrowserThread::UI, FROM_HERE,
493 base::Bind(&ClearSiteDataOnUIThread,
494 ResourceRequestInfo::ForRequest(request_)
495 ->GetWebContentsGetterForRequest(),
496 origin, clear_cookies, clear_storage, clear_cache, callback));
497 }
498
274 void ClearSiteDataThrottle::TaskFinished() { 499 void ClearSiteDataThrottle::TaskFinished() {
mmenke 2017/05/22 18:35:34 DCHECK(!clearing_started_.is_null());
mmenke 2017/05/22 18:35:34 DCHECK_CURRENTLY_ON(BrowserThread::IO);
msramek 2017/05/24 22:59:51 I didn't add this on purpose, because the unittest
msramek 2017/05/24 22:59:51 Done.
msramek 2017/05/30 21:58:44 Fixed this in the latest patchset.
275 DCHECK(clearing_in_progress_);
276 clearing_in_progress_ = false;
277
278 UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration", 500 UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration",
279 base::TimeTicks::Now() - clearing_started_, 501 base::TimeTicks::Now() - clearing_started_,
280 base::TimeDelta::FromMilliseconds(1), 502 base::TimeDelta::FromMilliseconds(1),
281 base::TimeDelta::FromSeconds(1), 50); 503 base::TimeDelta::FromSeconds(1), 50);
282 504
283 navigation_handle()->Resume(); 505 LOG(ERROR) << "*** DEBUG OUTPUT FOR TRYBOTS *** Defer.";
mmenke 2017/05/22 18:35:34 Remove this?
msramek 2017/05/24 22:59:51 Done. (Here and elsewhere) I still haven't debugg
506 Resume();
284 } 507 }
285 508
286 } // namespace content 509 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698