Changeset 83691 in webkit
- Timestamp:
- Apr 12, 2011 8:30:32 PM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r83690 r83691 1 2011-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 1 49 2011-04-12 Kenichi Ishibashi <bashi@chromium.org> 2 50 -
trunk/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp
r83673 r83691 150 150 } 151 151 152 QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReply* reply, QObject* parent) 152 QNetworkReplyHandlerCallQueue::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 161 void QNetworkReplyHandlerCallQueue::push(EnqueuedCall method) 162 { 163 m_enqueuedCalls.append(method); 164 flush(); 165 } 166 167 void QNetworkReplyHandlerCallQueue::lock() 168 { 169 ++m_locks; 170 } 171 172 void QNetworkReplyHandlerCallQueue::unlock() 173 { 174 if (!m_locks) 175 return; 176 177 --m_locks; 178 flush(); 179 } 180 181 void QNetworkReplyHandlerCallQueue::setDeferSignals(bool defer) 182 { 183 m_deferSignals = defer; 184 flush(); 185 } 186 187 void 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 200 class QueueLocker { 201 public: 202 QueueLocker(QNetworkReplyHandlerCallQueue* queue) : m_queue(queue) { m_queue->lock(); } 203 ~QueueLocker() { m_queue->unlock(); } 204 private: 205 QNetworkReplyHandlerCallQueue* m_queue; 206 }; 207 208 QNetworkReplyWrapper::QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue* queue, QNetworkReply* reply, QObject* parent) 153 209 : QObject(parent) 154 210 , m_reply(reply) 211 , m_queue(queue) 155 212 { 156 213 Q_ASSERT(m_reply); … … 165 222 if (m_reply) 166 223 m_reply->deleteLater(); 224 m_queue->clear(); 167 225 } 168 226 … … 191 249 resetConnections(); 192 250 251 QueueLocker lock(m_queue); 252 193 253 m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); 194 254 if (m_redirectionTargetUrl.isValid()) { 195 emit metaDataChanged();196 emit finished();255 m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded); 256 m_queue->push(&QNetworkReplyHandler::finish); 197 257 return; 198 258 } … … 202 262 m_advertisedMimeType = extractMIMETypeFromMediaType(contentType); 203 263 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 279 void QNetworkReplyWrapper::didReceiveReadyRead() 280 { 281 m_queue->push(&QNetworkReplyHandler::forwardData); 223 282 } 224 283 … … 227 286 // Disconnecting will make sure that nothing will happen after emitting the finished signal. 228 287 resetConnections(); 229 emit finished();288 m_queue->push(&QNetworkReplyHandler::finish); 230 289 } 231 290 … … 256 315 , m_resourceHandle(handle) 257 316 , m_loadType(loadType) 258 , m_deferred(deferred)259 317 , m_redirectionTries(gMaxRedirections) 318 , m_queue(this, deferred) 260 319 { 261 320 resetState(); … … 282 341 m_request = r.toNetworkRequest(originatingObject); 283 342 284 if (!m_deferred) 285 start(); 343 m_queue.push(&QNetworkReplyHandler::start); 286 344 } 287 345 … … 289 347 { 290 348 m_redirected = false; 291 m_responseSent = false;292 349 m_responseContainsData = false; 293 m_hasStarted = false;294 m_callFinishOnResume = false;295 m_callSendResponseIfNeededOnResume = false;296 m_callForwardDataOnResume = false;297 350 298 351 if (m_replyWrapper) { 299 m_replyWrapper->deleteLater();352 delete m_replyWrapper; 300 353 m_replyWrapper = 0; 301 354 } 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();330 355 } 331 356 … … 346 371 347 372 QNetworkReply* reply = m_replyWrapper->release(); 348 m_replyWrapper->deleteLater();373 delete m_replyWrapper; 349 374 m_replyWrapper = 0; 350 375 return reply; … … 366 391 void QNetworkReplyHandler::finish() 367 392 { 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()); 382 394 383 395 ResourceHandleClient* client = m_resourceHandle->client(); 384 396 if (!client) { 385 m_replyWrapper->deleteLater();397 delete m_replyWrapper; 386 398 m_replyWrapper = 0; 387 399 return; … … 390 402 if (m_redirected) { 391 403 resetState(); 392 start();404 m_queue.push(&QNetworkReplyHandler::start); 393 405 return; 394 406 } … … 410 422 411 423 if (m_replyWrapper) { 412 m_replyWrapper->deleteLater();424 delete m_replyWrapper; 413 425 m_replyWrapper = 0; 414 426 } … … 417 429 void QNetworkReplyHandler::sendResponseIfNeeded() 418 430 { 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()); 427 432 428 433 if (m_replyWrapper->reply()->error() && !shouldIgnoreHttpError(m_replyWrapper->reply(), m_responseContainsData)) 429 434 return; 430 431 if (wasAborted())432 return;433 434 if (m_responseSent)435 return;436 m_responseSent = true;437 435 438 436 ResourceHandleClient* client = m_resourceHandle->client(); … … 534 532 void QNetworkReplyHandler::forwardData() 535 533 { 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); 544 537 545 538 if (m_replyWrapper->reply()->bytesAvailable()) 546 539 m_responseContainsData = true; 547 548 sendResponseIfNeeded();549 550 // don't emit the "Document has moved here" type of HTML551 if (m_redirected)552 return;553 554 if (wasAborted())555 return;556 540 557 541 QByteArray data = m_replyWrapper->reply()->read(m_replyWrapper->reply()->bytesAvailable()); … … 640 624 void QNetworkReplyHandler::start() 641 625 { 642 ASSERT(!m_hasStarted);643 m_hasStarted = true;644 645 626 QNetworkReply* reply = sendNetworkRequest(); 646 627 if (!reply) 647 628 return; 648 629 649 m_replyWrapper = new QNetworkReplyWrapper( reply, this);630 m_replyWrapper = new QNetworkReplyWrapper(&m_queue, reply, this); 650 631 651 632 if (m_loadType == SynchronousLoad && m_replyWrapper->reply()->isFinished()) { … … 654 635 } 655 636 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 660 637 if (m_resourceHandle->firstRequest().reportUploadProgress()) 661 638 connect(m_replyWrapper->reply(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64))); 662 639 } 663 640 641 void QNetworkReplyHandler::synchronousLoad() 642 { 643 if (m_replyWrapper) 644 m_replyWrapper->synchronousLoad(); 645 } 646 664 647 } 665 648 -
trunk/Source/WebCore/platform/network/qt/QNetworkReplyHandler.h
r83673 r83691 36 36 class ResourceHandle; 37 37 class ResourceResponse; 38 class QNetworkReplyHandler; 39 40 class QNetworkReplyHandlerCallQueue { 41 public: 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(); 52 private: 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 }; 38 61 39 62 class QNetworkReplyWrapper : public QObject { 40 63 Q_OBJECT 41 64 public: 42 QNetworkReplyWrapper(QNetworkReply *, QObject* parent = 0);65 QNetworkReplyWrapper(QNetworkReplyHandlerCallQueue*, QNetworkReply*, QObject* parent = 0); 43 66 ~QNetworkReplyWrapper(); 44 67 … … 46 69 QNetworkReply* release(); 47 70 71 void synchronousLoad() { receiveMetaData(); } 72 48 73 QUrl redirectionTargetUrl() const { return m_redirectionTargetUrl; } 49 74 QString encoding() const { return m_encoding; } 50 75 QString advertisedMimeType() const { return m_advertisedMimeType; } 51 76 52 Q_SIGNALS:53 void finished();54 void metaDataChanged();55 void readyRead();56 void uploadProgress(qint64 bytesSent, qint64 bytesTotal);57 58 77 private Q_SLOTS: 59 78 void receiveMetaData(); 60 79 void didReceiveFinished(); 80 void didReceiveReadyRead(); 61 81 62 82 private: … … 68 88 QString m_encoding; 69 89 QString m_advertisedMimeType; 90 91 QNetworkReplyHandlerCallQueue* m_queue; 70 92 }; 71 93 … … 80 102 81 103 QNetworkReplyHandler(ResourceHandle*, LoadType, bool deferred = false); 82 void setLoadingDeferred(bool );104 void setLoadingDeferred(bool deferred) { m_queue.setDeferSignals(deferred); } 83 105 84 106 QNetworkReply* reply() const { return m_replyWrapper ? m_replyWrapper->reply() : 0; } … … 87 109 88 110 QNetworkReply* release(); 111 112 void synchronousLoad(); 89 113 90 114 public slots: … … 98 122 void resetState(); 99 123 String httpMethod() const; 100 void resumeDeferredLoad();101 124 void redirect(ResourceResponse&, const QUrl&); 102 125 bool wasAborted() const { return !m_resourceHandle; } … … 106 129 ResourceHandle* m_resourceHandle; 107 130 bool m_redirected; 108 bool m_responseSent;109 131 bool m_responseContainsData; 110 132 LoadType m_loadType; … … 112 134 QNetworkRequest m_request; 113 135 114 bool m_deferred; 136 // defer state holding 137 int m_redirectionTries; 115 138 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; 122 140 }; 123 141 -
trunk/Source/WebCore/platform/network/qt/ResourceHandleQt.cpp
r83673 r83691 211 211 if (reply->isFinished()) { 212 212 syncLoader.setReplyFinished(true); 213 d->m_job->forwardData(); 214 d->m_job->finish(); 213 d->m_job->synchronousLoad(); 215 214 } else 216 215 syncLoader.waitForCompletion();
Note: See TracChangeset
for help on using the changeset viewer.