Changeset 83691 in webkit


Ignore:
Timestamp:
Apr 12, 2011 8:30:32 PM (13 years ago)
Author:
luiz@webkit.org
Message:

[Qt] QNetworkReplyHandler refactoring: signal queue
https://bugs.webkit.org/show_bug.cgi?id=57075

Reviewed by Andreas Kling.

The idea is to make all signals that come from the QNetworkReply to pass through a queue and to
stop that queue when loading is deferred. This way almost all the deferred logic can be removed
from QNetworkReplyHandler class and encapsulated in its own class.

To stop the queue during wrapper methods execution avoids stacking handler methods over wrapper
methods. Because of this there is no chance for the wrapper to be destroyed inside one of its methods.
This together with empting the queue at wrapper destruction time makes sure that the handler will
not receive calls from a dead wrapper.

The new class is named QNetworkReplyHandlerCallQueue.

  • platform/network/qt/QNetworkReplyHandler.cpp:

(WebCore::QNetworkReplyHandlerCallQueue::QNetworkReplyHandlerCallQueue):
(WebCore::QNetworkReplyHandlerCallQueue::push):
(WebCore::QNetworkReplyHandlerCallQueue::lock):
(WebCore::QNetworkReplyHandlerCallQueue::unlock):
(WebCore::QNetworkReplyHandlerCallQueue::setDeferSignals):
(WebCore::QNetworkReplyHandlerCallQueue::flush):
(WebCore::QueueLocker::QueueLocker):
(WebCore::QueueLocker::~QueueLocker):
(WebCore::QNetworkReplyWrapper::QNetworkReplyWrapper):
(WebCore::QNetworkReplyWrapper::~QNetworkReplyWrapper):
(WebCore::QNetworkReplyWrapper::receiveMetaData):
(WebCore::QNetworkReplyWrapper::readyRead):
(WebCore::QNetworkReplyWrapper::didReceiveFinished):
(WebCore::QNetworkReplyHandler::QNetworkReplyHandler):
(WebCore::QNetworkReplyHandler::resetState):
(WebCore::QNetworkReplyHandler::release):
(WebCore::QNetworkReplyHandler::finish):
(WebCore::QNetworkReplyHandler::sendResponseIfNeeded):
(WebCore::QNetworkReplyHandler::forwardData):
(WebCore::QNetworkReplyHandler::start):
(WebCore::QNetworkReplyHandler::synchronousLoad):

  • platform/network/qt/QNetworkReplyHandler.h:

(WebCore::QNetworkReplyHandlerCallQueue::deferSignals):
(WebCore::QNetworkReplyHandlerCallQueue::clear):
(WebCore::QNetworkReplyWrapper::synchronousLoad):
(WebCore::QNetworkReplyHandler::setLoadingDeferred):

  • platform/network/qt/ResourceHandleQt.cpp:

(WebCore::ResourceHandle::loadResourceSynchronously):

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r83690 r83691  
     12011-04-12  Luiz Agostini  <luiz.agostini@openbossa.org>
     2
     3        Reviewed by Andreas Kling.
     4
     5        [Qt] QNetworkReplyHandler refactoring: signal queue
     6        https://bugs.webkit.org/show_bug.cgi?id=57075
     7
     8        The idea is to make all signals that come from the QNetworkReply to pass through a queue and to
     9        stop that queue when loading is deferred. This way almost all the deferred logic can be removed
     10        from QNetworkReplyHandler class and encapsulated in its own class.
     11
     12        To stop the queue during wrapper methods execution avoids stacking handler methods over wrapper
     13        methods. Because of this there is no chance for the wrapper to be destroyed inside one of its methods.
     14        This together with empting the queue at wrapper destruction time makes sure that the handler will
     15        not receive calls from a dead wrapper.
     16
     17        The new class is named QNetworkReplyHandlerCallQueue.
     18
     19        * platform/network/qt/QNetworkReplyHandler.cpp:
     20        (WebCore::QNetworkReplyHandlerCallQueue::QNetworkReplyHandlerCallQueue):
     21        (WebCore::QNetworkReplyHandlerCallQueue::push):
     22        (WebCore::QNetworkReplyHandlerCallQueue::lock):
     23        (WebCore::QNetworkReplyHandlerCallQueue::unlock):
     24        (WebCore::QNetworkReplyHandlerCallQueue::setDeferSignals):
     25        (WebCore::QNetworkReplyHandlerCallQueue::flush):
     26        (WebCore::QueueLocker::QueueLocker):
     27        (WebCore::QueueLocker::~QueueLocker):
     28        (WebCore::QNetworkReplyWrapper::QNetworkReplyWrapper):
     29        (WebCore::QNetworkReplyWrapper::~QNetworkReplyWrapper):
     30        (WebCore::QNetworkReplyWrapper::receiveMetaData):
     31        (WebCore::QNetworkReplyWrapper::readyRead):
     32        (WebCore::QNetworkReplyWrapper::didReceiveFinished):
     33        (WebCore::QNetworkReplyHandler::QNetworkReplyHandler):
     34        (WebCore::QNetworkReplyHandler::resetState):
     35        (WebCore::QNetworkReplyHandler::release):
     36        (WebCore::QNetworkReplyHandler::finish):
     37        (WebCore::QNetworkReplyHandler::sendResponseIfNeeded):
     38        (WebCore::QNetworkReplyHandler::forwardData):
     39        (WebCore::QNetworkReplyHandler::start):
     40        (WebCore::QNetworkReplyHandler::synchronousLoad):
     41        * platform/network/qt/QNetworkReplyHandler.h:
     42        (WebCore::QNetworkReplyHandlerCallQueue::deferSignals):
     43        (WebCore::QNetworkReplyHandlerCallQueue::clear):
     44        (WebCore::QNetworkReplyWrapper::synchronousLoad):
     45        (WebCore::QNetworkReplyHandler::setLoadingDeferred):
     46        * platform/network/qt/ResourceHandleQt.cpp:
     47        (WebCore::ResourceHandle::loadResourceSynchronously):
     48
    1492011-04-12  Kenichi Ishibashi  <bashi@chromium.org>
    250
  • trunk/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp

    r83673 r83691  
    150150}
    151151
    152 QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReply* reply, QObject* parent)
     152QNetworkReplyHandlerCallQueue::QNetworkReplyHandlerCallQueue(QNetworkReplyHandler* handler, bool deferSignals)
     153    : m_replyHandler(handler)
     154    , m_locks(0)
     155    , m_deferSignals(deferSignals)
     156    , m_flushing(false)
     157{
     158    Q_ASSERT(handler);
     159}
     160
     161void QNetworkReplyHandlerCallQueue::push(EnqueuedCall method)
     162{
     163    m_enqueuedCalls.append(method);
     164    flush();
     165}
     166
     167void QNetworkReplyHandlerCallQueue::lock()
     168{
     169    ++m_locks;
     170}
     171
     172void QNetworkReplyHandlerCallQueue::unlock()
     173{
     174    if (!m_locks)
     175        return;
     176
     177    --m_locks;
     178    flush();
     179}
     180
     181void QNetworkReplyHandlerCallQueue::setDeferSignals(bool defer)
     182{
     183    m_deferSignals = defer;
     184    flush();
     185}
     186
     187void QNetworkReplyHandlerCallQueue::flush()
     188{
     189    if (m_flushing)
     190        return;
     191
     192    m_flushing = true;
     193
     194    while (!m_deferSignals && !m_locks && !m_enqueuedCalls.isEmpty())
     195        (m_replyHandler->*(m_enqueuedCalls.takeFirst()))();
     196
     197    m_flushing = false;
     198}
     199
     200class QueueLocker {
     201public:
     202    QueueLocker(QNetworkReplyHandlerCallQueue* queue) : m_queue(queue) { m_queue->lock(); }
     203    ~QueueLocker() { m_queue->unlock(); }
     204private:
     205    QNetworkReplyHandlerCallQueue* m_queue;
     206};
     207
     208QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue* queue, QNetworkReply* reply, QObject* parent)
    153209    : QObject(parent)
    154210    , m_reply(reply)
     211    , m_queue(queue)
    155212{
    156213    Q_ASSERT(m_reply);
     
    165222    if (m_reply)
    166223        m_reply->deleteLater();
     224    m_queue->clear();
    167225}
    168226
     
    191249    resetConnections();
    192250
     251    QueueLocker lock(m_queue);
     252
    193253    m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
    194254    if (m_redirectionTargetUrl.isValid()) {
    195         emit metaDataChanged();
    196         emit finished();
     255        m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded);
     256        m_queue->push(&QNetworkReplyHandler::finish);
    197257        return;
    198258    }
     
    202262    m_advertisedMimeType = extractMIMETypeFromMediaType(contentType);
    203263
    204     bool hasData = m_reply->bytesAvailable();
    205     bool isFinished = m_reply->isFinished();
    206 
    207     if (!isFinished) {
    208         // If not finished, connect to the slots that will be used from this point on.
    209         connect(m_reply, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
    210         connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished()));
    211     }
    212 
    213     emit metaDataChanged();
    214 
    215     if (hasData)
    216         emit readyRead();
    217 
    218     if (isFinished) {
    219         emit finished();
    220         return;
    221     }
    222 
     264    m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded);
     265
     266    if (m_reply->bytesAvailable())
     267        m_queue->push(&QNetworkReplyHandler::forwardData);
     268
     269    if (m_reply->isFinished()) {
     270        m_queue->push(&QNetworkReplyHandler::finish);
     271        return;
     272    }
     273
     274    // If not finished, connect to the slots that will be used from this point on.
     275    connect(m_reply, SIGNAL(readyRead()), this, SLOT(didReceiveReadyRead()));
     276    connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished()));
     277}
     278
     279void QNetworkReplyWrapper::didReceiveReadyRead()
     280{
     281    m_queue->push(&QNetworkReplyHandler::forwardData);
    223282}
    224283
     
    227286    // Disconnecting will make sure that nothing will happen after emitting the finished signal.
    228287    resetConnections();
    229     emit finished();
     288    m_queue->push(&QNetworkReplyHandler::finish);
    230289}
    231290
     
    256315    , m_resourceHandle(handle)
    257316    , m_loadType(loadType)
    258     , m_deferred(deferred)
    259317    , m_redirectionTries(gMaxRedirections)
     318    , m_queue(this, deferred)
    260319{
    261320    resetState();
     
    282341    m_request = r.toNetworkRequest(originatingObject);
    283342
    284     if (!m_deferred)
    285         start();
     343    m_queue.push(&QNetworkReplyHandler::start);
    286344}
    287345
     
    289347{
    290348    m_redirected = false;
    291     m_responseSent = false;
    292349    m_responseContainsData = false;
    293     m_hasStarted = false;
    294     m_callFinishOnResume = false;
    295     m_callSendResponseIfNeededOnResume = false;
    296     m_callForwardDataOnResume = false;
    297350
    298351    if (m_replyWrapper) {
    299         m_replyWrapper->deleteLater();
     352        delete m_replyWrapper;
    300353        m_replyWrapper = 0;
    301354    }
    302 }
    303 
    304 void QNetworkReplyHandler::setLoadingDeferred(bool deferred)
    305 {
    306     m_deferred = deferred;
    307 
    308     if (!deferred)
    309         resumeDeferredLoad();
    310 }
    311 
    312 void QNetworkReplyHandler::resumeDeferredLoad()
    313 {
    314     if (!m_hasStarted) {
    315         ASSERT(!m_callSendResponseIfNeededOnResume);
    316         ASSERT(!m_callForwardDataOnResume);
    317         ASSERT(!m_callFinishOnResume);
    318         start();
    319         return;
    320     }
    321 
    322     if (m_callSendResponseIfNeededOnResume)
    323         sendResponseIfNeeded();
    324 
    325     if (m_callForwardDataOnResume)
    326         forwardData();
    327 
    328     if (m_callFinishOnResume)
    329         finish();
    330355}
    331356
     
    346371
    347372    QNetworkReply* reply = m_replyWrapper->release();
    348     m_replyWrapper->deleteLater();
     373    delete m_replyWrapper;
    349374    m_replyWrapper = 0;
    350375    return reply;
     
    366391void QNetworkReplyHandler::finish()
    367392{
    368     ASSERT(m_hasStarted);
    369 
    370     m_callFinishOnResume = m_deferred;
    371     if (m_deferred)
    372         return;
    373 
    374     if (!m_replyWrapper || !m_replyWrapper->reply())
    375         return;
    376 
    377 
    378     sendResponseIfNeeded();
    379 
    380     if (wasAborted())
    381         return;
     393    ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
    382394
    383395    ResourceHandleClient* client = m_resourceHandle->client();
    384396    if (!client) {
    385         m_replyWrapper->deleteLater();
     397        delete m_replyWrapper;
    386398        m_replyWrapper = 0;
    387399        return;
     
    390402    if (m_redirected) {
    391403        resetState();
    392         start();
     404        m_queue.push(&QNetworkReplyHandler::start);
    393405        return;
    394406    }
     
    410422
    411423    if (m_replyWrapper) {
    412         m_replyWrapper->deleteLater();
     424        delete m_replyWrapper;
    413425        m_replyWrapper = 0;
    414426    }
     
    417429void QNetworkReplyHandler::sendResponseIfNeeded()
    418430{
    419     ASSERT(m_hasStarted);
    420 
    421     m_callSendResponseIfNeededOnResume = m_deferred;
    422     if (m_deferred)
    423         return;
    424 
    425     if (!m_replyWrapper || !m_replyWrapper->reply())
    426         return;
     431    ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
    427432
    428433    if (m_replyWrapper->reply()->error() && !shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData))
    429434        return;
    430 
    431     if (wasAborted())
    432         return;
    433 
    434     if (m_responseSent)
    435         return;
    436     m_responseSent = true;
    437435
    438436    ResourceHandleClient* client = m_resourceHandle->client();
     
    534532void QNetworkReplyHandler::forwardData()
    535533{
    536     ASSERT(m_hasStarted);
    537 
    538     m_callForwardDataOnResume = m_deferred;
    539     if (m_deferred)
    540         return;
    541 
    542     if (!m_replyWrapper || !m_replyWrapper->reply())
    543         return;
     534    ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
     535
     536    ASSERT(!m_redirected);
    544537
    545538    if (m_replyWrapper->reply()->bytesAvailable())
    546539        m_responseContainsData = true;
    547 
    548     sendResponseIfNeeded();
    549 
    550     // don't emit the "Document has moved here" type of HTML
    551     if (m_redirected)
    552         return;
    553 
    554     if (wasAborted())
    555         return;
    556540
    557541    QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable());
     
    640624void QNetworkReplyHandler::start()
    641625{
    642     ASSERT(!m_hasStarted);
    643     m_hasStarted = true;
    644 
    645626    QNetworkReply* reply = sendNetworkRequest();
    646627    if (!reply)
    647628        return;
    648629
    649     m_replyWrapper = new QNetworkReplyWrapper(reply, this);
     630    m_replyWrapper = new QNetworkReplyWrapper(&m_queue, reply, this);
    650631
    651632    if (m_loadType == SynchronousLoad && m_replyWrapper->reply()->isFinished()) {
     
    654635    }
    655636
    656     connect(m_replyWrapper, SIGNAL(finished()), this, SLOT(finish()));
    657     connect(m_replyWrapper, SIGNAL(metaDataChanged()), this, SLOT(sendResponseIfNeeded()));
    658     connect(m_replyWrapper, SIGNAL(readyRead()), this, SLOT(forwardData()));
    659 
    660637    if (m_resourceHandle->firstRequest().reportUploadProgress())
    661638        connect(m_replyWrapper->reply(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
    662639}
    663640
     641void QNetworkReplyHandler::synchronousLoad()
     642{
     643    if (m_replyWrapper)
     644        m_replyWrapper->synchronousLoad();
     645}
     646
    664647}
    665648
  • trunk/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h

    r83673 r83691  
    3636class ResourceHandle;
    3737class ResourceResponse;
     38class QNetworkReplyHandler;
     39
     40class QNetworkReplyHandlerCallQueue {
     41public:
     42    QNetworkReplyHandlerCallQueue(QNetworkReplyHandler*, bool deferSignals);
     43    bool deferSignals() const { return m_deferSignals; }
     44    void setDeferSignals(bool);
     45
     46    typedef void (QNetworkReplyHandler::*EnqueuedCall)();
     47    void push(EnqueuedCall method);
     48    void clear() { m_enqueuedCalls.clear(); }
     49
     50    void lock();
     51    void unlock();
     52private:
     53    QNetworkReplyHandler* m_replyHandler;
     54    int m_locks;
     55    bool m_deferSignals;
     56    bool m_flushing;
     57    QList<EnqueuedCall> m_enqueuedCalls;
     58
     59    void flush();
     60};
    3861
    3962class QNetworkReplyWrapper : public QObject {
    4063    Q_OBJECT
    4164public:
    42     QNetworkReplyWrapper(QNetworkReply*, QObject* parent = 0);
     65    QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue*, QNetworkReply*, QObject* parent = 0);
    4366    ~QNetworkReplyWrapper();
    4467
     
    4669    QNetworkReply* release();
    4770
     71    void synchronousLoad() { receiveMetaData(); }
     72
    4873    QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; }
    4974    QString encoding() const { return m_encoding; }
    5075    QString advertisedMimeType() const { return m_advertisedMimeType; }
    5176
    52 Q_SIGNALS:
    53     void finished();
    54     void metaDataChanged();
    55     void readyRead();
    56     void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
    57 
    5877private Q_SLOTS:
    5978    void receiveMetaData();
    6079    void didReceiveFinished();
     80    void didReceiveReadyRead();
    6181
    6282private:
     
    6888    QString m_encoding;
    6989    QString m_advertisedMimeType;
     90
     91    QNetworkReplyHandlerCallQueue* m_queue;
    7092};
    7193
     
    80102
    81103    QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false);
    82     void setLoadingDeferred(bool);
     104    void setLoadingDeferred(bool deferred) { m_queue.setDeferSignals(deferred); }
    83105
    84106    QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; }
     
    87109
    88110    QNetworkReply* release();
     111
     112    void synchronousLoad();
    89113
    90114public slots:
     
    98122    void resetState();
    99123    String httpMethod() const;
    100     void resumeDeferredLoad();
    101124    void redirect(ResourceResponse&, const QUrl&);
    102125    bool wasAborted() const { return !m_resourceHandle; }
     
    106129    ResourceHandle* m_resourceHandle;
    107130    bool m_redirected;
    108     bool m_responseSent;
    109131    bool m_responseContainsData;
    110132    LoadType m_loadType;
     
    112134    QNetworkRequest m_request;
    113135
    114     bool m_deferred;
     136    // defer state holding
     137    int m_redirectionTries;
    115138
    116     // defer state holding
    117     bool m_hasStarted;
    118     bool m_callFinishOnResume;
    119     bool m_callSendResponseIfNeededOnResume;
    120     bool m_callForwardDataOnResume;
    121     int m_redirectionTries;
     139    QNetworkReplyHandlerCallQueue m_queue;
    122140};
    123141
  • trunk/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp

    r83673 r83691  
    211211    if (reply->isFinished()) {
    212212        syncLoader.setReplyFinished(true);
    213         d->m_job->forwardData();
    214         d->m_job->finish();
     213        d->m_job->synchronousLoad();
    215214    } else
    216215        syncLoader.waitForCompletion();
Note: See TracChangeset for help on using the changeset viewer.