1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/network/restricted_cookie_manager.h"
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/compiler_specific.h" // for FALLTHROUGH;
13 #include "base/debug/crash_logging.h"
14 #include "base/debug/dump_without_crashing.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/threading/sequenced_task_runner_handle.h"
20 #include "mojo/public/cpp/bindings/message.h"
21 #include "mojo/public/cpp/bindings/remote.h"
22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
23 #include "net/cookies/cookie_constants.h"
24 #include "net/cookies/cookie_options.h"
25 #include "net/cookies/cookie_store.h"
26 #include "net/cookies/cookie_util.h"
27 #include "services/network/cookie_settings.h"
28 #include "services/network/public/mojom/network_context.mojom.h"
29 #include "services/network/public/mojom/network_service.mojom.h"
30 #include "url/gurl.h"
31
32 namespace network {
33
34 namespace {
35
MakeOptionsForSet(mojom::RestrictedCookieManagerRole role,const GURL & url,const net::SiteForCookies & site_for_cookies,const CookieSettings * cookie_settings)36 net::CookieOptions MakeOptionsForSet(
37 mojom::RestrictedCookieManagerRole role,
38 const GURL& url,
39 const net::SiteForCookies& site_for_cookies,
40 const CookieSettings* cookie_settings) {
41 net::CookieOptions options;
42 bool attach_same_site_cookies =
43 cookie_settings->ShouldIgnoreSameSiteRestrictions(
44 url, site_for_cookies.RepresentativeUrl());
45 if (role == mojom::RestrictedCookieManagerRole::SCRIPT) {
46 options.set_exclude_httponly(); // Default, but make it explicit here.
47 options.set_same_site_cookie_context(
48 net::cookie_util::ComputeSameSiteContextForScriptSet(
49 url, site_for_cookies, attach_same_site_cookies));
50 } else {
51 // mojom::RestrictedCookieManagerRole::NETWORK
52 options.set_include_httponly();
53 options.set_same_site_cookie_context(
54 net::cookie_util::ComputeSameSiteContextForSubresource(
55 url, site_for_cookies, attach_same_site_cookies));
56 }
57 return options;
58 }
59
MakeOptionsForGet(mojom::RestrictedCookieManagerRole role,const GURL & url,const net::SiteForCookies & site_for_cookies,const CookieSettings * cookie_settings)60 net::CookieOptions MakeOptionsForGet(
61 mojom::RestrictedCookieManagerRole role,
62 const GURL& url,
63 const net::SiteForCookies& site_for_cookies,
64 const CookieSettings* cookie_settings) {
65 // TODO(https://crbug.com/925311): Wire initiator here.
66 net::CookieOptions options;
67 bool attach_same_site_cookies =
68 cookie_settings->ShouldIgnoreSameSiteRestrictions(
69 url, site_for_cookies.RepresentativeUrl());
70 if (role == mojom::RestrictedCookieManagerRole::SCRIPT) {
71 options.set_exclude_httponly(); // Default, but make it explicit here.
72 options.set_same_site_cookie_context(
73 net::cookie_util::ComputeSameSiteContextForScriptGet(
74 url, site_for_cookies, base::nullopt /*initiator*/,
75 attach_same_site_cookies));
76 } else {
77 // mojom::RestrictedCookieManagerRole::NETWORK
78 options.set_include_httponly();
79 options.set_same_site_cookie_context(
80 net::cookie_util::ComputeSameSiteContextForSubresource(
81 url, site_for_cookies, attach_same_site_cookies));
82 }
83 return options;
84 }
85
86 } // namespace
87
88 using CookieInclusionStatus = net::CanonicalCookie::CookieInclusionStatus;
89
90 class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
91 public:
Listener(net::CookieStore * cookie_store,const RestrictedCookieManager * restricted_cookie_manager,const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,net::CookieOptions options,mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener)92 Listener(net::CookieStore* cookie_store,
93 const RestrictedCookieManager* restricted_cookie_manager,
94 const GURL& url,
95 const net::SiteForCookies& site_for_cookies,
96 const url::Origin& top_frame_origin,
97 net::CookieOptions options,
98 mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener)
99 : restricted_cookie_manager_(restricted_cookie_manager),
100 url_(url),
101 site_for_cookies_(site_for_cookies),
102 top_frame_origin_(top_frame_origin),
103 options_(options),
104 mojo_listener_(std::move(mojo_listener)) {
105 // TODO(pwnall): add a constructor w/options to net::CookieChangeDispatcher.
106 cookie_store_subscription_ =
107 cookie_store->GetChangeDispatcher().AddCallbackForUrl(
108 url,
109 base::BindRepeating(
110 &Listener::OnCookieChange,
111 // Safe because net::CookieChangeDispatcher guarantees that the
112 // callback will stop being called immediately after we remove
113 // the subscription, and the cookie store lives on the same
114 // thread as we do.
115 base::Unretained(this)));
116 }
117
~Listener()118 ~Listener() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
119
mojo_listener()120 mojo::Remote<mojom::CookieChangeListener>& mojo_listener() {
121 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
122 return mojo_listener_;
123 }
124
125 private:
126 // net::CookieChangeDispatcher callback.
OnCookieChange(const net::CookieChangeInfo & change)127 void OnCookieChange(const net::CookieChangeInfo& change) {
128 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
129 if (!change.cookie
130 .IncludeForRequestURL(url_, options_, change.access_semantics)
131 .IsInclude()) {
132 return;
133 }
134
135 // When a user blocks a site's access to cookies, the existing cookies are
136 // not deleted. This check prevents the site from observing their cookies
137 // being deleted at a later time, which can happen due to eviction or due to
138 // the user explicitly deleting all cookies.
139 if (!restricted_cookie_manager_->cookie_settings()->IsCookieAccessAllowed(
140 url_, site_for_cookies_.RepresentativeUrl(), top_frame_origin_)) {
141 return;
142 }
143
144 mojo_listener_->OnCookieChange(change);
145 }
146
147 // The CookieChangeDispatcher subscription used by this listener.
148 std::unique_ptr<net::CookieChangeSubscription> cookie_store_subscription_;
149
150 // Raw pointer usage is safe because RestrictedCookieManager owns this
151 // instance and is guaranteed to outlive it.
152 const RestrictedCookieManager* const restricted_cookie_manager_;
153
154 // The URL whose cookies this listener is interested in.
155 const GURL url_;
156
157 // Site context in which we're used; used to determine if a cookie is accessed
158 // in a third-party context.
159 const net::SiteForCookies site_for_cookies_;
160
161 // Site context in which we're used; used to check content settings.
162 const url::Origin top_frame_origin_;
163
164 // CanonicalCookie::IncludeForRequestURL options for this listener's interest.
165 const net::CookieOptions options_;
166
167 mojo::Remote<mojom::CookieChangeListener> mojo_listener_;
168
169 SEQUENCE_CHECKER(sequence_checker_);
170
171 DISALLOW_COPY_AND_ASSIGN(Listener);
172 };
173
RestrictedCookieManager(const mojom::RestrictedCookieManagerRole role,net::CookieStore * cookie_store,const CookieSettings * cookie_settings,const url::Origin & origin,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,mojom::NetworkContextClient * network_context_client,bool is_service_worker,int32_t process_id,int32_t frame_id)174 RestrictedCookieManager::RestrictedCookieManager(
175 const mojom::RestrictedCookieManagerRole role,
176 net::CookieStore* cookie_store,
177 const CookieSettings* cookie_settings,
178 const url::Origin& origin,
179 const net::SiteForCookies& site_for_cookies,
180 const url::Origin& top_frame_origin,
181 mojom::NetworkContextClient* network_context_client,
182 bool is_service_worker,
183 int32_t process_id,
184 int32_t frame_id)
185 : role_(role),
186 cookie_store_(cookie_store),
187 cookie_settings_(cookie_settings),
188 origin_(origin),
189 site_for_cookies_(site_for_cookies),
190 top_frame_origin_(top_frame_origin),
191 network_context_client_(network_context_client),
192 is_service_worker_(is_service_worker),
193 process_id_(process_id),
194 frame_id_(frame_id) {
195 DCHECK(cookie_store);
196 }
197
~RestrictedCookieManager()198 RestrictedCookieManager::~RestrictedCookieManager() {
199 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
200
201 base::LinkNode<Listener>* node = listeners_.head();
202 while (node != listeners_.end()) {
203 Listener* listener_reference = node->value();
204 node = node->next();
205 // The entire list is going away, no need to remove nodes from it.
206 delete listener_reference;
207 }
208 }
209
GetAllForUrl(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,mojom::CookieManagerGetOptionsPtr options,GetAllForUrlCallback callback)210 void RestrictedCookieManager::GetAllForUrl(
211 const GURL& url,
212 const net::SiteForCookies& site_for_cookies,
213 const url::Origin& top_frame_origin,
214 mojom::CookieManagerGetOptionsPtr options,
215 GetAllForUrlCallback callback) {
216 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
217
218 if (!ValidateAccessToCookiesAt(url, site_for_cookies, top_frame_origin)) {
219 std::move(callback).Run({});
220 return;
221 }
222
223 // TODO(morlovich): Try to validate site_for_cookies as well.
224
225 net::CookieOptions net_options =
226 MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
227 // TODO(https://crbug.com/977040): remove set_return_excluded_cookies() once
228 // removing deprecation warnings.
229 net_options.set_return_excluded_cookies();
230
231 cookie_store_->GetCookieListWithOptionsAsync(
232 url, net_options,
233 base::BindOnce(&RestrictedCookieManager::CookieListToGetAllForUrlCallback,
234 weak_ptr_factory_.GetWeakPtr(), url, site_for_cookies,
235 top_frame_origin, net_options, std::move(options),
236 std::move(callback)));
237 }
238
CookieListToGetAllForUrlCallback(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,const net::CookieOptions & net_options,mojom::CookieManagerGetOptionsPtr options,GetAllForUrlCallback callback,const net::CookieStatusList & cookie_list,const net::CookieStatusList & excluded_cookies)239 void RestrictedCookieManager::CookieListToGetAllForUrlCallback(
240 const GURL& url,
241 const net::SiteForCookies& site_for_cookies,
242 const url::Origin& top_frame_origin,
243 const net::CookieOptions& net_options,
244 mojom::CookieManagerGetOptionsPtr options,
245 GetAllForUrlCallback callback,
246 const net::CookieStatusList& cookie_list,
247 const net::CookieStatusList& excluded_cookies) {
248 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
249
250 bool blocked = !cookie_settings_->IsCookieAccessAllowed(
251 url, site_for_cookies.RepresentativeUrl(), top_frame_origin);
252
253 std::vector<net::CanonicalCookie> result;
254 std::vector<net::CookieWithStatus> result_with_status;
255
256 // TODO(https://crbug.com/977040): Remove once samesite tightening up is
257 // rolled out.
258 for (const auto& cookie_and_status : excluded_cookies) {
259 if (cookie_and_status.status.ShouldWarn()) {
260 result_with_status.push_back(
261 {cookie_and_status.cookie, cookie_and_status.status});
262 }
263 }
264
265 if (!blocked)
266 result.reserve(cookie_list.size());
267 mojom::CookieMatchType match_type = options->match_type;
268 const std::string& match_name = options->name;
269 // TODO(https://crbug.com/993843): Use the statuses passed in |cookie_list|.
270 for (size_t i = 0; i < cookie_list.size(); ++i) {
271 const net::CanonicalCookie& cookie = cookie_list[i].cookie;
272 CookieInclusionStatus status = cookie_list[i].status;
273 const std::string& cookie_name = cookie.Name();
274
275 if (match_type == mojom::CookieMatchType::EQUALS) {
276 if (cookie_name != match_name)
277 continue;
278 } else if (match_type == mojom::CookieMatchType::STARTS_WITH) {
279 if (!base::StartsWith(cookie_name, match_name,
280 base::CompareCase::SENSITIVE)) {
281 continue;
282 }
283 } else {
284 NOTREACHED();
285 }
286
287 if (blocked) {
288 status.AddExclusionReason(
289 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
290 } else {
291 result.push_back(cookie);
292 }
293 result_with_status.push_back({cookie, status});
294 }
295
296 if (network_context_client_) {
297 network_context_client_->OnCookiesRead(is_service_worker_, process_id_,
298 frame_id_, url, site_for_cookies,
299 result_with_status);
300 }
301
302 if (blocked) {
303 DCHECK(result.empty());
304 std::move(callback).Run({});
305 return;
306 }
307
308 std::move(callback).Run(std::move(result));
309 }
310
SetCanonicalCookie(const net::CanonicalCookie & cookie,const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,SetCanonicalCookieCallback callback)311 void RestrictedCookieManager::SetCanonicalCookie(
312 const net::CanonicalCookie& cookie,
313 const GURL& url,
314 const net::SiteForCookies& site_for_cookies,
315 const url::Origin& top_frame_origin,
316 SetCanonicalCookieCallback callback) {
317 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
318 if (!ValidateAccessToCookiesAt(url, site_for_cookies, top_frame_origin)) {
319 std::move(callback).Run(false);
320 return;
321 }
322
323 // TODO(morlovich): Try to validate site_for_cookies as well.
324 bool blocked = !cookie_settings_->IsCookieAccessAllowed(
325 url, site_for_cookies.RepresentativeUrl(), top_frame_origin);
326
327 CookieInclusionStatus status;
328 if (blocked)
329 status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
330
331 // Don't allow URLs with leading dots like https://.some-weird-domain.com
332 // This probably never happens.
333 if (!net::cookie_util::DomainIsHostOnly(url.host()))
334 status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
335
336 // Don't allow setting cookies on other domains.
337 // TODO(crbug.com/996786): This should never happen. This should eventually
338 // result in a renderer kill, but for now just log metrics.
339 bool domain_match = cookie.IsDomainMatch(url.host());
340 if (!domain_match)
341 status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
342 UMA_HISTOGRAM_BOOLEAN(
343 "Net.RestrictedCookieManager.SetCanonicalCookieDomainMatch",
344 domain_match);
345
346 if (!status.IsInclude()) {
347 if (network_context_client_) {
348 std::vector<net::CookieWithStatus> result_with_status = {
349 {cookie, status}};
350 network_context_client_->OnCookiesChanged(
351 is_service_worker_, process_id_, frame_id_, url, site_for_cookies,
352 result_with_status);
353 }
354 std::move(callback).Run(false);
355 return;
356 }
357
358 // TODO(pwnall): Validate the CanonicalCookie fields.
359
360 // Update the creation and last access times.
361 base::Time now = base::Time::NowFromSystemTime();
362 // TODO(http://crbug.com/1024053): Log metrics
363 net::CookieSourceScheme source_scheme =
364 GURL::SchemeIsCryptographic(origin_.scheme())
365 ? net::CookieSourceScheme::kSecure
366 : net::CookieSourceScheme::kNonSecure;
367 auto sanitized_cookie = std::make_unique<net::CanonicalCookie>(
368 cookie.Name(), cookie.Value(), cookie.Domain(), cookie.Path(), now,
369 cookie.ExpiryDate(), now, cookie.IsSecure(), cookie.IsHttpOnly(),
370 cookie.SameSite(), cookie.Priority(), source_scheme);
371 net::CanonicalCookie cookie_copy = *sanitized_cookie;
372
373 net::CookieOptions options =
374 MakeOptionsForSet(role_, url, site_for_cookies, cookie_settings());
375 cookie_store_->SetCanonicalCookieAsync(
376 std::move(sanitized_cookie), origin_.scheme(), options,
377 base::BindOnce(&RestrictedCookieManager::SetCanonicalCookieResult,
378 weak_ptr_factory_.GetWeakPtr(), url, site_for_cookies,
379 cookie_copy, options, std::move(callback)));
380 }
381
SetCanonicalCookieResult(const GURL & url,const net::SiteForCookies & site_for_cookies,const net::CanonicalCookie & cookie,const net::CookieOptions & net_options,SetCanonicalCookieCallback user_callback,net::CanonicalCookie::CookieInclusionStatus status)382 void RestrictedCookieManager::SetCanonicalCookieResult(
383 const GURL& url,
384 const net::SiteForCookies& site_for_cookies,
385 const net::CanonicalCookie& cookie,
386 const net::CookieOptions& net_options,
387 SetCanonicalCookieCallback user_callback,
388 net::CanonicalCookie::CookieInclusionStatus status) {
389 std::vector<net::CookieWithStatus> notify;
390 // TODO(https://crbug.com/977040): Only report pure INCLUDE once samesite
391 // tightening up is rolled out.
392 DCHECK(!status.HasExclusionReason(
393 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES));
394
395 if (network_context_client_) {
396 if (status.IsInclude() || status.ShouldWarn()) {
397 notify.push_back({cookie, status});
398 network_context_client_->OnCookiesChanged(
399 is_service_worker_, process_id_, frame_id_, url, site_for_cookies,
400 std::move(notify));
401 }
402 }
403 std::move(user_callback).Run(status.IsInclude());
404 }
405
AddChangeListener(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener,AddChangeListenerCallback callback)406 void RestrictedCookieManager::AddChangeListener(
407 const GURL& url,
408 const net::SiteForCookies& site_for_cookies,
409 const url::Origin& top_frame_origin,
410 mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener,
411 AddChangeListenerCallback callback) {
412 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
413 if (!ValidateAccessToCookiesAt(url, site_for_cookies, top_frame_origin)) {
414 std::move(callback).Run();
415 return;
416 }
417
418 net::CookieOptions net_options =
419 MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
420 auto listener = std::make_unique<Listener>(
421 cookie_store_, this, url, site_for_cookies, top_frame_origin, net_options,
422 std::move(mojo_listener));
423
424 listener->mojo_listener().set_disconnect_handler(
425 base::BindOnce(&RestrictedCookieManager::RemoveChangeListener,
426 weak_ptr_factory_.GetWeakPtr(),
427 // Safe because this owns the listener, so the listener is
428 // guaranteed to be alive for as long as the weak pointer
429 // above resolves.
430 base::Unretained(listener.get())));
431
432 // The linked list takes over the Listener ownership.
433 listeners_.Append(listener.release());
434 std::move(callback).Run();
435 }
436
SetCookieFromString(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,const std::string & cookie,SetCookieFromStringCallback callback)437 void RestrictedCookieManager::SetCookieFromString(
438 const GURL& url,
439 const net::SiteForCookies& site_for_cookies,
440 const url::Origin& top_frame_origin,
441 const std::string& cookie,
442 SetCookieFromStringCallback callback) {
443 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
444
445 std::unique_ptr<net::CanonicalCookie> parsed_cookie =
446 net::CanonicalCookie::Create(url, cookie, base::Time::Now(),
447 base::nullopt /* server_time */);
448 if (!parsed_cookie) {
449 std::move(callback).Run();
450 return;
451 }
452
453 // Further checks (origin_, settings), as well as logging done by
454 // SetCanonicalCookie()
455 SetCanonicalCookie(
456 *parsed_cookie, url, site_for_cookies, top_frame_origin,
457 base::BindOnce([](SetCookieFromStringCallback user_callback,
458 bool success) { std::move(user_callback).Run(); },
459 std::move(callback)));
460 }
461
GetCookiesString(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,GetCookiesStringCallback callback)462 void RestrictedCookieManager::GetCookiesString(
463 const GURL& url,
464 const net::SiteForCookies& site_for_cookies,
465 const url::Origin& top_frame_origin,
466 GetCookiesStringCallback callback) {
467 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
468 // Checks done by GetAllForUrl.
469
470 // Match everything.
471 auto match_options = mojom::CookieManagerGetOptions::New();
472 match_options->name = "";
473 match_options->match_type = mojom::CookieMatchType::STARTS_WITH;
474 GetAllForUrl(url, site_for_cookies, top_frame_origin,
475 std::move(match_options),
476 base::BindOnce(
477 [](GetCookiesStringCallback user_callback,
478 const std::vector<net::CanonicalCookie>& cookies) {
479 std::move(user_callback)
480 .Run(net::CanonicalCookie::BuildCookieLine(cookies));
481 },
482 std::move(callback)));
483 }
484
CookiesEnabledFor(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin,CookiesEnabledForCallback callback)485 void RestrictedCookieManager::CookiesEnabledFor(
486 const GURL& url,
487 const net::SiteForCookies& site_for_cookies,
488 const url::Origin& top_frame_origin,
489 CookiesEnabledForCallback callback) {
490 if (!ValidateAccessToCookiesAt(url, site_for_cookies, top_frame_origin)) {
491 std::move(callback).Run(false);
492 return;
493 }
494
495 std::move(callback).Run(cookie_settings_->IsCookieAccessAllowed(
496 url, site_for_cookies.RepresentativeUrl(), top_frame_origin));
497 }
498
RemoveChangeListener(Listener * listener)499 void RestrictedCookieManager::RemoveChangeListener(Listener* listener) {
500 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
501 listener->RemoveFromList();
502 delete listener;
503 }
504
ValidateAccessToCookiesAt(const GURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin & top_frame_origin)505 bool RestrictedCookieManager::ValidateAccessToCookiesAt(
506 const GURL& url,
507 const net::SiteForCookies& site_for_cookies,
508 const url::Origin& top_frame_origin) {
509 bool site_for_cookies_ok = site_for_cookies_.IsEquivalent(site_for_cookies);
510
511 DCHECK(site_for_cookies_ok)
512 << "site_for_cookies from renderer='" << site_for_cookies.ToDebugString()
513 << "' from browser='" << site_for_cookies_.ToDebugString() << "';";
514
515 bool top_frame_origin_ok = (top_frame_origin == top_frame_origin_);
516 DCHECK(top_frame_origin_ok)
517 << "top_frame_origin from renderer='" << top_frame_origin
518 << "' from browser='" << top_frame_origin_ << "';";
519
520 UMA_HISTOGRAM_BOOLEAN("Net.RestrictedCookieManager.SiteForCookiesOK",
521 site_for_cookies_ok);
522 UMA_HISTOGRAM_BOOLEAN("Net.RestrictedCookieManager.TopFrameOriginOK",
523 top_frame_origin_ok);
524
525 if (origin_.IsSameOriginWith(url::Origin::Create(url)))
526 return true;
527
528 if (url.IsAboutBlank() || url.IsAboutSrcdoc()) {
529 // Temporary mitigation for 983090, classification improvement for parts of
530 // 992587.
531 static base::debug::CrashKeyString* bound_origin =
532 base::debug::AllocateCrashKeyString(
533 "restricted_cookie_manager_bound_origin",
534 base::debug::CrashKeySize::Size256);
535 base::debug::ScopedCrashKeyString(bound_origin, origin_.GetDebugString());
536
537 static base::debug::CrashKeyString* url_origin =
538 base::debug::AllocateCrashKeyString(
539 "restricted_cookie_manager_url_origin",
540 base::debug::CrashKeySize::Size256);
541 base::debug::ScopedCrashKeyString(
542 url_origin, url::Origin::Create(url).GetDebugString());
543
544 base::debug::DumpWithoutCrashing();
545 return false;
546 }
547
548 mojo::ReportBadMessage("Incorrect url origin");
549 return false;
550 }
551
552 } // namespace network
553