Gives QNetworkCookieJar a virtual API.
authorJonas M. Gastal <jgastal@profusion.mobi>
Wed, 11 Jan 2012 19:00:11 +0000 (17:00 -0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 27 Jan 2012 12:29:14 +0000 (13:29 +0100)
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>
src/network/access/qnetworkcookie.cpp
src/network/access/qnetworkcookie.h
src/network/access/qnetworkcookiejar.cpp
src/network/access/qnetworkcookiejar.h

index df7920d..38e2ef0 100644 (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
 {
@@ -172,6 +172,17 @@ bool QNetworkCookie::operator==(const QNetworkCookie &other) const
 }
 
 /*!
+    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)
 {
index ff68797..b6dc4e6 100644 (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:
index 7d3f67c..a49c5d7 100644 (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
index 5f30f62..3ae906c 100644 (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)