source: trunk/src/network/access/qnetworkreplyimpl.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 23.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
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**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qnetworkreplyimpl_p.h"
43#include "qnetworkaccessbackend_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 "qnetworkaccesshttpbackend_p.h"
50
51#include <QtCore/QCoreApplication>
52
53QT_BEGIN_NAMESPACE
54
55inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
56 : backend(0), outgoingData(0), outgoingDataBuffer(0),
57 copyDevice(0),
58 cacheEnabled(false), cacheSaveDevice(0),
59 notificationHandlingPaused(false),
60 bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
61 httpStatusCode(0),
62 state(Idle)
63{
64}
65
66void QNetworkReplyImplPrivate::_q_startOperation()
67{
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 }
73 state = Working;
74
75 // note: if that method is called directly, it cannot happen that the backend is 0,
76 // because we just checked via a qobject_cast that we got a http backend (see
77 // QNetworkReplyImplPrivate::setup())
78 if (!backend) {
79 error(QNetworkReplyImpl::ProtocolUnknownError,
80 QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!;
81 finished();
82 return;
83 }
84
85 backend->open();
86 if (state != Finished) {
87 if (operation == QNetworkAccessManager::GetOperation)
88 pendingNotifications.append(NotifyDownstreamReadyWrite);
89
90 handleNotifications();
91 }
92}
93
94void QNetworkReplyImplPrivate::_q_copyReadyRead()
95{
96 Q_Q(QNetworkReplyImpl);
97 if (state != Working)
98 return;
99 if (!copyDevice || !q->isOpen())
100 return;
101
102 forever {
103 qint64 bytesToRead = nextDownstreamBlockSize();
104 if (bytesToRead == 0)
105 // we'll be called again, eventually
106 break;
107
108 bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable());
109 QByteArray byteData;
110 byteData.resize(bytesToRead);
111 qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size());
112 if (bytesActuallyRead == -1) {
113 byteData.clear();
114 backendNotify(NotifyCopyFinished);
115 break;
116 }
117
118 byteData.resize(bytesActuallyRead);
119 readBuffer.append(byteData);
120
121 if (!copyDevice->isSequential() && copyDevice->atEnd()) {
122 backendNotify(NotifyCopyFinished);
123 bytesDownloaded += bytesActuallyRead;
124 break;
125 }
126
127 bytesDownloaded += bytesActuallyRead;
128 }
129
130 if (bytesDownloaded == lastBytesDownloaded) {
131 // we didn't read anything
132 return;
133 }
134
135 lastBytesDownloaded = bytesDownloaded;
136 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
137 pauseNotificationHandling();
138 emit q->downloadProgress(bytesDownloaded,
139 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
140 emit q->readyRead();
141 resumeNotificationHandling();
142}
143
144void QNetworkReplyImplPrivate::_q_copyReadChannelFinished()
145{
146 _q_copyReadyRead();
147}
148
149void QNetworkReplyImplPrivate::_q_bufferOutgoingDataFinished()
150{
151 Q_Q(QNetworkReplyImpl);
152
153 // make sure this is only called once, ever.
154 //_q_bufferOutgoingData may call it or the readChannelFinished emission
155 if (state != Buffering)
156 return;
157
158 // disconnect signals
159 QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
160 QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
161
162 // finally, start the request
163 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
164}
165
166void QNetworkReplyImplPrivate::_q_bufferOutgoingData()
167{
168 Q_Q(QNetworkReplyImpl);
169
170 if (!outgoingDataBuffer) {
171 // first call, create our buffer
172 outgoingDataBuffer = new QRingBuffer();
173
174 QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
175 QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
176 }
177
178 qint64 bytesBuffered = 0;
179 qint64 bytesToBuffer = 0;
180
181 // read data into our buffer
182 forever {
183 bytesToBuffer = outgoingData->bytesAvailable();
184 // unknown? just try 2 kB, this also ensures we always try to read the EOF
185 if (bytesToBuffer <= 0)
186 bytesToBuffer = 2*1024;
187
188 char *dst = outgoingDataBuffer->reserve(bytesToBuffer);
189 bytesBuffered = outgoingData->read(dst, bytesToBuffer);
190
191 if (bytesBuffered == -1) {
192 // EOF has been reached.
193 outgoingDataBuffer->chop(bytesToBuffer);
194
195 _q_bufferOutgoingDataFinished();
196 break;
197 } else if (bytesBuffered == 0) {
198 // nothing read right now, just wait until we get called again
199 outgoingDataBuffer->chop(bytesToBuffer);
200
201 break;
202 } else {
203 // don't break, try to read() again
204 outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
205 }
206 }
207}
208
209void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
210 QIODevice *data)
211{
212 Q_Q(QNetworkReplyImpl);
213
214 outgoingData = data;
215 request = req;
216 url = request.url();
217 operation = op;
218
219 if (outgoingData && backend) {
220 // there is data to be uploaded, e.g. HTTP POST.
221
222 if (!backend->needsResetableUploadData() || !outgoingData->isSequential()) {
223 // backend does not need upload buffering or
224 // fixed size non-sequential
225 // just start the operation
226 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
227 } else {
228 bool bufferingDisallowed =
229 req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute,
230 false).toBool();
231
232 if (bufferingDisallowed) {
233 // if a valid content-length header for the request was supplied, we can disable buffering
234 // if not, we will buffer anyway
235 if (req.header(QNetworkRequest::ContentLengthHeader).isValid()) {
236 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
237 } else {
238 state = Buffering;
239 QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection);
240 }
241 } else {
242 // _q_startOperation will be called when the buffering has finished.
243 state = Buffering;
244 QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection);
245 }
246 }
247 } else {
248 // No outgoing data (e.g. HTTP GET request)
249 // or no backend
250 // if no backend, _q_startOperation will handle the error of this
251
252 // for HTTP, we want to send out the request as fast as possible to the network, without
253 // invoking methods in a QueuedConnection
254 if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
255 _q_startOperation();
256 } else {
257 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
258 }
259 }
260
261 q->QIODevice::open(QIODevice::ReadOnly);
262}
263
264void QNetworkReplyImplPrivate::backendNotify(InternalNotifications notification)
265{
266 Q_Q(QNetworkReplyImpl);
267 if (!pendingNotifications.contains(notification))
268 pendingNotifications.enqueue(notification);
269
270 if (pendingNotifications.size() == 1)
271 QCoreApplication::postEvent(q, new QEvent(QEvent::NetworkReplyUpdated));
272}
273
274void QNetworkReplyImplPrivate::handleNotifications()
275{
276 if (notificationHandlingPaused)
277 return;
278
279 NotificationQueue current = pendingNotifications;
280 pendingNotifications.clear();
281
282 if (state != Working)
283 return;
284
285 while (state == Working && !current.isEmpty()) {
286 InternalNotifications notification = current.dequeue();
287 switch (notification) {
288 case NotifyDownstreamReadyWrite:
289 if (copyDevice)
290 _q_copyReadyRead();
291 else
292 backend->downstreamReadyWrite();
293 break;
294
295 case NotifyCloseDownstreamChannel:
296 backend->closeDownstreamChannel();
297 break;
298
299 case NotifyCopyFinished: {
300 QIODevice *dev = copyDevice;
301 copyDevice = 0;
302 backend->copyFinished(dev);
303 break;
304 }
305 }
306 }
307}
308
309// Do not handle the notifications while we are emitting downloadProgress
310// or readyRead
311void QNetworkReplyImplPrivate::pauseNotificationHandling()
312{
313 notificationHandlingPaused = true;
314}
315
316// Resume notification handling
317void QNetworkReplyImplPrivate::resumeNotificationHandling()
318{
319 Q_Q(QNetworkReplyImpl);
320 notificationHandlingPaused = false;
321 if (pendingNotifications.size() >= 1)
322 QCoreApplication::postEvent(q, new QEvent(QEvent::NetworkReplyUpdated));
323}
324
325QAbstractNetworkCache *QNetworkReplyImplPrivate::networkCache() const
326{
327 if (!backend)
328 return 0;
329 return backend->networkCache();
330}
331
332void QNetworkReplyImplPrivate::createCache()
333{
334 // check if we can save and if we're allowed to
335 if (!networkCache()
336 || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool()
337 || request.attribute(QNetworkRequest::CacheLoadControlAttribute,
338 QNetworkRequest::PreferNetwork).toInt()
339 == QNetworkRequest::AlwaysNetwork)
340 return;
341 cacheEnabled = true;
342}
343
344bool QNetworkReplyImplPrivate::isCachingEnabled() const
345{
346 return (cacheEnabled && networkCache() != 0);
347}
348
349void QNetworkReplyImplPrivate::setCachingEnabled(bool enable)
350{
351 if (!enable && !cacheEnabled)
352 return; // nothing to do
353 if (enable && cacheEnabled)
354 return; // nothing to do either!
355
356 if (enable) {
357 if (bytesDownloaded) {
358 // refuse to enable in this case
359 qCritical("QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written");
360 return;
361 }
362
363 createCache();
364 } else {
365 // someone told us to turn on, then back off?
366 // ok... but you should make up your mind
367 qDebug("QNetworkReplyImpl: setCachingEnabled(true) called after setCachingEnabled(false) -- "
368 "backend %s probably needs to be fixed",
369 backend->metaObject()->className());
370 networkCache()->remove(url);
371 cacheSaveDevice = 0;
372 cacheEnabled = false;
373 }
374}
375
376void QNetworkReplyImplPrivate::completeCacheSave()
377{
378 if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) {
379 networkCache()->remove(url);
380 } else if (cacheEnabled && cacheSaveDevice) {
381 networkCache()->insert(cacheSaveDevice);
382 }
383 cacheSaveDevice = 0;
384 cacheEnabled = false;
385}
386
387void QNetworkReplyImplPrivate::emitUploadProgress(qint64 bytesSent, qint64 bytesTotal)
388{
389 Q_Q(QNetworkReplyImpl);
390 bytesUploaded = bytesSent;
391 pauseNotificationHandling();
392 emit q->uploadProgress(bytesSent, bytesTotal);
393 resumeNotificationHandling();
394}
395
396
397qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const
398{
399 enum { DesiredBufferSize = 32 * 1024 };
400 if (readBufferMaxSize == 0)
401 return DesiredBufferSize;
402
403 return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount());
404}
405
406void QNetworkReplyImplPrivate::initCacheSaveDevice()
407{
408 Q_Q(QNetworkReplyImpl);
409
410 // save the meta data
411 QNetworkCacheMetaData metaData;
412 metaData.setUrl(url);
413 metaData = backend->fetchCacheMetaData(metaData);
414
415 // save the redirect request also in the cache
416 QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute);
417 if (redirectionTarget.isValid()) {
418 QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes();
419 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget);
420 metaData.setAttributes(attributes);
421 }
422
423 cacheSaveDevice = networkCache()->prepare(metaData);
424
425 if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) {
426 if (cacheSaveDevice && !cacheSaveDevice->isOpen())
427 qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- "
428 "class %s probably needs to be fixed",
429 networkCache()->metaObject()->className());
430
431 networkCache()->remove(url);
432 cacheSaveDevice = 0;
433 cacheEnabled = false;
434 }
435}
436
437// we received downstream data and send this to the cache
438// and to our readBuffer (which in turn gets read by the user of QNetworkReply)
439void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data)
440{
441 Q_Q(QNetworkReplyImpl);
442 if (!q->isOpen())
443 return;
444
445 if (cacheEnabled && !cacheSaveDevice) {
446 initCacheSaveDevice();
447 }
448
449 qint64 bytesWritten = 0;
450 for (int i = 0; i < data.bufferCount(); i++) {
451 QByteArray const &item = data[i];
452
453 if (cacheSaveDevice)
454 cacheSaveDevice->write(item.constData(), item.size());
455 readBuffer.append(item);
456
457 bytesWritten += item.size();
458 }
459 data.clear();
460
461 bytesDownloaded += bytesWritten;
462 lastBytesDownloaded = bytesDownloaded;
463
464 appendDownstreamDataSignalEmissions();
465}
466
467void QNetworkReplyImplPrivate::appendDownstreamDataSignalEmissions()
468{
469 Q_Q(QNetworkReplyImpl);
470
471 QPointer<QNetworkReplyImpl> qq = q;
472
473 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
474 pauseNotificationHandling();
475 emit q->downloadProgress(bytesDownloaded,
476 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
477 // important: At the point of this readyRead(), the data parameter list must be empty,
478 // else implicit sharing will trigger memcpy when the user is reading data!
479 emit q->readyRead();
480
481 // hopefully we haven't been deleted here
482 if (!qq.isNull()) {
483 resumeNotificationHandling();
484 // do we still have room in the buffer?
485 if (nextDownstreamBlockSize() > 0)
486 backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
487 }
488}
489
490// this is used when it was fetched from the cache, right?
491void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
492{
493 Q_Q(QNetworkReplyImpl);
494 if (!q->isOpen())
495 return;
496
497 // read until EOF from data
498 if (copyDevice) {
499 qCritical("QNetworkReplyImpl: copy from QIODevice already in progress -- "
500 "backend probly needs to be fixed");
501 return;
502 }
503
504 copyDevice = data;
505 q->connect(copyDevice, SIGNAL(readyRead()), SLOT(_q_copyReadyRead()));
506 q->connect(copyDevice, SIGNAL(readChannelFinished()), SLOT(_q_copyReadChannelFinished()));
507
508 // start the copy:
509 _q_copyReadyRead();
510}
511
512void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data)
513{
514 // TODO implement
515
516 // TODO call
517
518 qFatal("QNetworkReplyImplPrivate::appendDownstreamData not implemented");
519}
520
521void QNetworkReplyImplPrivate::finished()
522{
523 Q_Q(QNetworkReplyImpl);
524 if (state == Finished || state == Aborted)
525 return;
526
527 state = Finished;
528 pendingNotifications.clear();
529
530 pauseNotificationHandling();
531 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
532 if (totalSize.isNull() || totalSize == -1) {
533 emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
534 }
535
536 if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
537 emit q->uploadProgress(0, 0);
538 resumeNotificationHandling();
539
540 completeCacheSave();
541
542 // note: might not be a good idea, since users could decide to delete us
543 // which would delete the backend too...
544 // maybe we should protect the backend
545 pauseNotificationHandling();
546 emit q->readChannelFinished();
547 emit q->finished();
548 resumeNotificationHandling();
549}
550
551void QNetworkReplyImplPrivate::error(QNetworkReplyImpl::NetworkError code, const QString &errorMessage)
552{
553 Q_Q(QNetworkReplyImpl);
554
555 errorCode = code;
556 q->setErrorString(errorMessage);
557
558 // note: might not be a good idea, since users could decide to delete us
559 // which would delete the backend too...
560 // maybe we should protect the backend
561 emit q->error(code);
562}
563
564void QNetworkReplyImplPrivate::metaDataChanged()
565{
566 Q_Q(QNetworkReplyImpl);
567 // do we have cookies?
568 if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && !manager.isNull()) {
569 QList<QNetworkCookie> cookies =
570 qvariant_cast<QList<QNetworkCookie> >(cookedHeaders.value(QNetworkRequest::SetCookieHeader));
571 QNetworkCookieJar *jar = manager->cookieJar();
572 if (jar)
573 jar->setCookiesFromUrl(cookies, url);
574 }
575 emit q->metaDataChanged();
576}
577
578void QNetworkReplyImplPrivate::redirectionRequested(const QUrl &target)
579{
580 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, target);
581}
582
583void QNetworkReplyImplPrivate::sslErrors(const QList<QSslError> &errors)
584{
585#ifndef QT_NO_OPENSSL
586 Q_Q(QNetworkReplyImpl);
587 emit q->sslErrors(errors);
588#else
589 Q_UNUSED(errors);
590#endif
591}
592
593bool QNetworkReplyImplPrivate::isFinished() const
594{
595 return (state == Finished || state == Aborted);
596}
597
598QNetworkReplyImpl::QNetworkReplyImpl(QObject *parent)
599 : QNetworkReply(*new QNetworkReplyImplPrivate, parent)
600{
601}
602
603QNetworkReplyImpl::~QNetworkReplyImpl()
604{
605 Q_D(QNetworkReplyImpl);
606
607 // This code removes the data from the cache if it was prematurely aborted.
608 // See QNetworkReplyImplPrivate::completeCacheSave(), we disable caching there after the cache
609 // save had been properly finished. So if it is still enabled it means we got deleted/aborted.
610 if (d->isCachingEnabled())
611 d->networkCache()->remove(url());
612
613 if (d->outgoingDataBuffer)
614 delete d->outgoingDataBuffer;
615}
616
617void QNetworkReplyImpl::abort()
618{
619 Q_D(QNetworkReplyImpl);
620 if (d->state == QNetworkReplyImplPrivate::Finished || d->state == QNetworkReplyImplPrivate::Aborted)
621 return;
622
623 // stop both upload and download
624 if (d->outgoingData)
625 disconnect(d->outgoingData, 0, this, 0);
626 if (d->copyDevice)
627 disconnect(d->copyDevice, 0, this, 0);
628
629 QNetworkReply::close();
630
631 if (d->state != QNetworkReplyImplPrivate::Finished) {
632 // emit signals
633 d->error(OperationCanceledError, tr("Operation canceled"));
634 d->finished();
635 }
636 d->state = QNetworkReplyImplPrivate::Aborted;
637
638 // finished may access the backend
639 if (d->backend) {
640 d->backend->deleteLater();
641 d->backend = 0;
642 }
643}
644
645void QNetworkReplyImpl::close()
646{
647 Q_D(QNetworkReplyImpl);
648 if (d->state == QNetworkReplyImplPrivate::Aborted ||
649 d->state == QNetworkReplyImplPrivate::Finished)
650 return;
651
652 // stop the download
653 if (d->backend)
654 d->backend->closeDownstreamChannel();
655 if (d->copyDevice)
656 disconnect(d->copyDevice, 0, this, 0);
657
658 QNetworkReply::close();
659
660 // emit signals
661 d->error(OperationCanceledError, tr("Operation canceled"));
662 d->finished();
663}
664
665/*!
666 Returns the number of bytes available for reading with
667 QIODevice::read(). The number of bytes available may grow until
668 the finished() signal is emitted.
669*/
670qint64 QNetworkReplyImpl::bytesAvailable() const
671{
672 return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount();
673}
674
675void QNetworkReplyImpl::setReadBufferSize(qint64 size)
676{
677 Q_D(QNetworkReplyImpl);
678 if (size > d->readBufferMaxSize &&
679 size > d->readBuffer.byteAmount())
680 d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
681
682 QNetworkReply::setReadBufferSize(size);
683
684 if (d->backend)
685 d->backend->setDownstreamLimited(d->readBufferMaxSize > 0);
686}
687
688#ifndef QT_NO_OPENSSL
689QSslConfiguration QNetworkReplyImpl::sslConfigurationImplementation() const
690{
691 Q_D(const QNetworkReplyImpl);
692 QSslConfiguration config;
693 if (d->backend)
694 d->backend->fetchSslConfiguration(config);
695 return config;
696}
697
698void QNetworkReplyImpl::setSslConfigurationImplementation(const QSslConfiguration &config)
699{
700 Q_D(QNetworkReplyImpl);
701 if (d->backend && !config.isNull())
702 d->backend->setSslConfiguration(config);
703}
704
705void QNetworkReplyImpl::ignoreSslErrors()
706{
707 Q_D(QNetworkReplyImpl);
708 if (d->backend)
709 d->backend->ignoreSslErrors();
710}
711
712void QNetworkReplyImpl::ignoreSslErrorsImplementation(const QList<QSslError> &errors)
713{
714 Q_D(QNetworkReplyImpl);
715 if (d->backend)
716 d->backend->ignoreSslErrors(errors);
717}
718#endif // QT_NO_OPENSSL
719
720/*!
721 \internal
722*/
723qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
724{
725 Q_D(QNetworkReplyImpl);
726 if (d->readBuffer.isEmpty())
727 return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
728
729 d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
730 if (maxlen == 1) {
731 // optimization for getChar()
732 *data = d->readBuffer.getChar();
733 return 1;
734 }
735
736 maxlen = qMin<qint64>(maxlen, d->readBuffer.byteAmount());
737 return d->readBuffer.read(data, maxlen);
738}
739
740/*!
741 \internal Reimplemented for internal purposes
742*/
743bool QNetworkReplyImpl::event(QEvent *e)
744{
745 if (e->type() == QEvent::NetworkReplyUpdated) {
746 d_func()->handleNotifications();
747 return true;
748 }
749
750 return QObject::event(e);
751}
752
753QT_END_NAMESPACE
754
755#include "moc_qnetworkreplyimpl_p.cpp"
756
Note: See TracBrowser for help on using the repository browser.