- add sources.
[platform/framework/web/crosswalk.git] / src / android_webview / native / cookie_manager.cc
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.
4
5 #include "android_webview/native/cookie_manager.h"
6
7 #include "android_webview/browser/aw_cookie_access_policy.h"
8 #include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
9 #include "android_webview/native/aw_browser_dependency_factory.h"
10 #include "base/android/jni_string.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/lazy_instance.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/common/url_constants.h"
21 #include "jni/AwCookieManager_jni.h"
22 #include "net/cookies/cookie_monster.h"
23 #include "net/cookies/cookie_options.h"
24 #include "net/url_request/url_request_context.h"
25
26 using base::android::ConvertJavaStringToUTF8;
27 using base::android::ConvertJavaStringToUTF16;
28 using content::BrowserThread;
29 using net::CookieList;
30 using net::CookieMonster;
31
32 // In the future, we may instead want to inject an explicit CookieStore
33 // dependency into this object during process initialization to avoid
34 // depending on the URLRequestContext.
35 // See issue http://crbug.com/157683
36
37 // All functions on the CookieManager can be called from any thread, including
38 // threads without a message loop. BrowserThread::IO is used to call methods
39 // on CookieMonster that needs to be called, and called back, on a chrome
40 // thread.
41
42 namespace android_webview {
43
44 namespace {
45
46 class CookieManager {
47  public:
48   static CookieManager* GetInstance();
49
50   void SetCookieMonster(net::CookieMonster* cookie_monster);
51
52   void SetAcceptCookie(bool accept);
53   bool AcceptCookie();
54   void SetCookie(const GURL& host, const std::string& cookie_value);
55   std::string GetCookie(const GURL& host);
56   void RemoveSessionCookie();
57   void RemoveAllCookie();
58   void RemoveExpiredCookie();
59   void FlushCookieStore();
60   bool HasCookies();
61   bool AllowFileSchemeCookies();
62   void SetAcceptFileSchemeCookies(bool accept);
63
64  private:
65   friend struct base::DefaultLazyInstanceTraits<CookieManager>;
66
67   CookieManager();
68   ~CookieManager();
69
70   typedef base::Callback<void(base::WaitableEvent*)> CookieTask;
71   void ExecCookieTask(const CookieTask& task,
72                       const bool wait_for_completion);
73
74   void SetCookieAsyncHelper(
75       const GURL& host,
76       const std::string& value,
77       base::WaitableEvent* completion);
78   void SetCookieCompleted(bool success);
79
80   void GetCookieValueAsyncHelper(
81       const GURL& host,
82       std::string* result,
83       base::WaitableEvent* completion);
84   void GetCookieValueCompleted(base::WaitableEvent* completion,
85                                std::string* result,
86                                const std::string& value);
87
88   void RemoveSessionCookieAsyncHelper(base::WaitableEvent* completion);
89   void RemoveAllCookieAsyncHelper(base::WaitableEvent* completion);
90   void RemoveCookiesCompleted(int num_deleted);
91
92   void FlushCookieStoreAsyncHelper(base::WaitableEvent* completion);
93
94   void HasCookiesAsyncHelper(bool* result,
95                              base::WaitableEvent* completion);
96   void HasCookiesCompleted(base::WaitableEvent* completion,
97                            bool* result,
98                            const CookieList& cookies);
99
100   scoped_refptr<net::CookieMonster> cookie_monster_;
101
102   DISALLOW_COPY_AND_ASSIGN(CookieManager);
103 };
104
105 base::LazyInstance<CookieManager>::Leaky g_lazy_instance;
106
107 // static
108 CookieManager* CookieManager::GetInstance() {
109   return g_lazy_instance.Pointer();
110 }
111
112 CookieManager::CookieManager() {
113 }
114
115 CookieManager::~CookieManager() {
116 }
117
118 // Executes the |task| on the FILE thread. |wait_for_completion| should only be
119 // true if the Java API method returns a value or is explicitly stated to be
120 // synchronous.
121 void CookieManager::ExecCookieTask(const CookieTask& task,
122                                    const bool wait_for_completion) {
123   base::WaitableEvent completion(false, false);
124
125   DCHECK(cookie_monster_.get());
126
127   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
128       base::Bind(task, wait_for_completion ? &completion : NULL));
129
130   if (wait_for_completion) {
131     ScopedAllowWaitForLegacyWebViewApi wait;
132     completion.Wait();
133   }
134 }
135
136 void CookieManager::SetCookieMonster(net::CookieMonster* cookie_monster) {
137   DCHECK(!cookie_monster_.get());
138   cookie_monster_ = cookie_monster;
139 }
140
141 void CookieManager::SetAcceptCookie(bool accept) {
142   AwCookieAccessPolicy::GetInstance()->SetGlobalAllowAccess(accept);
143 }
144
145 bool CookieManager::AcceptCookie() {
146   return AwCookieAccessPolicy::GetInstance()->GetGlobalAllowAccess();
147 }
148
149 void CookieManager::SetCookie(const GURL& host,
150                               const std::string& cookie_value) {
151   ExecCookieTask(base::Bind(&CookieManager::SetCookieAsyncHelper,
152                             base::Unretained(this),
153                             host,
154                             cookie_value), false);
155 }
156
157 void CookieManager::SetCookieAsyncHelper(
158     const GURL& host,
159     const std::string& value,
160     base::WaitableEvent* completion) {
161   DCHECK(!completion);
162   net::CookieOptions options;
163   options.set_include_httponly();
164
165   cookie_monster_->SetCookieWithOptionsAsync(
166       host, value, options,
167       base::Bind(&CookieManager::SetCookieCompleted, base::Unretained(this)));
168 }
169
170 void CookieManager::SetCookieCompleted(bool success) {
171   // The CookieManager API does not return a value for SetCookie,
172   // so we don't need to propagate the |success| value back to the caller.
173 }
174
175 std::string CookieManager::GetCookie(const GURL& host) {
176   std::string cookie_value;
177   ExecCookieTask(base::Bind(&CookieManager::GetCookieValueAsyncHelper,
178                             base::Unretained(this),
179                             host,
180                             &cookie_value), true);
181
182   return cookie_value;
183 }
184
185 void CookieManager::GetCookieValueAsyncHelper(
186     const GURL& host,
187     std::string* result,
188     base::WaitableEvent* completion) {
189   net::CookieOptions options;
190   options.set_include_httponly();
191
192   cookie_monster_->GetCookiesWithOptionsAsync(
193       host,
194       options,
195       base::Bind(&CookieManager::GetCookieValueCompleted,
196                  base::Unretained(this),
197                  completion,
198                  result));
199 }
200
201 void CookieManager::GetCookieValueCompleted(base::WaitableEvent* completion,
202                                             std::string* result,
203                                             const std::string& value) {
204   *result = value;
205   DCHECK(completion);
206   completion->Signal();
207 }
208
209 void CookieManager::RemoveSessionCookie() {
210   ExecCookieTask(base::Bind(&CookieManager::RemoveSessionCookieAsyncHelper,
211                             base::Unretained(this)), false);
212 }
213
214 void CookieManager::RemoveSessionCookieAsyncHelper(
215     base::WaitableEvent* completion) {
216   DCHECK(!completion);
217   cookie_monster_->DeleteSessionCookiesAsync(
218       base::Bind(&CookieManager::RemoveCookiesCompleted,
219                  base::Unretained(this)));
220 }
221
222 void CookieManager::RemoveCookiesCompleted(int num_deleted) {
223   // The CookieManager API does not return a value for removeSessionCookie or
224   // removeAllCookie, so we don't need to propagate the |num_deleted| value back
225   // to the caller.
226 }
227
228 void CookieManager::RemoveAllCookie() {
229   ExecCookieTask(base::Bind(&CookieManager::RemoveAllCookieAsyncHelper,
230                             base::Unretained(this)), false);
231 }
232
233 // TODO(kristianm): Pass a null callback so it will not be invoked
234 // across threads.
235 void CookieManager::RemoveAllCookieAsyncHelper(
236     base::WaitableEvent* completion) {
237   DCHECK(!completion);
238   cookie_monster_->DeleteAllAsync(
239       base::Bind(&CookieManager::RemoveCookiesCompleted,
240                  base::Unretained(this)));
241 }
242
243 void CookieManager::RemoveExpiredCookie() {
244   // HasCookies will call GetAllCookiesAsync, which in turn will force a GC.
245   HasCookies();
246 }
247
248 void CookieManager::FlushCookieStoreAsyncHelper(
249     base::WaitableEvent* completion) {
250   DCHECK(!completion);
251   cookie_monster_->FlushStore(base::Bind(&base::DoNothing));
252 }
253
254 void CookieManager::FlushCookieStore() {
255   ExecCookieTask(base::Bind(&CookieManager::FlushCookieStoreAsyncHelper,
256                             base::Unretained(this)), false);
257 }
258
259 bool CookieManager::HasCookies() {
260   bool has_cookies;
261   ExecCookieTask(base::Bind(&CookieManager::HasCookiesAsyncHelper,
262                             base::Unretained(this),
263                             &has_cookies), true);
264   return has_cookies;
265 }
266
267 // TODO(kristianm): Simplify this, copying the entire list around
268 // should not be needed.
269 void CookieManager::HasCookiesAsyncHelper(bool* result,
270                                   base::WaitableEvent* completion) {
271   cookie_monster_->GetAllCookiesAsync(
272       base::Bind(&CookieManager::HasCookiesCompleted,
273                  base::Unretained(this),
274                  completion,
275                  result));
276 }
277
278 void CookieManager::HasCookiesCompleted(base::WaitableEvent* completion,
279                                         bool* result,
280                                         const CookieList& cookies) {
281   *result = cookies.size() != 0;
282   DCHECK(completion);
283   completion->Signal();
284 }
285
286 bool CookieManager::AllowFileSchemeCookies() {
287   return cookie_monster_->IsCookieableScheme(chrome::kFileScheme);
288 }
289
290 void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
291   // The docs on CookieManager base class state the API must not be called after
292   // creating a CookieManager instance (which contradicts its own internal
293   // implementation) but this code does rely on the essence of that comment, as
294   // the monster will DCHECK here if it has already been lazy initialized (i.e.
295   // if cookies have been read or written from the store). If that turns out to
296   // be a problemin future, it looks like it maybe possible to relax the DCHECK.
297   cookie_monster_->SetEnableFileScheme(accept);
298 }
299
300 }  // namespace
301
302 static void SetAcceptCookie(JNIEnv* env, jobject obj, jboolean accept) {
303   CookieManager::GetInstance()->SetAcceptCookie(accept);
304 }
305
306 static jboolean AcceptCookie(JNIEnv* env, jobject obj) {
307   return CookieManager::GetInstance()->AcceptCookie();
308 }
309
310 static void SetCookie(JNIEnv* env, jobject obj, jstring url, jstring value) {
311   GURL host(ConvertJavaStringToUTF16(env, url));
312   std::string cookie_value(ConvertJavaStringToUTF8(env, value));
313
314   CookieManager::GetInstance()->SetCookie(host, cookie_value);
315 }
316
317 static jstring GetCookie(JNIEnv* env, jobject obj, jstring url) {
318   GURL host(ConvertJavaStringToUTF16(env, url));
319
320   return base::android::ConvertUTF8ToJavaString(
321       env,
322       CookieManager::GetInstance()->GetCookie(host)).Release();
323 }
324
325 static void RemoveSessionCookie(JNIEnv* env, jobject obj) {
326   CookieManager::GetInstance()->RemoveSessionCookie();
327 }
328
329 static void RemoveAllCookie(JNIEnv* env, jobject obj) {
330   CookieManager::GetInstance()->RemoveAllCookie();
331 }
332
333 static void RemoveExpiredCookie(JNIEnv* env, jobject obj) {
334   CookieManager::GetInstance()->RemoveExpiredCookie();
335 }
336
337 static void FlushCookieStore(JNIEnv* env, jobject obj) {
338   CookieManager::GetInstance()->FlushCookieStore();
339 }
340
341 static jboolean HasCookies(JNIEnv* env, jobject obj) {
342   return CookieManager::GetInstance()->HasCookies();
343 }
344
345 static jboolean AllowFileSchemeCookies(JNIEnv* env, jobject obj) {
346   return CookieManager::GetInstance()->AllowFileSchemeCookies();
347 }
348
349 static void SetAcceptFileSchemeCookies(JNIEnv* env, jobject obj,
350                                        jboolean accept) {
351   return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
352 }
353
354 void SetCookieMonsterOnNetworkStackInit(net::CookieMonster* cookie_monster) {
355   CookieManager::GetInstance()->SetCookieMonster(cookie_monster);
356 }
357
358 bool RegisterCookieManager(JNIEnv* env) {
359   return RegisterNativesImpl(env);
360 }
361
362 }  // android_webview namespace