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