Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qnetworkcookiejar.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
"qnetworkcookiejar.h"
6
#
include
"qnetworkcookiejar_p.h"
7
8
#
include
"QtNetwork/qnetworkcookie.h"
9
#
include
"QtCore/qurl.h"
10
#
include
"QtCore/qdatetime.h"
11
#
if
QT_CONFIG
(
topleveldomain
)
12
#
include
"private/qtldurl_p.h"
13
#
else
14
QT_BEGIN_NAMESPACE
15
static
bool
qIsEffectiveTLD
(QStringView domain)
16
{
17
// provide minimal checking by not accepting cookies on real TLDs
18
return
!domain.contains(u'.');
19
}
20
QT_END_NAMESPACE
21
#
endif
22
23
QT_BEGIN_NAMESPACE
24
25
using
namespace
Qt::StringLiterals;
26
27
/*!
28
\class QNetworkCookieJar
29
\since 4.4
30
\inmodule QtNetwork
31
32
\brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects.
33
34
Cookies are small bits of information that stateless protocols
35
like HTTP use to maintain some persistent information across
36
requests.
37
38
A cookie is set by a remote server when it replies to a request
39
and it expects the same cookie to be sent back when further
40
requests are sent.
41
42
The cookie jar is the object that holds all cookies set in
43
previous requests. Web browsers save their cookie jars to disk in
44
order to conserve permanent cookies across invocations of the
45
application.
46
47
QNetworkCookieJar does not implement permanent storage: it only
48
keeps the cookies in memory. Once the QNetworkCookieJar object is
49
deleted, all cookies it held will be discarded as well. If you
50
want to save the cookies, you should derive from this class and
51
implement the saving to disk to your own storage format.
52
53
This class implements only the basic security recommended by the
54
cookie specifications and does not implement any cookie acceptance
55
policy (it accepts all cookies set by any requests). In order to
56
override those rules, you should reimplement the
57
cookiesForUrl() and setCookiesFromUrl() virtual
58
functions. They are called by QNetworkReply and
59
QNetworkAccessManager when they detect new cookies and when they
60
require cookies.
61
62
\sa QNetworkCookie, QNetworkAccessManager, QNetworkReply,
63
QNetworkRequest, QNetworkAccessManager::setCookieJar()
64
*/
65
66
/*!
67
Creates a QNetworkCookieJar object and sets the parent object to
68
be \a parent.
69
70
The cookie jar is initialized to empty.
71
*/
72
QNetworkCookieJar::QNetworkCookieJar(QObject *parent)
73
: QObject(*
new
QNetworkCookieJarPrivate, parent)
74
{
75
}
76
77
/*!
78
Destroys this cookie jar object and discards all cookies stored in
79
it. Cookies are not saved to disk in the QNetworkCookieJar default
80
implementation.
81
82
If you need to save the cookies to disk, you have to derive from
83
QNetworkCookieJar and save the cookies to disk yourself.
84
*/
85
QNetworkCookieJar::~QNetworkCookieJar()
86
{
87
}
88
89
/*!
90
Returns all cookies stored in this cookie jar. This function is
91
suitable for derived classes to save cookies to disk, as well as
92
to implement cookie expiration and other policies.
93
94
\sa setAllCookies(), cookiesForUrl()
95
*/
96
QList<QNetworkCookie> QNetworkCookieJar::allCookies()
const
97
{
98
return
d_func()->allCookies;
99
}
100
101
/*!
102
Sets the internal list of cookies held by this cookie jar to be \a
103
cookieList. This function is suitable for derived classes to
104
implement loading cookies from permanent storage, or their own
105
cookie acceptance policies by reimplementing
106
setCookiesFromUrl().
107
108
\sa allCookies(), setCookiesFromUrl()
109
*/
110
void
QNetworkCookieJar::setAllCookies(
const
QList<QNetworkCookie> &cookieList)
111
{
112
Q_D(QNetworkCookieJar);
113
d->allCookies = cookieList;
114
}
115
116
static
inline
bool
isParentPath
(QStringView path, QStringView reference)
117
{
118
if
((path.isEmpty() && reference ==
"/"_L1
) || path.startsWith(reference)) {
119
//The cookie-path and the request-path are identical.
120
if
(path.size() == reference.size())
121
return
true
;
122
//The cookie-path is a prefix of the request-path, and the last
123
//character of the cookie-path is %x2F ("/").
124
if
(reference.endsWith(u'/'))
125
return
true
;
126
//The cookie-path is a prefix of the request-path, and the first
127
//character of the request-path that is not included in the cookie-
128
//path is a %x2F ("/") character.
129
if
(path.at(reference.size()) == u'/')
130
return
true
;
131
}
132
return
false
;
133
}
134
135
static
inline
bool
isParentDomain
(QStringView domain, QStringView reference)
136
{
137
if
(!reference.startsWith(u'.'))
138
return
domain == reference;
139
140
return
domain.endsWith(reference) || domain == reference.mid(1);
141
}
142
143
/*!
144
Adds the cookies in the list \a cookieList to this cookie
145
jar. Before being inserted cookies are normalized.
146
147
Returns \c true if one or more cookies are set for \a url,
148
otherwise false.
149
150
If a cookie already exists in the cookie jar, it will be
151
overridden by those in \a cookieList.
152
153
The default QNetworkCookieJar class implements only a very basic
154
security policy (it makes sure that the cookies' domain and path
155
match the reply's). To enhance the security policy with your own
156
algorithms, override setCookiesFromUrl().
157
158
Also, QNetworkCookieJar does not have a maximum cookie jar
159
size. Reimplement this function to discard older cookies to create
160
room for new ones.
161
162
\sa cookiesForUrl(), QNetworkAccessManager::setCookieJar(), QNetworkCookie::normalize()
163
*/
164
bool
QNetworkCookieJar::setCookiesFromUrl(
const
QList<QNetworkCookie> &cookieList,
165
const
QUrl &url)
166
{
167
bool
added =
false
;
168
for
(QNetworkCookie cookie : cookieList) {
169
cookie.normalize(url);
170
if
(validateCookie(cookie, url) && insertCookie(cookie))
171
added =
true
;
172
}
173
return
added;
174
}
175
176
/*!
177
Returns the cookies to be added to when a request is sent to
178
\a url. This function is called by the default
179
QNetworkAccessManager::createRequest(), which adds the
180
cookies returned by this function to the request being sent.
181
182
If more than one cookie with the same name is found, but with
183
differing paths, the one with longer path is returned before the
184
one with shorter path. In other words, this function returns
185
cookies sorted decreasingly by path length.
186
187
The default QNetworkCookieJar class implements only a very basic
188
security policy (it makes sure that the cookies' domain and path
189
match the reply's). To enhance the security policy with your own
190
algorithms, override cookiesForUrl().
191
192
\sa setCookiesFromUrl(), QNetworkAccessManager::setCookieJar()
193
*/
194
QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(
const
QUrl &url)
const
195
{
196
// \b Warning! This is only a dumb implementation!
197
// It does NOT follow all of the recommendations from
198
// http://wp.netscape.com/newsref/std/cookie_spec.html
199
// It does not implement a very good cross-domain verification yet.
200
201
Q_D(
const
QNetworkCookieJar);
202
const
QDateTime now = QDateTime::currentDateTimeUtc();
203
QList<QNetworkCookie> result;
204
const
bool
isEncrypted = url.scheme() ==
"https"_L1
;
205
206
// scan our cookies for something that matches
207
for
(
const
auto
&cookie : std::as_const(d->allCookies)) {
208
if
(!isEncrypted && cookie.isSecure())
209
continue
;
210
if
(!cookie.isSessionCookie() && cookie.expirationDate() < now)
211
continue
;
212
const
QString urlHost = url.host();
213
const
QString cookieDomain = cookie.domain();
214
if
(!isParentDomain(urlHost, cookieDomain))
215
continue
;
216
if
(!isParentPath(url.path(), cookie.path()))
217
continue
;
218
219
QStringView domain = cookieDomain;
220
if
(domain.startsWith(u'.'))
/// Qt6?: remove when compliant with RFC6265
221
domain = domain.sliced(1);
222
#
if
QT_CONFIG
(
topleveldomain
)
223
if
(urlHost != domain && qIsEffectiveTLD(domain))
224
continue
;
225
#
else
226
if
(!domain.contains(u'.') && urlHost != domain)
227
continue
;
228
#
endif
// topleveldomain
229
230
result += cookie;
231
}
232
233
auto
longerPath = [](
const
auto
&c1,
const
auto
&c2)
234
{
return
c1.path().size() > c2.path().size(); };
235
std::sort(result.begin(), result.end(), longerPath);
236
return
result;
237
}
238
239
/*!
240
\since 5.0
241
Adds \a cookie to this cookie jar.
242
243
Returns \c true if \a cookie was added, false otherwise.
244
245
If a cookie with the same identifier already exists in the
246
cookie jar, it will be overridden.
247
*/
248
bool
QNetworkCookieJar::insertCookie(
const
QNetworkCookie &cookie)
249
{
250
Q_D(QNetworkCookieJar);
251
const
QDateTime now = QDateTime::currentDateTimeUtc();
252
bool
isDeletion = !cookie.isSessionCookie() &&
253
cookie.expirationDate() < now;
254
255
deleteCookie(cookie);
256
257
if
(!isDeletion) {
258
d->allCookies += cookie;
259
return
true
;
260
}
261
return
false
;
262
}
263
264
/*!
265
\since 5.0
266
If a cookie with the same identifier as \a cookie exists in this cookie jar
267
it will be updated. This function uses insertCookie().
268
269
Returns \c true if \a cookie was updated, false if no cookie in the jar matches
270
the identifier of \a cookie.
271
272
\sa QNetworkCookie::hasSameIdentifier()
273
*/
274
bool
QNetworkCookieJar::updateCookie(
const
QNetworkCookie &cookie)
275
{
276
if
(deleteCookie(cookie))
277
return
insertCookie(cookie);
278
return
false
;
279
}
280
281
/*!
282
\since 5.0
283
Deletes from cookie jar the cookie found to have the same identifier as \a cookie.
284
285
Returns \c true if a cookie was deleted, false otherwise.
286
287
\sa QNetworkCookie::hasSameIdentifier()
288
*/
289
bool
QNetworkCookieJar::deleteCookie(
const
QNetworkCookie &cookie)
290
{
291
Q_D(QNetworkCookieJar);
292
const
auto
it = std::find_if(d->allCookies.cbegin(), d->allCookies.cend(),
293
[&cookie](
const
auto
&c) {
return
c.hasSameIdentifier(cookie); });
294
if
(it != d->allCookies.cend()) {
295
d->allCookies.erase(it);
296
return
true
;
297
}
298
return
false
;
299
}
300
301
/*!
302
\since 5.0
303
Returns \c true if the domain and path of \a cookie are valid, false otherwise.
304
The \a url parameter is used to determine if the domain specified in the cookie
305
is allowed.
306
*/
307
bool
QNetworkCookieJar::validateCookie(
const
QNetworkCookie &cookie,
const
QUrl &url)
const
308
{
309
const
QString cookieDomain = cookie.domain();
310
QStringView domain = cookieDomain;
311
const
QString host = url.host();
312
if
(!isParentDomain(domain, host) && !isParentDomain(host, domain))
313
return
false
;
// not accepted
314
315
if
(domain.startsWith(u'.'))
316
domain = domain.sliced(1);
317
318
// We shouldn't reject if:
319
// "[...] the domain-attribute is identical to the canonicalized request-host"
320
// https://tools.ietf.org/html/rfc6265#section-5.3 step 5
321
if
(host == domain)
322
return
true
;
323
// the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
324
// redundant; the "leading dot" rule has been relaxed anyway, see QNetworkCookie::normalize()
325
// we remove the leading dot for this check if it's present
326
// Normally defined in qtldurl_p.h, but uses fall-back in this file when topleveldomain isn't
327
// configured:
328
return
!qIsEffectiveTLD(domain);
329
}
330
331
QT_END_NAMESPACE
332
333
#
include
"moc_qnetworkcookiejar.cpp"
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qIsEffectiveTLD
static QT_BEGIN_NAMESPACE bool qIsEffectiveTLD(QStringView domain)
Definition
qnetworkcookiejar.cpp:15
isParentDomain
static bool isParentDomain(QStringView domain, QStringView reference)
Definition
qnetworkcookiejar.cpp:135
isParentPath
static bool isParentPath(QStringView path, QStringView reference)
Definition
qnetworkcookiejar.cpp:116
qtbase
src
network
access
qnetworkcookiejar.cpp
Generated on
for Qt by
1.18.0