choke uploadProgress signals
[profile/ivi/qtbase.git] / src / network / access / qnetworkcookiejar.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qnetworkcookiejar.h"
43 #include "qnetworkcookiejar_p.h"
44
45 #include "QtNetwork/qnetworkcookie.h"
46 #include "QtCore/qurl.h"
47 #include "QtCore/qdatetime.h"
48 #include "private/qtldurl_p.h"
49
50 QT_BEGIN_NAMESPACE
51
52 /*!
53     \class QNetworkCookieJar
54     \since 4.4
55     \inmodule QtNetwork
56
57     \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects
58
59     Cookies are small bits of information that stateless protocols
60     like HTTP use to maintain some persistent information across
61     requests.
62
63     A cookie is set by a remote server when it replies to a request
64     and it expects the same cookie to be sent back when further
65     requests are sent.
66
67     The cookie jar is the object that holds all cookies set in
68     previous requests. Web browsers save their cookie jars to disk in
69     order to conserve permanent cookies across invocations of the
70     application.
71
72     QNetworkCookieJar does not implement permanent storage: it only
73     keeps the cookies in memory. Once the QNetworkCookieJar object is
74     deleted, all cookies it held will be discarded as well. If you
75     want to save the cookies, you should derive from this class and
76     implement the saving to disk to your own storage format.
77
78     This class implements only the basic security recommended by the
79     cookie specifications and does not implement any cookie acceptance
80     policy (it accepts all cookies set by any requests). In order to
81     override those rules, you should reimplement the
82     cookiesForUrl() and setCookiesFromUrl() virtual
83     functions. They are called by QNetworkReply and
84     QNetworkAccessManager when they detect new cookies and when they
85     require cookies.
86
87     \sa QNetworkCookie, QNetworkAccessManager, QNetworkReply,
88     QNetworkRequest, QNetworkAccessManager::setCookieJar()
89 */
90
91 /*!
92     Creates a QNetworkCookieJar object and sets the parent object to
93     be \a parent.
94
95     The cookie jar is initialized to empty.
96 */
97 QNetworkCookieJar::QNetworkCookieJar(QObject *parent)
98     : QObject(*new QNetworkCookieJarPrivate, parent)
99 {
100 }
101
102 /*!
103     Destroys this cookie jar object and discards all cookies stored in
104     it. Cookies are not saved to disk in the QNetworkCookieJar default
105     implementation.
106
107     If you need to save the cookies to disk, you have to derive from
108     QNetworkCookieJar and save the cookies to disk yourself.
109 */
110 QNetworkCookieJar::~QNetworkCookieJar()
111 {
112 }
113
114 /*!
115     Returns all cookies stored in this cookie jar. This function is
116     suitable for derived classes to save cookies to disk, as well as
117     to implement cookie expiration and other policies.
118
119     \sa setAllCookies(), cookiesForUrl()
120 */
121 QList<QNetworkCookie> QNetworkCookieJar::allCookies() const
122 {
123     return d_func()->allCookies;
124 }
125
126 /*!
127     Sets the internal list of cookies held by this cookie jar to be \a
128     cookieList. This function is suitable for derived classes to
129     implement loading cookies from permanent storage, or their own
130     cookie acceptance policies by reimplementing
131     setCookiesFromUrl().
132
133     \sa allCookies(), setCookiesFromUrl()
134 */
135 void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)
136 {
137     Q_D(QNetworkCookieJar);
138     d->allCookies = cookieList;
139 }
140
141 static inline bool isParentPath(QString path, QString reference)
142 {
143     if (!path.endsWith(QLatin1Char('/')))
144         path += QLatin1Char('/');
145     if (!reference.endsWith(QLatin1Char('/')))
146         reference += QLatin1Char('/');
147     return path.startsWith(reference);
148 }
149
150 static inline bool isParentDomain(QString domain, QString reference)
151 {
152     if (!reference.startsWith(QLatin1Char('.')))
153         return domain == reference;
154
155     return domain.endsWith(reference) || domain == reference.mid(1);
156 }
157
158 /*!
159     Adds the cookies in the list \a cookieList to this cookie
160     jar. Before being inserted cookies are normalized.
161
162     Returns true if one or more cookies are set for \a url,
163     otherwise false.
164
165     If a cookie already exists in the cookie jar, it will be
166     overridden by those in \a cookieList.
167
168     The default QNetworkCookieJar class implements only a very basic
169     security policy (it makes sure that the cookies' domain and path
170     match the reply's). To enhance the security policy with your own
171     algorithms, override setCookiesFromUrl().
172
173     Also, QNetworkCookieJar does not have a maximum cookie jar
174     size. Reimplement this function to discard older cookies to create
175     room for new ones.
176
177     \sa cookiesForUrl(), QNetworkAccessManager::setCookieJar(), QNetworkCookie::normalize()
178 */
179 bool QNetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList,
180                                           const QUrl &url)
181 {
182     bool added = false;
183     foreach (QNetworkCookie cookie, cookieList) {
184         cookie.normalize(url);
185         if (validateCookie(cookie, url) && insertCookie(cookie))
186             added = true;
187     }
188     return added;
189 }
190
191 /*!
192     Returns the cookies to be added to when a request is sent to
193     \a url. This function is called by the default
194     QNetworkAccessManager::createRequest(), which adds the
195     cookies returned by this function to the request being sent.
196
197     If more than one cookie with the same name is found, but with
198     differing paths, the one with longer path is returned before the
199     one with shorter path. In other words, this function returns
200     cookies sorted decreasingly by path length.
201
202     The default QNetworkCookieJar class implements only a very basic
203     security policy (it makes sure that the cookies' domain and path
204     match the reply's). To enhance the security policy with your own
205     algorithms, override cookiesForUrl().
206
207     \sa setCookiesFromUrl(), QNetworkAccessManager::setCookieJar()
208 */
209 QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(const QUrl &url) const
210 {
211 //     \b Warning! This is only a dumb implementation!
212 //     It does NOT follow all of the recommendations from
213 //     http://wp.netscape.com/newsref/std/cookie_spec.html
214 //     It does not implement a very good cross-domain verification yet.
215
216     Q_D(const QNetworkCookieJar);
217     QDateTime now = QDateTime::currentDateTime();
218     QList<QNetworkCookie> result;
219     bool isEncrypted = url.scheme().toLower() == QLatin1String("https");
220
221     // scan our cookies for something that matches
222     QList<QNetworkCookie>::ConstIterator it = d->allCookies.constBegin(),
223                                         end = d->allCookies.constEnd();
224     for ( ; it != end; ++it) {
225         if (!isParentDomain(url.host(), it->domain()))
226             continue;
227         if (!isParentPath(url.path(), it->path()))
228             continue;
229         if (!(*it).isSessionCookie() && (*it).expirationDate() < now)
230             continue;
231         if ((*it).isSecure() && !isEncrypted)
232             continue;
233
234         // insert this cookie into result, sorted by path
235         QList<QNetworkCookie>::Iterator insertIt = result.begin();
236         while (insertIt != result.end()) {
237             if (insertIt->path().length() < it->path().length()) {
238                 // insert here
239                 insertIt = result.insert(insertIt, *it);
240                 break;
241             } else {
242                 ++insertIt;
243             }
244         }
245
246         // this is the shortest path yet, just append
247         if (insertIt == result.end())
248             result += *it;
249     }
250
251     return result;
252 }
253
254 /*!
255     \since 5.0
256     Adds \a cookie to this cookie jar.
257
258     Returns true if \a cookie was added, false otherwise.
259
260     If a cookie with the same identifier already exists in the
261     cookie jar, it will be overridden.
262 */
263 bool QNetworkCookieJar::insertCookie(const QNetworkCookie &cookie)
264 {
265     Q_D(QNetworkCookieJar);
266     QDateTime now = QDateTime::currentDateTime();
267     bool isDeletion = !cookie.isSessionCookie() &&
268                       cookie.expirationDate() < now;
269
270     deleteCookie(cookie);
271
272     if (!isDeletion) {
273         d->allCookies += cookie;
274         return true;
275     }
276     return false;
277 }
278
279 /*!
280     \since 5.0
281     If a cookie with the same identifier as \a cookie exists in this cookie jar
282     it will be updated. This function uses insertCookie().
283
284     Returns true if \a cookie was updated, false if no cookie in the jar matches
285     the identifier of \a cookie.
286
287     \sa QNetworkCookie::hasSameIdentifier()
288 */
289 bool QNetworkCookieJar::updateCookie(const QNetworkCookie &cookie)
290 {
291     if (deleteCookie(cookie))
292         return insertCookie(cookie);
293     return false;
294 }
295
296 /*!
297     \since 5.0
298     Deletes from cookie jar the cookie found to have the same identifier as \a cookie.
299
300     Returns true if a cookie was deleted, false otherwise.
301
302     \sa QNetworkCookie::hasSameIdentifier()
303 */
304 bool QNetworkCookieJar::deleteCookie(const QNetworkCookie &cookie)
305 {
306     Q_D(QNetworkCookieJar);
307     QList<QNetworkCookie>::Iterator it;
308     for (it = d->allCookies.begin(); it != d->allCookies.end(); it++)
309         if (it->hasSameIdentifier(cookie)) {
310             d->allCookies.erase(it);
311             return true;
312         }
313     return false;
314 }
315
316 /*!
317     \since 5.0
318     Returns true if the domain and path of \a cookie are valid, false otherwise.
319     The \a url parameter is used to determine if the domain specified in the cookie
320     is allowed.
321 */
322 bool QNetworkCookieJar::validateCookie(const QNetworkCookie &cookie, const QUrl &url) const
323 {
324     QString domain = cookie.domain();
325     if (!(isParentDomain(domain, url.host()) || isParentDomain(url.host(), domain)))
326         return false; // not accepted
327
328     // the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
329     // redundant; the "leading dot" rule has been relaxed anyway, see QNetworkCookie::normalize()
330     // we remove the leading dot for this check if it's present
331     if (qIsEffectiveTLD(domain.startsWith('.') ? domain.remove(0, 1) : domain))
332         return false; // not accepted
333
334     return true;
335 }
336
337 QT_END_NAMESPACE