1 // Copyright (c) 2011 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.
5 #include "android_webview/native/cookie_manager.h"
7 #include "android_webview/browser/aw_cookie_access_policy.h"
8 #include "android_webview/native/aw_browser_dependency_factory.h"
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/cookies/cookie_monster.h"
16 #include "net/cookies/cookie_options.h"
17 #include "net/cookies/cookie_store.h"
18 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_context_getter.h"
20 #include "jni/CookieManager_jni.h"
22 using base::android::ConvertJavaStringToUTF8
;
23 using base::android::ConvertJavaStringToUTF16
;
24 using content::BrowserThread
;
25 using net::CookieList
;
26 using net::CookieMonster
;
27 using net::URLRequestContextGetter
;
29 // This class is only available when building the chromium back-end for andriod
30 // webview: it is required where API backward compatibility demands that the UI
31 // thread must block waiting on other threads e.g. to obtain a synchronous
32 // return value. Long term, asynchronous overloads of all such methods will be
33 // added in the public API, and and no new uses of this will be allowed.
34 class ScopedAllowWaitForLegacyWebViewApi
{
36 base::ThreadRestrictions::ScopedAllowWait wait
;
39 // CookieManager should be refactored to not require all tasks accessing the
40 // CookieStore to be piped through the IO thread. It is currently required as
41 // the URLRequestContext provides the easiest mechanism for accessing the
42 // CookieStore, but the CookieStore is threadsafe. In the future, we may
43 // instead want to inject an explicit CookieStore dependency into this object
44 // during process initialization to avoid depending on the URLRequestContext.
46 // In addition to the IO thread being the easiest access mechanism, it is also
47 // used because the async cookie tasks need to be processed on a different
48 // thread than the caller from Java, which can be any thread. But, the calling
49 // thread will be 'dead' blocked waiting on the async task to complete, so we
50 // need it to complete on a 'live' (non-blocked) thread that is still pumping
53 // We could refactor to only provide an asynchronous (but thread safe) API on
54 // the native side, and move this support for legacy synchronous blocking
55 // messages into a java-side worker thread.
57 namespace android_webview
{
61 typedef base::Callback
<void(scoped_refptr
<URLRequestContextGetter
>,
62 base::WaitableEvent
*)> CookieTask
;
64 // Executes the |callback| task on the IO thread and |wait_for_completion|
65 // should only be true if the Java API method returns a value or is explicitly
66 // stated to be synchronous.
67 static void ExecCookieTask(const CookieTask
& callback
,
68 const bool wait_for_completion
) {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
71 content::BrowserContext
* context
=
72 android_webview::AwBrowserDependencyFactory::GetInstance()->
73 GetBrowserContext(false);
77 scoped_refptr
<URLRequestContextGetter
> context_getter(
78 context
->GetRequestContext());
80 if (wait_for_completion
) {
81 base::WaitableEvent
completion(false, false);
83 context
->GetRequestContext()->GetNetworkTaskRunner()->PostTask(
84 FROM_HERE
, base::Bind(callback
, context_getter
, &completion
));
86 ScopedAllowWaitForLegacyWebViewApi wait
;
89 base::WaitableEvent
* cb
= NULL
;
90 context
->GetRequestContext()->GetNetworkTaskRunner()->PostTask(
91 FROM_HERE
, base::Bind(callback
, context_getter
, cb
));
97 static void SetAcceptCookie(JNIEnv
* env
, jobject obj
, jboolean accept
) {
98 AwCookieAccessPolicy::GetInstance()->SetGlobalAllowAccess(accept
);
101 static jboolean
AcceptCookie(JNIEnv
* env
, jobject obj
) {
102 return AwCookieAccessPolicy::GetInstance()->GetGlobalAllowAccess();
107 // The CookieManager API does not return a value for SetCookie,
108 // so we don't need to propagate the |success| value back to the caller.
109 static void SetCookieCompleted(bool success
) {
112 static void SetCookieAsyncHelper(
114 const std::string
& value
,
115 scoped_refptr
<URLRequestContextGetter
> context_getter
,
116 base::WaitableEvent
* completion
) {
118 net::CookieOptions options
;
119 options
.set_include_httponly();
121 context_getter
->GetURLRequestContext()->cookie_store()->
122 SetCookieWithOptionsAsync(host
, value
, options
,
123 base::Bind(&SetCookieCompleted
));
128 static void SetCookie(JNIEnv
* env
, jobject obj
, jstring url
, jstring value
) {
129 GURL
host(ConvertJavaStringToUTF16(env
, url
));
130 std::string
cookie_value(ConvertJavaStringToUTF8(env
, value
));
132 ExecCookieTask(base::Bind(&SetCookieAsyncHelper
, host
, cookie_value
), false);
137 static void GetCookieValueCompleted(base::WaitableEvent
* completion
,
139 const std::string
& value
) {
142 completion
->Signal();
145 static void GetCookieValueAsyncHelper(
148 scoped_refptr
<URLRequestContextGetter
> context_getter
,
149 base::WaitableEvent
* completion
) {
151 net::CookieOptions options
;
152 options
.set_include_httponly();
154 context_getter
->GetURLRequestContext()->cookie_store()->
155 GetCookiesWithOptionsAsync(host
, options
,
156 base::Bind(&GetCookieValueCompleted
,
163 static jstring
GetCookie(JNIEnv
* env
, jobject obj
, jstring url
) {
164 GURL
host(ConvertJavaStringToUTF16(env
, url
));
165 std::string cookie_value
;
166 ExecCookieTask(base::Bind(&GetCookieValueAsyncHelper
, host
, &cookie_value
),
169 return base::android::ConvertUTF8ToJavaString(env
, cookie_value
).Release();
174 static void RemoveSessionCookieCompleted(int num_deleted
) {
175 // The CookieManager API does not return a value for removeSessionCookie,
176 // so we don't need to propagate the |num_deleted| value back to the caller.
179 static void RemoveSessionCookieAsyncHelper(
180 scoped_refptr
<URLRequestContextGetter
> context_getter
,
181 base::WaitableEvent
* completion
) {
183 net::CookieOptions options
;
184 options
.set_include_httponly();
186 CookieMonster
* monster
= context_getter
->GetURLRequestContext()->
187 cookie_store()->GetCookieMonster();
188 monster
->DeleteSessionCookiesAsync(base::Bind(&RemoveSessionCookieCompleted
));
193 static void RemoveSessionCookie(JNIEnv
* env
, jobject obj
) {
194 ExecCookieTask(base::Bind(&RemoveSessionCookieAsyncHelper
), false);
199 static void RemoveAllCookieCompleted(int num_deleted
) {
200 // The CookieManager API does not return a value for removeAllCookie,
201 // so we don't need to propagate the |num_deleted| value back to the caller.
204 static void RemoveAllCookieAsyncHelper(
205 scoped_refptr
<URLRequestContextGetter
> context_getter
,
206 base::WaitableEvent
* completion
) {
208 CookieMonster
* monster
= context_getter
->GetURLRequestContext()->
209 cookie_store()->GetCookieMonster();
210 monster
->DeleteAllAsync(base::Bind(&RemoveAllCookieCompleted
));
215 static void RemoveAllCookie(JNIEnv
* env
, jobject obj
) {
216 ExecCookieTask(base::Bind(&RemoveAllCookieAsyncHelper
), false);
219 static void RemoveExpiredCookie(JNIEnv
* env
, jobject obj
) {
220 // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
221 HasCookies(env
, obj
);
226 static void HasCookiesCompleted(base::WaitableEvent
* completion
,
228 const CookieList
& cookies
) {
229 *result
= cookies
.size() != 0;
231 completion
->Signal();
234 static void HasCookiesAsyncHelper(
236 scoped_refptr
<URLRequestContextGetter
> context_getter
,
237 base::WaitableEvent
* completion
) {
239 CookieMonster
* monster
= context_getter
->GetURLRequestContext()->
240 cookie_store()->GetCookieMonster();
241 monster
->GetAllCookiesAsync(base::Bind(&HasCookiesCompleted
, completion
,
247 static jboolean
HasCookies(JNIEnv
* env
, jobject obj
) {
249 ExecCookieTask(base::Bind(&HasCookiesAsyncHelper
, &has_cookies
), true);
255 static void AllowFileSchemeCookiesAsyncHelper(
257 scoped_refptr
<URLRequestContextGetter
> context_getter
,
258 base::WaitableEvent
* completion
) {
260 CookieMonster
* monster
= context_getter
->GetURLRequestContext()->
261 cookie_store()->GetCookieMonster();
262 *accept
= monster
->IsCookieableScheme("file");
265 completion
->Signal();
270 static jboolean
AllowFileSchemeCookies(JNIEnv
* env
, jclass obj
) {
272 ExecCookieTask(base::Bind(&AllowFileSchemeCookiesAsyncHelper
, &accept
), true);
278 static void SetAcceptFileSchemeCookiesAsyncHelper(
280 scoped_refptr
<URLRequestContextGetter
> context_getter
,
281 base::WaitableEvent
* completion
) {
283 CookieMonster
* monster
= context_getter
->GetURLRequestContext()->
284 cookie_store()->GetCookieMonster();
285 monster
->SetEnableFileScheme(accept
);
288 completion
->Signal();
293 static void SetAcceptFileSchemeCookies(JNIEnv
* env
, jclass obj
,
295 ExecCookieTask(base::Bind(&SetAcceptFileSchemeCookiesAsyncHelper
, accept
),
299 bool RegisterCookieManager(JNIEnv
* env
) {
300 return RegisterNativesImpl(env
);
303 } // android_webview namespace