/* * Copyright (C) 2006 George Staikos * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "CookieJarQt.h" #include "Cookie.h" #include "URL.h" #include "NetworkingContext.h" #include "NotImplemented.h" #include "PlatformCookieJar.h" #include "SQLiteStatement.h" #include "SQLiteTransaction.h" #include "ThirdPartyCookiesQt.h" #include #include #include #include #include #include #include namespace WebCore { static SharedCookieJarQt* s_sharedCookieJarQt = 0; static void appendCookie(StringBuilder& builder, const QNetworkCookie& cookie) { if (!builder.isEmpty()) builder.append("; "); QByteArray rawData = cookie.toRawForm(QNetworkCookie::NameAndValueOnly); builder.append(rawData.constData(), rawData.length()); } void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& value) { QNetworkCookieJar* jar = session.context() ? session.context()->networkAccessManager()->cookieJar() : SharedCookieJarQt::shared(); if (!jar) return; QUrl urlForCookies(url); QUrl firstPartyUrl(firstParty); if (!thirdPartyCookiePolicyPermits(session.context(), urlForCookies, firstPartyUrl)) return; CString cookieString = value.latin1(); QList cookies = QNetworkCookie::parseCookies(QByteArray::fromRawData(cookieString.data(), cookieString.length())); QList::Iterator it = cookies.begin(); while (it != cookies.end()) { if (it->isHttpOnly()) it = cookies.erase(it); else ++it; } jar->setCookiesFromUrl(cookies, urlForCookies); } String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url) { QNetworkCookieJar* jar = session.context() ? session.context()->networkAccessManager()->cookieJar() : SharedCookieJarQt::shared(); if (!jar) return String(); QUrl urlForCookies(url); QUrl firstPartyUrl(firstParty); if (!thirdPartyCookiePolicyPermits(session.context(), urlForCookies, firstPartyUrl)) return String(); QList cookies = jar->cookiesForUrl(urlForCookies); if (cookies.isEmpty()) return String(); StringBuilder builder; for (const auto& cookie : cookies) { if (cookie.isHttpOnly()) continue; appendCookie(builder, cookie); } return builder.toString(); } String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& url) { QNetworkCookieJar* jar = session.context() ? session.context()->networkAccessManager()->cookieJar() : SharedCookieJarQt::shared(); if (!jar) return String(); QList cookies = jar->cookiesForUrl(QUrl(url)); if (cookies.isEmpty()) return String(); StringBuilder builder; for (const auto& cookie : cookies) appendCookie(builder, cookie); return builder.toString(); } bool cookiesEnabled(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/) { return session.context() ? session.context()->networkAccessManager()->cookieJar() : SharedCookieJarQt::shared(); } bool getRawCookies(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/, Vector& rawCookies) { // FIXME: Not yet implemented rawCookies.clear(); return false; // return true when implemented } void deleteCookie(const NetworkStorageSession&, const URL&, const String&) { // FIXME: Not yet implemented } void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet& hostnames) { ASSERT_UNUSED(session, !session.context()); // Not yet implemented for cookie jars other than the shared one. SharedCookieJarQt* jar = SharedCookieJarQt::shared(); if (jar) jar->getHostnamesWithCookies(hostnames); } void deleteCookiesForHostnames(const NetworkStorageSession& session, const Vector& hostNames) { ASSERT_UNUSED(session, !session.context()); // Not yet implemented for cookie jars other than the shared one. SharedCookieJarQt* jar = SharedCookieJarQt::shared(); if (jar) jar->deleteCookiesForHostnames(hostNames); } void deleteAllCookies(const NetworkStorageSession& session) { ASSERT_UNUSED(session, !session.context()); // Not yet implemented for cookie jars other than the shared one. SharedCookieJarQt* jar = SharedCookieJarQt::shared(); if (jar) jar->deleteAllCookies(); } void deleteAllCookiesModifiedSince(const NetworkStorageSession& session, std::chrono::system_clock::time_point time) { ASSERT_UNUSED(session, !session.context()); // Not yet implemented for cookie jars other than the shared one. SharedCookieJarQt* jar = SharedCookieJarQt::shared(); if (jar) jar->deleteAllCookiesModifiedSince(time); } SharedCookieJarQt* SharedCookieJarQt::shared() { return s_sharedCookieJarQt; } SharedCookieJarQt* SharedCookieJarQt::create(const String& cookieStorageDirectory) { if (!s_sharedCookieJarQt) s_sharedCookieJarQt = new SharedCookieJarQt(cookieStorageDirectory); return s_sharedCookieJarQt; } void SharedCookieJarQt::destroy() { delete s_sharedCookieJarQt; s_sharedCookieJarQt = 0; } void SharedCookieJarQt::getHostnamesWithCookies(HashSet& hostnames) { QList cookies = allCookies(); foreach (const QNetworkCookie& networkCookie, cookies) hostnames.add(networkCookie.domain()); } bool SharedCookieJarQt::deleteCookie(const QNetworkCookie& cookie) { if (!QNetworkCookieJar::deleteCookie(cookie)) return false; if (!m_database.isOpen()) return false; SQLiteStatement sqlQuery(m_database, ASCIILiteral("DELETE FROM cookies WHERE cookieId=?")); if (sqlQuery.prepare() != SQLITE_OK) { qWarning("Failed to prepare delete statement - cannot write to cookie database"); return false; } sqlQuery.bindText(1, cookie.domain().append(QLatin1String(cookie.name()))); int result = sqlQuery.step(); if (result != SQLITE_DONE) { qWarning("Failed to delete cookie from database - %i", result); return false; } return true; } void SharedCookieJarQt::deleteCookiesForHostnames(const Vector& hostNames) { // QTFIXME: Implement as one statement or transaction for (auto& hostname : hostNames) deleteCookiesForHostname(hostname); } void SharedCookieJarQt::deleteCookiesForHostname(const String& hostname) { if (!m_database.isOpen()) return; QList cookies = allCookies(); QList::Iterator it = cookies.begin(); QList::Iterator end = cookies.end(); SQLiteStatement sqlQuery(m_database, ASCIILiteral("DELETE FROM cookies WHERE cookieId=?")); if (sqlQuery.prepare() != SQLITE_OK) { qWarning("Failed to prepare delete statement - cannot write to cookie database"); return; } SQLiteTransaction transaction(m_database); transaction.begin(); while (it != end) { if (it->domain() == QString(hostname)) { sqlQuery.bindText(1, it->domain().append(QLatin1String(it->name()))); int result = sqlQuery.step(); if (result != SQLITE_DONE) qWarning("Failed to remove cookie from database - %i", result); sqlQuery.reset(); it = cookies.erase(it); } else it++; } transaction.commit(); setAllCookies(cookies); } void SharedCookieJarQt::deleteAllCookies() { if (!m_database.isOpen()) return; if (!m_database.executeCommand(ASCIILiteral("DELETE FROM cookies"))) qWarning("Failed to clear cookies database"); setAllCookies(QList()); } void SharedCookieJarQt::deleteAllCookiesModifiedSince(std::chrono::system_clock::time_point) { // QTFIXME notImplemented(); } SharedCookieJarQt::SharedCookieJarQt(const String& cookieStorageDirectory) { if (!m_database.open(cookieStorageDirectory + ASCIILiteral("/cookies.db"))) { qWarning("Can't open cookie database"); return; } m_database.setSynchronous(SQLiteDatabase::SyncOff); m_database.executeCommand(ASCIILiteral("PRAGMA secure_delete = 1;")); if (ensureDatabaseTable()) loadCookies(); else m_database.close(); } SharedCookieJarQt::~SharedCookieJarQt() { m_database.close(); } bool SharedCookieJarQt::setCookiesFromUrl(const QList& cookieList, const QUrl& url) { if (!QNetworkCookieJar::setCookiesFromUrl(cookieList, url)) return false; if (!m_database.isOpen()) return false; SQLiteStatement sqlQuery(m_database, ASCIILiteral("INSERT OR REPLACE INTO cookies (cookieId, cookie) VALUES (?, ?)")); if (sqlQuery.prepare() != SQLITE_OK) return false; SQLiteTransaction transaction(m_database); transaction.begin(); foreach (const QNetworkCookie &cookie, cookiesForUrl(url)) { if (cookie.isSessionCookie()) continue; sqlQuery.bindText(1, cookie.domain().append(QLatin1String(cookie.name()))); QByteArray rawCookie = cookie.toRawForm(); sqlQuery.bindBlob(2, rawCookie.constData(), rawCookie.size()); int result = sqlQuery.step(); if (result != SQLITE_DONE) qWarning("Failed to insert cookie into database - %i", result); sqlQuery.reset(); } transaction.commit(); return true; } bool SharedCookieJarQt::ensureDatabaseTable() { if (!m_database.executeCommand(ASCIILiteral("CREATE TABLE IF NOT EXISTS cookies (cookieId VARCHAR PRIMARY KEY, cookie BLOB);"))) { qWarning("Failed to create cookie table"); return false; } return true; } void SharedCookieJarQt::loadCookies() { if (!m_database.isOpen()) return; QList cookies; SQLiteStatement sqlQuery(m_database, ASCIILiteral("SELECT cookie FROM cookies")); if (sqlQuery.prepare() != SQLITE_OK) return; int result = sqlQuery.step(); while (result == SQLITE_ROW) { Vector blob; sqlQuery.getColumnBlobAsVector(0, blob); cookies.append(QNetworkCookie::parseCookies(QByteArray::fromRawData(blob.data(), blob.size()))); result = sqlQuery.step(); } if (result != SQLITE_DONE) { LOG_ERROR("Error reading cookies from database"); return; } setAllCookies(cookies); } #include "moc_CookieJarQt.cpp" } // vim: ts=4 sw=4 et