Changeset 73710 in webkit


Ignore:
Timestamp:
Dec 10, 2010 2:50:05 AM (13 years ago)
Author:
jocelyn.turcotte@nokia.com
Message:

2010-12-10 Jocelyn Turcotte <jocelyn.turcotte@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@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):
Location:
trunk
Files:
2 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r73708 r73710  
     12010-12-10  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
     2
     3        Reviewed by Kenneth Rohde Christiansen.
     4
     5        [Qt] Support a QNetworkAccessManager affined to a different thread.
     6        https://bugs.webkit.org/show_bug.cgi?id=50080
     7
     8        This patch introduce thread safe proxy classes for QNetworkAccessManager
     9        and QNetworkReply.
     10        If run in the same thread, these objects will forward the calls with
     11        Qt::DirectConnection bindings, while in the other case they will use
     12        Qt::QueuedConnection to carry requests accross threads.
     13
     14        This patch basically:
     15        - Makes sure that all access goes through these objects
     16        - Reorders signal connections to make sure we are connected when the
     17          signal comes
     18        - Makes sure that no QObject in the WebCore thread is a child of the
     19          reply which might be in a different thread.
     20        - Forward the data directly in QByteArrays in signals instead of collecting
     21          the data when the signal is handled.
     22
     23        New test: tst_QWebPage::networkAccessManagerOnDifferentThread
     24
     25        * WebCore.pro:
     26        * platform/graphics/qt/MediaPlayerPrivateQt.cpp:
     27        (WebCore::MediaPlayerPrivateQt::commitLoad):
     28        * platform/network/qt/QNetworkReplyHandler.cpp:
     29        (WebCore::FormDataIODevice::FormDataIODevice):
     30        (WebCore::QNetworkReplyHandler::QNetworkReplyHandler):
     31        (WebCore::QNetworkReplyHandler::~QNetworkReplyHandler):
     32        (WebCore::QNetworkReplyHandler::setLoadMode):
     33        (WebCore::QNetworkReplyHandler::abort):
     34        (WebCore::QNetworkReplyHandler::release):
     35        (WebCore::ignoreHttpError):
     36        (WebCore::QNetworkReplyHandler::finish):
     37        (WebCore::QNetworkReplyHandler::sendResponseIfNeeded):
     38        (WebCore::QNetworkReplyHandler::forwardData):
     39        (WebCore::QNetworkReplyHandler::start):
     40        (WebCore::QNetworkReplyHandler::sendQueuedItems):
     41        * platform/network/qt/QNetworkReplyHandler.h:
     42        * platform/network/qt/QtNAMThreadSafeProxy.cpp: Added.
     43        * platform/network/qt/QtNAMThreadSafeProxy.h: Added.
     44        * platform/network/qt/ResourceHandleQt.cpp:
     45        (WebCore::ResourceHandle::willLoadFromCache):
     46        * platform/qt/CookieJarQt.cpp:
     47        (WebCore::networkAccessManager):
     48        (WebCore::setCookies):
     49        (WebCore::cookies):
     50        (WebCore::cookieRequestHeaderFieldValue):
     51        (WebCore::cookiesEnabled):
     52
    1532010-12-09  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
    254
  • trunk/WebCore/WebCore.pro

    r73690 r73710  
    21602160    platform/network/ProtectionSpace.h \
    21612161    platform/network/ProxyServer.h \
     2162    platform/network/qt/QtNAMThreadSafeProxy.h \
    21622163    platform/network/qt/QNetworkReplyHandler.h \
    21632164    platform/network/ResourceErrorBase.h \
     
    26852686    platform/network/qt/ResourceRequestQt.cpp \
    26862687    platform/network/qt/DnsPrefetchHelper.cpp \
     2688    platform/network/qt/QtNAMThreadSafeProxy.cpp \
    26872689    platform/network/qt/ProxyServerQt.cpp \
    26882690    platform/network/qt/QNetworkReplyHandler.cpp \
  • trunk/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp

    r69772 r73710  
    2626#include "HTMLMediaElement.h"
    2727#include "HTMLVideoElement.h"
     28#include "QtNAMThreadSafeProxy.h"
    2829#include "NetworkingContext.h"
    2930#include "NotImplemented.h"
     
    210211        if (document && manager) {
    211212            // Set the cookies
    212             QNetworkCookieJar* jar = manager->cookieJar();
    213             QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl);
     213            QtNAMThreadSafeProxy managerProxy(manager);
     214            QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(rUrl);
    214215
    215216            // Don't set the header if there are no cookies.
  • trunk/WebCore/platform/network/qt/QNetworkReplyHandler.cpp

    r73708 r73710  
    2424#include "HTTPParsers.h"
    2525#include "MIMETypeRegistry.h"
     26#include "QtNAMThreadSafeProxy.h"
    2627#include "ResourceHandle.h"
    2728#include "ResourceHandleClient.h"
     
    4748// and https://bugs.webkit.org/show_bug.cgi?id=36755
    4849#if QT_VERSION > QT_VERSION_CHECK(4, 6, 2)
    49 #define SIGNAL_CONN Qt::DirectConnection
     50#define SIGNAL_CONN Qt::AutoConnection
    5051#else
    5152#define SIGNAL_CONN Qt::QueuedConnection
     
    5758
    5859// Take a deep copy of the FormDataElement
    59 FormDataIODevice::FormDataIODevice(FormData* data)
    60     : m_formElements(data ? data->elements() : Vector<FormDataElement>())
     60FormDataIODevice::FormDataIODevice(FormData* data, QObject* parent)
     61    : QIODevice(parent)
     62    , m_formElements(data ? data->elements() : Vector<FormDataElement>())
    6163    , m_currentFile(0)
    6264    , m_currentDelta(0)
     
    193195    , m_redirectionTries(gMaxRecursionLimit)
    194196{
     197    // Make this a direct function call once we require 4.6.1+.
     198    connect(this, SIGNAL(processQueuedItems()), this, SLOT(sendQueuedItems()), SIGNAL_CONN);
     199
    195200    const ResourceRequest &r = m_resourceHandle->firstRequest();
    196201
     
    223228}
    224229
     230QNetworkReplyHandler::~QNetworkReplyHandler()
     231{
     232    if (m_reply)
     233        m_reply->deleteLater();
     234}
     235
    225236void QNetworkReplyHandler::setLoadMode(LoadMode mode)
    226237{
     
    232243        m_loadMode = LoadResuming;
    233244        emit processQueuedItems();
     245        // Restart forwarding only after processQueuedItems to make sure
     246        // our buffered data was handled before any incoming data.
     247        m_reply->setForwardingDefered(false);
    234248        break;
    235249    case LoadDeferred:
    236250        m_loadMode = LoadDeferred;
     251        m_reply->setForwardingDefered(true);
    237252        break;
    238253    case LoadResuming:
     
    246261    m_resourceHandle = 0;
    247262    if (m_reply) {
    248         QNetworkReply* reply = release();
     263        QtNetworkReplyThreadSafeProxy* reply = release();
    249264        reply->abort();
    250265        reply->deleteLater();
     
    253268}
    254269
    255 QNetworkReply* QNetworkReplyHandler::release()
    256 {
    257     QNetworkReply* reply = m_reply;
     270QtNetworkReplyThreadSafeProxy* QNetworkReplyHandler::release()
     271{
     272    QtNetworkReplyThreadSafeProxy* reply = m_reply;
    258273    if (m_reply) {
    259274        disconnect(m_reply, 0, this, 0);
     
    262277        // don't reach the slots in our instance.
    263278        QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
    264         m_reply->setParent(0);
    265279        m_reply = 0;
    266280    }
     
    268282}
    269283
    270 static bool ignoreHttpError(QNetworkReply* reply, bool receivedData)
    271 {
    272     int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
     284static bool ignoreHttpError(QtNetworkReplyThreadSafeProxy* reply, bool receivedData)
     285{
     286    int httpStatusCode = reply->httpStatusCode();
    273287
    274288    if (httpStatusCode == 401 || httpStatusCode == 407)
     
    302316
    303317    if (!m_redirected) {
    304         if (!m_reply->error() || ignoreHttpError(m_reply, m_responseContainsData)) {
     318        if (!m_reply->error() || ignoreHttpError(m_reply, m_responseContainsData))
    305319            client->didFinishLoading(m_resourceHandle, 0);
    306         } else {
     320        else {
    307321            QUrl url = m_reply->url();
    308             int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
     322            int httpStatusCode = m_reply->httpStatusCode();
    309323
    310324            if (httpStatusCode) {
    311                 ResourceError error("HTTP", httpStatusCode, url.toString(), m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
     325                ResourceError error("HTTP", httpStatusCode, url.toString(), QString::fromAscii(m_reply->httpReasonPhrase()));
    312326                client->didFail(m_resourceHandle, error);
    313327            } else {
     
    347361        return;
    348362
    349     WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
     363    WTF::String contentType = m_reply->contentTypeHeader();
    350364    WTF::String encoding = extractCharsetFromMediaType(contentType);
    351365    WTF::String mimeType = extractMIMETypeFromMediaType(contentType);
     
    358372    KURL url(m_reply->url());
    359373    ResourceResponse response(url, mimeType.lower(),
    360                               m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(),
     374                              m_reply->contentLengthHeader(),
    361375                              encoding, String());
    362376
     
    367381
    368382    // The status code is equal to 0 for protocols not in the HTTP family.
    369     int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
     383    int statusCode = m_reply->httpStatusCode();
    370384
    371385    if (url.protocolInHTTPFamily()) {
    372         String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition")));
     386        String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->contentDispositionHeader()));
    373387
    374388        if (!suggestedFilename.isEmpty())
     
    378392
    379393        response.setHTTPStatusCode(statusCode);
    380         response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData());
     394        response.setHTTPStatusText(m_reply->httpReasonPhrase().constData());
    381395
    382396        // Add remaining headers.
    383 #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
    384         foreach (const QNetworkReply::RawHeaderPair& pair, m_reply->rawHeaderPairs()) {
     397        foreach (const QtNetworkReplyThreadSafeProxy::RawHeaderPair& pair, m_reply->rawHeaderPairs()) {
    385398            response.setHTTPHeaderField(QString::fromAscii(pair.first), QString::fromAscii(pair.second));
    386399        }
    387 #else
    388         foreach (const QByteArray& headerName, m_reply->rawHeaderList()) {
    389             response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName)));
    390         }
    391 #endif
    392     }
    393 
    394     QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
     400    }
     401
     402    QUrl redirection = m_reply->redirectionTarget();
    395403    if (redirection.isValid()) {
    396404        QUrl newUrl = m_reply->url().resolved(redirection);
     
    437445}
    438446
    439 void QNetworkReplyHandler::forwardData()
     447void QNetworkReplyHandler::forwardData(const QByteArray &data)
    440448{
    441449    m_shouldForwardData = (m_loadMode != LoadNormal);
    442     if (m_shouldForwardData)
    443         return;
    444 
    445     if (m_reply->bytesAvailable())
     450    if (m_shouldForwardData) {
     451        m_bufferedData += data;
     452        return;
     453    }
     454
     455    if (!data.isEmpty())
    446456        m_responseContainsData = true;
    447457
     
    454464    if (!m_resourceHandle)
    455465        return;
    456 
    457     QByteArray data = m_reply->read(m_reply->bytesAvailable());
    458466
    459467    ResourceHandleClient* client = m_resourceHandle->client();
     
    499507        m_method = QNetworkAccessManager::GetOperation;
    500508
     509    m_reply = new QtNetworkReplyThreadSafeProxy(manager);
     510    connect(m_reply, SIGNAL(finished()), this, SLOT(finish()), SIGNAL_CONN);
     511
     512    // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
     513    // can send the response as early as possible
     514    if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
     515        connect(m_reply, SIGNAL(metaDataChanged()), this, SLOT(sendResponseIfNeeded()), SIGNAL_CONN);
     516
     517    connect(m_reply, SIGNAL(dataReceived(const QByteArray&)), this, SLOT(forwardData(const QByteArray&)), SIGNAL_CONN);
     518
     519    if (m_resourceHandle->firstRequest().reportUploadProgress())
     520        connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN);
     521
    501522    switch (m_method) {
    502523        case QNetworkAccessManager::GetOperation:
    503             m_reply = manager->get(m_request);
     524            m_reply->get(m_request);
    504525            break;
    505526        case QNetworkAccessManager::PostOperation: {
    506             FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody());
     527            FormDataIODevice* postDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this);
    507528            // We may be uploading files so prevent QNR from buffering data
    508529            m_request.setHeader(QNetworkRequest::ContentLengthHeader, postDevice->getFormDataSize());
    509530            m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
    510             m_reply = manager->post(m_request, postDevice);
    511             postDevice->setParent(m_reply);
     531            m_reply->post(m_request, postDevice);
    512532            break;
    513533        }
    514534        case QNetworkAccessManager::HeadOperation:
    515             m_reply = manager->head(m_request);
     535            m_reply->head(m_request);
    516536            break;
    517537        case QNetworkAccessManager::PutOperation: {
    518             FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody());
     538            FormDataIODevice* putDevice = new FormDataIODevice(d->m_firstRequest.httpBody(), this);
    519539            // We may be uploading files so prevent QNR from buffering data
    520540            m_request.setHeader(QNetworkRequest::ContentLengthHeader, putDevice->getFormDataSize());
    521541            m_request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(true));
    522             m_reply = manager->put(m_request, putDevice);
    523             putDevice->setParent(m_reply);
     542            m_reply->put(m_request, putDevice);
    524543            break;
    525544        }
    526545        case QNetworkAccessManager::DeleteOperation: {
    527             m_reply = manager->deleteResource(m_request);
     546            m_reply->deleteResource(m_request);
    528547            break;
    529548        }
    530549#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
    531550        case QNetworkAccessManager::CustomOperation:
    532             m_reply = manager->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
     551            m_reply->sendCustomRequest(m_request, m_resourceHandle->firstRequest().httpMethod().latin1().data());
    533552            break;
    534553#endif
    535554        case QNetworkAccessManager::UnknownOperation: {
     555            m_reply->deleteLater();
    536556            m_reply = 0;
    537557            ResourceHandleClient* client = m_resourceHandle->client();
     
    545565        }
    546566    }
    547 
    548     m_reply->setParent(this);
    549 
    550     connect(m_reply, SIGNAL(finished()),
    551             this, SLOT(finish()), SIGNAL_CONN);
    552 
    553     // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
    554     // can send the response as early as possible
    555     if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
    556         connect(m_reply, SIGNAL(metaDataChanged()),
    557                 this, SLOT(sendResponseIfNeeded()), SIGNAL_CONN);
    558 
    559     connect(m_reply, SIGNAL(readyRead()),
    560             this, SLOT(forwardData()), SIGNAL_CONN);
    561 
    562     if (m_resourceHandle->firstRequest().reportUploadProgress()) {
    563         connect(m_reply, SIGNAL(uploadProgress(qint64, qint64)),
    564                 this, SLOT(uploadProgress(qint64, qint64)), SIGNAL_CONN);
    565     }
    566 
    567     // Make this a direct function call once we require 4.6.1+.
    568     connect(this, SIGNAL(processQueuedItems()),
    569             this, SLOT(sendQueuedItems()), SIGNAL_CONN);
    570567}
    571568
     
    593590        sendResponseIfNeeded();
    594591
    595     if (m_shouldForwardData)
    596         forwardData();
     592    if (m_shouldForwardData) {
     593        forwardData(m_bufferedData);
     594        m_bufferedData.clear();
     595    }
    597596
    598597    if (m_shouldFinish)
  • trunk/WebCore/platform/network/qt/QNetworkReplyHandler.h

    r73707 r73710  
    2424#include <QNetworkRequest>
    2525#include <QNetworkAccessManager>
     26#include <QNetworkReply>
    2627
    2728#include "FormData.h"
     
    3536
    3637class ResourceHandle;
     38class QtNetworkReplyThreadSafeProxy;
    3739
    3840class QNetworkReplyHandler : public QObject
     
    4749
    4850    QNetworkReplyHandler(ResourceHandle *handle, LoadMode);
     51    ~QNetworkReplyHandler();
    4952    void setLoadMode(LoadMode);
    50 
    51     QNetworkReply* reply() const { return m_reply; }
    5253
    5354    void abort();
    5455
    55     QNetworkReply* release();
     56    QtNetworkReplyThreadSafeProxy* release();
    5657
    5758signals:
     
    6162    void finish();
    6263    void sendResponseIfNeeded();
    63     void forwardData();
     64    void forwardData(const QByteArray &data);
    6465    void sendQueuedItems();
    6566    void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
     
    7071    String httpMethod() const;
    7172
    72     QNetworkReply* m_reply;
     73    QtNetworkReplyThreadSafeProxy* m_reply;
    7374    ResourceHandle* m_resourceHandle;
    7475    bool m_redirected;
     
    8586    bool m_shouldForwardData;
    8687    int m_redirectionTries;
     88    QByteArray m_bufferedData;
    8789};
    8890
     
    9597    Q_OBJECT
    9698public:
    97     FormDataIODevice(FormData*);
     99    FormDataIODevice(FormData*, QObject* parent = 0);
    98100    ~FormDataIODevice();
    99101
  • trunk/WebCore/platform/network/qt/ResourceHandleQt.cpp

    r72736 r73710  
    3636#include "FrameNetworkingContext.h"
    3737#include "FrameLoaderClientQt.h"
     38#include "QtNAMThreadSafeProxy.h"
    3839#include "NotImplemented.h"
    3940#include "Page.h"
     
    157158        return false;
    158159
    159     QNetworkAccessManager* manager = 0;
    160     QAbstractNetworkCache* cache = 0;
    161160    if (frame->loader()->networkingContext()) {
    162         manager = frame->loader()->networkingContext()->networkAccessManager();
    163         cache = manager->cache();
    164     }
    165 
    166     if (!cache)
    167         return false;
    168 
    169     QNetworkCacheMetaData data = cache->metaData(request.url());
    170     if (data.isValid()) {
    171         request.setCachePolicy(ReturnCacheDataDontLoad);
    172         return true;
     161        QNetworkAccessManager* manager = frame->loader()->networkingContext()->networkAccessManager();
     162        QtNAMThreadSafeProxy managerProxy(manager);
     163        if (managerProxy.willLoadFromCache(request.url())) {
     164            request.setCachePolicy(ReturnCacheDataDontLoad);
     165            return true;
     166        }
    173167    }
    174168
  • trunk/WebCore/platform/qt/CookieJarQt.cpp

    r72049 r73710  
    3232#include "Document.h"
    3333#include "KURL.h"
     34#include "QtNAMThreadSafeProxy.h"
    3435#include "NetworkingContext.h"
    3536#include "PlatformString.h"
     
    4445namespace WebCore {
    4546
    46 static QNetworkCookieJar *cookieJar(const Document *document)
     47
     48static QNetworkAccessManager *networkAccessManager(const Document *document)
    4749{
    4850    if (!document)
     
    5456    if (!loader)
    5557        return 0;
    56     QNetworkAccessManager* manager = loader->networkingContext()->networkAccessManager();
    57     QNetworkCookieJar* jar = manager->cookieJar();
    58     return jar;
     58    return loader->networkingContext()->networkAccessManager();
    5959}
    6060
    6161void setCookies(Document* document, const KURL& url, const String& value)
    6262{
    63     QUrl u(url);
    64     QUrl p(document->firstPartyForCookies());
    65     QNetworkCookieJar* jar = cookieJar(document);
    66     if (!jar)
     63    QNetworkAccessManager* manager = networkAccessManager(document);
     64    if (!manager)
    6765        return;
    6866
    69     QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(QString(value).toAscii());
    70     QList<QNetworkCookie>::Iterator it = cookies.begin();
    71     while (it != cookies.end()) {
    72         if (it->isHttpOnly())
    73             it = cookies.erase(it);
    74         else
    75             ++it;
    76     }
    77     jar->setCookiesFromUrl(cookies, u);
     67    // Create the manipulator on the heap to let it live until the
     68    // async request is picked by the other thread's event loop.
     69    QtNAMThreadSafeProxy* managerProxy = new QtNAMThreadSafeProxy(manager);
     70    managerProxy->setCookies(url, value);
     71    managerProxy->deleteLater();
    7872}
    7973
    8074String cookies(const Document* document, const KURL& url)
    8175{
    82     QUrl u(url);
    83     QNetworkCookieJar* jar = cookieJar(document);
    84     if (!jar)
     76    QNetworkAccessManager* manager = networkAccessManager(document);
     77    if (!manager)
    8578        return String();
    8679
    87     QList<QNetworkCookie> cookies = jar->cookiesForUrl(u);
     80    QtNAMThreadSafeProxy managerProxy(manager);
     81    QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(url);
    8882    if (cookies.isEmpty())
    8983        return String();
     
    10296String cookieRequestHeaderFieldValue(const Document* document, const KURL &url)
    10397{
    104     QUrl u(url);
    105     QNetworkCookieJar* jar = cookieJar(document);
    106     if (!jar)
     98    QNetworkAccessManager* manager = networkAccessManager(document);
     99    if (!manager)
    107100        return String();
    108101
    109     QList<QNetworkCookie> cookies = jar->cookiesForUrl(u);
     102    QtNAMThreadSafeProxy managerProxy(manager);
     103    QList<QNetworkCookie> cookies = managerProxy.cookiesForUrl(url);
    110104    if (cookies.isEmpty())
    111105        return String();
     
    122116bool cookiesEnabled(const Document* document)
    123117{
    124     QNetworkCookieJar* jar = cookieJar(document);
    125     return (jar != 0);
     118    return networkAccessManager(document);
    126119}
    127120
  • trunk/WebKit/qt/ChangeLog

    r73642 r73710  
     12010-12-10  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
     2
     3        Reviewed by Kenneth Rohde Christiansen.
     4
     5        [Qt] Support a QNetworkAccessManager affined to a different thread.
     6        https://bugs.webkit.org/show_bug.cgi?id=50080
     7
     8        This patch introduce thread safe proxy classes for QNetworkAccessManager
     9        and QNetworkReply.
     10        If run in the same thread, these objects will forward the calls with
     11        Qt::DirectConnection bindings, while in the other case they will use
     12        Qt::QueuedConnection to carry requests accross threads.
     13
     14        This patch basically:
     15        - Makes sure that all access goes through these objects
     16        - Reorders signal connections to make sure we are connected when the
     17          signal comes
     18        - Makes sure that no QObject in the WebCore thread is a child of the
     19          reply which might be in a different thread.
     20        - Forward the data directly in QByteArrays in signals instead of collecting
     21          the data when the signal is handled.
     22
     23        New test: tst_QWebPage::networkAccessManagerOnDifferentThread
     24
     25        * WebCoreSupport/FrameLoaderClientQt.cpp:
     26        (WebCore::FrameLoaderClientQt::download):
     27        * tests/qwebpage/tst_qwebpage.cpp:
     28        (QtNAMThread::QtNAMThread):
     29        (QtNAMThread::~QtNAMThread):
     30        (QtNAMThread::networkAccessManager):
     31        (QtNAMThread::run):
     32        (tst_QWebPage::networkAccessManagerOnDifferentThread):
     33
    1342010-12-09  Sheriff Bot  <webkit.review.bot@gmail.com>
    235
  • trunk/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp

    r73436 r73710  
    6060#include "HTMLPlugInElement.h"
    6161#include "HTTPParsers.h"
     62#include "QtNAMThreadSafeProxy.h"
    6263#include "NotImplemented.h"
    6364#include "QNetworkReplyHandler.h"
     
    976977
    977978    QNetworkReplyHandler* handler = handle->getInternal()->m_job;
    978     QNetworkReply* reply = handler->release();
    979     if (reply) {
     979    QtNetworkReplyThreadSafeProxy* replyProxy = handler->release();
     980    if (replyProxy) {
    980981        QWebPage *page = m_webFrame->page();
    981982        if (page->forwardUnsupportedContent())
    982             emit page->unsupportedContent(reply);
     983            emit page->unsupportedContent(replyProxy->reply());
    983984        else
    984             reply->abort();
     985            replyProxy->abort();
    985986    }
    986987}
  • trunk/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp

    r72697 r73710  
    129129    void supportedContentType();
    130130    void infiniteLoopJS();
     131    void networkAccessManagerOnDifferentThread();
    131132   
    132133private:
     
    26002601}
    26012602
     2603class QtNAMThread : public QThread {
     2604public:
     2605    QtNAMThread()
     2606    {
     2607        m_qnamFuture.reportStarted();
     2608    }
     2609    ~QtNAMThread()
     2610    {
     2611        quit();
     2612        wait();
     2613    }
     2614
     2615    QFuture<QNetworkAccessManager*> networkAccessManager()
     2616    {
     2617        return m_qnamFuture.future();
     2618    }
     2619protected:
     2620    void run()
     2621    {
     2622        QNetworkAccessManager* qnam = new QNetworkAccessManager;
     2623        m_qnamFuture.reportFinished(&qnam);
     2624        exec();
     2625        delete qnam;
     2626    }
     2627private:
     2628    QFutureInterface<QNetworkAccessManager*> m_qnamFuture;
     2629};
     2630
     2631void tst_QWebPage::networkAccessManagerOnDifferentThread()
     2632{
     2633    QtNAMThread qnamThread;
     2634    qnamThread.start();
     2635    m_page->setNetworkAccessManager(qnamThread.networkAccessManager());
     2636    QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
     2637    QUrl url = QUrl("qrc:///resources/index.html");
     2638    m_page->mainFrame()->load(url);
     2639    QTRY_COMPARE(loadSpy.count(), 1);
     2640    QCOMPARE(m_page->mainFrame()->childFrames()[0]->url(), QUrl("qrc:///resources/frame_a.html"));
     2641}
     2642
    26022643QTEST_MAIN(tst_QWebPage)
    26032644#include "tst_qwebpage.moc"
Note: See TracChangeset for help on using the changeset viewer.