summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp')
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
new file mode 100644
index 0000000..99de67e
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebCookieJar.h"
+
+#include "JNIUtility.h"
+#include "WebCoreJni.h"
+#include "WebRequestContext.h"
+#include "WebUrlLoaderClient.h"
+
+#include <cutils/log.h>
+#include <dirent.h>
+
+#undef ASSERT
+#define ASSERT(assertion, ...) do \
+ if (!(assertion)) { \
+ android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \
+ } \
+while (0)
+
+namespace android {
+
+static WTF::Mutex instanceMutex;
+static bool isFirstInstanceCreated = false;
+static bool fileSchemeCookiesEnabled = false;
+
+static const std::string& databaseDirectory()
+{
+ // This method may be called on any thread, as the Java method is
+ // synchronized.
+ static WTF::Mutex databaseDirectoryMutex;
+ MutexLocker lock(databaseDirectoryMutex);
+ static std::string databaseDirectory;
+ if (databaseDirectory.empty()) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
+ jmethodID method = env->GetStaticMethodID(bridgeClass, "getDatabaseDirectory", "()Ljava/lang/String;");
+ databaseDirectory = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
+ env->DeleteLocalRef(bridgeClass);
+ }
+ return databaseDirectory;
+}
+
+static void removeFileOrDirectory(const char* filename)
+{
+ struct stat filetype;
+ if (stat(filename, &filetype) != 0)
+ return;
+ if (S_ISDIR(filetype.st_mode)) {
+ DIR* directory = opendir(filename);
+ if (directory) {
+ while (struct dirent* entry = readdir(directory)) {
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+ continue;
+ std::string entryName(filename);
+ entryName.append("/");
+ entryName.append(entry->d_name);
+ removeFileOrDirectory(entryName.c_str());
+ }
+ closedir(directory);
+ rmdir(filename);
+ }
+ return;
+ }
+ unlink(filename);
+}
+
+static std::string databaseDirectory(bool isPrivateBrowsing)
+{
+ static const char* const kDatabaseFilename = "/webviewCookiesChromium.db";
+ static const char* const kDatabaseFilenamePrivateBrowsing = "/webviewCookiesChromiumPrivate.db";
+
+ std::string databaseFilePath = databaseDirectory();
+ databaseFilePath.append(isPrivateBrowsing ? kDatabaseFilenamePrivateBrowsing : kDatabaseFilename);
+ return databaseFilePath;
+}
+
+scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing)
+{
+ static scoped_refptr<WebCookieJar> regularInstance;
+ static scoped_refptr<WebCookieJar> privateInstance;
+ return isPrivateBrowsing ? &privateInstance : &regularInstance;
+}
+
+WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing)
+{
+ MutexLocker lock(instanceMutex);
+ if (!isFirstInstanceCreated && fileSchemeCookiesEnabled)
+ net::CookieMonster::EnableFileScheme();
+ isFirstInstanceCreated = true;
+ scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing);
+ if (!instancePtr->get())
+ *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing));
+ return instancePtr->get();
+}
+
+void WebCookieJar::cleanup(bool isPrivateBrowsing)
+{
+ // This is called on the UI thread.
+ MutexLocker lock(instanceMutex);
+ scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing);
+ *instancePtr = 0;
+ removeFileOrDirectory(databaseDirectory(isPrivateBrowsing).c_str());
+}
+
+WebCookieJar::WebCookieJar(const std::string& databaseFilePath)
+ : m_allowCookies(true)
+{
+ // Setup the permissions for the file
+ const char* cDatabasePath = databaseFilePath.c_str();
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+ if (access(cDatabasePath, F_OK) == 0)
+ chmod(cDatabasePath, mode);
+ else {
+ int fd = open(cDatabasePath, O_CREAT, mode);
+ if (fd >= 0)
+ close(fd);
+ }
+
+ FilePath cookiePath(databaseFilePath.c_str());
+ m_cookieDb = new SQLitePersistentCookieStore(cookiePath);
+ m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0);
+}
+
+bool WebCookieJar::allowCookies()
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ return m_allowCookies;
+}
+
+void WebCookieJar::setAllowCookies(bool allow)
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ m_allowCookies = allow;
+}
+
+int WebCookieJar::getNumCookiesInDatabase()
+{
+ if (!m_cookieStore)
+ return 0;
+ return m_cookieStore->GetCookieMonster()->GetAllCookies().size();
+}
+
+// From CookiePolicy in chromium
+int WebCookieJar::CanGetCookies(const GURL&, const GURL&, net::CompletionCallback*)
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED;
+}
+
+// From CookiePolicy in chromium
+int WebCookieJar::CanSetCookie(const GURL&, const GURL&, const std::string&, net::CompletionCallback*)
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED;
+}
+
+class FlushSemaphore : public base::RefCounted<FlushSemaphore>
+{
+public:
+ FlushSemaphore()
+ : m_condition(&m_lock)
+ , m_count(0)
+ {}
+
+ void SendFlushRequest(net::CookieMonster* monster) {
+ // FlushStore() needs to run on a Chrome thread (because it will need
+ // to post the callback, and it may want to do so on its own thread.)
+ // We use the IO thread for this purpose.
+ //
+ // TODO(husky): Our threads are hidden away in various files. Clean this
+ // up and consider integrating with Chrome's browser_thread.h. Might be
+ // a better idea to use the DB thread here rather than the IO thread.
+
+ base::Thread* ioThread = WebUrlLoaderClient::ioThread();
+ if (ioThread) {
+ Task* callback = NewRunnableMethod(this, &FlushSemaphore::Callback);
+ ioThread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ monster, &net::CookieMonster::FlushStore, callback));
+ } else {
+ Callback();
+ }
+ }
+
+ // Block until the given number of callbacks has been made.
+ void Wait(int numCallbacks) {
+ AutoLock al(m_lock);
+ int lastCount = m_count;
+ while (m_count < numCallbacks) {
+ // TODO(husky): Maybe use TimedWait() here? But it's not obvious what
+ // to do if the flush fails. Might be okay just to let the OS kill us.
+ m_condition.Wait();
+ ASSERT(lastCount != m_count, "Wait finished without incrementing m_count %d %d", m_count, lastCount);
+ lastCount = m_count;
+ }
+ m_count -= numCallbacks;
+ }
+
+private:
+ friend class base::RefCounted<FlushSemaphore>;
+
+ void Callback() {
+ AutoLock al(m_lock);
+ m_count++;
+ m_condition.Broadcast();
+ }
+
+ Lock m_lock;
+ ConditionVariable m_condition;
+ volatile int m_count;
+};
+
+void WebCookieJar::flush()
+{
+ // Flush both cookie stores (private and non-private), wait for 2 callbacks.
+ static scoped_refptr<FlushSemaphore> semaphore(new FlushSemaphore());
+ semaphore->SendFlushRequest(get(false)->cookieStore()->GetCookieMonster());
+ semaphore->SendFlushRequest(get(true)->cookieStore()->GetCookieMonster());
+ semaphore->Wait(2);
+}
+
+bool WebCookieJar::acceptFileSchemeCookies()
+{
+ MutexLocker lock(instanceMutex);
+ return fileSchemeCookiesEnabled;
+}
+
+void WebCookieJar::setAcceptFileSchemeCookies(bool accept)
+{
+ // The Chromium HTTP stack only reflects changes to this flag when creating
+ // a new CookieMonster instance. While we could track whether any
+ // CookieMonster instances currently exist, this would be complicated and is
+ // not required, so we only allow this flag to be changed before the first
+ // instance is created.
+ MutexLocker lock(instanceMutex);
+ if (!isFirstInstanceCreated)
+ fileSchemeCookiesEnabled = accept;
+}
+
+}