Gives QNetworkCookieJar a virtual API.

QNetworkCookieJar now has the following virtual methods:
    virtual bool validateCookie(QNetworkCookie &cookie);
    virtual bool insertCookie(const QNetworkCookie &cookie, const QUrl &url);
    virtual bool updateCookie(const QNetworkCookie &cookie);
    virtual void deleteCookie(const QNetworkCookie &cookie);
Their implementation is such that the behavior the class previously
had(in memory storage of the cookies) is mantained.

Task-number: QTBUG-23145
Change-Id: I1420894d31e8072eca6903c3c7ffd6f06205a257
Reviewed-by: Peter Hartmann <peter.hartmann@nokia.com>
Reviewed-by: Alexis Menard <alexis.menard@openbossa.org>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Reviewed-by: Shane Kearns <ext-shane.2.kearns@nokia.com>
bb10
Jonas M. Gastal 2012-01-11 17:00:11 -02:00 committed by Qt by Nokia
parent 1166ad8603
commit ed429ebfc9
4 changed files with 128 additions and 63 deletions

View File

@ -156,7 +156,7 @@ QNetworkCookie &QNetworkCookie::operator=(const QNetworkCookie &other)
However, in some contexts, two cookies of the same name could be
considered equal.
\sa operator!=()
\sa operator!=(), hasSameIdentifier()
*/
bool QNetworkCookie::operator==(const QNetworkCookie &other) const
{
@ -171,6 +171,17 @@ bool QNetworkCookie::operator==(const QNetworkCookie &other) const
d->comment == other.d->comment;
}
/*!
Returns true if this cookie has the same identifier tuple as \a other.
The identifier tuple is composed of the name, domain and path.
\sa operator==()
*/
bool QNetworkCookie::hasSameIdentifier(const QNetworkCookie &other) const
{
return d->name == other.d->name && d->domain == other.d->domain && d->path == other.d->path;
}
/*!
Returns true if the "secure" option was specified in the cookie
string, false otherwise.
@ -1042,6 +1053,30 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
return result;
}
/*!
This functions normalizes the path and domain of the cookie if they were previously empty.
*/
void QNetworkCookie::normalize(const QUrl &url)
{
// don't do path checking. See http://bugreports.qt.nokia.com/browse/QTBUG-5815
if (d->path.isEmpty()) {
QString pathAndFileName = url.path();
QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(QLatin1Char('/'))+1);
if (defaultPath.isEmpty())
defaultPath = QLatin1Char('/');
d->path = defaultPath;
}
if (d->domain.isEmpty())
d->domain = url.host();
else if (!d->domain.startsWith(QLatin1Char('.')))
// Ensure the domain starts with a dot if its field was not empty
// in the HTTP header. There are some servers that forget the
// leading dot and this is actually forbidden according to RFC 2109,
// but all browsers accept it anyway so we do that as well.
d->domain.prepend(QLatin1Char('.'));
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug s, const QNetworkCookie &cookie)
{

View File

@ -97,6 +97,9 @@ public:
QByteArray toRawForm(RawForm form = Full) const;
bool hasSameIdentifier(const QNetworkCookie &other) const;
void normalize(const QUrl &url);
static QList<QNetworkCookie> parseCookies(const QByteArray &cookieString);
private:

View File

@ -155,8 +155,7 @@ static inline bool isParentDomain(QString domain, QString reference)
/*!
Adds the cookies in the list \a cookieList to this cookie
jar. Default values for path and domain are taken from the \a
url object.
jar. Before being inserted cookies are normalized.
Returns true if one or more cookies are set for \a url,
otherwise false.
@ -173,72 +172,18 @@ static inline bool isParentDomain(QString domain, QString reference)
size. Reimplement this function to discard older cookies to create
room for new ones.
\sa cookiesForUrl(), QNetworkAccessManager::setCookieJar()
\sa cookiesForUrl(), QNetworkAccessManager::setCookieJar(), QNetworkCookie::normalize()
*/
bool QNetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList,
const QUrl &url)
{
Q_D(QNetworkCookieJar);
QString defaultDomain = url.host();
QString pathAndFileName = url.path();
QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(QLatin1Char('/'))+1);
if (defaultPath.isEmpty())
defaultPath = QLatin1Char('/');
int added = 0;
QDateTime now = QDateTime::currentDateTime();
bool added = false;
foreach (QNetworkCookie cookie, cookieList) {
bool isDeletion = !cookie.isSessionCookie() &&
cookie.expirationDate() < now;
// validate the cookie & set the defaults if unset
if (cookie.path().isEmpty())
cookie.setPath(defaultPath);
// don't do path checking. See http://bugreports.qt.nokia.com/browse/QTBUG-5815
// else if (!isParentPath(pathAndFileName, cookie.path())) {
// continue; // not accepted
// }
if (cookie.domain().isEmpty()) {
cookie.setDomain(defaultDomain);
} else {
// Ensure the domain starts with a dot if its field was not empty
// in the HTTP header. There are some servers that forget the
// leading dot and this is actually forbidden according to RFC 2109,
// but all browsers accept it anyway so we do that as well.
if (!cookie.domain().startsWith(QLatin1Char('.')))
cookie.setDomain(QLatin1Char('.') + cookie.domain());
QString domain = cookie.domain();
if (!(isParentDomain(domain, defaultDomain)
|| isParentDomain(defaultDomain, domain)))
continue; // not accepted
// the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
// redundant; the "leading dot" rule has been relaxed anyway, see above
// we remove the leading dot for this check
if (qIsEffectiveTLD(domain.remove(0, 1)))
continue; // not accepted
}
QList<QNetworkCookie>::Iterator it = d->allCookies.begin(),
end = d->allCookies.end();
for ( ; it != end; ++it)
// does this cookie already exist?
if (cookie.name() == it->name() &&
cookie.domain() == it->domain() &&
cookie.path() == it->path()) {
// found a match
d->allCookies.erase(it);
break;
}
// did not find a match
if (!isDeletion) {
d->allCookies += cookie;
++added;
}
cookie.normalize(url);
if (validateCookie(cookie, url) && insertCookie(cookie))
added = true;
}
return (added > 0);
return added;
}
/*!
@ -304,4 +249,81 @@ QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(const QUrl &url) const
return result;
}
/*!
Adds \a cookie to this cookie jar.
Returns true if \a cookie was added, false otherwise.
If a cookie with the same identifier already exists in the
cookie jar, it will be overridden.
*/
bool QNetworkCookieJar::insertCookie(const QNetworkCookie &cookie)
{
Q_D(QNetworkCookieJar);
QDateTime now = QDateTime::currentDateTime();
bool isDeletion = !cookie.isSessionCookie() &&
cookie.expirationDate() < now;
deleteCookie(cookie);
if (!isDeletion) {
d->allCookies += cookie;
return true;
}
return false;
}
/*!
If a cookie with the same identifier as \a cookie exists in this cookie jar
it will be updated. This function uses insertCookie().
Returns true if \a cookie was updated, false if no cookie in the jar matches
the identifier of \a cookie.
\sa QNetworkCookie::hasSameIdentifier()
*/
bool QNetworkCookieJar::updateCookie(const QNetworkCookie &cookie)
{
if (deleteCookie(cookie))
return insertCookie(cookie);
return false;
}
/*!
Deletes from cookie jar the cookie found to have the same identifier as \a cookie.
Returns true if a cookie was deleted, false otherwise.
\sa QNetworkCookie::hasSameIdentifier()
*/
bool QNetworkCookieJar::deleteCookie(const QNetworkCookie &cookie)
{
Q_D(QNetworkCookieJar);
QList<QNetworkCookie>::Iterator it;
for (it = d->allCookies.begin(); it != d->allCookies.end(); it++)
if (it->hasSameIdentifier(cookie)) {
d->allCookies.erase(it);
return true;
}
return false;
}
/*!
Returns true if the domain and path of \a cookie are valid, false otherwise.
*/
bool QNetworkCookieJar::validateCookie(const QNetworkCookie &cookie, const QUrl &url) const
{
QString domain = cookie.domain();
if (!(isParentDomain(domain, url.host()) || isParentDomain(url.host(), domain)))
return false; // not accepted
// the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
// redundant; the "leading dot" rule has been relaxed anyway, see QNetworkCookie::normalize()
// we remove the leading dot for this check if it's present
if (qIsEffectiveTLD(domain.startsWith('.') ? domain.remove(0, 1) : domain))
return false; // not accepted
return true;
}
QT_END_NAMESPACE

View File

@ -63,9 +63,14 @@ public:
virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
virtual bool insertCookie(const QNetworkCookie &cookie);
virtual bool updateCookie(const QNetworkCookie &cookie);
virtual bool deleteCookie(const QNetworkCookie &cookie);
protected:
QList<QNetworkCookie> allCookies() const;
void setAllCookies(const QList<QNetworkCookie> &cookieList);
virtual bool validateCookie(const QNetworkCookie &cookie, const QUrl &url) const;
private:
Q_DECLARE_PRIVATE(QNetworkCookieJar)