1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "ChromiumIncludes.h"
29#include "WebCookieJar.h"
30#include "WebCoreJni.h"
31#include <JNIHelp.h>
32
33using namespace base;
34using namespace net;
35
36namespace android {
37
38// JNI for android.webkit.CookieManager
39static const char* javaCookieManagerClass = "android/webkit/CookieManager";
40
41static bool acceptCookie(JNIEnv*, jobject)
42{
43#if USE(CHROME_NETWORK_STACK)
44    // This is a static method which gets the cookie policy for all WebViews. We
45    // always apply the same configuration to the contexts for both regular and
46    // private browsing, so expect the same result here.
47    bool regularAcceptCookies = WebCookieJar::get(false)->allowCookies();
48    ASSERT(regularAcceptCookies == WebCookieJar::get(true)->allowCookies());
49    return regularAcceptCookies;
50#else
51    // The Android HTTP stack is implemented Java-side.
52    ASSERT_NOT_REACHED();
53    return false;
54#endif
55}
56
57static jstring getCookie(JNIEnv* env, jobject, jstring url, jboolean privateBrowsing)
58{
59#if USE(CHROME_NETWORK_STACK)
60    GURL gurl(jstringToStdString(env, url));
61    CookieOptions options;
62    options.set_include_httponly();
63    std::string cookies = WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->GetCookiesWithOptions(gurl, options);
64    return stdStringToJstring(env, cookies);
65#else
66    // The Android HTTP stack is implemented Java-side.
67    ASSERT_NOT_REACHED();
68    return jstring();
69#endif
70}
71
72static bool hasCookies(JNIEnv*, jobject, jboolean privateBrowsing)
73{
74#if USE(CHROME_NETWORK_STACK)
75    return WebCookieJar::get(privateBrowsing)->getNumCookiesInDatabase() > 0;
76#else
77    // The Android HTTP stack is implemented Java-side.
78    ASSERT_NOT_REACHED();
79    return false;
80#endif
81}
82
83static void removeAllCookie(JNIEnv*, jobject)
84{
85#if USE(CHROME_NETWORK_STACK)
86    WebCookieJar::get(false)->cookieStore()->GetCookieMonster()->DeleteAll(true);
87    // This will lazily create a new private browsing context. However, if the
88    // context doesn't already exist, there's no need to create it, as cookies
89    // for such contexts are cleared up when we're done with them.
90    // TODO: Consider adding an optimisation to not create the context if it
91    // doesn't already exist.
92    WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->DeleteAll(true);
93
94    // The Java code removes cookies directly from the backing database, so we do the same,
95    // but with a NULL callback so it's asynchronous.
96    WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->FlushStore(NULL);
97#endif
98}
99
100static void removeExpiredCookie(JNIEnv*, jobject)
101{
102#if USE(CHROME_NETWORK_STACK)
103    // This simply forces a GC. The getters delete expired cookies so won't return expired cookies anyway.
104    WebCookieJar::get(false)->cookieStore()->GetCookieMonster()->GetAllCookies();
105    WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->GetAllCookies();
106#endif
107}
108
109static void removeSessionCookies(WebCookieJar* cookieJar)
110{
111#if USE(CHROME_NETWORK_STACK)
112  CookieMonster* cookieMonster = cookieJar->cookieStore()->GetCookieMonster();
113  CookieList cookies = cookieMonster->GetAllCookies();
114  for (CookieList::const_iterator iter = cookies.begin(); iter != cookies.end(); ++iter) {
115    if (iter->IsSessionCookie())
116      cookieMonster->DeleteCanonicalCookie(*iter);
117  }
118#endif
119}
120
121static void removeSessionCookie(JNIEnv*, jobject)
122{
123#if USE(CHROME_NETWORK_STACK)
124  removeSessionCookies(WebCookieJar::get(false));
125  removeSessionCookies(WebCookieJar::get(true));
126#endif
127}
128
129static void setAcceptCookie(JNIEnv*, jobject, jboolean accept)
130{
131#if USE(CHROME_NETWORK_STACK)
132    // This is a static method which configures the cookie policy for all
133    // WebViews, so we configure the contexts for both regular and private
134    // browsing.
135    WebCookieJar::get(false)->setAllowCookies(accept);
136    WebCookieJar::get(true)->setAllowCookies(accept);
137#endif
138}
139
140static void setCookie(JNIEnv* env, jobject, jstring url, jstring value, jboolean privateBrowsing)
141{
142#if USE(CHROME_NETWORK_STACK)
143    GURL gurl(jstringToStdString(env, url));
144    std::string line(jstringToStdString(env, value));
145    CookieOptions options;
146    options.set_include_httponly();
147    WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->SetCookieWithOptions(gurl, line, options);
148#endif
149}
150
151static void flushCookieStore(JNIEnv*, jobject)
152{
153#if USE(CHROME_NETWORK_STACK)
154    WebCookieJar::flush();
155#endif
156}
157
158static bool acceptFileSchemeCookies(JNIEnv*, jobject)
159{
160#if USE(CHROME_NETWORK_STACK)
161    return WebCookieJar::acceptFileSchemeCookies();
162#else
163    // File scheme cookies are always accepted with the Android HTTP stack.
164    return true;
165#endif
166}
167
168static void setAcceptFileSchemeCookies(JNIEnv*, jobject, jboolean accept)
169{
170#if USE(CHROME_NETWORK_STACK)
171    WebCookieJar::setAcceptFileSchemeCookies(accept);
172#else
173    // File scheme cookies are always accepted with the Android HTTP stack.
174#endif
175}
176
177static JNINativeMethod gCookieManagerMethods[] = {
178    { "nativeAcceptCookie", "()Z", (void*) acceptCookie },
179    { "nativeGetCookie", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) getCookie },
180    { "nativeHasCookies", "(Z)Z", (void*) hasCookies },
181    { "nativeRemoveAllCookie", "()V", (void*) removeAllCookie },
182    { "nativeRemoveExpiredCookie", "()V", (void*) removeExpiredCookie },
183    { "nativeRemoveSessionCookie", "()V", (void*) removeSessionCookie },
184    { "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie },
185    { "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*) setCookie },
186    { "nativeFlushCookieStore", "()V", (void*) flushCookieStore },
187    { "nativeAcceptFileSchemeCookies", "()Z", (void*) acceptFileSchemeCookies },
188    { "nativeSetAcceptFileSchemeCookies", "(Z)V", (void*) setAcceptFileSchemeCookies },
189};
190
191int registerCookieManager(JNIEnv* env)
192{
193#ifndef NDEBUG
194    jclass cookieManager = env->FindClass(javaCookieManagerClass);
195    LOG_ASSERT(cookieManager, "Unable to find class");
196    env->DeleteLocalRef(cookieManager);
197#endif
198    return jniRegisterNativeMethods(env, javaCookieManagerClass, gCookieManagerMethods, NELEM(gCookieManagerMethods));
199}
200
201} // namespace android
202