1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtNetwork module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
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.
|
---|
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 are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department 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 |
|
---|
50 | #include <QtCore/QCoreApplication>
|
---|
51 |
|
---|
52 | QT_BEGIN_NAMESPACE
|
---|
53 |
|
---|
54 | inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
|
---|
55 | : copyDevice(0), networkCache(0),
|
---|
56 | cacheEnabled(false), cacheSaveDevice(0),
|
---|
57 | bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
|
---|
58 | state(Idle)
|
---|
59 | {
|
---|
60 | }
|
---|
61 |
|
---|
62 | void QNetworkReplyImplPrivate::_q_startOperation()
|
---|
63 | {
|
---|
64 | // This function is called exactly once
|
---|
65 | state = Working;
|
---|
66 | if (!backend) {
|
---|
67 | error(QNetworkReplyImpl::ProtocolUnknownError,
|
---|
68 | QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!;
|
---|
69 | finished();
|
---|
70 | return;
|
---|
71 | }
|
---|
72 |
|
---|
73 | backend->open();
|
---|
74 | if (state != Finished) {
|
---|
75 | if (operation == QNetworkAccessManager::GetOperation)
|
---|
76 | pendingNotifications.append(NotifyDownstreamReadyWrite);
|
---|
77 | if (outgoingData) {
|
---|
78 | _q_sourceReadyRead();
|
---|
79 | #if 0 // ### FIXME
|
---|
80 | if (outgoingData->atEndOfStream() && writeBuffer.isEmpty())
|
---|
81 | // empty upload
|
---|
82 | emit q->uploadProgress(0, 0);
|
---|
83 | #endif
|
---|
84 | }
|
---|
85 |
|
---|
86 | handleNotifications();
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | void QNetworkReplyImplPrivate::_q_sourceReadyRead()
|
---|
91 | {
|
---|
92 | // read data from the outgoingData QIODevice into our internal buffer
|
---|
93 | enum { DesiredBufferSize = 32 * 1024 };
|
---|
94 |
|
---|
95 | if (writeBuffer.size() >= DesiredBufferSize)
|
---|
96 | return; // don't grow the buffer too much
|
---|
97 |
|
---|
98 | // read as many bytes are available or up until we fill up the buffer
|
---|
99 | // but always read at least one byte
|
---|
100 | 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 | // EOF
|
---|
106 | 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 it
|
---|
115 | if (bytesActuallyRead)
|
---|
116 | backendNotify(NotifyUpstreamReadyRead);
|
---|
117 |
|
---|
118 | // check for EOF again
|
---|
119 | if (!outgoingData->isSequential() && outgoingData->atEnd())
|
---|
120 | backendNotify(NotifyCloseUpstreamChannel);
|
---|
121 | }
|
---|
122 |
|
---|
123 | void QNetworkReplyImplPrivate::_q_sourceReadChannelFinished()
|
---|
124 | {
|
---|
125 | _q_sourceReadyRead();
|
---|
126 | }
|
---|
127 |
|
---|
128 | void QNetworkReplyImplPrivate::_q_copyReadyRead()
|
---|
129 | {
|
---|
130 | 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;
|
---|
155 | lastBytesDownloaded = bytesDownloaded;
|
---|
156 | QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
|
---|
157 | emit q->downloadProgress(bytesDownloaded,
|
---|
158 | totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
|
---|
159 | emit q->readyRead();
|
---|
160 | }
|
---|
161 |
|
---|
162 | void QNetworkReplyImplPrivate::_q_copyReadChannelFinished()
|
---|
163 | {
|
---|
164 | _q_copyReadyRead();
|
---|
165 | }
|
---|
166 |
|
---|
167 | void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
|
---|
168 | QIODevice *data)
|
---|
169 | {
|
---|
170 | Q_Q(QNetworkReplyImpl);
|
---|
171 |
|
---|
172 | outgoingData = data;
|
---|
173 | request = req;
|
---|
174 | url = request.url();
|
---|
175 | operation = op;
|
---|
176 |
|
---|
177 | if (outgoingData) {
|
---|
178 | q->connect(outgoingData, SIGNAL(readyRead()), SLOT(_q_sourceReadyRead()));
|
---|
179 | q->connect(outgoingData, SIGNAL(readChannelFinished()), SLOT(_q_sourceReadChannelFinished()));
|
---|
180 | }
|
---|
181 |
|
---|
182 | 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 | }
|
---|
190 |
|
---|
191 | void QNetworkReplyImplPrivate::backendNotify(InternalNotifications notification)
|
---|
192 | {
|
---|
193 | Q_Q(QNetworkReplyImpl);
|
---|
194 | if (!pendingNotifications.contains(notification))
|
---|
195 | pendingNotifications.enqueue(notification);
|
---|
196 |
|
---|
197 | if (pendingNotifications.size() == 1)
|
---|
198 | QCoreApplication::postEvent(q, new QEvent(QEvent::NetworkReplyUpdated));
|
---|
199 | }
|
---|
200 |
|
---|
201 | void QNetworkReplyImplPrivate::handleNotifications()
|
---|
202 | {
|
---|
203 | NotificationQueue current = pendingNotifications;
|
---|
204 | pendingNotifications.clear();
|
---|
205 |
|
---|
206 | if (state != Working)
|
---|
207 | return;
|
---|
208 |
|
---|
209 | while (!current.isEmpty()) {
|
---|
210 | InternalNotifications notification = current.dequeue();
|
---|
211 | switch (notification) {
|
---|
212 | case NotifyDownstreamReadyWrite:
|
---|
213 | if (copyDevice)
|
---|
214 | _q_copyReadyRead();
|
---|
215 | else
|
---|
216 | backend->downstreamReadyWrite();
|
---|
217 | break;
|
---|
218 |
|
---|
219 | case NotifyUpstreamReadyRead:
|
---|
220 | backend->upstreamReadyRead();
|
---|
221 | break;
|
---|
222 |
|
---|
223 | case NotifyCloseDownstreamChannel:
|
---|
224 | backend->closeDownstreamChannel();
|
---|
225 | break;
|
---|
226 |
|
---|
227 | case NotifyCloseUpstreamChannel:
|
---|
228 | backend->closeUpstreamChannel();
|
---|
229 | break;
|
---|
230 |
|
---|
231 | case NotifyCopyFinished: {
|
---|
232 | QIODevice *dev = copyDevice;
|
---|
233 | copyDevice = 0;
|
---|
234 | backend->copyFinished(dev);
|
---|
235 | break;
|
---|
236 | }
|
---|
237 | }
|
---|
238 | }
|
---|
239 | }
|
---|
240 |
|
---|
241 | void QNetworkReplyImplPrivate::createCache()
|
---|
242 | {
|
---|
243 | // check if we can save and if we're allowed to
|
---|
244 | if (!networkCache || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool())
|
---|
245 | return;
|
---|
246 | cacheEnabled = true;
|
---|
247 | }
|
---|
248 |
|
---|
249 | bool QNetworkReplyImplPrivate::isCachingEnabled() const
|
---|
250 | {
|
---|
251 | return (cacheEnabled && networkCache != 0);
|
---|
252 | }
|
---|
253 |
|
---|
254 | void QNetworkReplyImplPrivate::setCachingEnabled(bool enable)
|
---|
255 | {
|
---|
256 | if (!enable && !cacheEnabled)
|
---|
257 | return; // nothing to do
|
---|
258 | if (enable && cacheEnabled)
|
---|
259 | return; // nothing to do either!
|
---|
260 |
|
---|
261 | if (enable) {
|
---|
262 | if (bytesDownloaded) {
|
---|
263 | // refuse to enable in this case
|
---|
264 | qCritical("QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written");
|
---|
265 | return;
|
---|
266 | }
|
---|
267 |
|
---|
268 | createCache();
|
---|
269 | } else {
|
---|
270 | // someone told us to turn on, then back off?
|
---|
271 | // ok... but you should make up your mind
|
---|
272 | qDebug("QNetworkReplyImpl: setCachingEnabled(true) called after setCachingEnabled(false) -- "
|
---|
273 | "backend %s probably needs to be fixed",
|
---|
274 | backend->metaObject()->className());
|
---|
275 | networkCache->remove(url);
|
---|
276 | cacheSaveDevice = 0;
|
---|
277 | cacheEnabled = false;
|
---|
278 | }
|
---|
279 | }
|
---|
280 |
|
---|
281 | void QNetworkReplyImplPrivate::completeCacheSave()
|
---|
282 | {
|
---|
283 | if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) {
|
---|
284 | networkCache->remove(url);
|
---|
285 | } else if (cacheEnabled && cacheSaveDevice) {
|
---|
286 | networkCache->insert(cacheSaveDevice);
|
---|
287 | }
|
---|
288 | cacheSaveDevice = 0;
|
---|
289 | cacheEnabled = false;
|
---|
290 | }
|
---|
291 |
|
---|
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 | }
|
---|
314 |
|
---|
315 | qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const
|
---|
316 | {
|
---|
317 | enum { DesiredBufferSize = 32 * 1024 };
|
---|
318 | if (readBufferMaxSize == 0)
|
---|
319 | return DesiredBufferSize;
|
---|
320 |
|
---|
321 | return qMax<qint64>(0, readBufferMaxSize - readBuffer.size());
|
---|
322 | }
|
---|
323 |
|
---|
324 | void QNetworkReplyImplPrivate::feed(const QByteArray &data)
|
---|
325 | {
|
---|
326 | Q_Q(QNetworkReplyImpl);
|
---|
327 | if (!q->isOpen())
|
---|
328 | return;
|
---|
329 |
|
---|
330 | char *ptr = readBuffer.reserve(data.size());
|
---|
331 | memcpy(ptr, data.constData(), data.size());
|
---|
332 |
|
---|
333 | if (cacheEnabled && !cacheSaveDevice) {
|
---|
334 | // save the meta data
|
---|
335 | QNetworkCacheMetaData metaData;
|
---|
336 | metaData.setUrl(url);
|
---|
337 | metaData = backend->fetchCacheMetaData(metaData);
|
---|
338 | cacheSaveDevice = networkCache->prepare(metaData);
|
---|
339 | if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) {
|
---|
340 | if (cacheSaveDevice && !cacheSaveDevice->isOpen())
|
---|
341 | qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- "
|
---|
342 | "class %s probably needs to be fixed",
|
---|
343 | networkCache->metaObject()->className());
|
---|
344 |
|
---|
345 | networkCache->remove(url);
|
---|
346 | cacheSaveDevice = 0;
|
---|
347 | cacheEnabled = false;
|
---|
348 | }
|
---|
349 | }
|
---|
350 |
|
---|
351 | if (cacheSaveDevice)
|
---|
352 | cacheSaveDevice->write(data);
|
---|
353 |
|
---|
354 | bytesDownloaded += data.size();
|
---|
355 | lastBytesDownloaded = bytesDownloaded;
|
---|
356 |
|
---|
357 | QPointer<QNetworkReplyImpl> qq = q;
|
---|
358 |
|
---|
359 | QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
|
---|
360 | emit q->downloadProgress(bytesDownloaded,
|
---|
361 | totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
|
---|
362 | emit q->readyRead();
|
---|
363 |
|
---|
364 | // hopefully we haven't been deleted here
|
---|
365 | if (!qq.isNull()) {
|
---|
366 | // do we still have room in the buffer?
|
---|
367 | if (nextDownstreamBlockSize() > 0)
|
---|
368 | backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
|
---|
369 | }
|
---|
370 | }
|
---|
371 |
|
---|
372 | void QNetworkReplyImplPrivate::feed(QIODevice *data)
|
---|
373 | {
|
---|
374 | Q_Q(QNetworkReplyImpl);
|
---|
375 | Q_ASSERT(q->isOpen());
|
---|
376 |
|
---|
377 | // read until EOF from data
|
---|
378 | if (copyDevice) {
|
---|
379 | qCritical("QNetworkReplyImpl: copy from QIODevice already in progress -- "
|
---|
380 | "backend probly needs to be fixed");
|
---|
381 | return;
|
---|
382 | }
|
---|
383 |
|
---|
384 | copyDevice = data;
|
---|
385 | q->connect(copyDevice, SIGNAL(readyRead()), SLOT(_q_copyReadyRead()));
|
---|
386 | q->connect(copyDevice, SIGNAL(readChannelFinished()), SLOT(_q_copyReadChannelFinished()));
|
---|
387 |
|
---|
388 | // start the copy:
|
---|
389 | _q_copyReadyRead();
|
---|
390 | }
|
---|
391 |
|
---|
392 | void QNetworkReplyImplPrivate::finished()
|
---|
393 | {
|
---|
394 | Q_Q(QNetworkReplyImpl);
|
---|
395 | Q_ASSERT_X(state != Finished, "QNetworkReplyImpl",
|
---|
396 | "Backend called finished/finishedWithError more than once");
|
---|
397 |
|
---|
398 | state = Finished;
|
---|
399 | pendingNotifications.clear();
|
---|
400 |
|
---|
401 | QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
|
---|
402 | if (bytesDownloaded != lastBytesDownloaded || totalSize.isNull())
|
---|
403 | emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
|
---|
404 | if (bytesUploaded == -1 && outgoingData)
|
---|
405 | emit q->uploadProgress(0, 0);
|
---|
406 |
|
---|
407 | completeCacheSave();
|
---|
408 |
|
---|
409 | // note: might not be a good idea, since users could decide to delete us
|
---|
410 | // which would delete the backend too...
|
---|
411 | // maybe we should protect the backend
|
---|
412 | emit q->readChannelFinished();
|
---|
413 | emit q->finished();
|
---|
414 | }
|
---|
415 |
|
---|
416 | void QNetworkReplyImplPrivate::error(QNetworkReplyImpl::NetworkError code, const QString &errorMessage)
|
---|
417 | {
|
---|
418 | Q_Q(QNetworkReplyImpl);
|
---|
419 |
|
---|
420 | errorCode = code;
|
---|
421 | q->setErrorString(errorMessage);
|
---|
422 |
|
---|
423 | // note: might not be a good idea, since users could decide to delete us
|
---|
424 | // which would delete the backend too...
|
---|
425 | // maybe we should protect the backend
|
---|
426 | emit q->error(code);
|
---|
427 | }
|
---|
428 |
|
---|
429 | void QNetworkReplyImplPrivate::metaDataChanged()
|
---|
430 | {
|
---|
431 | Q_Q(QNetworkReplyImpl);
|
---|
432 | // do we have cookies?
|
---|
433 | if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && !manager.isNull()) {
|
---|
434 | QList<QNetworkCookie> cookies =
|
---|
435 | qvariant_cast<QList<QNetworkCookie> >(cookedHeaders.value(QNetworkRequest::SetCookieHeader));
|
---|
436 | QNetworkCookieJar *jar = manager->cookieJar();
|
---|
437 | if (jar)
|
---|
438 | jar->setCookiesFromUrl(cookies, url);
|
---|
439 | }
|
---|
440 | emit q->metaDataChanged();
|
---|
441 | }
|
---|
442 |
|
---|
443 | void QNetworkReplyImplPrivate::redirectionRequested(const QUrl &target)
|
---|
444 | {
|
---|
445 | attributes.insert(QNetworkRequest::RedirectionTargetAttribute, target);
|
---|
446 | }
|
---|
447 |
|
---|
448 | void QNetworkReplyImplPrivate::sslErrors(const QList<QSslError> &errors)
|
---|
449 | {
|
---|
450 | #ifndef QT_NO_OPENSSL
|
---|
451 | Q_Q(QNetworkReplyImpl);
|
---|
452 | emit q->sslErrors(errors);
|
---|
453 | #else
|
---|
454 | Q_UNUSED(errors);
|
---|
455 | #endif
|
---|
456 | }
|
---|
457 |
|
---|
458 | QNetworkReplyImpl::QNetworkReplyImpl(QObject *parent)
|
---|
459 | : QNetworkReply(*new QNetworkReplyImplPrivate, parent)
|
---|
460 | {
|
---|
461 | }
|
---|
462 |
|
---|
463 | QNetworkReplyImpl::~QNetworkReplyImpl()
|
---|
464 | {
|
---|
465 | Q_D(QNetworkReplyImpl);
|
---|
466 | if (d->isCachingEnabled())
|
---|
467 | d->networkCache->remove(url());
|
---|
468 | }
|
---|
469 |
|
---|
470 | void QNetworkReplyImpl::abort()
|
---|
471 | {
|
---|
472 | Q_D(QNetworkReplyImpl);
|
---|
473 | if (d->state == QNetworkReplyImplPrivate::Aborted)
|
---|
474 | return;
|
---|
475 |
|
---|
476 | // stop both upload and download
|
---|
477 | if (d->backend) {
|
---|
478 | d->backend->deleteLater();
|
---|
479 | d->backend = 0;
|
---|
480 | }
|
---|
481 | if (d->outgoingData)
|
---|
482 | disconnect(d->outgoingData, 0, this, 0);
|
---|
483 | if (d->copyDevice)
|
---|
484 | disconnect(d->copyDevice, 0, this, 0);
|
---|
485 |
|
---|
486 | QNetworkReply::close();
|
---|
487 |
|
---|
488 | if (d->state != QNetworkReplyImplPrivate::Finished) {
|
---|
489 | // emit signals
|
---|
490 | d->error(OperationCanceledError, tr("Operation canceled"));
|
---|
491 | d->finished();
|
---|
492 | }
|
---|
493 | d->state = QNetworkReplyImplPrivate::Aborted;
|
---|
494 | }
|
---|
495 |
|
---|
496 | void QNetworkReplyImpl::close()
|
---|
497 | {
|
---|
498 | Q_D(QNetworkReplyImpl);
|
---|
499 | if (d->state == QNetworkReplyImplPrivate::Aborted ||
|
---|
500 | d->state == QNetworkReplyImplPrivate::Finished)
|
---|
501 | return;
|
---|
502 |
|
---|
503 | // stop the download
|
---|
504 | if (d->backend)
|
---|
505 | d->backend->closeDownstreamChannel();
|
---|
506 | if (d->copyDevice)
|
---|
507 | disconnect(d->copyDevice, 0, this, 0);
|
---|
508 |
|
---|
509 | QNetworkReply::close();
|
---|
510 |
|
---|
511 | // emit signals
|
---|
512 | d->error(OperationCanceledError, tr("Operation canceled"));
|
---|
513 | d->finished();
|
---|
514 | }
|
---|
515 |
|
---|
516 | /*!
|
---|
517 | Returns the number of bytes available for reading with
|
---|
518 | QIODevice::read(). The number of bytes available may grow until
|
---|
519 | the finished() signal is emitted.
|
---|
520 | */
|
---|
521 | qint64 QNetworkReplyImpl::bytesAvailable() const
|
---|
522 | {
|
---|
523 | return QNetworkReply::bytesAvailable() + d_func()->readBuffer.size();
|
---|
524 | }
|
---|
525 |
|
---|
526 | void QNetworkReplyImpl::setReadBufferSize(qint64 size)
|
---|
527 | {
|
---|
528 | Q_D(QNetworkReplyImpl);
|
---|
529 | if (size > d->readBufferMaxSize &&
|
---|
530 | size == d->readBuffer.size())
|
---|
531 | d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
|
---|
532 |
|
---|
533 | QNetworkReply::setReadBufferSize(size);
|
---|
534 | }
|
---|
535 |
|
---|
536 | #ifndef QT_NO_OPENSSL
|
---|
537 | QSslConfiguration QNetworkReplyImpl::sslConfigurationImplementation() const
|
---|
538 | {
|
---|
539 | Q_D(const QNetworkReplyImpl);
|
---|
540 | QSslConfiguration config;
|
---|
541 | if (d->backend)
|
---|
542 | d->backend->fetchSslConfiguration(config);
|
---|
543 | return config;
|
---|
544 | }
|
---|
545 |
|
---|
546 | void QNetworkReplyImpl::setSslConfigurationImplementation(const QSslConfiguration &config)
|
---|
547 | {
|
---|
548 | Q_D(QNetworkReplyImpl);
|
---|
549 | if (d->backend && !config.isNull())
|
---|
550 | d->backend->setSslConfiguration(config);
|
---|
551 | }
|
---|
552 |
|
---|
553 | void QNetworkReplyImpl::ignoreSslErrors()
|
---|
554 | {
|
---|
555 | Q_D(QNetworkReplyImpl);
|
---|
556 | if (d->backend)
|
---|
557 | d->backend->ignoreSslErrors();
|
---|
558 | }
|
---|
559 |
|
---|
560 | #endif // QT_NO_OPENSSL
|
---|
561 |
|
---|
562 | /*!
|
---|
563 | \internal
|
---|
564 | */
|
---|
565 | qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
|
---|
566 | {
|
---|
567 | Q_D(QNetworkReplyImpl);
|
---|
568 | if (d->readBuffer.isEmpty())
|
---|
569 | return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
|
---|
570 |
|
---|
571 | d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
|
---|
572 | if (maxlen == 1) {
|
---|
573 | // optimization for getChar()
|
---|
574 | *data = d->readBuffer.getChar();
|
---|
575 | return 1;
|
---|
576 | }
|
---|
577 |
|
---|
578 | maxlen = qMin<qint64>(maxlen, d->readBuffer.size());
|
---|
579 | return d->readBuffer.read(data, maxlen);
|
---|
580 | }
|
---|
581 |
|
---|
582 | /*!
|
---|
583 | \internal Reimplemented for internal purposes
|
---|
584 | */
|
---|
585 | bool QNetworkReplyImpl::event(QEvent *e)
|
---|
586 | {
|
---|
587 | if (e->type() == QEvent::NetworkReplyUpdated) {
|
---|
588 | d_func()->handleNotifications();
|
---|
589 | return true;
|
---|
590 | }
|
---|
591 |
|
---|
592 | return QObject::event(e);
|
---|
593 | }
|
---|
594 |
|
---|
595 | QT_END_NAMESPACE
|
---|
596 |
|
---|
597 | #include "moc_qnetworkreplyimpl_p.cpp"
|
---|
598 |
|
---|