• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4 
5 #include "libcef/browser/net_service/cookie_manager_impl.h"
6 
7 #include "libcef/common/net_service/net_service_util.h"
8 #include "libcef/common/time_util.h"
9 
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/storage_partition.h"
14 #include "services/network/public/mojom/cookie_manager.mojom.h"
15 #include "url/gurl.h"
16 
17 using network::mojom::CookieManager;
18 
19 namespace {
20 
21 // Do not keep a reference to the object returned by this method.
GetBrowserContext(const CefBrowserContext::Getter & getter)22 CefBrowserContext* GetBrowserContext(const CefBrowserContext::Getter& getter) {
23   CEF_REQUIRE_UIT();
24   DCHECK(!getter.is_null());
25 
26   // Will return nullptr if the BrowserContext has been shut down.
27   return getter.Run();
28 }
29 
30 // Do not keep a reference to the object returned by this method.
GetCookieManager(CefBrowserContext * browser_context)31 CookieManager* GetCookieManager(CefBrowserContext* browser_context) {
32   CEF_REQUIRE_UIT();
33   return browser_context->AsBrowserContext()
34       ->GetDefaultStoragePartition()
35       ->GetCookieManagerForBrowserProcess();
36 }
37 
38 // Always execute the callback asynchronously.
RunAsyncCompletionOnUIThread(CefRefPtr<CefCompletionCallback> callback)39 void RunAsyncCompletionOnUIThread(CefRefPtr<CefCompletionCallback> callback) {
40   if (!callback.get())
41     return;
42   CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefCompletionCallback::OnComplete,
43                                         callback.get()));
44 }
45 
46 // Always execute the callback asynchronously.
SetCookieCallbackImpl(CefRefPtr<CefSetCookieCallback> callback,net::CookieAccessResult access_result)47 void SetCookieCallbackImpl(CefRefPtr<CefSetCookieCallback> callback,
48                            net::CookieAccessResult access_result) {
49   if (!callback.get())
50     return;
51   const bool is_include = access_result.status.IsInclude();
52   if (!is_include) {
53     LOG(WARNING) << "SetCookie failed with reason: "
54                  << access_result.status.GetDebugString();
55   }
56   CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefSetCookieCallback::OnComplete,
57                                         callback.get(), is_include));
58 }
59 
60 // Always execute the callback asynchronously.
DeleteCookiesCallbackImpl(CefRefPtr<CefDeleteCookiesCallback> callback,uint32_t num_deleted)61 void DeleteCookiesCallbackImpl(CefRefPtr<CefDeleteCookiesCallback> callback,
62                                uint32_t num_deleted) {
63   if (!callback.get())
64     return;
65   CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefDeleteCookiesCallback::OnComplete,
66                                         callback.get(), num_deleted));
67 }
68 
ExecuteVisitor(CefRefPtr<CefCookieVisitor> visitor,const CefBrowserContext::Getter & browser_context_getter,const std::vector<net::CanonicalCookie> & cookies)69 void ExecuteVisitor(CefRefPtr<CefCookieVisitor> visitor,
70                     const CefBrowserContext::Getter& browser_context_getter,
71                     const std::vector<net::CanonicalCookie>& cookies) {
72   CEF_REQUIRE_UIT();
73 
74   auto browser_context = GetBrowserContext(browser_context_getter);
75   if (!browser_context)
76     return;
77 
78   auto cookie_manager = GetCookieManager(browser_context);
79 
80   int total = cookies.size(), count = 0;
81   for (const auto& cc : cookies) {
82     CefCookie cookie;
83     net_service::MakeCefCookie(cc, cookie);
84 
85     bool deleteCookie = false;
86     bool keepLooping = visitor->Visit(cookie, count, total, deleteCookie);
87     if (deleteCookie) {
88       cookie_manager->DeleteCanonicalCookie(
89           cc, CookieManager::DeleteCanonicalCookieCallback());
90     }
91     if (!keepLooping)
92       break;
93     count++;
94   }
95 }
96 
97 // Always execute the callback asynchronously.
GetAllCookiesCallbackImpl(CefRefPtr<CefCookieVisitor> visitor,const CefBrowserContext::Getter & browser_context_getter,const net::CookieList & cookies)98 void GetAllCookiesCallbackImpl(
99     CefRefPtr<CefCookieVisitor> visitor,
100     const CefBrowserContext::Getter& browser_context_getter,
101     const net::CookieList& cookies) {
102   CEF_POST_TASK(CEF_UIT, base::BindOnce(&ExecuteVisitor, visitor,
103                                         browser_context_getter, cookies));
104 }
105 
GetCookiesCallbackImpl(CefRefPtr<CefCookieVisitor> visitor,const CefBrowserContext::Getter & browser_context_getter,const net::CookieAccessResultList & include_cookies,const net::CookieAccessResultList &)106 void GetCookiesCallbackImpl(
107     CefRefPtr<CefCookieVisitor> visitor,
108     const CefBrowserContext::Getter& browser_context_getter,
109     const net::CookieAccessResultList& include_cookies,
110     const net::CookieAccessResultList&) {
111   net::CookieList cookies;
112   for (const auto& status : include_cookies) {
113     cookies.push_back(status.cookie);
114   }
115   GetAllCookiesCallbackImpl(visitor, browser_context_getter, cookies);
116 }
117 
118 }  // namespace
119 
CefCookieManagerImpl()120 CefCookieManagerImpl::CefCookieManagerImpl() {}
121 
Initialize(CefBrowserContext::Getter browser_context_getter,CefRefPtr<CefCompletionCallback> callback)122 void CefCookieManagerImpl::Initialize(
123     CefBrowserContext::Getter browser_context_getter,
124     CefRefPtr<CefCompletionCallback> callback) {
125   CEF_REQUIRE_UIT();
126   DCHECK(!initialized_);
127   DCHECK(!browser_context_getter.is_null());
128   DCHECK(browser_context_getter_.is_null());
129   browser_context_getter_ = browser_context_getter;
130 
131   initialized_ = true;
132   if (!init_callbacks_.empty()) {
133     for (auto& callback : init_callbacks_) {
134       std::move(callback).Run();
135     }
136     init_callbacks_.clear();
137   }
138 
139   RunAsyncCompletionOnUIThread(callback);
140 }
141 
VisitAllCookies(CefRefPtr<CefCookieVisitor> visitor)142 bool CefCookieManagerImpl::VisitAllCookies(
143     CefRefPtr<CefCookieVisitor> visitor) {
144   if (!visitor.get())
145     return false;
146 
147   if (!ValidContext()) {
148     StoreOrTriggerInitCallback(base::BindOnce(
149         base::IgnoreResult(&CefCookieManagerImpl::VisitAllCookiesInternal),
150         this, visitor));
151     return true;
152   }
153 
154   return VisitAllCookiesInternal(visitor);
155 }
156 
VisitUrlCookies(const CefString & url,bool includeHttpOnly,CefRefPtr<CefCookieVisitor> visitor)157 bool CefCookieManagerImpl::VisitUrlCookies(
158     const CefString& url,
159     bool includeHttpOnly,
160     CefRefPtr<CefCookieVisitor> visitor) {
161   if (!visitor.get())
162     return false;
163 
164   GURL gurl = GURL(url.ToString());
165   if (!gurl.is_valid())
166     return false;
167 
168   if (!ValidContext()) {
169     StoreOrTriggerInitCallback(base::BindOnce(
170         base::IgnoreResult(&CefCookieManagerImpl::VisitUrlCookiesInternal),
171         this, gurl, includeHttpOnly, visitor));
172     return true;
173   }
174 
175   return VisitUrlCookiesInternal(gurl, includeHttpOnly, visitor);
176 }
177 
SetCookie(const CefString & url,const CefCookie & cookie,CefRefPtr<CefSetCookieCallback> callback)178 bool CefCookieManagerImpl::SetCookie(const CefString& url,
179                                      const CefCookie& cookie,
180                                      CefRefPtr<CefSetCookieCallback> callback) {
181   GURL gurl = GURL(url.ToString());
182   if (!gurl.is_valid())
183     return false;
184 
185   if (!ValidContext()) {
186     StoreOrTriggerInitCallback(base::BindOnce(
187         base::IgnoreResult(&CefCookieManagerImpl::SetCookieInternal), this,
188         gurl, cookie, callback));
189     return true;
190   }
191 
192   return SetCookieInternal(gurl, cookie, callback);
193 }
194 
DeleteCookies(const CefString & url,const CefString & cookie_name,CefRefPtr<CefDeleteCookiesCallback> callback)195 bool CefCookieManagerImpl::DeleteCookies(
196     const CefString& url,
197     const CefString& cookie_name,
198     CefRefPtr<CefDeleteCookiesCallback> callback) {
199   // Empty URLs are allowed but not invalid URLs.
200   GURL gurl = GURL(url.ToString());
201   if (!gurl.is_empty() && !gurl.is_valid())
202     return false;
203 
204   if (!ValidContext()) {
205     StoreOrTriggerInitCallback(base::BindOnce(
206         base::IgnoreResult(&CefCookieManagerImpl::DeleteCookiesInternal), this,
207         gurl, cookie_name, callback));
208     return true;
209   }
210 
211   return DeleteCookiesInternal(gurl, cookie_name, callback);
212 }
213 
FlushStore(CefRefPtr<CefCompletionCallback> callback)214 bool CefCookieManagerImpl::FlushStore(
215     CefRefPtr<CefCompletionCallback> callback) {
216   if (!ValidContext()) {
217     StoreOrTriggerInitCallback(base::BindOnce(
218         base::IgnoreResult(&CefCookieManagerImpl::FlushStoreInternal), this,
219         callback));
220     return true;
221   }
222 
223   return FlushStoreInternal(callback);
224 }
225 
VisitAllCookiesInternal(CefRefPtr<CefCookieVisitor> visitor)226 bool CefCookieManagerImpl::VisitAllCookiesInternal(
227     CefRefPtr<CefCookieVisitor> visitor) {
228   DCHECK(ValidContext());
229   DCHECK(visitor);
230 
231   auto browser_context = GetBrowserContext(browser_context_getter_);
232   if (!browser_context)
233     return false;
234 
235   GetCookieManager(browser_context)
236       ->GetAllCookies(base::BindOnce(&GetAllCookiesCallbackImpl, visitor,
237                                      browser_context_getter_));
238   return true;
239 }
240 
VisitUrlCookiesInternal(const GURL & url,bool includeHttpOnly,CefRefPtr<CefCookieVisitor> visitor)241 bool CefCookieManagerImpl::VisitUrlCookiesInternal(
242     const GURL& url,
243     bool includeHttpOnly,
244     CefRefPtr<CefCookieVisitor> visitor) {
245   DCHECK(ValidContext());
246   DCHECK(visitor);
247   DCHECK(url.is_valid());
248 
249   net::CookieOptions options;
250   if (includeHttpOnly)
251     options.set_include_httponly();
252   options.set_same_site_cookie_context(
253       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
254 
255   auto browser_context = GetBrowserContext(browser_context_getter_);
256   if (!browser_context)
257     return false;
258 
259   GetCookieManager(browser_context)
260       ->GetCookieList(url, options, net::CookiePartitionKeyCollection(),
261                       base::BindOnce(&GetCookiesCallbackImpl, visitor,
262                                      browser_context_getter_));
263   return true;
264 }
265 
SetCookieInternal(const GURL & url,const CefCookie & cookie,CefRefPtr<CefSetCookieCallback> callback)266 bool CefCookieManagerImpl::SetCookieInternal(
267     const GURL& url,
268     const CefCookie& cookie,
269     CefRefPtr<CefSetCookieCallback> callback) {
270   DCHECK(ValidContext());
271   DCHECK(url.is_valid());
272 
273   std::string name = CefString(&cookie.name).ToString();
274   std::string value = CefString(&cookie.value).ToString();
275   std::string domain = CefString(&cookie.domain).ToString();
276   std::string path = CefString(&cookie.path).ToString();
277 
278   base::Time expiration_time;
279   if (cookie.has_expires)
280     cef_time_to_basetime(cookie.expires, expiration_time);
281 
282   net::CookieSameSite same_site =
283       net_service::MakeCookieSameSite(cookie.same_site);
284   net::CookiePriority priority =
285       net_service::MakeCookiePriority(cookie.priority);
286 
287   auto canonical_cookie = net::CanonicalCookie::CreateSanitizedCookie(
288       url, name, value, domain, path,
289       base::Time(),  // Creation time.
290       expiration_time,
291       base::Time(),  // Last access time.
292       cookie.secure ? true : false, cookie.httponly ? true : false, same_site,
293       priority, /*same_party=*/false, net::CookiePartitionKey::Todo());
294 
295   if (!canonical_cookie) {
296     SetCookieCallbackImpl(
297         callback, net::CookieAccessResult(net::CookieInclusionStatus(
298                       net::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)));
299     return true;
300   }
301 
302   net::CookieOptions options;
303   if (cookie.httponly)
304     options.set_include_httponly();
305   options.set_same_site_cookie_context(
306       net::CookieOptions::SameSiteCookieContext::MakeInclusive());
307 
308   auto browser_context = GetBrowserContext(browser_context_getter_);
309   if (!browser_context)
310     return false;
311 
312   GetCookieManager(browser_context)
313       ->SetCanonicalCookie(*canonical_cookie, url, options,
314                            base::BindOnce(SetCookieCallbackImpl, callback));
315   return true;
316 }
317 
DeleteCookiesInternal(const GURL & url,const CefString & cookie_name,CefRefPtr<CefDeleteCookiesCallback> callback)318 bool CefCookieManagerImpl::DeleteCookiesInternal(
319     const GURL& url,
320     const CefString& cookie_name,
321     CefRefPtr<CefDeleteCookiesCallback> callback) {
322   DCHECK(ValidContext());
323   DCHECK(url.is_empty() || url.is_valid());
324 
325   network::mojom::CookieDeletionFilterPtr deletion_filter =
326       network::mojom::CookieDeletionFilter::New();
327 
328   if (url.is_empty()) {
329     // Delete all cookies.
330   } else if (cookie_name.empty()) {
331     // Delete all matching host cookies.
332     deletion_filter->host_name = url.host();
333   } else {
334     // Delete all matching host and domain cookies.
335     deletion_filter->url = url;
336     deletion_filter->cookie_name = cookie_name;
337   }
338 
339   auto browser_context = GetBrowserContext(browser_context_getter_);
340   if (!browser_context)
341     return false;
342 
343   GetCookieManager(browser_context)
344       ->DeleteCookies(std::move(deletion_filter),
345                       base::BindOnce(DeleteCookiesCallbackImpl, callback));
346   return true;
347 }
348 
FlushStoreInternal(CefRefPtr<CefCompletionCallback> callback)349 bool CefCookieManagerImpl::FlushStoreInternal(
350     CefRefPtr<CefCompletionCallback> callback) {
351   DCHECK(ValidContext());
352 
353   auto browser_context = GetBrowserContext(browser_context_getter_);
354   if (!browser_context)
355     return false;
356 
357   GetCookieManager(browser_context)
358       ->FlushCookieStore(
359           base::BindOnce(RunAsyncCompletionOnUIThread, callback));
360   return true;
361 }
362 
StoreOrTriggerInitCallback(base::OnceClosure callback)363 void CefCookieManagerImpl::StoreOrTriggerInitCallback(
364     base::OnceClosure callback) {
365   if (!CEF_CURRENTLY_ON_UIT()) {
366     CEF_POST_TASK(
367         CEF_UIT,
368         base::BindOnce(&CefCookieManagerImpl::StoreOrTriggerInitCallback, this,
369                        std::move(callback)));
370     return;
371   }
372 
373   if (initialized_) {
374     std::move(callback).Run();
375   } else {
376     init_callbacks_.emplace_back(std::move(callback));
377   }
378 }
379 
ValidContext() const380 bool CefCookieManagerImpl::ValidContext() const {
381   return CEF_CURRENTLY_ON_UIT() && initialized_;
382 }
383 
384 // CefCookieManager methods ----------------------------------------------------
385 
386 // static
GetGlobalManager(CefRefPtr<CefCompletionCallback> callback)387 CefRefPtr<CefCookieManager> CefCookieManager::GetGlobalManager(
388     CefRefPtr<CefCompletionCallback> callback) {
389   CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
390   return context ? context->GetCookieManager(callback) : nullptr;
391 }
392