Qt 4.8
qnetworkreplyimpl.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qnetworkreplyimpl_p.h"
44 #include "qnetworkcookie.h"
45 #include "qabstractnetworkcache.h"
46 #include "QtCore/qcoreapplication.h"
47 #include "QtCore/qdatetime.h"
48 #include "QtNetwork/qsslconfiguration.h"
49 #include "QtNetwork/qnetworksession.h"
52 
53 #include <QtCore/QCoreApplication>
54 
56 
58 
60  : backend(0), outgoingData(0),
61  copyDevice(0),
62  cacheEnabled(false), cacheSaveDevice(0),
63  notificationHandlingPaused(false),
64  bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), preMigrationDownloaded(-1),
65  httpStatusCode(0),
66  state(Idle)
67  , downloadBufferReadPosition(0)
68  , downloadBufferCurrentSize(0)
69  , downloadBufferMaximumSize(0)
70  , downloadBuffer(0)
71 {
72 }
73 
75 {
76  // ensure this function is only being called once
77  if (state == Working || state == Finished) {
78  qDebug("QNetworkReplyImpl::_q_startOperation was called more than once");
79  return;
80  }
81  state = Working;
82 
83  // note: if that method is called directly, it cannot happen that the backend is 0,
84  // because we just checked via a qobject_cast that we got a http backend (see
85  // QNetworkReplyImplPrivate::setup())
86  if (!backend) {
88  QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!;
89  finished();
90  return;
91  }
92 
93  if (!backend->start()) {
94 #ifndef QT_NO_BEARERMANAGEMENT
95  // backend failed to start because the session state is not Connected.
96  // QNetworkAccessManager will call _q_startOperation again for us when the session
97  // state changes.
99 
100  QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
101 
102  if (session) {
104 
107 
108  if (!session->isOpen())
109  session->open();
110  } else {
111  qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
112  state = Working;
114  QCoreApplication::translate("QNetworkReply", "Network session error."));
115  finished();
116  }
117 #else
118  qWarning("Backend start failed");
119  state = Working;
121  QCoreApplication::translate("QNetworkReply", "backend start error."));
122  finished();
123 #endif
124  return;
125  }
126 
127  if (backend && backend->isSynchronous()) {
128  state = Finished;
129  q_func()->setFinished(true);
130  } else {
131  if (state != Finished) {
134 
136  }
137  }
138 }
139 
141 {
143  if (state != Working)
144  return;
145  if (!copyDevice || !q->isOpen())
146  return;
147 
148  // FIXME Optimize to use download buffer if it is a QBuffer.
149  // Needs to be done where sendCacheContents() (?) of HTTP is emitting
150  // metaDataChanged ?
151 
152  forever {
153  qint64 bytesToRead = nextDownstreamBlockSize();
154  if (bytesToRead == 0)
155  // we'll be called again, eventually
156  break;
157 
158  bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable());
159  QByteArray byteData;
160  byteData.resize(bytesToRead);
161  qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size());
162  if (bytesActuallyRead == -1) {
163  byteData.clear();
165  break;
166  }
167 
168  byteData.resize(bytesActuallyRead);
169  readBuffer.append(byteData);
170 
171  if (!copyDevice->isSequential() && copyDevice->atEnd()) {
173  bytesDownloaded += bytesActuallyRead;
174  break;
175  }
176 
177  bytesDownloaded += bytesActuallyRead;
178  }
179 
181  // we didn't read anything
182  return;
183  }
184 
188  totalSize = totalSize.toLongLong() + preMigrationDownloaded;
190  // emit readyRead before downloadProgress incase this will cause events to be
191  // processed and we get into a recursive call (as in QProgressDialog).
192  emit q->readyRead();
193  emit q->downloadProgress(bytesDownloaded,
194  totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
196 }
197 
199 {
201 }
202 
204 {
206 
207  // make sure this is only called once, ever.
208  //_q_bufferOutgoingData may call it or the readChannelFinished emission
209  if (state != Buffering)
210  return;
211 
212  // disconnect signals
215 
216  // finally, start the request
217  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
218 }
219 
221 {
223 
224  if (!outgoingDataBuffer) {
225  // first call, create our buffer
227 
230  }
231 
232  qint64 bytesBuffered = 0;
233  qint64 bytesToBuffer = 0;
234 
235  // read data into our buffer
236  forever {
237  bytesToBuffer = outgoingData->bytesAvailable();
238  // unknown? just try 2 kB, this also ensures we always try to read the EOF
239  if (bytesToBuffer <= 0)
240  bytesToBuffer = 2*1024;
241 
242  char *dst = outgoingDataBuffer->reserve(bytesToBuffer);
243  bytesBuffered = outgoingData->read(dst, bytesToBuffer);
244 
245  if (bytesBuffered == -1) {
246  // EOF has been reached.
247  outgoingDataBuffer->chop(bytesToBuffer);
248 
250  break;
251  } else if (bytesBuffered == 0) {
252  // nothing read right now, just wait until we get called again
253  outgoingDataBuffer->chop(bytesToBuffer);
254 
255  break;
256  } else {
257  // don't break, try to read() again
258  outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
259  }
260  }
261 }
262 
263 #ifndef QT_NO_BEARERMANAGEMENT
265 {
267 
268  if (manager.isNull())
269  return;
270 
271  QSharedPointer<QNetworkSession> session = manager->d_func()->getNetworkSession();
272  if (!session)
273  return;
274 
275  if (session->state() != QNetworkSession::Connected)
276  return;
277 
278  #ifndef QT_NO_NETWORKPROXY
279  // Re-set proxies here as new session might have changed them
280  proxyList = manager->d_func()->queryProxy(QNetworkProxyQuery(request.url()));
281  #endif
282 
283  switch (state) {
287  // Migrate existing downloads to new network connection.
288  migrateBackend();
289  break;
291  // Start waiting requests.
292  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
293  break;
294  default:
295  ;
296  }
297 }
298 
300 {
301  // Abort waiting and working replies.
302  if (state == WaitingForSession || state == Working) {
303  state = Working;
305  QCoreApplication::translate("QNetworkReply", "Network session error."));
306  finished();
307  }
308 }
309 #endif
310 
312  QIODevice *data)
313 {
315 
316  outgoingData = data;
317  request = req;
318  url = request.url();
319  operation = op;
320 
321  q->QIODevice::open(QIODevice::ReadOnly);
322  // Internal code that does a HTTP reply for the synchronous Ajax
323  // in QtWebKit.
324  QVariant synchronousHttpAttribute = req.attribute(
325  static_cast<QNetworkRequest::Attribute>(QNetworkRequest::SynchronousRequestAttribute));
326  // The synchronous HTTP is a corner case, we will put all upload data in one big QByteArray in the outgoingDataBuffer.
327  // Yes, this is not the most efficient thing to do, but on the other hand synchronous XHR needs to die anyway.
328  if (synchronousHttpAttribute.toBool() && outgoingData) {
330  qint64 previousDataSize = 0;
331  do {
332  previousDataSize = outgoingDataBuffer->size();
334  } while (outgoingDataBuffer->size() != previousDataSize);
335  }
336 
337  if (backend)
338  backend->setSynchronous(synchronousHttpAttribute.toBool());
339 
340 
341  if (outgoingData && backend && !backend->isSynchronous()) {
342  // there is data to be uploaded, e.g. HTTP POST.
343 
345  // backend does not need upload buffering or
346  // fixed size non-sequential
347  // just start the operation
348  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
349  } else {
350  bool bufferingDisallowed =
352  false).toBool();
353 
354  if (bufferingDisallowed) {
355  // if a valid content-length header for the request was supplied, we can disable buffering
356  // if not, we will buffer anyway
358  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
359  } else {
360  state = Buffering;
361  QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection);
362  }
363  } else {
364  // _q_startOperation will be called when the buffering has finished.
365  state = Buffering;
366  QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection);
367  }
368  }
369  } else {
370  // for HTTP, we want to send out the request as fast as possible to the network, without
371  // invoking methods in a QueuedConnection
372 #ifndef QT_NO_HTTP
373  if (qobject_cast<QNetworkAccessHttpBackend *>(backend) || (backend && backend->isSynchronous())) {
375  } else {
376  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
377  }
378 #else
379  if (backend && backend->isSynchronous())
381  else
382  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
383 #endif // QT_NO_HTTP
384  }
385 }
386 
388 {
390  if (!pendingNotifications.contains(notification))
391  pendingNotifications.enqueue(notification);
392 
393  if (pendingNotifications.size() == 1)
395 }
396 
398 {
400  return;
401 
404 
405  if (state != Working)
406  return;
407 
408  while (state == Working && !current.isEmpty()) {
409  InternalNotifications notification = current.dequeue();
410  switch (notification) {
412  if (copyDevice)
414  else
416  break;
417 
420  break;
421 
422  case NotifyCopyFinished: {
423  QIODevice *dev = copyDevice;
424  copyDevice = 0;
425  backend->copyFinished(dev);
426  break;
427  }
428  }
429  }
430 }
431 
432 // Do not handle the notifications while we are emitting downloadProgress
433 // or readyRead
435 {
437 }
438 
439 // Resume notification handling
441 {
444  if (pendingNotifications.size() >= 1)
446 }
447 
449 {
450  if (!backend)
451  return 0;
452  return backend->networkCache();
453 }
454 
456 {
457  // check if we can save and if we're allowed to
458  if (!networkCache()
463  return;
464  cacheEnabled = true;
465 }
466 
468 {
469  return (cacheEnabled && networkCache() != 0);
470 }
471 
473 {
475  if (!enable && !cacheEnabled)
476  return; // nothing to do
477  if (enable && cacheEnabled)
478  return; // nothing to do either!
479 
480  if (enable) {
481  if (bytesDownloaded) {
482  // refuse to enable in this case
483  qCritical("QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written");
484  return;
485  }
486 
487  createCache();
488  } else {
489  // someone told us to turn on, then back off?
490  // ok... but you should make up your mind
491  qDebug("QNetworkReplyImpl: setCachingEnabled(true) called after setCachingEnabled(false) -- "
492  "backend %s probably needs to be fixed",
494  networkCache()->remove(url);
495  cacheSaveDevice = 0;
496  cacheEnabled = false;
498  }
499 }
500 
502 {
503  //destruction of cache invalidates cacheSaveDevice
504  cacheSaveDevice = 0;
505  cacheEnabled = false;
506 }
507 
509 {
511  if (cacheEnabled) {
513  networkCache()->remove(url);
514  } else if (cacheSaveDevice) {
516  }
518  }
519  cacheSaveDevice = 0;
520  cacheEnabled = false;
521 }
522 
524 {
526  bytesUploaded = bytesSent;
528  emit q->uploadProgress(bytesSent, bytesTotal);
530 }
531 
532 
534 {
535  enum { DesiredBufferSize = 32 * 1024 };
536  if (readBufferMaxSize == 0)
537  return DesiredBufferSize;
538 
539  return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount());
540 }
541 
543 {
545 
546  // The disk cache does not support partial content, so don't even try to
547  // save any such content into the cache.
548  if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) {
549  cacheEnabled = false;
550  return;
551  }
552 
553  // save the meta data
554  QNetworkCacheMetaData metaData;
555  metaData.setUrl(url);
556  metaData = backend->fetchCacheMetaData(metaData);
557 
558  // save the redirect request also in the cache
559  QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute);
560  if (redirectionTarget.isValid()) {
562  attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget);
563  metaData.setAttributes(attributes);
564  }
565 
566  cacheSaveDevice = networkCache()->prepare(metaData);
567 
570  qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- "
571  "class %s probably needs to be fixed",
573 
574  networkCache()->remove(url);
575  cacheSaveDevice = 0;
576  cacheEnabled = false;
577  } else {
578  q->connect(networkCache(), SIGNAL(destroyed()), SLOT(_q_cacheDestroyed()));
579  }
580 }
581 
582 // we received downstream data and send this to the cache
583 // and to our readBuffer (which in turn gets read by the user of QNetworkReply)
585 {
587  if (!q->isOpen())
588  return;
589 
590  if (cacheEnabled && !cacheSaveDevice) {
592  }
593 
594  qint64 bytesWritten = 0;
595  for (int i = 0; i < data.bufferCount(); i++) {
596  QByteArray const &item = data[i];
597 
598  if (cacheSaveDevice)
599  cacheSaveDevice->write(item.constData(), item.size());
600  readBuffer.append(item);
601 
602  bytesWritten += item.size();
603  }
604  data.clear();
605 
606  bytesDownloaded += bytesWritten;
608 
610 }
611 
613 {
615 
618  totalSize = totalSize.toLongLong() + preMigrationDownloaded;
620  // important: At the point of this readyRead(), the data parameter list must be empty,
621  // else implicit sharing will trigger memcpy when the user is reading data!
622  emit q->readyRead();
623  // emit readyRead before downloadProgress incase this will cause events to be
624  // processed and we get into a recursive call (as in QProgressDialog).
625  emit q->downloadProgress(bytesDownloaded,
626  totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
627 
629  // do we still have room in the buffer?
630  if (nextDownstreamBlockSize() > 0)
632 }
633 
634 // this is used when it was fetched from the cache, right?
636 {
638  if (!q->isOpen())
639  return;
640 
641  // read until EOF from data
642  if (copyDevice) {
643  qCritical("QNetworkReplyImpl: copy from QIODevice already in progress -- "
644  "backend probly needs to be fixed");
645  return;
646  }
647 
648  copyDevice = data;
649  q->connect(copyDevice, SIGNAL(readyRead()), SLOT(_q_copyReadyRead()));
650  q->connect(copyDevice, SIGNAL(readChannelFinished()), SLOT(_q_copyReadChannelFinished()));
651 
652  // start the copy:
654 }
655 
657 {
658  Q_UNUSED(data)
659  // TODO implement
660 
661  // TODO call
662 
663  qFatal("QNetworkReplyImplPrivate::appendDownstreamData not implemented");
664 }
665 
666 static void downloadBufferDeleter(char *ptr)
667 {
668  delete[] ptr;
669 }
670 
672 {
674 
675  if (!downloadBuffer) {
676  // We are requested to create it
677  // Check attribute() if allocating a buffer of that size can be allowed
679  if (bufferAllocationPolicy.isValid() && bufferAllocationPolicy.toLongLong() >= size) {
682  downloadBuffer = new char[downloadBufferMaximumSize]; // throws if allocation fails
684 
686  }
687  }
688 
689  return downloadBuffer;
690 }
691 
693 {
695 
701 }
702 
703 
705 {
707  if (!q->isOpen())
708  return;
709 
712 
713  if (cacheSaveDevice && bytesReceived == bytesTotal) {
714 // if (lastBytesDownloaded == -1)
715 // lastBytesDownloaded = 0;
716 // cacheSaveDevice->write(downloadBuffer + lastBytesDownloaded, bytesReceived - lastBytesDownloaded);
717 
718  // Write everything in one go if we use a download buffer. might be more performant.
719  cacheSaveDevice->write(downloadBuffer, bytesTotal);
720  }
721 
722  bytesDownloaded = bytesReceived;
723  lastBytesDownloaded = bytesReceived;
724 
725  downloadBufferCurrentSize = bytesReceived;
726 
727  // Only emit readyRead when actual data is there
728  // emit readyRead before downloadProgress incase this will cause events to be
729  // processed and we get into a recursive call (as in QProgressDialog).
730  if (bytesDownloaded > 0)
731  emit q->readyRead();
732  emit q->downloadProgress(bytesDownloaded, bytesTotal);
733 }
734 
736 {
738 
739  if (state == Finished || state == Aborted || state == WaitingForSession)
740  return;
741 
745  totalSize = totalSize.toLongLong() + preMigrationDownloaded;
746 
747  if (!manager.isNull()) {
748 #ifndef QT_NO_BEARERMANAGEMENT
749  QSharedPointer<QNetworkSession> session (manager->d_func()->getNetworkSession());
750  if (session && session->state() == QNetworkSession::Roaming &&
752  // only content with a known size will fail with a temporary network failure error
753  if (!totalSize.isNull()) {
754  if (bytesDownloaded != totalSize) {
755  if (migrateBackend()) {
756  // either we are migrating or the request is finished/aborted
757  if (state == Reconnecting || state == WaitingForSession) {
759  return; // exit early if we are migrating.
760  }
761  } else {
763  QNetworkReply::tr("Temporary network failure."));
764  }
765  }
766  }
767  }
768 #endif
769  }
771 
772  state = Finished;
773  q->setFinished(true);
774 
776 
778  if (totalSize.isNull() || totalSize == -1) {
779  emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
780  }
781 
783  emit q->uploadProgress(0, 0);
785 
786  // if we don't know the total size of or we received everything save the cache
787  if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
789 
790  // note: might not be a good idea, since users could decide to delete us
791  // which would delete the backend too...
792  // maybe we should protect the backend
794  emit q->readChannelFinished();
795  emit q->finished();
797 }
798 
800 {
802  // Can't set and emit multiple errors.
804  qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
805  return;
806  }
807 
808  errorCode = code;
809  q->setErrorString(errorMessage);
810 
811  // note: might not be a good idea, since users could decide to delete us
812  // which would delete the backend too...
813  // maybe we should protect the backend
814  emit q->error(code);
815 }
816 
818 {
820  // 1. do we have cookies?
821  // 2. are we allowed to set them?
823  && (static_cast<QNetworkRequest::LoadControl>
826  QList<QNetworkCookie> cookies =
829  if (jar)
830  jar->setCookiesFromUrl(cookies, url);
831  }
832  emit q->metaDataChanged();
833 }
834 
836 {
838 }
839 
841 {
842 #ifndef QT_NO_OPENSSL
844  emit q->sslErrors(errors);
845 #else
846  Q_UNUSED(errors);
847 #endif
848 }
849 
852 {
853 }
854 
856 {
858 
859  // This code removes the data from the cache if it was prematurely aborted.
860  // See QNetworkReplyImplPrivate::completeCacheSave(), we disable caching there after the cache
861  // save had been properly finished. So if it is still enabled it means we got deleted/aborted.
862  if (d->isCachingEnabled())
863  d->networkCache()->remove(url());
864 }
865 
867 {
870  return;
871 
872  // stop both upload and download
873  if (d->outgoingData)
874  disconnect(d->outgoingData, 0, this, 0);
875  if (d->copyDevice)
876  disconnect(d->copyDevice, 0, this, 0);
877 
879 
880  if (d->state != QNetworkReplyImplPrivate::Finished) {
881  // call finished which will emit signals
882  d->error(OperationCanceledError, tr("Operation canceled"));
885  d->finished();
886  }
888 
889  // finished may access the backend
890  if (d->backend) {
891  d->backend->deleteLater();
892  d->backend = 0;
893  }
894 }
895 
897 {
899  if (d->state == QNetworkReplyImplPrivate::Aborted ||
901  return;
902 
903  // stop the download
904  if (d->backend)
905  d->backend->closeDownstreamChannel();
906  if (d->copyDevice)
907  disconnect(d->copyDevice, 0, this, 0);
908 
910 
911  // call finished which will emit signals
912  d->error(OperationCanceledError, tr("Operation canceled"));
913  d->finished();
914 }
915 
917 {
918  Q_D(const QNetworkReplyImpl);
919  return QNetworkReply::canReadLine() || d->readBuffer.canReadLine();
920 }
921 
922 
929 {
930  // Special case for the "zero copy" download buffer
931  Q_D(const QNetworkReplyImpl);
932  if (d->downloadBuffer) {
933  qint64 maxAvail = d->downloadBufferCurrentSize - d->downloadBufferReadPosition;
934  return QNetworkReply::bytesAvailable() + maxAvail;
935  }
936 
937  return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount();
938 }
939 
941 {
943  if (size > d->readBufferMaxSize &&
944  size > d->readBuffer.byteAmount())
946 
948 
949  if (d->backend) {
950  d->backend->setDownstreamLimited(d->readBufferMaxSize > 0);
951  d->backend->setReadBufferSize(size);
952  }
953 }
954 
955 #ifndef QT_NO_OPENSSL
957 {
958  Q_D(const QNetworkReplyImpl);
959  QSslConfiguration config;
960  if (d->backend)
961  d->backend->fetchSslConfiguration(config);
962  return config;
963 }
964 
966 {
968  if (d->backend && !config.isNull())
969  d->backend->setSslConfiguration(config);
970 }
971 
973 {
975  if (d->backend)
976  d->backend->ignoreSslErrors();
977 }
978 
980 {
982  if (d->backend)
983  d->backend->ignoreSslErrors(errors);
984 }
985 #endif // QT_NO_OPENSSL
986 
991 {
993 
994  // Special case code if we have the "zero copy" download buffer
995  if (d->downloadBuffer) {
996  qint64 maxAvail = qMin<qint64>(d->downloadBufferCurrentSize - d->downloadBufferReadPosition, maxlen);
997  if (maxAvail == 0)
998  return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
999  // FIXME what about "Aborted" state?
1000  qMemCopy(data, d->downloadBuffer + d->downloadBufferReadPosition, maxAvail);
1001  d->downloadBufferReadPosition += maxAvail;
1002  return maxAvail;
1003  }
1004 
1005 
1006  if (d->readBuffer.isEmpty())
1007  return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
1008  // FIXME what about "Aborted" state?
1009 
1011  if (maxlen == 1) {
1012  // optimization for getChar()
1013  *data = d->readBuffer.getChar();
1014  if (d->backend && readBufferSize())
1015  d->backend->emitReadBufferFreed(1);
1016  return 1;
1017  }
1018 
1019  maxlen = qMin<qint64>(maxlen, d->readBuffer.byteAmount());
1020  qint64 bytesRead = d->readBuffer.read(data, maxlen);
1021  if (d->backend && readBufferSize())
1022  d->backend->emitReadBufferFreed(bytesRead);
1023  return bytesRead;
1024 }
1025 
1030 {
1031  if (e->type() == QEvent::NetworkReplyUpdated) {
1032  d_func()->handleNotifications();
1033  return true;
1034  }
1035 
1036  return QObject::event(e);
1037 }
1038 
1039 /*
1040  Migrates the backend of the QNetworkReply to a new network connection if required. Returns
1041  true if the reply is migrated or it is not required; otherwise returns false.
1042 */
1044 {
1046 
1047  // Network reply is already finished or aborted, don't need to migrate.
1048  if (state == Finished || state == Aborted)
1049  return true;
1050 
1051  // Request has outgoing data, not migrating.
1052  if (outgoingData)
1053  return false;
1054 
1055  // Request is serviced from the cache, don't need to migrate.
1056  if (copyDevice)
1057  return true;
1058 
1059  // Backend does not support resuming download.
1060  if (backend && !backend->canResume())
1061  return false;
1062 
1064 
1065  if (backend) {
1066  delete backend;
1067  backend = 0;
1068  }
1069 
1070  cookedHeaders.clear();
1071  rawHeaders.clear();
1072 
1073  preMigrationDownloaded = bytesDownloaded;
1074 
1075  backend = manager->d_func()->findBackend(operation, request);
1076 
1077  if (backend) {
1078  backend->setParent(q);
1079  backend->reply = this;
1080  backend->setResumeOffset(bytesDownloaded);
1081  }
1082 
1083 #ifndef QT_NO_HTTP
1084  if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
1085  _q_startOperation();
1086  } else {
1087  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
1088  }
1089 #else
1090  QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
1091 #endif // QT_NO_HTTP
1092 
1093  return true;
1094 }
1095 
1096 #ifndef QT_NO_BEARERMANAGEMENT
1098  const QNetworkRequest &req,
1100 : QNetworkReply(parent)
1101 {
1102  setRequest(req);
1103  setUrl(req.url());
1104  setOperation(op);
1105 
1106  qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
1107 
1108  QString msg = QCoreApplication::translate("QNetworkAccessManager",
1109  "Network access is disabled.");
1111 
1115 }
1116 
1118 {
1119 }
1120 #endif
1121 
1123 
1124 #include "moc_qnetworkreplyimpl_p.cpp"
1125 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
double d
Definition: qnumeric_p.h:62
void appendDownstreamDataDownloadBuffer(qint64, qint64)
QDisabledNetworkReply(QObject *parent, const QNetworkRequest &req, QNetworkAccessManager::Operation op)
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
Definition: qiodevice.cpp:642
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QVariant qVariantFromValue(const T &)
Definition: qvariant.h:451
void setUrl(const QUrl &url)
Sets the URL being processed to be url.
virtual bool needsResetableUploadData()
virtual void setReadBufferSize(qint64 size)
Sets the size of the read buffer to be size bytes.
virtual qint64 readData(char *data, qint64 maxlen)
void setError(NetworkError errorCode, const QString &errorString)
Sets the error condition to be errorCode.
bool isNull() const
Returns true if this is a NULL variant, false otherwise.
Definition: qvariant.cpp:3102
QPointer< QNetworkAccessManager > manager
bool isNull() const
Returns true if the referenced object has been destroyed or if there is no referenced object; otherwi...
Definition: qpointer.h:70
static void downloadBufferDeleter(char *ptr)
void append(const QByteArray &qba)
virtual void ignoreSslErrors()
If this function is called, SSL errors related to network connection will be ignored, including certificate validation errors.
static void postEvent(QObject *receiver, QEvent *event)
Adds the event event, with the object receiver as the receiver of the event, to an event queue and re...
virtual void closeDownstreamChannel()=0
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
Definition: qnetworkreply.h:65
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
QVariant attribute(Attribute code, const QVariant &defaultValue=QVariant()) const
Returns the attribute associated with the code code.
#define SLOT(a)
Definition: qobjectdefs.h:226
NetworkError
Indicates all possible error conditions found during the processing of the request.
Definition: qnetworkreply.h:70
Operation
Indicates the operation this reply is processing.
virtual void setReadBufferSize(qint64 size)
Sets the size of the read buffer to be size bytes.
QList< QNetworkProxy > proxyList
#define Q_ARG(type, data)
Definition: qobjectdefs.h:246
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
bool toBool() const
Returns the variant as a bool if the variant has type() Bool.
Definition: qvariant.cpp:2691
QNetworkAccessBackend * backend
void setAttributes(const AttributesMap &attributes)
Sets all attributes of this cache item to be the map attributes.
void append(QByteDataBuffer &other)
Definition: qbytedata_p.h:77
NotificationQueue pendingNotifications
virtual QNetworkCacheMetaData fetchCacheMetaData(const QNetworkCacheMetaData &metaData) const
virtual bool remove(const QUrl &url)=0
Removes the cache entry for url, returning true if success otherwise false.
qint64 nextDownstreamBlockSize() const
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
QSharedPointer< char > downloadBufferPointer
void appendDownstreamData(QByteDataBuffer &data)
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
virtual Q_INVOKABLE void ignoreSslErrorsImplementation(const QList< QSslError > &errors)
#define Q_D(Class)
Definition: qglobal.h:2482
QNetworkRequest request() const
Returns the request that was posted for this reply.
virtual bool atEnd() const
Returns true if the current read and write position is at the end of the device (i.e.
Definition: qiodevice.cpp:711
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
virtual void insert(QIODevice *device)=0
Inserts the data in device and the prepared meta data into the cache.
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
QUrl url() const
Returns the URL this network request is referring to.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
void setParent(QObject *)
Makes the object a child of parent.
Definition: qobject.cpp:1950
static QString translate(const char *context, const char *key, const char *disambiguation=0, Encoding encoding=CodecForTr)
void setOperation(QNetworkAccessManager::Operation operation)
Sets the associated operation for this object to be operation.
#define Q_Q(Class)
Definition: qglobal.h:2483
int toInt(bool *ok=0) const
Returns the variant as an int if the variant has type() Int , Bool , ByteArray , Char ...
Definition: qvariant.cpp:2625
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
void redirectionRequested(const QUrl &target)
Q_CORE_EXPORT void qDebug(const char *,...)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
void setUrl(const QUrl &url)
Sets the URL this network cache meta data to to be url.
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
char * reserve(int bytes)
SessionError
This enum describes the session errors that can occur.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
qlonglong toLongLong(bool *ok=0) const
Returns the variant as a long long int if the variant has type() LongLong , Bool , ByteArray , Char , Double , Int , String , UInt , or ULongLong ; otherwise returns 0.
Definition: qvariant.cpp:2659
bool isOpen() const
Returns true if the device is open; otherwise returns false.
Definition: qiodevice.cpp:530
QBool contains(const T &t) const
Returns true if the list contains an occurrence of value; otherwise returns false.
Definition: qlist.h:880
void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
virtual void close()
Closes this device for reading.
QVariant header(KnownHeaders header) const
Returns the value of the known network header header if it is present in this request.
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
#define emit
Definition: qobjectdefs.h:76
bool isNull() const
Returns true if this is a null QSslConfiguration object.
LoadControl
Indicates if an aspect of the request&#39;s loading mechanism has been manually overridden, e.
Q_CORE_EXPORT void qWarning(const char *,...)
qint64 readBufferSize() const
Returns the size of the read buffer, in bytes.
static const char * data(const QByteArray &arr)
AttributesMap attributes() const
Returns all the attributes stored with this cache item.
virtual bool setCookiesFromUrl(const QList< QNetworkCookie > &cookieList, const QUrl &url)
Adds the cookies in the list cookieList to this cookie jar.
char * getDownloadBuffer(qint64 size)
const T * ptr(const T &t)
QNetworkAccessManager::Operation operation
void clear()
Removes all items from the list.
Definition: qlist.h:764
__int64 qint64
Definition: qglobal.h:942
QAbstractNetworkCache * networkCache() const
virtual QIODevice * prepare(const QNetworkCacheMetaData &metaData)=0
Returns the device that should be populated with the data for the cache item metaData.
void setRequest(const QNetworkRequest &request)
Sets the associated request for this object to be request.
void setDownloadBuffer(QSharedPointer< char > sp, qint64 size)
#define Q_DECLARE_METATYPE(TYPE)
This macro makes the type Type known to QMetaType as long as it provides a public default constructor...
Definition: qmetatype.h:265
State state() const
Returns the state of the session.
QAbstractNetworkCache * networkCache() const
The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
Definition: qiodevice.cpp:454
QNetworkReply::NetworkError errorCode
#define Q_INT64_C(c)
Definition: qglobal.h:940
The QNetworkProxyQuery class is used to query the proxy settings for a socket.
Definition: qnetworkproxy.h:60
QNetworkRequest request
T * data() const
Returns the value of the pointer referenced by this object.
void * qMemCopy(void *dest, const void *src, size_t n)
Definition: qglobal.cpp:2508
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition: qqueue.h:60
Q_CORE_EXPORT void qFatal(const char *,...)
QString scheme() const
Returns the scheme of the URL.
Definition: qurl.cpp:4550
QSharedPointer< QRingBuffer > outgoingDataBuffer
CookedHeadersMap cookedHeaders
virtual void close()
Closes this device for reading.
void chop(int bytes)
void sslErrors(const QList< QSslError > &errors)
Q_INVOKABLE QSslConfiguration sslConfigurationImplementation() const
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
void resize(int size)
Sets the size of the byte array to size bytes.
void error(QNetworkReply::NetworkError code, const QString &errorString)
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
Definition: qiodevice.cpp:752
const char * className() const
Returns the class name.
Definition: qobjectdefs.h:491
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
T qvariant_cast(const QVariant &)
Definition: qvariant.h:571
QNetworkReplyImpl(QObject *parent=0)
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
Q_INVOKABLE void setSslConfigurationImplementation(const QSslConfiguration &configuration)
virtual void abort()
Aborts the operation immediately and close down any network connections still open.
QObject * parent
Definition: qobject.h:92
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
The QSslConfiguration class holds the configuration and state of an SSL connection.
void setCachingEnabled(bool enable)
virtual bool canReadLine() const
Returns true if a complete line of data can be read from the device; otherwise returns false...
Definition: qiodevice.cpp:1330
virtual void copyFinished(QIODevice *)
QUrl url() const
Returns the URL of the content downloaded or uploaded.
QNetworkAccessManager * manager() const
Returns the QNetworkAccessManager that was used to create this QNetworkReply object.
T dequeue()
Removes the head item in the queue and returns it.
Definition: qqueue.h:61
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
bool isValid() const
Returns true if the storage type of this variant is not QVariant::Invalid; otherwise returns false...
Definition: qvariant.h:485
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal)
qint64 bufferCount() const
Definition: qbytedata_p.h:187
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
QNetworkAccessManager::Operation operation() const
Returns the operation that was posted for this reply.
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
void backendNotify(InternalNotifications notification)
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
virtual qint64 bytesAvailable() const
Returns the number of bytes available for reading with QIODevice::read().
virtual bool canReadLine() const
Returns true if a complete line of data can be read from the device; otherwise returns false...
qint64 byteAmount() const
Definition: qbytedata_p.h:181
QNetworkCookieJar * cookieJar() const
Returns the QNetworkCookieJar that is used to store cookies obtained from the network as well as cook...
The QNetworkCacheMetaData class provides cache information.
virtual bool event(QEvent *)
virtual const QMetaObject * metaObject() const
Returns a pointer to the meta-object of this object.
virtual bool start()
Starts the backend.
Q_CORE_EXPORT void qCritical(const char *,...)
int size() const
The QAbstractNetworkCache class provides the interface for cache implementations. ...
#define forever
This macro is provided for convenience for writing infinite loops.
Definition: qglobal.h:2452