[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