Changeset 561 for trunk/src/network/access/qnetworkreplyimpl.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/network/access/qnetworkreplyimpl.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 47 47 #include "QtCore/qdatetime.h" 48 48 #include "QtNetwork/qsslconfiguration.h" 49 49 50 50 51 #include <QtCore/QCoreApplication> … … 53 54 54 55 inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() 55 : copyDevice(0), networkCache(0), 56 : backend(0), outgoingData(0), outgoingDataBuffer(0), 57 copyDevice(0), 56 58 cacheEnabled(false), cacheSaveDevice(0), 59 57 60 bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), 61 58 62 state(Idle) 59 63 { … … 62 66 void QNetworkReplyImplPrivate::_q_startOperation() 63 67 { 64 // This function is called exactly once 68 // ensure this function is only being called once 69 if (state == Working) { 70 qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); 71 return; 72 } 65 73 state = Working; 74 66 75 if (!backend) { 67 76 error(QNetworkReplyImpl::ProtocolUnknownError, … … 75 84 if (operation == QNetworkAccessManager::GetOperation) 76 85 pendingNotifications.append(NotifyDownstreamReadyWrite); 77 if (outgoingData) {78 _q_sourceReadyRead();79 #if 0 // ### FIXME80 if (outgoingData->atEndOfStream() && writeBuffer.isEmpty())81 // empty upload82 emit q->uploadProgress(0, 0);83 #endif84 }85 86 86 87 handleNotifications(); … … 88 89 } 89 90 90 void QNetworkReplyImplPrivate::_q_sourceReadyRead()91 {92 // read data from the outgoingData QIODevice into our internal buffer93 enum { DesiredBufferSize = 32 * 1024 };94 95 if (writeBuffer.size() >= DesiredBufferSize)96 return; // don't grow the buffer too much97 98 // read as many bytes are available or up until we fill up the buffer99 // but always read at least one byte100 qint64 bytesToRead = qBound<qint64>(1, outgoingData->bytesAvailable(),101 DesiredBufferSize - writeBuffer.size());102 char *ptr = writeBuffer.reserve(bytesToRead);103 qint64 bytesActuallyRead = outgoingData->read(ptr, bytesToRead);104 if (bytesActuallyRead == -1) {105 // EOF106 writeBuffer.chop(bytesToRead);107 backendNotify(NotifyCloseUpstreamChannel);108 return;109 }110 111 if (bytesActuallyRead < bytesToRead)112 writeBuffer.chop(bytesToRead - bytesActuallyRead);113 114 // if we did read anything, let the backend know and handle it115 if (bytesActuallyRead)116 backendNotify(NotifyUpstreamReadyRead);117 118 // check for EOF again119 if (!outgoingData->isSequential() && outgoingData->atEnd())120 backendNotify(NotifyCloseUpstreamChannel);121 }122 123 void QNetworkReplyImplPrivate::_q_sourceReadChannelFinished()124 {125 _q_sourceReadyRead();126 }127 128 91 void QNetworkReplyImplPrivate::_q_copyReadyRead() 129 92 { 130 93 Q_Q(QNetworkReplyImpl); 131 if (!copyDevice && !q->isOpen()) 132 return; 133 134 qint64 bytesToRead = nextDownstreamBlockSize(); 135 if (bytesToRead == 0) 136 // we'll be called again, eventually 137 return; 138 139 bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); 140 char *ptr = readBuffer.reserve(bytesToRead); 141 qint64 bytesActuallyRead = copyDevice->read(ptr, bytesToRead); 142 if (bytesActuallyRead == -1) { 143 readBuffer.chop(bytesToRead); 144 backendNotify(NotifyCopyFinished); 145 return; 146 } 147 148 if (bytesActuallyRead != bytesToRead) 149 readBuffer.chop(bytesToRead - bytesActuallyRead); 150 151 if (!copyDevice->isSequential() && copyDevice->atEnd()) 152 backendNotify(NotifyCopyFinished); 153 154 bytesDownloaded += bytesActuallyRead; 94 if (state != Working) 95 return; 96 if (!copyDevice || !q->isOpen()) 97 return; 98 99 forever { 100 qint64 bytesToRead = nextDownstreamBlockSize(); 101 if (bytesToRead == 0) 102 // we'll be called again, eventually 103 break; 104 105 bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); 106 QByteArray byteData; 107 byteData.resize(bytesToRead); 108 qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size()); 109 if (bytesActuallyRead == -1) { 110 byteData.clear(); 111 backendNotify(NotifyCopyFinished); 112 break; 113 } 114 115 byteData.resize(bytesActuallyRead); 116 readBuffer.append(byteData); 117 118 if (!copyDevice->isSequential() && copyDevice->atEnd()) { 119 backendNotify(NotifyCopyFinished); 120 bytesDownloaded += bytesActuallyRead; 121 break; 122 } 123 124 bytesDownloaded += bytesActuallyRead; 125 } 126 127 if (bytesDownloaded == lastBytesDownloaded) { 128 // we didn't read anything 129 return; 130 } 131 155 132 lastBytesDownloaded = bytesDownloaded; 156 133 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); 134 157 135 emit q->downloadProgress(bytesDownloaded, 158 136 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); 159 137 emit q->readyRead(); 138 160 139 } 161 140 … … 164 143 _q_copyReadyRead(); 165 144 } 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 166 206 167 207 void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, … … 175 215 operation = op; 176 216 177 if (outgoingData) { 178 q->connect(outgoingData, SIGNAL(readyRead()), SLOT(_q_sourceReadyRead())); 179 q->connect(outgoingData, SIGNAL(readChannelFinished()), SLOT(_q_sourceReadChannelFinished())); 217 if (outgoingData && backend) { 218 // there is data to be uploaded, e.g. HTTP POST. 219 220 if (!backend->needsResetableUploadData() || !outgoingData->isSequential()) { 221 // backend does not need upload buffering or 222 // fixed size non-sequential 223 // just start the operation 224 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 225 } else { 226 bool bufferingDisallowed = 227 req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, 228 false).toBool(); 229 230 if (bufferingDisallowed) { 231 // if a valid content-length header for the request was supplied, we can disable buffering 232 // if not, we will buffer anyway 233 if (req.header(QNetworkRequest::ContentLengthHeader).isValid()) { 234 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 235 } else { 236 state = Buffering; 237 QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); 238 } 239 } else { 240 // _q_startOperation will be called when the buffering has finished. 241 state = Buffering; 242 QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); 243 } 244 } 245 } else { 246 // No outgoing data (e.g. HTTP GET request) 247 // or no backend 248 // if no backend, _q_startOperation will handle the error of this 249 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 180 250 } 181 251 182 252 q->QIODevice::open(QIODevice::ReadOnly); 183 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);184 }185 186 void QNetworkReplyImplPrivate::setNetworkCache(QAbstractNetworkCache *nc)187 {188 networkCache = nc;189 253 } 190 254 … … 201 265 void QNetworkReplyImplPrivate::handleNotifications() 202 266 { 267 268 269 203 270 NotificationQueue current = pendingNotifications; 204 271 pendingNotifications.clear(); … … 207 274 return; 208 275 209 while ( !current.isEmpty()) {276 while (!current.isEmpty()) { 210 277 InternalNotifications notification = current.dequeue(); 211 278 switch (notification) { … … 217 284 break; 218 285 219 case NotifyUpstreamReadyRead:220 backend->upstreamReadyRead();221 break;222 223 286 case NotifyCloseDownstreamChannel: 224 287 backend->closeDownstreamChannel(); 225 break;226 227 case NotifyCloseUpstreamChannel:228 backend->closeUpstreamChannel();229 288 break; 230 289 … … 239 298 } 240 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 241 323 void QNetworkReplyImplPrivate::createCache() 242 324 { 243 325 // check if we can save and if we're allowed to 244 if (!networkCache || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool()) 326 if (!networkCache() 327 || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool() 328 || request.attribute(QNetworkRequest::CacheLoadControlAttribute, 329 QNetworkRequest::PreferNetwork).toInt() 330 == QNetworkRequest::AlwaysNetwork) 245 331 return; 246 332 cacheEnabled = true; … … 249 335 bool QNetworkReplyImplPrivate::isCachingEnabled() const 250 336 { 251 return (cacheEnabled && networkCache != 0);337 return (cacheEnabled && networkCache != 0); 252 338 } 253 339 … … 273 359 "backend %s probably needs to be fixed", 274 360 backend->metaObject()->className()); 275 networkCache ->remove(url);361 networkCache->remove(url); 276 362 cacheSaveDevice = 0; 277 363 cacheEnabled = false; … … 282 368 { 283 369 if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) { 284 networkCache ->remove(url);370 networkCache->remove(url); 285 371 } else if (cacheEnabled && cacheSaveDevice) { 286 networkCache ->insert(cacheSaveDevice);372 networkCache->insert(cacheSaveDevice); 287 373 } 288 374 cacheSaveDevice = 0; … … 290 376 } 291 377 292 void QNetworkReplyImplPrivate::consume(qint64 count) 293 { 294 Q_Q(QNetworkReplyImpl); 295 if (count <= 0) { 296 qWarning("QNetworkConnection: backend signalled that it consumed %ld bytes", long(count)); 297 return; 298 } 299 300 if (outgoingData) 301 // schedule another read from the source 302 QMetaObject::invokeMethod(q_func(), "_q_sourceReadyRead", Qt::QueuedConnection); 303 304 writeBuffer.skip(count); 305 if (bytesUploaded == -1) 306 bytesUploaded = count; 307 else 308 bytesUploaded += count; 309 310 QVariant totalSize = request.header(QNetworkRequest::ContentLengthHeader); 311 emit q->uploadProgress(bytesUploaded, 312 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); 313 } 378 void QNetworkReplyImplPrivate::emitUploadProgress(qint64 bytesSent, qint64 bytesTotal) 379 { 380 Q_Q(QNetworkReplyImpl); 381 bytesUploaded = bytesSent; 382 pauseNotificationHandling(); 383 emit q->uploadProgress(bytesSent, bytesTotal); 384 resumeNotificationHandling(); 385 } 386 314 387 315 388 qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const … … 319 392 return DesiredBufferSize; 320 393 321 return qMax<qint64>(0, readBufferMaxSize - readBuffer.size()); 322 } 323 324 void QNetworkReplyImplPrivate::feed(const QByteArray &data) 394 return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount()); 395 } 396 397 // we received downstream data and send this to the cache 398 // and to our readBuffer (which in turn gets read by the user of QNetworkReply) 399 void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) 325 400 { 326 401 Q_Q(QNetworkReplyImpl); 327 402 if (!q->isOpen()) 328 403 return; 329 330 char *ptr = readBuffer.reserve(data.size());331 memcpy(ptr, data.constData(), data.size());332 404 333 405 if (cacheEnabled && !cacheSaveDevice) { … … 336 408 metaData.setUrl(url); 337 409 metaData = backend->fetchCacheMetaData(metaData); 338 cacheSaveDevice = networkCache->prepare(metaData); 410 411 // save the redirect request also in the cache 412 QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute); 413 if (redirectionTarget.isValid()) { 414 QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes(); 415 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget); 416 metaData.setAttributes(attributes); 417 } 418 419 cacheSaveDevice = networkCache()->prepare(metaData); 420 339 421 if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) { 340 422 if (cacheSaveDevice && !cacheSaveDevice->isOpen()) 341 423 qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- " 342 424 "class %s probably needs to be fixed", 343 networkCache ->metaObject()->className());344 345 networkCache ->remove(url);425 networkCache->metaObject()->className()); 426 427 networkCache->remove(url); 346 428 cacheSaveDevice = 0; 347 429 cacheEnabled = false; … … 349 431 } 350 432 351 if (cacheSaveDevice) 352 cacheSaveDevice->write(data); 353 354 bytesDownloaded += data.size(); 433 qint64 bytesWritten = 0; 434 for (int i = 0; i < data.bufferCount(); i++) { 435 QByteArray item = data[i]; 436 437 if (cacheSaveDevice) 438 cacheSaveDevice->write(item.constData(), item.size()); 439 readBuffer.append(item); 440 441 bytesWritten += item.size(); 442 } 443 data.clear(); 444 445 bytesDownloaded += bytesWritten; 355 446 lastBytesDownloaded = bytesDownloaded; 356 447 … … 358 449 359 450 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); 451 360 452 emit q->downloadProgress(bytesDownloaded, 361 453 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); 454 455 362 456 emit q->readyRead(); 363 457 364 458 // hopefully we haven't been deleted here 365 459 if (!qq.isNull()) { 460 366 461 // do we still have room in the buffer? 367 462 if (nextDownstreamBlockSize() > 0) … … 370 465 } 371 466 372 void QNetworkReplyImplPrivate::feed(QIODevice *data) 373 { 374 Q_Q(QNetworkReplyImpl); 375 Q_ASSERT(q->isOpen()); 467 // this is used when it was fetched from the cache, right? 468 void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) 469 { 470 Q_Q(QNetworkReplyImpl); 471 if (!q->isOpen()) 472 return; 376 473 377 474 // read until EOF from data … … 393 490 { 394 491 Q_Q(QNetworkReplyImpl); 395 Q_ASSERT_X(state != Finished, "QNetworkReplyImpl",396 "Backend called finished/finishedWithError more than once");492 493 ; 397 494 398 495 state = Finished; 399 496 pendingNotifications.clear(); 400 497 498 401 499 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); 402 if ( bytesDownloaded != lastBytesDownloaded || totalSize.isNull())500 if ( 403 501 emit q->downloadProgress(bytesDownloaded, bytesDownloaded); 404 if (bytesUploaded == -1 && outgoingData) 502 } 503 504 if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer)) 405 505 emit q->uploadProgress(0, 0); 506 406 507 407 508 completeCacheSave(); … … 410 511 // which would delete the backend too... 411 512 // maybe we should protect the backend 513 412 514 emit q->readChannelFinished(); 413 515 emit q->finished(); 516 414 517 } 415 518 … … 456 559 } 457 560 561 562 563 564 565 458 566 QNetworkReplyImpl::QNetworkReplyImpl(QObject *parent) 459 567 : QNetworkReply(*new QNetworkReplyImplPrivate, parent) … … 465 573 Q_D(QNetworkReplyImpl); 466 574 if (d->isCachingEnabled()) 467 d->networkCache->remove(url()); 575 d->networkCache()->remove(url()); 576 if (d->outgoingDataBuffer) 577 delete d->outgoingDataBuffer; 468 578 } 469 579 … … 471 581 { 472 582 Q_D(QNetworkReplyImpl); 473 if (d->state == QNetworkReplyImplPrivate:: Aborted)583 if (d->state == QNetworkReplyImplPrivate::Aborted) 474 584 return; 475 585 476 586 // stop both upload and download 477 if (d->backend) {478 d->backend->deleteLater();479 d->backend = 0;480 }481 587 if (d->outgoingData) 482 588 disconnect(d->outgoingData, 0, this, 0); … … 492 598 } 493 599 d->state = QNetworkReplyImplPrivate::Aborted; 600 601 602 603 604 605 494 606 } 495 607 … … 521 633 qint64 QNetworkReplyImpl::bytesAvailable() const 522 634 { 523 return QNetworkReply::bytesAvailable() + d_func()->readBuffer. size();635 return QNetworkReply::bytesAvailable() + d_func()->readBuffer.(); 524 636 } 525 637 … … 528 640 Q_D(QNetworkReplyImpl); 529 641 if (size > d->readBufferMaxSize && 530 size == d->readBuffer.size())642 size ()) 531 643 d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite); 532 644 … … 558 670 } 559 671 672 673 674 675 676 677 560 678 #endif // QT_NO_OPENSSL 561 679 … … 576 694 } 577 695 578 maxlen = qMin<qint64>(maxlen, d->readBuffer. size());696 maxlen = qMin<qint64>(maxlen, d->readBuffer.()); 579 697 return d->readBuffer.read(data, maxlen); 580 698 }
Note:
See TracChangeset
for help on using the changeset viewer.