2
* Copyright 2008-2009 Benjamin C. Meyer <ben@meyerhome.net>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301 USA
20
/****************************************************************************
22
** Copyright (C) 2007-2008 Trolltech ASA. All rights reserved.
24
** This file is part of the demonstration applications of the Qt Toolkit.
26
** This file may be used under the terms of the GNU General Public
27
** License versions 2.0 or 3.0 as published by the Free Software
28
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
29
** included in the packaging of this file. Alternatively you may (at
30
** your option) use any later version of the GNU General Public
31
** License if such license has been publicly approved by Trolltech ASA
32
** (or its successors, if any) and the KDE Free Qt Foundation. In
33
** addition, as a special exception, Trolltech gives you certain
34
** additional rights. These rights are described in the Trolltech GPL
35
** Exception version 1.2, which can be found at
36
** http://www.trolltech.com/products/qt/gplexception/ and in the file
37
** GPL_EXCEPTION.txt in this package.
39
** Please review the following information to ensure GNU General
40
** Public Licensing requirements will be met:
41
** http://trolltech.com/products/qt/licenses/licensing/opensource/. If
42
** you are unsure which license is appropriate for your use, please
43
** review the following information:
44
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
45
** or contact the sales department at sales@trolltech.com.
47
** In addition, as a special exception, Trolltech, as the sole
48
** copyright holder for Qt Designer, grants users of the Qt/Eclipse
49
** Integration plug-in the right for the Qt/Eclipse Integration to
50
** link to functionality provided by Qt Designer and its related
53
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
54
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
55
** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly
58
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
59
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
61
****************************************************************************/
63
#include "cookiejar.h"
65
#include "autosaver.h"
67
#include <qapplication.h>
68
#include <qdesktopservices.h>
70
#include <qmetaobject.h>
71
#include <qsettings.h>
76
static const unsigned int JAR_VERSION = 23;
79
QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list)
81
stream << JAR_VERSION;
82
stream << quint32(list.size());
83
for (int i = 0; i < list.size(); ++i)
84
stream << list.at(i).toRawForm();
88
QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
95
if (version != JAR_VERSION)
100
for (quint32 i = 0; i < count; ++i) {
103
QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
104
if (newCookies.count() == 0 && value.length() != 0) {
105
qWarning() << "CookieJar: Unable to parse saved cookie:" << value;
107
for (int j = 0; j < newCookies.count(); ++j)
108
list.append(newCookies.at(j));
116
CookieJar::CookieJar(QObject *parent)
117
: NetworkCookieJar(parent)
119
, m_saveTimer(new AutoSaver(this))
120
, m_filterTrackingCookies(false)
121
, m_acceptCookies(AcceptOnlyFromSitesNavigatedTo)
126
CookieJar::~CookieJar()
128
if (m_loaded && m_keepCookies == KeepUntilExit)
130
m_saveTimer->saveIfNeccessary();
133
void CookieJar::setPrivate(bool isPrivate)
135
m_isPrivate = isPrivate;
138
void CookieJar::clear()
142
setAllCookies(QList<QNetworkCookie>());
143
m_saveTimer->changeOccurred();
144
emit cookiesChanged();
147
void CookieJar::load()
151
// load cookies and exceptions
152
qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>");
153
QSettings cookieSettings(QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/cookies.ini"), QSettings::IniFormat);
155
setAllCookies(qvariant_cast<QList<QNetworkCookie> >(cookieSettings.value(QLatin1String("cookies"))));
157
cookieSettings.beginGroup(QLatin1String("Exceptions"));
158
m_exceptions_block = cookieSettings.value(QLatin1String("block")).toStringList();
159
m_exceptions_allow = cookieSettings.value(QLatin1String("allow")).toStringList();
160
m_exceptions_allowForSession = cookieSettings.value(QLatin1String("allowForSession")).toStringList();
161
qSort(m_exceptions_block.begin(), m_exceptions_block.end());
162
qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
163
qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
168
void CookieJar::loadSettings()
171
settings.beginGroup(QLatin1String("cookies"));
172
QByteArray value = settings.value(QLatin1String("acceptCookies"),
173
QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray();
174
QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
175
m_acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ?
176
AcceptOnlyFromSitesNavigatedTo :
177
static_cast<AcceptPolicy>(acceptPolicyEnum.keyToValue(value));
179
value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("KeepUntilExpire")).toByteArray();
180
QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
181
m_keepCookies = keepPolicyEnum.keyToValue(value) == -1 ?
183
static_cast<KeepPolicy>(keepPolicyEnum.keyToValue(value));
185
if (m_keepCookies == KeepUntilExit)
186
setAllCookies(QList<QNetworkCookie>());
189
m_filterTrackingCookies = settings.value(QLatin1String("filterTrackingCookies"), m_filterTrackingCookies).toBool();
190
emit cookiesChanged();
193
void CookieJar::save()
195
if (!m_loaded || m_isPrivate)
198
QString directory = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
199
if (directory.isEmpty())
200
directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
201
if (!QFile::exists(directory)) {
203
dir.mkpath(directory);
205
QSettings cookieSettings(directory + QLatin1String("/cookies.ini"), QSettings::IniFormat);
206
QList<QNetworkCookie> cookies = allCookies();
207
for (int i = cookies.count() - 1; i >= 0; --i) {
208
if (cookies.at(i).isSessionCookie())
211
cookieSettings.setValue(QLatin1String("cookies"), qVariantFromValue<QList<QNetworkCookie> >(cookies));
212
cookieSettings.beginGroup(QLatin1String("Exceptions"));
213
cookieSettings.setValue(QLatin1String("block"), m_exceptions_block);
214
cookieSettings.setValue(QLatin1String("allow"), m_exceptions_allow);
215
cookieSettings.setValue(QLatin1String("allowForSession"), m_exceptions_allowForSession);
217
// save cookie settings
219
settings.beginGroup(QLatin1String("cookies"));
220
QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
221
settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(m_acceptCookies)));
223
QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
224
settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(m_keepCookies)));
226
settings.setValue(QLatin1String("filterTrackingCookies"), m_filterTrackingCookies);
229
void CookieJar::purgeOldCookies()
231
QList<QNetworkCookie> cookies = allCookies();
232
if (cookies.isEmpty())
234
int oldCount = cookies.count();
235
QDateTime now = QDateTime::currentDateTime();
236
for (int i = cookies.count() - 1; i >= 0; --i) {
237
if (!cookies.at(i).isSessionCookie() && cookies.at(i).expirationDate() < now)
240
if (oldCount == cookies.count())
242
setAllCookies(cookies);
243
emit cookiesChanged();
246
QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
248
CookieJar *that = const_cast<CookieJar*>(this);
252
return NetworkCookieJar::cookiesForUrl(url);
255
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
260
QString host = url.host();
261
bool eBlock = isOnDomainList(m_exceptions_block, host);
262
bool eAllow = !eBlock && isOnDomainList(m_exceptions_allow, host);
263
bool eAllowSession = !eBlock && !eAllow && isOnDomainList(m_exceptions_allowForSession, host);
265
bool addedCookies = false;
267
bool acceptInitially = (m_acceptCookies != AcceptNever);
268
if ((acceptInitially && !eBlock)
269
|| (!acceptInitially && (eAllow || eAllowSession))) {
270
// pass url domain == cookie domain
271
QDateTime soon = QDateTime::currentDateTime();
272
soon = soon.addDays(90);
273
foreach (QNetworkCookie cookie, cookieList) {
274
QList<QNetworkCookie> lst;
275
if (!(m_filterTrackingCookies && cookie.name().startsWith("__utm"))) {
279
cookie.setExpirationDate(QDateTime());
281
if (m_keepCookies == KeepUntilTimeLimit
282
&& !cookie.isSessionCookie()
283
&& cookie.expirationDate() > soon) {
284
cookie.setExpirationDate(soon);
287
if (NetworkCookieJar::setCookiesFromUrl(lst, url)) {
290
// finally force it in if wanted
291
if (m_acceptCookies == AcceptAlways) {
292
QList<QNetworkCookie> cookies = allCookies();
293
QList<QNetworkCookie>::Iterator it = cookies.begin(),
295
for ( ; it != end; ++it) {
296
// does this cookie already exist?
297
if (cookie.name() == it->name() &&
298
cookie.domain() == it->domain() &&
299
cookie.path() == it->path()) {
307
setAllCookies(cookies);
312
qWarning() << "setCookiesFromUrl failed" << url << cookieList.value(0).toRawForm();
317
qWarning() << "cookie treated as tracking cookie" << cookie;
324
m_saveTimer->changeOccurred();
325
emit cookiesChanged();
330
bool CookieJar::isOnDomainList(const QStringList &rules, const QString &domain)
332
// Either the rule matches the domain exactly
333
// or the domain ends with ".rule"
334
foreach (const QString &rule, rules) {
335
if (rule.startsWith(QLatin1String("."))) {
336
if (domain.endsWith(rule))
339
QStringRef withoutDot = rule.rightRef(rule.size() - 1);
340
if (domain == withoutDot)
343
QStringRef domainEnding = domain.rightRef(rule.size() + 1);
344
if (!domainEnding.isEmpty()
345
&& domainEnding.at(0) == QLatin1Char('.')
346
&& domain.endsWith(rule)) {
357
CookieJar::AcceptPolicy CookieJar::acceptPolicy() const
360
(const_cast<CookieJar*>(this))->load();
361
return m_acceptCookies;
364
void CookieJar::setAcceptPolicy(AcceptPolicy policy)
368
if (policy == m_acceptCookies)
370
m_acceptCookies = policy;
371
m_saveTimer->changeOccurred();
374
CookieJar::KeepPolicy CookieJar::keepPolicy() const
377
(const_cast<CookieJar*>(this))->load();
378
return m_keepCookies;
381
void CookieJar::setKeepPolicy(KeepPolicy policy)
385
if (policy == m_keepCookies)
387
m_keepCookies = policy;
388
m_saveTimer->changeOccurred();
391
QStringList CookieJar::blockedCookies() const
394
(const_cast<CookieJar*>(this))->load();
395
return m_exceptions_block;
398
QStringList CookieJar::allowedCookies() const
401
(const_cast<CookieJar*>(this))->load();
402
return m_exceptions_allow;
405
QStringList CookieJar::allowForSessionCookies() const
408
(const_cast<CookieJar*>(this))->load();
409
return m_exceptions_allowForSession;
412
void CookieJar::setBlockedCookies(const QStringList &list)
416
m_exceptions_block = list;
417
qSort(m_exceptions_block.begin(), m_exceptions_block.end());
419
m_saveTimer->changeOccurred();
422
void CookieJar::setAllowedCookies(const QStringList &list)
426
m_exceptions_allow = list;
427
qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
429
m_saveTimer->changeOccurred();
432
void CookieJar::setAllowForSessionCookies(const QStringList &list)
436
m_exceptions_allowForSession = list;
437
qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
439
m_saveTimer->changeOccurred();
442
void CookieJar::applyRules()
444
QList<QNetworkCookie> cookies = allCookies();
445
bool changed = false;
446
for (int i = cookies.count() - 1; i >= 0; --i) {
447
const QNetworkCookie &cookie = cookies.at(i);
448
if (isOnDomainList(m_exceptions_block, cookie.domain())) {
451
} else if (isOnDomainList(m_exceptions_allowForSession, cookie.domain())) {
452
const_cast<QNetworkCookie&>(cookie).setExpirationDate(QDateTime());
457
setAllCookies(cookies);
458
m_saveTimer->changeOccurred();
459
emit cookiesChanged();
463
bool CookieJar::filterTrackingCookies() const
465
return this->m_filterTrackingCookies;
468
void CookieJar::setFilterTrackingCookies(bool filterTrackingCookies)
470
this->m_filterTrackingCookies = filterTrackingCookies;