[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-10851-g50815da

jocelyn.turcotte at nokia.com jocelyn.turcotte at nokia.com
Wed Dec 22 18:23:21 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 38910f316b15980368d414490a5194c5a145f0b0
Author: jocelyn.turcotte at nokia.com <jocelyn.turcotte at nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Dec 10 10:50:05 2010 +0000

    2010-12-10  Jocelyn Turcotte  <jocelyn.turcotte at nokia.com>
    
            Reviewed by Kenneth Rohde Christiansen.
    
            [Qt] Support a QNetworkAccessManager affined to a different thread.
            https://bugs.webkit.org/show_bug.cgi?id=50080
    
            This patch introduce thread safe proxy classes for QNetworkAccessManager
            and QNetworkReply.
            If run in the same thread, these objects will forward the calls with
            Qt::DirectConnection bindings, while in the other case they will use
            Qt::QueuedConnection to carry requests accross threads.
    
            This patch basically:
            - Makes sure that all access goes through these objects
            - Reorders signal connections to make sure we are connected when the
              signal comes
            - Makes sure that no QObject in the WebCore thread is a child of the
              reply which might be in a different thread.
            - Forward the data directly in QByteArrays in signals instead of collecting
              the data when the signal is handled.
    
            New test: tst_QWebPage::networkAccessManagerOnDifferentThread
    
            * WebCore.pro:
            * platform/graphics/qt/MediaPlayerPrivateQt.cpp:
            (WebCore::MediaPlayerPrivateQt::commitLoad):
            * platform/network/qt/QNetworkReplyHandler.cpp:
            (WebCore::FormDataIODevice::FormDataIODevice):
            (WebCore::QNetworkReplyHandler::QNetworkReplyHandler):
            (WebCore::QNetworkReplyHandler::~QNetworkReplyHandler):
            (WebCore::QNetworkReplyHandler::setLoadMode):
            (WebCore::QNetworkReplyHandler::abort):
            (WebCore::QNetworkReplyHandler::release):
            (WebCore::ignoreHttpError):
            (WebCore::QNetworkReplyHandler::finish):
            (WebCore::QNetworkReplyHandler::sendResponseIfNeeded):
            (WebCore::QNetworkReplyHandler::forwardData):
            (WebCore::QNetworkReplyHandler::start):
            (WebCore::QNetworkReplyHandler::sendQueuedItems):
            * platform/network/qt/QNetworkReplyHandler.h:
            * platform/network/qt/QtNAMThreadSafeProxy.cpp: Added.
            * platform/network/qt/QtNAMThreadSafeProxy.h: Added.
            * platform/network/qt/ResourceHandleQt.cpp:
            (WebCore::ResourceHandle::willLoadFromCache):
            * platform/qt/CookieJarQt.cpp:
            (WebCore::networkAccessManager):
            (WebCore::setCookies):
            (WebCore::cookies):
            (WebCore::cookieRequestHeaderFieldValue):
            (WebCore::cookiesEnabled):
    2010-12-10  Jocelyn Turcotte  <jocelyn.turcotte at nokia.com>
    
            Reviewed by Kenneth Rohde Christiansen.
    
            [Qt] Support a QNetworkAccessManager affined to a different thread.
            https://bugs.webkit.org/show_bug.cgi?id=50080
    
            This patch introduce thread safe proxy classes for QNetworkAccessManager
            and QNetworkReply.
            If run in the same thread, these objects will forward the calls with
            Qt::DirectConnection bindings, while in the other case they will use
            Qt::QueuedConnection to carry requests accross threads.
    
            This patch basically:
            - Makes sure that all access goes through these objects
            - Reorders signal connections to make sure we are connected when the
              signal comes
            - Makes sure that no QObject in the WebCore thread is a child of the
              reply which might be in a different thread.
            - Forward the data directly in QByteArrays in signals instead of collecting
              the data when the signal is handled.
    
            New test: tst_QWebPage::networkAccessManagerOnDifferentThread
    
            * WebCoreSupport/FrameLoaderClientQt.cpp:
            (WebCore::FrameLoaderClientQt::download):
            * tests/qwebpage/tst_qwebpage.cpp:
            (QtNAMThread::QtNAMThread):
            (QtNAMThread::~QtNAMThread):
            (QtNAMThread::networkAccessManager):
            (QtNAMThread::run):
            (tst_QWebPage::networkAccessManagerOnDifferentThread):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@73710 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index d19a814..c31c9e7 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,55 @@
+2010-12-10  Jocelyn Turcotte  <jocelyn.turcotte at nokia.com>
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        [Qt] Support a QNetworkAccessManager affined to a different thread.
+        https://bugs.webkit.org/show_bug.cgi?id=50080
+
+        This patch introduce thread safe proxy classes for QNetworkAccessManager
+        and QNetworkReply.
+        If run in the same thread, these objects will forward the calls with
+        Qt::DirectConnection bindings, while in the other case they will use
+        Qt::QueuedConnection to carry requests accross threads.
+
+        This patch basically:
+        - Makes sure that all access goes through these objects
+        - Reorders signal connections to make sure we are connected when the
+          signal comes
+        - Makes sure that no QObject in the WebCore thread is a child of the
+          reply which might be in a different thread.
+        - Forward the data directly in QByteArrays in signals instead of collecting
+          the data when the signal is handled.
+
+        New test: tst_QWebPage::networkAccessManagerOnDifferentThread
+
+        * WebCore.pro:
+        * platform/graphics/qt/MediaPlayerPrivateQt.cpp:
+        (WebCore::MediaPlayerPrivateQt::commitLoad):
+        * platform/network/qt/QNetworkReplyHandler.cpp:
+        (WebCore::FormDataIODevice::FormDataIODevice):
+        (WebCore::QNetworkReplyHandler::QNetworkReplyHandler):
+        (WebCore::QNetworkReplyHandler::~QNetworkReplyHandler):
+        (WebCore::QNetworkReplyHandler::setLoadMode):
+        (WebCore::QNetworkReplyHandler::abort):
+        (WebCore::QNetworkReplyHandler::release):
+        (WebCore::ignoreHttpError):
+        (WebCore::QNetworkReplyHandler::finish):
+        (WebCore::QNetworkReplyHandler::sendResponseIfNeeded):
+        (WebCore::QNetworkReplyHandler::forwardData):
+        (WebCore::QNetworkReplyHandler::start):
+        (WebCore::QNetworkReplyHandler::sendQueuedItems):
+        * platform/network/qt/QNetworkReplyHandler.h:
+        * platform/network/qt/QtNAMThreadSafeProxy.cpp: Added.
+        * platform/network/qt/QtNAMThreadSafeProxy.h: Added.
+        * platform/network/qt/ResourceHandleQt.cpp:
+        (WebCore::ResourceHandle::willLoadFromCache):
+        * platform/qt/CookieJarQt.cpp:
+        (WebCore::networkAccessManager):
+        (WebCore::setCookies):
+        (WebCore::cookies):
+        (WebCore::cookieRequestHeaderFieldValue):
+        (WebCore::cookiesEnabled):
+
 2010-12-09  Jocelyn Turcotte  <jocelyn.turcotte at nokia.com>
 
         Reviewed by Kenneth Rohde Christiansen.
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 5f394ed..cc9194c 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -2159,6 +2159,7 @@ HEADERS += \
     platform/network/NetworkStateNotifier.h \
     platform/network/ProtectionSpace.h \
     platform/network/ProxyServer.h \
+    platform/network/qt/QtNAMThreadSafeProxy.h \
     platform/network/qt/QNetworkReplyHandler.h \
     platform/network/ResourceErrorBase.h \
     platform/network/ResourceHandle.h \
@@ -2684,6 +2685,7 @@ SOURCES += \
     platform/network/qt/ResourceHandleQt.cpp \
     platform/network/qt/ResourceRequestQt.cpp \
     platform/network/qt/DnsPrefetchHelper.cpp \
+    platform/network/qt/QtNAMThreadSafeProxy.cpp \
     platform/network/qt/ProxyServerQt.cpp \
     platform/network/qt/QNetworkReplyHandler.cpp \
     editing/qt/EditorQt.cpp \
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
index 962c931..dd4b6e6 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -25,6 +25,7 @@
 #include "GraphicsContext.h"
 #include "HTMLMediaElement.h"
 #include "HTMLVideoElement.h"
+#include "QtNAMThreadSafeProxy.h"
 #include "NetworkingContext.h"
 #include "NotImplemented.h"
 #include "RenderVideo.h"
@@ -209,8 +210,8 @@ void MediaPlayerPrivateQt::commitLoad(const String& url)
 
         if (document && manager) {
             // Set the cookies
-            QNetworkCookieJar* jar = manager->cookieJar();
-            QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl);
+            QtNAMThreadSafeProxy managerProxy(manager);
+            QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(rUrl);
 
             // Don't set the header if there are no cookies.
             // This prevents a warning from being emitted.
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
index 8bb0f85..2ff7d9c 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
@@ -23,6 +23,7 @@
 
 #include "HTTPParsers.h"
 #include "MIMETypeRegistry.h"
+#include "QtNAMThreadSafeProxy.h"
 #include "ResourceHandle.h"
 #include "ResourceHandleClient.h"
 #include "ResourceHandleInternal.h"
@@ -46,7 +47,7 @@
 // It is fixed in Qt 4.6.3. See https://bugs.webkit.org/show_bug.cgi?id=32113
 // and https://bugs.webkit.org/show_bug.cgi?id=36755
 #if QT_VERSION > QT_VERSION_CHECK(4, 6, 2)
-#define SIGNAL_CONN Qt::DirectConnection
+#define SIGNAL_CONN Qt::AutoConnection
 #else
 #define SIGNAL_CONN Qt::QueuedConnection
 #endif
@@ -56,8 +57,9 @@ static const int gMaxRecursionLimit = 10;
 namespace WebCore {
 
 // Take a deep copy of the FormDataElement
-FormDataIODevice::FormDataIODevice(FormData* data)
-    : m_formElements(data ? data->elements() : Vector<FormDataElement>())
+FormDataIODevice::FormDataIODevice(FormData* data, QObject* parent)
+    : QIODevice(parent)
+    , m_formElements(data ? data->elements() : Vector<FormDataElement>())
     , m_currentFile(0)
     , m_currentDelta(0)
     , m_fileSize(0)
@@ -192,6 +194,9 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load
     , m_shouldForwardData(false)
     , m_redirectionTries(gMaxRecursionLimit)
 {
+    // Make this a direct function call once we require 4.6.1+.
+    connect(this, SIGNAL(processQueuedItems()), this, SLOT(sendQueuedItems()), SIGNAL_CONN);
+
     const ResourceRequest &r = m_resourceHandle->firstRequest();
 
     if (r.httpMethod() == "GET")
@@ -222,6 +227,12 @@ QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode load
         start();
 }
 
+QNetworkReplyHandler::~QNetworkReplyHandler()
+{
+    if (m_reply)
+        m_reply->deleteLater();
+}
+
 void QNetworkReplyHandler::setLoadMode(LoadMode mode)
 {
     // https://bugs.webkit.org/show_bug.cgi?id=26556
@@ -231,9 +242,13 @@ void QNetworkReplyHandler::setLoadMode(LoadMode mode)
     case LoadNormal:
         m_loadMode = LoadResuming;
         emit processQueuedItems();
+        // Restart forwarding only after processQueuedItems to make sure
+        // our buffered data was handled before any incoming data.
+        m_reply->setForwardingDefered(false);
         break;
     case LoadDeferred:
         m_loadMode = LoadDeferred;
+        m_reply->setForwardingDefered(true);
         break;
     case LoadResuming:
         Q_ASSERT(0); // should never happen
@@ -245,31 +260,30 @@ void QNetworkReplyHandler::abort()
 {
     m_resourceHandle = 0;
     if (m_reply) {
-        QNetworkReply* reply = release();
+        QtNetworkReplyThreadSafeProxy* reply = release();
         reply->abort();
         reply->deleteLater();
     }
     deleteLater();
 }
 
-QNetworkReply* QNetworkReplyHandler::release()
+QtNetworkReplyThreadSafeProxy* QNetworkReplyHandler::release()
 {
-    QNetworkReply* reply = m_reply;
+    QtNetworkReplyThreadSafeProxy* reply = m_reply;
     if (m_reply) {
         disconnect(m_reply, 0, this, 0);
         // We have queued connections to the QNetworkReply. Make sure any
         // posted meta call events that were the result of a signal emission
         // don't reach the slots in our instance.
         QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
-        m_reply->setParent(0);
         m_reply = 0;
     }
     return reply;
 }
 
-static bool ignoreHttpError(QNetworkReply* reply, bool receivedData)
+static bool ignoreHttpError(QtNetworkReplyThreadSafeProxy* reply, bool receivedData)
 {
-    int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    int httpStatusCode = reply->httpStatusCode();
 
     if (httpStatusCode == 401 || httpStatusCode == 407)
         return true;
@@ -301,14 +315,14 @@ void QNetworkReplyHandler::finish()
     }
 
     if (!m_redirected) {
-        if (!m_reply->error() || ignoreHttpError(m_reply, m_responseContainsData)) {
+        if (!m_reply->error() || ignoreHttpError(m_reply, m_responseContainsData))
             client->didFinishLoading(m_resourceHandle, 0);
-        } else {
+        else {
             QUrl url = m_reply->url();
-            int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+            int httpStatusCode = m_reply->httpStatusCode();
 
             if (httpStatusCode) {
-                ResourceError error("HTTP", httpStatusCode, url.toString(), m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
+                ResourceError error("HTTP", httpStatusCode, url.toString(), QString::fromAscii(m_reply->httpReasonPhrase()));
                 client->didFail(m_resourceHandle, error);
             } else {
                 ResourceError error("QtNetwork", m_reply->error(), url.toString(), m_reply->errorString());
@@ -346,7 +360,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
     if (!client)
         return;
 
-    WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
+    WTF::String contentType = m_reply->contentTypeHeader();
     WTF::String encoding = extractCharsetFromMediaType(contentType);
     WTF::String mimeType = extractMIMETypeFromMediaType(contentType);
 
@@ -357,7 +371,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
 
     KURL url(m_reply->url());
     ResourceResponse response(url, mimeType.lower(),
-                              m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(),
+                              m_reply->contentLengthHeader(),
                               encoding, String());
 
     if (url.isLocalFile()) {
@@ -366,10 +380,10 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
     }
 
     // The status code is equal to 0 for protocols not in the HTTP family.
-    int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    int statusCode = m_reply->httpStatusCode();
 
     if (url.protocolInHTTPFamily()) {
-        String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition")));
+        String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->contentDispositionHeader()));
 
         if (!suggestedFilename.isEmpty())
             response.setSuggestedFilename(suggestedFilename);
@@ -377,21 +391,15 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
             response.setSuggestedFilename(url.lastPathComponent());
 
         response.setHTTPStatusCode(statusCode);
-        response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData());
+        response.setHTTPStatusText(m_reply->httpReasonPhrase().constData());
 
         // Add remaining headers.
-#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
-        foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) {
+        foreach (const QtNetworkReplyThreadSafeProxy::RawHeaderPair& pair, m_reply->rawHeaderPairs()) {
             response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second));
         }
-#else
-        foreach (const QByteArray& headerName, m_reply->rawHeaderList()) {
-            response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName)));
-        }
-#endif
     }
 
-    QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+    QUrl redirection = m_reply->redirectionTarget();
     if (redirection.isValid()) {
         QUrl newUrl = m_reply->url().resolved(redirection);
 
@@ -436,13 +444,15 @@ void QNetworkReplyHandler::sendResponseIfNeeded()
     client->didReceiveResponse(m_resourceHandle, response);
 }
 
-void QNetworkReplyHandler::forwardData()
+void QNetworkReplyHandler::forwardData(const QByteArray &data)
 {
     m_shouldForwardData = (m_loadMode != LoadNormal);
-    if (m_shouldForwardData)
+    if (m_shouldForwardData) {
+        m_bufferedData += data;
         return;
+    }
 
-    if (m_reply->bytesAvailable())
+    if (!data.isEmpty())
         m_responseContainsData = true;
 
     sendResponseIfNeeded();
@@ -454,8 +464,6 @@ void QNetworkReplyHandler::forwardData()
     if (!m_resourceHandle)
         return;
 
-    QByteArray data = m_reply->read(m_reply->bytesAvailable());
-
     ResourceHandleClient* client = m_resourceHandle->client();
     if (!client)
         return;
@@ -498,41 +506,53 @@ void QNetworkReplyHandler::start()
         && (!url.toLocalFile().isEmpty() || url.scheme() == QLatin1String("data")))
         m_method = QNetworkAccessManager::GetOperation;
 
+    m_reply = new QtNetworkReplyThreadSafeProxy(manager);
+    connect(m_reply, SIGNAL(finished()), this, SLOT(finish()), SIGNAL_CONN);
+
+    // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
+    // can send the response as early as possible
+    if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
+        connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(sendResponseIfNeeded()), SIGNAL_CONN);
+
+    connect(m_reply, SIGNAL(dataReceived(const QByteArray&)), this, SLOT(forwardData(const QByteArray&)), SIGNAL_CONN);
+
+    if (m_resourceHandle->firstRequest().reportUploadProgress())
+        connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN);
+
     switch (m_method) {
         case QNetworkAccessManager::GetOperation:
-            m_reply = manager->get(m_request);
+            m_reply->get(m_request);
             break;
         case QNetworkAccessManager::PostOperation: {
-            FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); 
+            FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this);
             // We may be uploading files so prevent QNR from buffering data
             m_request.setHeader(QNetworkRequest::ContentLengthHeader, postDevice->getFormDataSize());
             m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
-            m_reply = manager->post(m_request, postDevice);
-            postDevice->setParent(m_reply);
+            m_reply->post(m_request, postDevice);
             break;
         }
         case QNetworkAccessManager::HeadOperation:
-            m_reply = manager->head(m_request);
+            m_reply->head(m_request);
             break;
         case QNetworkAccessManager::PutOperation: {
-            FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody()); 
+            FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this);
             // We may be uploading files so prevent QNR from buffering data
             m_request.setHeader(QNetworkRequest::ContentLengthHeader, putDevice->getFormDataSize());
             m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
-            m_reply = manager->put(m_request, putDevice);
-            putDevice->setParent(m_reply);
+            m_reply->put(m_request, putDevice);
             break;
         }
         case QNetworkAccessManager::DeleteOperation: {
-            m_reply = manager->deleteResource(m_request);
+            m_reply->deleteResource(m_request);
             break;
         }
 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
         case QNetworkAccessManager::CustomOperation:
-            m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
+            m_reply->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
             break;
 #endif
         case QNetworkAccessManager::UnknownOperation: {
+            m_reply->deleteLater();
             m_reply = 0;
             ResourceHandleClient* client = m_resourceHandle->client();
             if (client) {
@@ -544,29 +564,6 @@ void QNetworkReplyHandler::start()
             return;
         }
     }
-
-    m_reply->setParent(this);
-
-    connect(m_reply, SIGNAL(finished()),
-            this, SLOT(finish()), SIGNAL_CONN);
-
-    // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
-    // can send the response as early as possible
-    if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
-        connect(m_reply, SIGNAL(metaDataChanged()),
-                this, SLOT(sendResponseIfNeeded()), SIGNAL_CONN);
-
-    connect(m_reply, SIGNAL(readyRead()),
-            this, SLOT(forwardData()), SIGNAL_CONN);
-
-    if (m_resourceHandle->firstRequest().reportUploadProgress()) {
-        connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)),
-                this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN);
-    }
-
-    // Make this a direct function call once we require 4.6.1+.
-    connect(this, SIGNAL(processQueuedItems()),
-            this, SLOT(sendQueuedItems()), SIGNAL_CONN);
 }
 
 void QNetworkReplyHandler::resetState()
@@ -592,8 +589,10 @@ void QNetworkReplyHandler::sendQueuedItems()
     if (m_shouldSendResponse)
         sendResponseIfNeeded();
 
-    if (m_shouldForwardData)
-        forwardData();
+    if (m_shouldForwardData) {
+        forwardData(m_bufferedData);
+        m_bufferedData.clear();
+    }
 
     if (m_shouldFinish)
         finish(); 
diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h
index 190f59f..11638b3 100644
--- a/WebCore/platform/network/qt/QNetworkReplyHandler.h
+++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h
@@ -23,6 +23,7 @@
 
 #include <QNetworkRequest>
 #include <QNetworkAccessManager>
+#include <QNetworkReply>
 
 #include "FormData.h"
 
@@ -34,6 +35,7 @@ QT_END_NAMESPACE
 namespace WebCore {
 
 class ResourceHandle;
+class QtNetworkReplyThreadSafeProxy;
 
 class QNetworkReplyHandler : public QObject
 {
@@ -46,13 +48,12 @@ public:
     };
 
     QNetworkReplyHandler(ResourceHandle *handle, LoadMode);
+    ~QNetworkReplyHandler();
     void setLoadMode(LoadMode);
 
-    QNetworkReply* reply() const { return m_reply; }
-
     void abort();
 
-    QNetworkReply* release();
+    QtNetworkReplyThreadSafeProxy* release();
 
 signals:
     void processQueuedItems();
@@ -60,7 +61,7 @@ signals:
 private slots:
     void finish();
     void sendResponseIfNeeded();
-    void forwardData();
+    void forwardData(const QByteArray &data);
     void sendQueuedItems();
     void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
 
@@ -69,7 +70,7 @@ private:
     void resetState();
     String httpMethod() const;
 
-    QNetworkReply* m_reply;
+    QtNetworkReplyThreadSafeProxy* m_reply;
     ResourceHandle* m_resourceHandle;
     bool m_redirected;
     bool m_responseSent;
@@ -84,6 +85,7 @@ private:
     bool m_shouldSendResponse;
     bool m_shouldForwardData;
     int m_redirectionTries;
+    QByteArray m_bufferedData;
 };
 
 // Self destructing QIODevice for FormData
@@ -94,7 +96,7 @@ private:
 class FormDataIODevice : public QIODevice {
     Q_OBJECT
 public:
-    FormDataIODevice(FormData*);
+    FormDataIODevice(FormData*, QObject* parent = 0);
     ~FormDataIODevice();
 
     bool isSequential() const;
diff --git a/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp
new file mode 100644
index 0000000..125fef8
--- /dev/null
+++ b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.cpp
@@ -0,0 +1,188 @@
+/*
+    Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+#include "config.h"
+#include "QtNAMThreadSafeProxy.h"
+
+#include "Assertions.h"
+#include <QAbstractNetworkCache>
+#include <QNetworkAccessManager>
+#include <QNetworkCookieJar>
+#include <QStringList>
+
+// Use unused variables to be able to call qRegisterMetaType statically.
+static int dummyStaticVar1 = qRegisterMetaType<QFutureInterface<bool> >("QFutureInterface<bool>");
+static int dummyStaticVar2 = qRegisterMetaType<QFutureInterface<QList<QNetworkCookie> > >("QFutureInterface<QList<QNetworkCookie> >");
+
+namespace WebCore {
+
+QtNAMThreadSafeProxy::QtNAMThreadSafeProxy(QNetworkAccessManager *manager)
+    : m_manager(manager)
+{
+    moveToThread(manager->thread());
+
+    connect(this, SIGNAL(localSetCookiesRequested(const QUrl&, const QString&)), SLOT(localSetCookies(const QUrl&, const QString&)));
+    connect(this, SIGNAL(localCookiesForUrlRequested(QFutureInterface<QList<QNetworkCookie> >, const QUrl&)), SLOT(localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> >, const QUrl&)));
+    connect(this, SIGNAL(localWillLoadFromCacheRequested(QFutureInterface<bool>, const QUrl&)), SLOT(localWillLoadFromCache(QFutureInterface<bool>, const QUrl&)));
+}
+
+void QtNAMThreadSafeProxy::localSetCookies(const QUrl& url, const QString& cookies)
+{
+    QList<QNetworkCookie> cookieList = QNetworkCookie::parseCookies(cookies.toAscii());
+    QList<QNetworkCookie>::Iterator it = cookieList.begin();
+    while (it != cookieList.end()) {
+        if (it->isHttpOnly())
+            it = cookieList.erase(it);
+        else
+            ++it;
+    }
+    m_manager->cookieJar()->setCookiesFromUrl(cookieList, url);
+}
+
+void QtNAMThreadSafeProxy::localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url)
+{
+    fi.reportResult(m_manager->cookieJar()->cookiesForUrl(url));
+    fi.reportFinished();
+}
+
+void QtNAMThreadSafeProxy::localWillLoadFromCache(QFutureInterface<bool> fi, const QUrl& url)
+{
+    bool retVal = false;
+    if (m_manager->cache())
+        retVal = m_manager->cache()->metaData(url).isValid();
+
+    fi.reportFinished(&retVal);
+}
+
+QtNetworkReplyThreadSafeProxy::QtNetworkReplyThreadSafeProxy(QNetworkAccessManager *manager)
+    : m_manager(manager)
+    , m_reply(0)
+    , m_forwardingDefered(false)
+    , m_contentLengthHeader(0)
+    , m_error(QNetworkReply::NoError)
+    , m_httpStatusCode(0)
+{
+    moveToThread(manager->thread());
+
+    // This might be unnecessarily heavy to do for each request while we could have the same wrapper for the manager instead
+    connect(this, SIGNAL(localGetRequested(const QNetworkRequest&)), SLOT(localGet(const QNetworkRequest&)));
+    connect(this, SIGNAL(localPostRequested(const QNetworkRequest&, QIODevice*)), SLOT(localPost(const QNetworkRequest&, QIODevice*)));
+    connect(this, SIGNAL(localHeadRequested(const QNetworkRequest&)), SLOT(localHead(const QNetworkRequest&)));
+    connect(this, SIGNAL(localPutRequested(const QNetworkRequest&, QIODevice*)), SLOT(localPut(const QNetworkRequest&, QIODevice*)));
+    connect(this, SIGNAL(localDeleteResourceRequested(const QNetworkRequest&)), SLOT(localDeleteResource(const QNetworkRequest&)));
+    connect(this, SIGNAL(localCustomRequestRequested(const QNetworkRequest&, const QByteArray&)), SLOT(localCustomRequest(const QNetworkRequest&, const QByteArray&)));
+    connect(this, SIGNAL(localAbortRequested()), SLOT(localAbort()));
+    connect(this, SIGNAL(localSetForwardingDeferedRequested(bool)), SLOT(localSetForwardingDefered(bool)));
+}
+
+QtNetworkReplyThreadSafeProxy::~QtNetworkReplyThreadSafeProxy()
+{
+    delete m_reply;
+}
+
+void QtNetworkReplyThreadSafeProxy::localGet(const QNetworkRequest& request)
+{
+    localSetReply(m_manager->get(request));
+}
+
+void QtNetworkReplyThreadSafeProxy::localPost(const QNetworkRequest& request, QIODevice* data)
+{
+    localSetReply(m_manager->post(request, data));
+}
+
+void QtNetworkReplyThreadSafeProxy::localHead(const QNetworkRequest& request)
+{
+    localSetReply(m_manager->head(request));
+}
+
+void QtNetworkReplyThreadSafeProxy::localPut(const QNetworkRequest& request, QIODevice* data)
+{
+    localSetReply(m_manager->put(request, data));
+}
+
+void QtNetworkReplyThreadSafeProxy::localDeleteResource(const QNetworkRequest& request)
+{
+    localSetReply(m_manager->deleteResource(request));
+}
+
+void QtNetworkReplyThreadSafeProxy::localCustomRequest(const QNetworkRequest& request, const QByteArray& verb)
+{
+    localSetReply(m_manager->sendCustomRequest(request, verb));
+}
+
+void QtNetworkReplyThreadSafeProxy::localAbort()
+{
+    if (m_reply)
+        m_reply->abort();
+}
+
+void QtNetworkReplyThreadSafeProxy::localForwardData()
+{
+    if (m_reply->bytesAvailable()) {
+        QByteArray data = m_reply->read(m_reply->bytesAvailable());
+        emit dataReceived(data);
+    }
+}
+
+void QtNetworkReplyThreadSafeProxy::localSetForwardingDefered(bool forwardingDefered)
+{
+    if (m_forwardingDefered && !forwardingDefered)
+        localForwardData();
+    m_forwardingDefered = forwardingDefered;
+}
+
+void QtNetworkReplyThreadSafeProxy::localMirrorMembers()
+{
+    ASSERT(m_reply);
+    QMutexLocker lock(&m_mirroredMembersMutex);
+
+    m_contentDispositionHeader = m_reply->rawHeader("Content-Disposition");
+    m_contentLengthHeader = m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
+    m_contentTypeHeader = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
+    m_error = m_reply->error();
+    m_errorString = m_reply->errorString();
+    m_httpReasonPhrase = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray();
+    m_httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    m_url = m_reply->url();
+    m_redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+    m_rawHeaderPairs = m_reply->rawHeaderPairs();
+#else
+    m_rawHeaderPairs.clear();
+    foreach (const QByteArray& headerName, m_reply->rawHeaderList())
+        m_rawHeaderPairs.append(RawHeaderPair(headerName, m_reply->rawHeader(headerName)));
+#endif
+}
+
+void QtNetworkReplyThreadSafeProxy::localSetReply(QNetworkReply *reply)
+{
+    ASSERT(!m_reply);
+    m_reply = reply;
+    m_reply->setParent(0);
+    connect(m_reply, SIGNAL(readyRead()), this, SLOT(localForwardData()));
+    // Make sure localMirrorMembers() is called before the outward signal
+    connect(m_reply, SIGNAL(finished()), this, SLOT(localMirrorMembers()), Qt::DirectConnection);
+    connect(m_reply, SIGNAL(finished()), this, SIGNAL(finished()));
+    // Make sure localMirrorMembers() is called before the outward signal
+    connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(localMirrorMembers()), Qt::DirectConnection);
+    connect(m_reply, SIGNAL(metaDataChanged()), this, SIGNAL(metaDataChanged()));
+    connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));
+}
+
+
+}
diff --git a/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h
new file mode 100644
index 0000000..8a757f4
--- /dev/null
+++ b/WebCore/platform/network/qt/QtNAMThreadSafeProxy.h
@@ -0,0 +1,184 @@
+/*
+    Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+#ifndef QtNAMThreadSafeProxy_h
+#define QtNAMThreadSafeProxy_h
+
+#include <QFuture>
+#include <QMutex>
+#include <QNetworkCookie>
+#include <QNetworkReply>
+#include <QObject>
+
+class QNetworkAccessManager;
+class QNetworkRequest;
+class QUrl;
+
+namespace WebCore {
+
+class QtNAMThreadSafeProxy : public QObject {
+    Q_OBJECT
+public:
+    QtNAMThreadSafeProxy(QNetworkAccessManager *manager);
+
+    void setCookies(const QUrl& url, const QString& cookies)
+    {
+        emit localSetCookiesRequested(url, cookies);
+    }
+
+    QFuture<QList<QNetworkCookie> > cookiesForUrl(const QUrl& url)
+    {
+        QFutureInterface<QList<QNetworkCookie> > fi;
+        fi.reportStarted();
+        emit localCookiesForUrlRequested(fi, url);
+        return fi.future();
+    }
+
+    QFuture<bool> willLoadFromCache(const QUrl& url)
+    {
+        QFutureInterface<bool> fi;
+        fi.reportStarted();
+        emit localWillLoadFromCacheRequested(fi, url);
+        return fi.future();
+    }
+
+signals:
+    void localSetCookiesRequested(const QUrl& url, const QString& cookies);
+    void localCookiesForUrlRequested(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url);
+    void localWillLoadFromCacheRequested(QFutureInterface<bool> fi, const QUrl& url);
+
+private slots:
+    void localSetCookies(const QUrl& url, const QString& cookies);
+    void localCookiesForUrl(QFutureInterface<QList<QNetworkCookie> > fi, const QUrl& url);
+    void localWillLoadFromCache(QFutureInterface<bool> fi, const QUrl& url);
+
+private:
+    QNetworkAccessManager* m_manager;
+};
+
+
+class QtNetworkReplyThreadSafeProxy : public QObject {
+    Q_OBJECT
+public:
+    typedef QPair<QByteArray, QByteArray> RawHeaderPair;
+    QtNetworkReplyThreadSafeProxy(QNetworkAccessManager *manager);
+    ~QtNetworkReplyThreadSafeProxy();
+    void abort()
+    {
+        emit localAbortRequested();
+    }
+    void setForwardingDefered(bool forwardingDefered)
+    {
+        emit localSetForwardingDeferedRequested(forwardingDefered);
+    }
+
+    QByteArray contentDispositionHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentDispositionHeader; }
+    qlonglong contentLengthHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentLengthHeader; }
+    QString contentTypeHeader() { QMutexLocker lock(&m_mirroredMembersMutex); return m_contentTypeHeader; }
+    QNetworkReply::NetworkError error() { QMutexLocker lock(&m_mirroredMembersMutex); return m_error; }
+    QString errorString() { QMutexLocker lock(&m_mirroredMembersMutex); return m_errorString; }
+    QByteArray httpReasonPhrase() { QMutexLocker lock(&m_mirroredMembersMutex); return m_httpReasonPhrase; }
+    int httpStatusCode() { QMutexLocker lock(&m_mirroredMembersMutex); return m_httpStatusCode; }
+    QUrl url() { QMutexLocker lock(&m_mirroredMembersMutex); return m_url; }
+    QUrl redirectionTarget() { QMutexLocker lock(&m_mirroredMembersMutex); return m_redirectionTarget; }
+    QList<RawHeaderPair> rawHeaderPairs() { QMutexLocker lock(&m_mirroredMembersMutex); return m_rawHeaderPairs; }
+
+    QNetworkReply* reply()
+    {
+        // Careful, acccessing the reply accross threads might be hazardous to your health
+        return m_reply;
+    }
+public:
+    void get(const QNetworkRequest &request)
+    {
+        emit localGetRequested(request);
+    }
+    void post(const QNetworkRequest &request, QIODevice* data)
+    {
+        emit localPostRequested(request, data);
+    }
+    void head(const QNetworkRequest &request)
+    {
+        emit localHeadRequested(request);
+    }
+    void put(const QNetworkRequest &request, QIODevice* data)
+    {
+        emit localPutRequested(request, data);
+    }
+    void deleteResource(const QNetworkRequest &request)
+    {
+        emit localDeleteResourceRequested(request);
+    }
+    void sendCustomRequest(const QNetworkRequest &request, const QByteArray& verb)
+    {
+        emit localCustomRequestRequested(request, verb);
+    }
+
+signals:
+    void localGetRequested(const QNetworkRequest& request);
+    void localPostRequested(const QNetworkRequest& request, QIODevice* data);
+    void localHeadRequested(const QNetworkRequest& request);
+    void localPutRequested(const QNetworkRequest& request, QIODevice* data);
+    void localDeleteResourceRequested(const QNetworkRequest& request);
+    void localCustomRequestRequested(const QNetworkRequest& request, const QByteArray& verb);
+    void localAbortRequested();
+    void localSetForwardingDeferedRequested(bool forwardingDefered);
+
+    void finished();
+    void readyRead();
+    void metaDataChanged();
+    void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
+    void dataReceived(const QByteArray &data);
+
+private slots:
+    void localGet(const QNetworkRequest& request);
+    void localPost(const QNetworkRequest& request, QIODevice* data);
+    void localHead(const QNetworkRequest& request);
+    void localPut(const QNetworkRequest& request, QIODevice* data);
+    void localDeleteResource(const QNetworkRequest& request);
+    void localCustomRequest(const QNetworkRequest& request, const QByteArray& verb);
+    void localAbort();
+    void localForwardData();
+    void localSetForwardingDefered(bool forwardingDefered);
+    void localMirrorMembers();
+
+private:
+    void localSetReply(QNetworkReply *reply);
+
+    QNetworkAccessManager *m_manager;
+    QNetworkReply *m_reply;
+    bool m_forwardingDefered;
+
+    // Mirrored members
+    QMutex m_mirroredMembersMutex;
+    QByteArray m_contentDispositionHeader;
+    qlonglong m_contentLengthHeader;
+    QString m_contentTypeHeader;
+    QNetworkReply::NetworkError m_error;
+    QString m_errorString;
+    QByteArray m_httpReasonPhrase;
+    int m_httpStatusCode;
+    QUrl m_url;
+    QUrl m_redirectionTarget;
+    QList<RawHeaderPair> m_rawHeaderPairs;
+};
+
+}
+
+
+#endif // QtNAMThreadSafeProxy_h
diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp
index a5ac4c3..f40b828 100644
--- a/WebCore/platform/network/qt/ResourceHandleQt.cpp
+++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp
@@ -35,6 +35,7 @@
 #include "Frame.h"
 #include "FrameNetworkingContext.h"
 #include "FrameLoaderClientQt.h"
+#include "QtNAMThreadSafeProxy.h"
 #include "NotImplemented.h"
 #include "Page.h"
 #include "QNetworkReplyHandler.h"
@@ -156,20 +157,13 @@ bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame* frame)
     if (!frame)
         return false;
 
-    QNetworkAccessManager* manager = 0;
-    QAbstractNetworkCache* cache = 0;
     if (frame->loader()->networkingContext()) {
-        manager = frame->loader()->networkingContext()->networkAccessManager();
-        cache = manager->cache();
-    }
-
-    if (!cache)
-        return false;
-
-    QNetworkCacheMetaData data = cache->metaData(request.url());
-    if (data.isValid()) {
-        request.setCachePolicy(ReturnCacheDataDontLoad);
-        return true;
+        QNetworkAccessManager* manager = frame->loader()->networkingContext()->networkAccessManager();
+        QtNAMThreadSafeProxy managerProxy(manager);
+        if (managerProxy.willLoadFromCache(request.url())) {
+            request.setCachePolicy(ReturnCacheDataDontLoad);
+            return true;
+        }
     }
 
     return false;
diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp
index 049ee0f..e5d36ba 100644
--- a/WebCore/platform/qt/CookieJarQt.cpp
+++ b/WebCore/platform/qt/CookieJarQt.cpp
@@ -31,6 +31,7 @@
 #include "Cookie.h"
 #include "Document.h"
 #include "KURL.h"
+#include "QtNAMThreadSafeProxy.h"
 #include "NetworkingContext.h"
 #include "PlatformString.h"
 
@@ -43,7 +44,8 @@
 
 namespace WebCore {
 
-static QNetworkCookieJar *cookieJar(const Document *document)
+
+static QNetworkAccessManager *networkAccessManager(const Document *document)
 {
     if (!document)
         return 0;
@@ -53,38 +55,30 @@ static QNetworkCookieJar *cookieJar(const Document *document)
     FrameLoader *loader = frame->loader();
     if (!loader)
         return 0;
-    QNetworkAccessManager* manager = loader->networkingContext()->networkAccessManager();
-    QNetworkCookieJar* jar = manager->cookieJar();
-    return jar;
+    return loader->networkingContext()->networkAccessManager();
 }
 
 void setCookies(Document* document, const KURL& url, const String& value)
 {
-    QUrl u(url);
-    QUrl p(document->firstPartyForCookies());
-    QNetworkCookieJar* jar = cookieJar(document);
-    if (!jar)
+    QNetworkAccessManager* manager = networkAccessManager(document);
+    if (!manager)
         return;
 
-    QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(QString(value).toAscii());
-    QList<QNetworkCookie>::Iterator it = cookies.begin();
-    while (it != cookies.end()) {
-        if (it->isHttpOnly())
-            it = cookies.erase(it);
-        else
-            ++it;
-    }
-    jar->setCookiesFromUrl(cookies, u);
+    // Create the manipulator on the heap to let it live until the
+    // async request is picked by the other thread's event loop.
+    QtNAMThreadSafeProxy* managerProxy = new QtNAMThreadSafeProxy(manager);
+    managerProxy->setCookies(url, value);
+    managerProxy->deleteLater();
 }
 
 String cookies(const Document* document, const KURL& url)
 {
-    QUrl u(url);
-    QNetworkCookieJar* jar = cookieJar(document);
-    if (!jar)
+    QNetworkAccessManager* manager = networkAccessManager(document);
+    if (!manager)
         return String();
 
-    QList<QNetworkCookie> cookies = jar->cookiesForUrl(u);
+    QtNAMThreadSafeProxy managerProxy(manager);
+    QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(url);
     if (cookies.isEmpty())
         return String();
 
@@ -101,12 +95,12 @@ String cookies(const Document* document, const KURL& url)
 
 String cookieRequestHeaderFieldValue(const Document* document, const KURL &url)
 {
-    QUrl u(url);
-    QNetworkCookieJar* jar = cookieJar(document);
-    if (!jar)
+    QNetworkAccessManager* manager = networkAccessManager(document);
+    if (!manager)
         return String();
 
-    QList<QNetworkCookie> cookies = jar->cookiesForUrl(u);
+    QtNAMThreadSafeProxy managerProxy(manager);
+    QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(url);
     if (cookies.isEmpty())
         return String();
 
@@ -121,8 +115,7 @@ String cookieRequestHeaderFieldValue(const Document* document, const KURL &url)
 
 bool cookiesEnabled(const Document* document)
 {
-    QNetworkCookieJar* jar = cookieJar(document);
-    return (jar != 0);
+    return networkAccessManager(document);
 }
 
 bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies)
diff --git a/WebKit/qt/ChangeLog b/WebKit/qt/ChangeLog
index 128940c..91a02d6 100644
--- a/WebKit/qt/ChangeLog
+++ b/WebKit/qt/ChangeLog
@@ -1,3 +1,36 @@
+2010-12-10  Jocelyn Turcotte  <jocelyn.turcotte at nokia.com>
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        [Qt] Support a QNetworkAccessManager affined to a different thread.
+        https://bugs.webkit.org/show_bug.cgi?id=50080
+
+        This patch introduce thread safe proxy classes for QNetworkAccessManager
+        and QNetworkReply.
+        If run in the same thread, these objects will forward the calls with
+        Qt::DirectConnection bindings, while in the other case they will use
+        Qt::QueuedConnection to carry requests accross threads.
+
+        This patch basically:
+        - Makes sure that all access goes through these objects
+        - Reorders signal connections to make sure we are connected when the
+          signal comes
+        - Makes sure that no QObject in the WebCore thread is a child of the
+          reply which might be in a different thread.
+        - Forward the data directly in QByteArrays in signals instead of collecting
+          the data when the signal is handled.
+
+        New test: tst_QWebPage::networkAccessManagerOnDifferentThread
+
+        * WebCoreSupport/FrameLoaderClientQt.cpp:
+        (WebCore::FrameLoaderClientQt::download):
+        * tests/qwebpage/tst_qwebpage.cpp:
+        (QtNAMThread::QtNAMThread):
+        (QtNAMThread::~QtNAMThread):
+        (QtNAMThread::networkAccessManager):
+        (QtNAMThread::run):
+        (tst_QWebPage::networkAccessManagerOnDifferentThread):
+
 2010-12-09  Sheriff Bot  <webkit.review.bot at gmail.com>
 
         Unreviewed, rolling out r73635.
diff --git a/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp b/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
index bf6e75a..6496b4b 100644
--- a/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
+++ b/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
@@ -59,6 +59,7 @@
 #include "HTMLFormElement.h"
 #include "HTMLPlugInElement.h"
 #include "HTTPParsers.h"
+#include "QtNAMThreadSafeProxy.h"
 #include "NotImplemented.h"
 #include "QNetworkReplyHandler.h"
 #include "ResourceHandleInternal.h"
@@ -975,13 +976,13 @@ void FrameLoaderClientQt::download(WebCore::ResourceHandle* handle, const WebCor
         return;
 
     QNetworkReplyHandler* handler = handle->getInternal()->m_job;
-    QNetworkReply* reply = handler->release();
-    if (reply) {
+    QtNetworkReplyThreadSafeProxy* replyProxy = handler->release();
+    if (replyProxy) {
         QWebPage *page = m_webFrame->page();
         if (page->forwardUnsupportedContent())
-            emit page->unsupportedContent(reply);
+            emit page->unsupportedContent(replyProxy->reply());
         else
-            reply->abort();
+            replyProxy->abort();
     }
 }
 
diff --git a/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp b/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp
index c27ba02..27d28f0 100644
--- a/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp
+++ b/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp
@@ -128,6 +128,7 @@ private slots:
     void findText();
     void supportedContentType();
     void infiniteLoopJS();
+    void networkAccessManagerOnDifferentThread();
     
 private:
     QWebView* m_view;
@@ -2599,5 +2600,45 @@ void tst_QWebPage::supportedContentType()
       QVERIFY2(m_page->supportsContentType(mimeType), QString("Cannot handle content types '%1'!").arg(mimeType).toLatin1());
 }
 
+class QtNAMThread : public QThread {
+public:
+    QtNAMThread()
+    {
+        m_qnamFuture.reportStarted();
+    }
+    ~QtNAMThread()
+    {
+        quit();
+        wait();
+    }
+
+    QFuture<QNetworkAccessManager*> networkAccessManager()
+    {
+        return m_qnamFuture.future();
+    }
+protected:
+    void run()
+    {
+        QNetworkAccessManager* qnam = new QNetworkAccessManager;
+        m_qnamFuture.reportFinished(&qnam);
+        exec();
+        delete qnam;
+    }
+private:
+    QFutureInterface<QNetworkAccessManager*> m_qnamFuture;
+};
+
+void tst_QWebPage::networkAccessManagerOnDifferentThread()
+{
+    QtNAMThread qnamThread;
+    qnamThread.start();
+    m_page->setNetworkAccessManager(qnamThread.networkAccessManager());
+    QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
+    QUrl url = QUrl("qrc:///resources/index.html");
+    m_page->mainFrame()->load(url);
+    QTRY_COMPARE(loadSpy.count(), 1);
+    QCOMPARE(m_page->mainFrame()->childFrames()[0]->url(), QUrl("qrc:///resources/frame_a.html"));
+}
+
 QTEST_MAIN(tst_QWebPage)
 #include "tst_qwebpage.moc"

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list