From ed429ebfc9920c3a0fc97170ff8df6d5520eefb9 Mon Sep 17 00:00:00 2001 From: "Jonas M. Gastal" Date: Wed, 11 Jan 2012 17:00:11 -0200 Subject: 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 Reviewed-by: Alexis Menard Reviewed-by: Lars Knoll Reviewed-by: Shane Kearns --- src/network/access/qnetworkcookie.cpp | 37 +++++++- src/network/access/qnetworkcookie.h | 3 + src/network/access/qnetworkcookiejar.cpp | 146 ++++++++++++++++++------------- src/network/access/qnetworkcookiejar.h | 5 ++ 4 files changed, 128 insertions(+), 63 deletions(-) diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index df7920de40..38e2ef093c 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -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 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) { diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h index ff68797702..b6dc4e62d0 100644 --- a/src/network/access/qnetworkcookie.h +++ b/src/network/access/qnetworkcookie.h @@ -97,6 +97,9 @@ public: QByteArray toRawForm(RawForm form = Full) const; + bool hasSameIdentifier(const QNetworkCookie &other) const; + void normalize(const QUrl &url); + static QList parseCookies(const QByteArray &cookieString); private: diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp index 7d3f67cc6e..a49c5d7c10 100644 --- a/src/network/access/qnetworkcookiejar.cpp +++ b/src/network/access/qnetworkcookiejar.cpp @@ -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 &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::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 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::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 diff --git a/src/network/access/qnetworkcookiejar.h b/src/network/access/qnetworkcookiejar.h index 5f30f62179..3ae906c978 100644 --- a/src/network/access/qnetworkcookiejar.h +++ b/src/network/access/qnetworkcookiejar.h @@ -63,9 +63,14 @@ public: virtual QList cookiesForUrl(const QUrl &url) const; virtual bool setCookiesFromUrl(const QList &cookieList, const QUrl &url); + virtual bool insertCookie(const QNetworkCookie &cookie); + virtual bool updateCookie(const QNetworkCookie &cookie); + virtual bool deleteCookie(const QNetworkCookie &cookie); + protected: QList allCookies() const; void setAllCookies(const QList &cookieList); + virtual bool validateCookie(const QNetworkCookie &cookie, const QUrl &url) const; private: Q_DECLARE_PRIVATE(QNetworkCookieJar) -- cgit v1.2.3