COMMIT_MESSAGE

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

Source/WebCore/ChangeLog

 12011-04-12 Luiz Agostini <luiz.agostini@openbossa.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 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::QueueLocker::QueueLocker):
 26 (WebCore::QueueLocker::~QueueLocker):
 27 (WebCore::QNetworkReplyWrapper::QNetworkReplyWrapper):
 28 (WebCore::QNetworkReplyWrapper::~QNetworkReplyWrapper):
 29 (WebCore::QNetworkReplyWrapper::receiveMetaData):
 30 (WebCore::QNetworkReplyWrapper::readyRead):
 31 (WebCore::QNetworkReplyWrapper::didReceiveFinished):
 32 (WebCore::QNetworkReplyHandler::QNetworkReplyHandler):
 33 (WebCore::QNetworkReplyHandler::resetState):
 34 (WebCore::QNetworkReplyHandler::release):
 35 (WebCore::QNetworkReplyHandler::finish):
 36 (WebCore::QNetworkReplyHandler::sendResponseIfNeeded):
 37 (WebCore::QNetworkReplyHandler::forwardData):
 38 (WebCore::QNetworkReplyHandler::start):
 39 * platform/network/qt/QNetworkReplyHandler.h:
 40 (WebCore::QNetworkReplyHandlerCallQueue::deferSignals):
 41 (WebCore::QNetworkReplyHandlerCallQueue::clear):
 42 (WebCore::QNetworkReplyWrapper::synchronousLoad):
 43 (WebCore::QNetworkReplyHandler::setLoadingDeferred):
 44
1452011-04-11 Abhishek Arya <inferno@chromium.org>
246
347 Reviewed by Dave Hyatt.

Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp

@@bool FormDataIODevice::isSequential() const
149149 return true;
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{
 157 Q_ASSERT(handler);
 158}
 159
 160void QNetworkReplyHandlerCallQueue::push(EnqueuedCall method)
 161{
 162 if (m_deferSignals || m_locks) {
 163 m_enqueuedCalls.append(method);
 164 return;
 165 }
 166
 167 (m_replyHandler->*method)();
 168}
 169
 170void QNetworkReplyHandlerCallQueue::lock()
 171{
 172 ++m_locks;
 173}
 174
 175void QNetworkReplyHandlerCallQueue::unlock()
 176{
 177 if (!m_locks)
 178 return;
 179
 180 --m_locks;
 181 setDeferSignals(m_deferSignals);
 182}
 183
 184void QNetworkReplyHandlerCallQueue::setDeferSignals(bool defer)
 185{
 186 m_deferSignals = defer;
 187
 188 if (m_deferSignals || m_locks)
 189 return;
 190
 191 while (!m_enqueuedCalls.isEmpty())
 192 (m_replyHandler->*(m_enqueuedCalls.takeFirst()))();
 193}
 194
 195class QueueLocker {
 196public:
 197 QueueLocker(QNetworkReplyHandlerCallQueue* queue) : m_queue(queue) { m_queue->lock(); }
 198 ~QueueLocker() { m_queue->unlock(); }
 199private:
 200 QNetworkReplyHandlerCallQueue* m_queue;
 201};
 202
 203QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue* queue, QNetworkReply* reply, QObject* parent)
153204 : QObject(parent)
154205 , m_reply(reply)
 206 , m_queue(queue)
155207{
156208 Q_ASSERT(m_reply);
157209

@@QNetworkReplyWrapper::~QNetworkReplyWrapper()
164216{
165217 if (m_reply)
166218 m_reply->deleteLater();
 219 m_queue->clear();
167220}
168221
169222QNetworkReply* QNetworkReplyWrapper::release()

@@void QNetworkReplyWrapper::receiveMetaData()
190243 // This slot is only used to receive the first signal from the QNetworkReply object.
191244 resetConnections();
192245
 246 QueueLocker lock(m_queue);
 247
193248 m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
194249 if (m_redirectionTargetUrl.isValid()) {
195  emit metaDataChanged();
196  emit finished();
 250 m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded);
 251 m_queue->push(&QNetworkReplyHandler::finish);
197252 return;
198253 }
199254

@@void QNetworkReplyWrapper::receiveMetaData()
201256 m_encoding = extractCharsetFromMediaType(contentType);
202257 m_advertisedMimeType = extractMIMETypeFromMediaType(contentType);
203258
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();
 259 m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded);
214260
215  if (hasData)
216  emit readyRead();
 261 if (m_reply->bytesAvailable())
 262 m_queue->push(&QNetworkReplyHandler::forwardData);
217263
218  if (isFinished) {
219  emit finished();
 264 if (m_reply->isFinished()) {
 265 m_queue->push(&QNetworkReplyHandler::finish);
220266 return;
221267 }
222268
 269 // If not finished, connect to the slots that will be used from this point on.
 270 connect(m_reply, SIGNAL(readyRead()), this, SLOT(readyRead()));
 271 connect(m_reply, SIGNAL(finished()), this, SLOT(didReceiveFinished()));
 272}
 273
 274void QNetworkReplyWrapper::readyRead()
 275{
 276 m_queue->push(&QNetworkReplyHandler::forwardData);
223277}
224278
225279void QNetworkReplyWrapper::didReceiveFinished()
226280{
227281 // Disconnecting will make sure that nothing will happen after emitting the finished signal.
228282 resetConnections();
229  emit finished();
 283 m_queue->push(&QNetworkReplyHandler::finish);
230284}
231285
232286String QNetworkReplyHandler::httpMethod() const

@@QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType load
255309 , m_replyWrapper(0)
256310 , m_resourceHandle(handle)
257311 , m_loadType(loadType)
258  , m_deferred(deferred)
259312 , m_redirectionTries(gMaxRedirections)
 313 , m_queue(this, deferred)
260314{
261315 resetState();
262316

@@QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadType load
281335
282336 m_request = r.toNetworkRequest(originatingObject);
283337
284  if (!m_deferred)
285  start();
 338 m_queue.push(&QNetworkReplyHandler::start);
286339}
287340
288341void QNetworkReplyHandler::resetState()
289342{
290343 m_redirected = false;
291  m_responseSent = false;
292344 m_responseContainsData = false;
293  m_hasStarted = false;
294  m_callFinishOnResume = false;
295  m_callSendResponseIfNeededOnResume = false;
296  m_callForwardDataOnResume = false;
297345
298346 if (m_replyWrapper) {
299  m_replyWrapper->deleteLater();
 347 delete m_replyWrapper;
300348 m_replyWrapper = 0;
301349 }
302350}
303351
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();
330 }
331 
332352void QNetworkReplyHandler::abort()
333353{
334354 m_resourceHandle = 0;

@@QNetworkReply* QNetworkReplyHandler::release()
345365 return 0;
346366
347367 QNetworkReply* reply = m_replyWrapper->release();
348  m_replyWrapper->deleteLater();
 368 delete m_replyWrapper;
349369 m_replyWrapper = 0;
350370 return reply;
351371}

@@static bool shouldIgnoreHttpError(QNetworkReply* reply, bool receivedData)
365385
366386void QNetworkReplyHandler::finish()
367387{
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;
 388 ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
382389
383390 ResourceHandleClient* client = m_resourceHandle->client();
384391 if (!client) {
385  m_replyWrapper->deleteLater();
 392 delete m_replyWrapper;
386393 m_replyWrapper = 0;
387394 return;
388395 }
389396
390397 if (m_redirected) {
391398 resetState();
392  start();
 399 m_queue.push(&QNetworkReplyHandler::start);
393400 return;
394401 }
395402

@@void QNetworkReplyHandler::finish()
409416 }
410417
411418 if (m_replyWrapper) {
412  m_replyWrapper->deleteLater();
 419 delete m_replyWrapper;
413420 m_replyWrapper = 0;
414421 }
415422}
416423
417424void QNetworkReplyHandler::sendResponseIfNeeded()
418425{
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;
 426 ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
427427
428428 if (m_replyWrapper->reply()->error() && !shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData))
429429 return;
430430
431  if (wasAborted())
432  return;
433 
434  if (m_responseSent)
435  return;
436  m_responseSent = true;
437 
438431 ResourceHandleClient* client = m_resourceHandle->client();
439432 if (!client)
440433 return;

@@void QNetworkReplyHandler::redirect(ResourceResponse& response, const QUrl& redi
533526
534527void QNetworkReplyHandler::forwardData()
535528{
536  ASSERT(m_hasStarted);
537 
538  m_callForwardDataOnResume = m_deferred;
539  if (m_deferred)
540  return;
 529 ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());
541530
542  if (!m_replyWrapper || !m_replyWrapper->reply())
543  return;
 531 ASSERT(!m_redirected);
544532
545533 if (m_replyWrapper->reply()->bytesAvailable())
546534 m_responseContainsData = true;
547535
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;
556 
557536 QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable());
558537
559538 ResourceHandleClient* client = m_resourceHandle->client();

@@QNetworkReply* QNetworkReplyHandler::sendNetworkRequest()
639618
640619void QNetworkReplyHandler::start()
641620{
642  ASSERT(!m_hasStarted);
643  m_hasStarted = true;
644 
645621 QNetworkReply* reply = sendNetworkRequest();
646622 if (!reply)
647623 return;
648624
649  m_replyWrapper = new QNetworkReplyWrapper(reply, this);
 625 m_replyWrapper = new QNetworkReplyWrapper(&m_queue, reply, this);
650626
651627 if (m_loadType == SynchronousLoad && m_replyWrapper->reply()->isFinished()) {
652628 // If supported, a synchronous request will be finished at this point, no need to hook up the signals.
653629 return;
654630 }
655631
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 
660632 if (m_resourceHandle->firstRequest().reportUploadProgress())
661633 connect(m_replyWrapper->reply(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
662634}

Source/WebCore/platform/network/qt/QNetworkReplyHandler.h

@@namespace WebCore {
3535
3636class ResourceHandle;
3737class ResourceResponse;
 38class QNetworkReplyHandler;
 39
 40class QNetworkReplyHandlerCallQueue {
 41public:
 42 QNetworkReplyHandlerCallQueue(QNetworkReplyHandler* handler, 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 QList<EnqueuedCall> m_enqueuedCalls;
 57};
3858
3959class QNetworkReplyWrapper : public QObject {
4060 Q_OBJECT
4161public:
42  QNetworkReplyWrapper(QNetworkReply*, QObject* parent = 0);
 62 QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue* queue, QNetworkReply*, QObject* parent = 0);
4363 ~QNetworkReplyWrapper();
4464
4565 QNetworkReply* reply() const { return m_reply; }
4666 QNetworkReply* release();
4767
 68 void synchronousLoad() { receiveMetaData(); }
 69
4870 QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; }
4971 QString encoding() const { return m_encoding; }
5072 QString advertisedMimeType() const { return m_advertisedMimeType; }
5173
52 Q_SIGNALS:
53  void finished();
54  void metaDataChanged();
55  void readyRead();
56  void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
57 
5874private Q_SLOTS:
5975 void receiveMetaData();
6076 void didReceiveFinished();
 77 void readyRead();
6178
6279private:
6380 void resetConnections();

@@private:
6784
6885 QString m_encoding;
6986 QString m_advertisedMimeType;
 87
 88 QNetworkReplyHandlerCallQueue* m_queue;
7089};
7190
7291class QNetworkReplyHandler : public QObject

@@public:
7998 };
8099
81100 QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false);
82  void setLoadingDeferred(bool);
 101 void setLoadingDeferred(bool deferred) { m_queue.setDeferSignals(deferred); }
83102
84103 QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; }
85104

@@private:
97116 void start();
98117 void resetState();
99118 String httpMethod() const;
100  void resumeDeferredLoad();
101119 void redirect(ResourceResponse&, const QUrl&);
102120 bool wasAborted() const { return !m_resourceHandle; }
103121 QNetworkReply* sendNetworkRequest();

@@private:
105123 QNetworkReplyWrapper* m_replyWrapper;
106124 ResourceHandle* m_resourceHandle;
107125 bool m_redirected;
108  bool m_responseSent;
109126 bool m_responseContainsData;
110127 LoadType m_loadType;
111128 QNetworkAccessManager::Operation m_method;
112129 QNetworkRequest m_request;
113130
114  bool m_deferred;
115 
116131 // defer state holding
117  bool m_hasStarted;
118  bool m_callFinishOnResume;
119  bool m_callSendResponseIfNeededOnResume;
120  bool m_callForwardDataOnResume;
121132 int m_redirectionTries;
 133
 134 QNetworkReplyHandlerCallQueue m_queue;
122135};
123136
124137// Self destructing QIODevice for FormData