access/qnetworkreplyhttpimpl.cpp

Source codeSwitch to Preprocessed file
LineSource CodeCoverage
1/****************************************************************************-
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/****************************************************************************
2** -
3** Copyright (C) 2013 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//#define QNETWORKACCESSHTTPBACKEND_DEBUG -
43 -
44#include "qnetworkreplyhttpimpl_p.h" -
45#include "qnetworkaccessmanager_p.h" -
46#include "qnetworkaccesscache_p.h" -
47#include "qabstractnetworkcache.h" -
48#include "qnetworkrequest.h" -
49#include "qnetworkreply.h" -
50#include "qnetworkrequest_p.h" -
51#include "qnetworkcookie.h" -
52#include "qnetworkcookie_p.h" -
53#include "QtCore/qdatetime.h" -
54#include "QtCore/qelapsedtimer.h" -
55#include "QtNetwork/qsslconfiguration.h" -
56#include "qhttpthreaddelegate_p.h" -
57#include "qthread.h" -
58#include "QtCore/qcoreapplication.h" -
59 -
60#include "qnetworkcookiejar.h" -
61 -
62#ifndef QT_NO_HTTP -
63 -
64#include <string.h> // for strchr -
65 -
66QT_BEGIN_NAMESPACE -
67 -
68class QNetworkProxy; -
69 -
70static inline bool isSeparator(register char c) -
71{ -
72 static const char separators[] = "()<>@,;:\\\"/[]?={}"; -
73 return isLWS(c) || strchr(separators, c) != 0; -
74} -
75 -
76// ### merge with nextField in cookiejar.cpp -
77static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &header) -
78{ -
79 // The HTTP header is of the form: -
80 // header = #1(directives) -
81 // directives = token | value-directive -
82 // value-directive = token "=" (token | quoted-string) -
83 QHash<QByteArray, QByteArray> result; -
84 -
85 int pos = 0; -
86 while (true) { -
87 // skip spaces -
88 pos = nextNonWhitespace(header, pos); -
89 if (pos == header.length()) -
90 return result; // end of parsing -
91 -
92 // pos points to a non-whitespace -
93 int comma = header.indexOf(',', pos); -
94 int equal = header.indexOf('=', pos); -
95 if (comma == pos || equal == pos) -
96 // huh? Broken header. -
97 return result; -
98 -
99 // The key name is delimited by either a comma, an equal sign or the end -
100 // of the header, whichever comes first -
101 int end = comma; -
102 if (end == -1) -
103 end = header.length(); -
104 if (equal != -1 && end > equal) -
105 end = equal; // equal sign comes before comma/end -
106 QByteArray key = QByteArray(header.constData() + pos, end - pos).trimmed().toLower(); -
107 pos = end + 1; -
108 -
109 if (uint(equal) < uint(comma)) { -
110 // case: token "=" (token | quoted-string) -
111 // skip spaces -
112 pos = nextNonWhitespace(header, pos); -
113 if (pos == header.length()) -
114 // huh? Broken header -
115 return result; -
116 -
117 QByteArray value; -
118 value.reserve(header.length() - pos); -
119 if (header.at(pos) == '"') { -
120 // case: quoted-string -
121 // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) -
122 // qdtext = <any TEXT except <">> -
123 // quoted-pair = "\" CHAR -
124 ++pos; -
125 while (pos < header.length()) { -
126 register char c = header.at(pos); -
127 if (c == '"') { -
128 // end of quoted text -
129 break; -
130 } else if (c == '\\') { -
131 ++pos; -
132 if (pos >= header.length()) -
133 // broken header -
134 return result; -
135 c = header.at(pos); -
136 } -
137 -
138 value += c; -
139 ++pos; -
140 } -
141 } else { -
142 // case: token -
143 while (pos < header.length()) { -
144 register char c = header.at(pos); -
145 if (isSeparator(c)) -
146 break; -
147 value += c; -
148 ++pos; -
149 } -
150 } -
151 -
152 result.insert(key, value); -
153 -
154 // find the comma now: -
155 comma = header.indexOf(',', pos); -
156 if (comma == -1) -
157 return result; // end of parsing -
158 pos = comma + 1; -
159 } else { -
160 // case: token -
161 // key is already set -
162 result.insert(key, QByteArray()); -
163 } -
164 } -
165} -
166 -
167QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manager, -
168 const QNetworkRequest& request, -
169 QNetworkAccessManager::Operation& operation, -
170 QIODevice* outgoingData) -
171 : QNetworkReply(*new QNetworkReplyHttpImplPrivate, manager) -
172{ -
173 Q_D(QNetworkReplyHttpImpl); -
174 d->manager = manager; -
175 d->managerPrivate = manager->d_func(); -
176 d->request = request; -
177 d->operation = operation; -
178 d->outgoingData = outgoingData; -
179 d->url = request.url(); -
180#ifndef QT_NO_SSL -
181 d->sslConfiguration = request.sslConfiguration(); -
182#endif -
183 -
184 // FIXME Later maybe set to Unbuffered, especially if it is zerocopy or from cache? -
185 QIODevice::open(QIODevice::ReadOnly); -
186 -
187 -
188 // Internal code that does a HTTP reply for the synchronous Ajax -
189 // in QtWebKitQt WebKit. -
190 QVariant synchronousHttpAttribute = request.attribute( -
191 static_cast<QNetworkRequest::Attribute>(QNetworkRequest::SynchronousRequestAttribute)); -
192 if (synchronousHttpAttribute.isValid()) { -
193 d->synchronous = synchronousHttpAttribute.toBool(); -
194 if (d->synchronous && outgoingData) { -
195 // The synchronous HTTP is a corner case, we will put all upload data in one big QByteArray in the outgoingDataBuffer. -
196 // Yes, this is not the most efficient thing to do, but on the other hand synchronous XHR needs to die anyway. -
197 d->outgoingDataBuffer = QSharedPointer<QRingBuffer>(new QRingBuffer()); -
198 qint64 previousDataSize = 0; -
199 do { -
200 previousDataSize = d->outgoingDataBuffer->size(); -
201 d->outgoingDataBuffer->append(d->outgoingData->readAll()); -
202 } while (d->outgoingDataBuffer->size() != previousDataSize); -
203 d->_q_startOperation(); -
204 return; -
205 } -
206 } -
207 -
208 -
209 if (outgoingData) { -
210 // there is data to be uploaded, e.g. HTTP POST. -
211 -
212 if (!d->outgoingData->isSequential()) { -
213 // fixed size non-sequential (random-access) -
214 // just start the operation -
215 QMetaObject::invokeMethod(this, "_q_startOperation", Qt::QueuedConnection); -
216 // FIXME make direct call? -
217 } else { -
218 bool bufferingDisallowed = -
219 request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, -
220 false).toBool(); -
221 -
222 if (bufferingDisallowed) { -
223 // if a valid content-length header for the request was supplied, we can disable buffering -
224 // if not, we will buffer anyway -
225 if (request.header(QNetworkRequest::ContentLengthHeader).isValid()) { -
226 QMetaObject::invokeMethod(this, "_q_startOperation", Qt::QueuedConnection); -
227 // FIXME make direct call? -
228 } else { -
229 d->state = d->Buffering; -
230 QMetaObject::invokeMethod(this, "_q_bufferOutgoingData", Qt::QueuedConnection); -
231 } -
232 } else { -
233 // _q_startOperation will be called when the buffering has finished. -
234 d->state = d->Buffering; -
235 QMetaObject::invokeMethod(this, "_q_bufferOutgoingData", Qt::QueuedConnection); -
236 } -
237 } -
238 } else { -
239 // No outgoing data (POST, ..) -
240 d->_q_startOperation(); -
241 } -
242} -
243 -
244QNetworkReplyHttpImpl::~QNetworkReplyHttpImpl() -
245{ -
246 // Most work is done in private destructor -
247} -
248 -
249void QNetworkReplyHttpImpl::close() -
250{ -
251 Q_D(QNetworkReplyHttpImpl); -
252 -
253 if (d->state == QNetworkReplyHttpImplPrivate::Aborted || -
254 d->state == QNetworkReplyHttpImplPrivate::Finished) -
255 return; -
256 -
257 // According to the documentation close only stops the download -
258 // by closing we can ignore the download part and continue uploading. -
259 QNetworkReply::close(); -
260 -
261 // call finished which will emit signals -
262 // FIXME shouldn't this be emitted Queued? -
263 d->error(OperationCanceledError, tr("Operation canceled")); -
264 d->finished(); -
265} -
266 -
267void QNetworkReplyHttpImpl::abort() -
268{ -
269 Q_D(QNetworkReplyHttpImpl); -
270 // FIXME -
271 if (d->state == QNetworkReplyHttpImplPrivate::Finished || d->state == QNetworkReplyHttpImplPrivate::Aborted) -
272 return; -
273 -
274 QNetworkReply::close(); -
275 -
276 if (d->state != QNetworkReplyHttpImplPrivate::Finished) { -
277 // call finished which will emit signals -
278 // FIXME shouldn't this be emitted Queued? -
279 d->error(OperationCanceledError, tr("Operation canceled")); -
280 d->finished(); -
281 } -
282 -
283 d->state = QNetworkReplyHttpImplPrivate::Aborted; -
284 -
285 emit abortHttpRequest(); -
286} -
287 -
288qint64 QNetworkReplyHttpImpl::bytesAvailable() const -
289{ -
290 Q_D(const QNetworkReplyHttpImpl); -
291 -
292 // if we load from cache device -
293 if (d->cacheLoadDevice) { -
294 return QNetworkReply::bytesAvailable() + d->cacheLoadDevice->bytesAvailable() + d->downloadMultiBuffer.byteAmount(); -
295 } -
296 -
297 // zerocopy buffer -
298 if (d->downloadZerocopyBuffer) { -
299 return QNetworkReply::bytesAvailable() + d->downloadBufferCurrentSize - d->downloadBufferReadPosition; -
300 } -
301 -
302 // normal buffer -
303 return QNetworkReply::bytesAvailable() + d->downloadMultiBuffer.byteAmount(); -
304} -
305 -
306bool QNetworkReplyHttpImpl::isSequential () const -
307{ -
308 // FIXME In the cache of a cached load or the zero-copy buffer we could actually be non-sequential. -
309 // FIXME however this requires us to implement stuff like seek() too. -
310 return true; -
311} -
312 -
313qint64 QNetworkReplyHttpImpl::size() const -
314{ -
315 // FIXME At some point, this could return a proper value, e.g. if we're non-sequential. -
316 return QNetworkReply::size(); -
317} -
318 -
319qint64 QNetworkReplyHttpImpl::readData(char* data, qint64 maxlen) -
320{ -
321 Q_D(QNetworkReplyHttpImpl); -
322 -
323 // cacheload device -
324 if (d->cacheLoadDevice) { -
325 // FIXME bytesdownloaded, position etc? -
326 -
327 // There is something already in the buffer we buffered before because the user did not read() -
328 // anything, so we read there first: -
329 if (!d->downloadMultiBuffer.isEmpty()) { -
330 return d->downloadMultiBuffer.read(data, maxlen); -
331 } -
332 -
333 qint64 ret = d->cacheLoadDevice->read(data, maxlen); -
334 return ret; -
335 } -
336 -
337 // zerocopy buffer -
338 if (d->downloadZerocopyBuffer) { -
339 // FIXME bytesdownloaded, position etc? -
340 -
341 qint64 howMuch = qMin(maxlen, (d->downloadBufferCurrentSize - d->downloadBufferReadPosition)); -
342 memcpy(data, d->downloadZerocopyBuffer + d->downloadBufferReadPosition, howMuch); -
343 d->downloadBufferReadPosition += howMuch; -
344 return howMuch; -
345 -
346 } -
347 -
348 // normal buffer -
349 if (d->downloadMultiBuffer.isEmpty()) { -
350 if (d->state == d->Finished || d->state == d->Aborted) -
351 return -1; -
352 return 0; -
353 } -
354 -
355 if (maxlen == 1) { -
356 // optimization for getChar() -
357 *data = d->downloadMultiBuffer.getChar(); -
358 if (readBufferSize()) -
359 emit readBufferFreed(1); -
360 return 1; -
361 } -
362 -
363 maxlen = qMin<qint64>(maxlen, d->downloadMultiBuffer.byteAmount()); -
364 qint64 bytesRead = d->downloadMultiBuffer.read(data, maxlen); -
365 if (readBufferSize()) -
366 emit readBufferFreed(bytesRead); -
367 return bytesRead; -
368} -
369 -
370void QNetworkReplyHttpImpl::setReadBufferSize(qint64 size) -
371{ -
372 QNetworkReply::setReadBufferSize(size); -
373 emit readBufferSizeChanged(size); -
374 return; -
375} -
376 -
377bool QNetworkReplyHttpImpl::canReadLine () const -
378{ -
379 Q_D(const QNetworkReplyHttpImpl); -
380 -
381 if (QNetworkReply::canReadLine()) -
382 return true; -
383 -
384 if (d->cacheLoadDevice) -
385 return d->cacheLoadDevice->canReadLine() || d->downloadMultiBuffer.canReadLine(); -
386 -
387 if (d->downloadZerocopyBuffer) -
388 return memchr(d->downloadZerocopyBuffer + d->downloadBufferReadPosition, '\n', d->downloadBufferCurrentSize - d->downloadBufferReadPosition); -
389 -
390 return d->downloadMultiBuffer.canReadLine(); -
391} -
392 -
393#ifndef QT_NO_SSL -
394void QNetworkReplyHttpImpl::ignoreSslErrors() -
395{ -
396 Q_D(QNetworkReplyHttpImpl); -
397 -
398 d->pendingIgnoreAllSslErrors = true; -
399} -
400 -
401void QNetworkReplyHttpImpl::ignoreSslErrorsImplementation(const QList<QSslError> &errors) -
402{ -
403 Q_D(QNetworkReplyHttpImpl); -
404 -
405 // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) -
406 // is called before QNetworkAccessManager::get() (or post(), etc.) -
407 d->pendingIgnoreSslErrorsList = errors; -
408} -
409 -
410void QNetworkReplyHttpImpl::setSslConfigurationImplementation(const QSslConfiguration &newconfig) -
411{ -
412 // Setting a SSL configuration on a reply is not supported. The user needs to set -
413 // her/his QSslConfiguration on the QNetworkRequest. -
414 Q_UNUSED(newconfig); -
415} -
416 -
417void QNetworkReplyHttpImpl::sslConfigurationImplementation(QSslConfiguration &configuration) const -
418{ -
419 Q_D(const QNetworkReplyHttpImpl); -
420 configuration = d->sslConfiguration; -
421} -
422#endif -
423 -
424QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() -
425 : QNetworkReplyPrivate() -
426 , manager(0) -
427 , managerPrivate(0) -
428 , synchronous(false) -
429 , state(Idle) -
430 , statusCode(0) -
431 , outgoingData(0) -
432 , bytesUploaded(-1) -
433 , cacheLoadDevice(0) -
434 , loadingFromCache(false) -
435 , cacheSaveDevice(0) -
436 , cacheEnabled(false) -
437 , resumeOffset(0) -
438 , preMigrationDownloaded(-1) -
439 , bytesDownloaded(0) -
440 , downloadBufferReadPosition(0) -
441 , downloadBufferCurrentSize(0) -
442 , downloadZerocopyBuffer(0) -
443 , pendingDownloadDataEmissions(new QAtomicInt()) -
444 , pendingDownloadProgressEmissions(new QAtomicInt()) -
445 #ifndef QT_NO_SSL -
446 , pendingIgnoreAllSslErrors(false) -
447 #endif -
448 -
449{ -
450} -
451 -
452QNetworkReplyHttpImplPrivate::~QNetworkReplyHttpImplPrivate() -
453{ -
454 Q_Q(QNetworkReplyHttpImpl); -
455 // This will do nothing if the request was already finished or aborted -
456 emit q->abortHttpRequest(); -
457} -
458 -
459/* -
460 For a given httpRequest -
461 1) If AlwaysNetwork, return -
462 2) If we have a cache entry for this url populate headers so the server can return 304 -
463 3) Calculate if response_is_fresh and if so send the cache and set loadedFromCache to true -
464 */ -
465bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &httpRequest) -
466{ -
467 QNetworkRequest::CacheLoadControl CacheLoadControlAttribute = -
468 (QNetworkRequest::CacheLoadControl)request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(); -
469 if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork) { -
470 // If the request does not already specify preferred cache-control -
471 // force reload from the network and tell any caching proxy servers to reload too -
472 if (!request.rawHeaderList().contains("Cache-Control")) { -
473 httpRequest.setHeaderField("Cache-Control", "no-cache"); -
474 httpRequest.setHeaderField("Pragma", "no-cache"); -
475 } -
476 return false; -
477 } -
478 -
479 // The disk cache API does not currently support partial content retrieval. -
480 // That is why we don't use the disk cache for any such requests. -
481 if (request.hasRawHeader("Range")) -
482 return false; -
483 -
484 QAbstractNetworkCache *nc = managerPrivate->networkCache; -
485 if (!nc) -
486 return false; // no local cache -
487 -
488 QNetworkCacheMetaData metaData = nc->metaData(request.url()); -
489 if (!metaData.isValid()) -
490 return false; // not in cache -
491 -
492 if (!metaData.saveToDisk()) -
493 return false; -
494 -
495 QNetworkHeadersPrivate cacheHeaders; -
496 QNetworkHeadersPrivate::RawHeadersList::ConstIterator it; -
497 cacheHeaders.setAllRawHeaders(metaData.rawHeaders()); -
498 -
499 it = cacheHeaders.findRawHeader("etag"); -
500 if (it != cacheHeaders.rawHeaders.constEnd()) -
501 httpRequest.setHeaderField("If-None-Match", it->second); -
502 -
503 QDateTime lastModified = metaData.lastModified(); -
504 if (lastModified.isValid()) -
505 httpRequest.setHeaderField("If-Modified-Since", QNetworkHeadersPrivate::toHttpDate(lastModified)); -
506 -
507 it = cacheHeaders.findRawHeader("Cache-Control"); -
508 if (it != cacheHeaders.rawHeaders.constEnd()) { -
509 QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second); -
510 if (cacheControl.contains("must-revalidate")) -
511 return false; -
512 } -
513 -
514 QDateTime currentDateTime = QDateTime::currentDateTime(); -
515 QDateTime expirationDate = metaData.expirationDate(); -
516 -
517 bool response_is_fresh; -
518 if (!expirationDate.isValid()) { -
519 /* -
520 * age_value -
521 * is the value of Age: header received by the cache with -
522 * this response. -
523 * date_value -
524 * is the value of the origin server's Date: header -
525 * request_time -
526 * is the (local) time when the cache made the request -
527 * that resulted in this cached response -
528 * response_time -
529 * is the (local) time when the cache received the -
530 * response -
531 * now -
532 * is the current (local) time -
533 */ -
534 int age_value = 0; -
535 it = cacheHeaders.findRawHeader("age"); -
536 if (it != cacheHeaders.rawHeaders.constEnd()) -
537 age_value = it->second.toInt(); -
538 -
539 QDateTime dateHeader; -
540 int date_value = 0; -
541 it = cacheHeaders.findRawHeader("date"); -
542 if (it != cacheHeaders.rawHeaders.constEnd()) { -
543 dateHeader = QNetworkHeadersPrivate::fromHttpDate(it->second); -
544 date_value = dateHeader.toTime_t(); -
545 } -
546 -
547 int now = currentDateTime.toUTC().toTime_t(); -
548 int request_time = now; -
549 int response_time = now; -
550 -
551 // Algorithm from RFC 2616 section 13.2.3 -
552 int apparent_age = qMax(0, response_time - date_value); -
553 int corrected_received_age = qMax(apparent_age, age_value); -
554 int response_delay = response_time - request_time; -
555 int corrected_initial_age = corrected_received_age + response_delay; -
556 int resident_time = now - response_time; -
557 int current_age = corrected_initial_age + resident_time; -
558 -
559 // RFC 2616 13.2.4 Expiration Calculations -
560 if (!expirationDate.isValid()) { -
561 if (lastModified.isValid()) { -
562 int diff = currentDateTime.secsTo(lastModified); -
563 expirationDate = lastModified; -
564 expirationDate.addSecs(diff / 10); -
565 if (httpRequest.headerField("Warning").isEmpty()) { -
566 QDateTime dt; -
567 dt.setTime_t(current_age); -
568 if (dt.daysTo(currentDateTime) > 1) -
569 httpRequest.setHeaderField("Warning", "113"); -
570 } -
571 } -
572 } -
573 -
574 // the cache-saving code below sets the expirationDate with date+max_age -
575 // if "max-age" is present, or to Expires otherwise -
576 int freshness_lifetime = dateHeader.secsTo(expirationDate); -
577 response_is_fresh = (freshness_lifetime > current_age); -
578 } else { -
579 // expiration date was calculated earlier (e.g. when storing object to the cache) -
580 response_is_fresh = currentDateTime.secsTo(expirationDate) >= 0; -
581 } -
582 -
583 if (!response_is_fresh) -
584 return false; -
585 -
586#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) -
587 qDebug() << "response_is_fresh" << CacheLoadControlAttribute; -
588#endif -
589 return sendCacheContents(metaData); -
590} -
591 -
592QHttpNetworkRequest::Priority QNetworkReplyHttpImplPrivate::convert(const QNetworkRequest::Priority& prio) -
593{ -
594 switch (prio) { -
595 case QNetworkRequest::LowPriority: -
596 return QHttpNetworkRequest::LowPriority; -
597 case QNetworkRequest::HighPriority: -
598 return QHttpNetworkRequest::HighPriority; -
599 case QNetworkRequest::NormalPriority: -
600 default: -
601 return QHttpNetworkRequest::NormalPriority; -
602 } -
603} -
604 -
605void QNetworkReplyHttpImplPrivate::postRequest() -
606{ -
607 Q_Q(QNetworkReplyHttpImpl);
executed (the execution status of this line is deduced): QNetworkReplyHttpImpl * const q = q_func();
-
608 -
609 QThread *thread = 0;
executed (the execution status of this line is deduced): QThread *thread = 0;
-
610 if (synchronous) {
evaluated: synchronous
TRUEFALSE
yes
Evaluation Count:76
yes
Evaluation Count:636
76-636
611 // A synchronous HTTP request uses its own thread -
612 thread = new QThread();
executed (the execution status of this line is deduced): thread = new QThread();
-
613 thread->setObjectName(QStringLiteral("httpReply"));
executed (the execution status of this line is deduced): thread->setObjectName(QString::fromUtf8("" "httpReply" "", sizeof("httpReply") - 1));
-
614 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
executed (the execution status of this line is deduced): QObject::connect(thread, "2""finished()", thread, "1""deleteLater()");
-
615 thread->start();
executed (the execution status of this line is deduced): thread->start();
-
616 } else if (!managerPrivate->httpThread) {
executed: }
Execution Count:76
evaluated: !managerPrivate->httpThread
TRUEFALSE
yes
Evaluation Count:436
yes
Evaluation Count:200
76-436
617 // We use the manager-global thread. -
618 // At some point we could switch to having multiple threads if it makes sense. -
619 managerPrivate->httpThread = new QThread();
executed (the execution status of this line is deduced): managerPrivate->httpThread = new QThread();
-
620 managerPrivate->httpThread->setObjectName(QStringLiteral("httpThread"));
executed (the execution status of this line is deduced): managerPrivate->httpThread->setObjectName(QString::fromUtf8("" "httpThread" "", sizeof("httpThread") - 1));
-
621 managerPrivate->httpThread->start();
executed (the execution status of this line is deduced): managerPrivate->httpThread->start();
-
622 -
623 thread = managerPrivate->httpThread;
executed (the execution status of this line is deduced): thread = managerPrivate->httpThread;
-
624 } else {
executed: }
Execution Count:436
436
625 // Asynchronous request, thread already exists -
626 thread = managerPrivate->httpThread;
executed (the execution status of this line is deduced): thread = managerPrivate->httpThread;
-
627 }
executed: }
Execution Count:200
200
628 -
629 QUrl url = request.url();
executed (the execution status of this line is deduced): QUrl url = request.url();
-
630 httpRequest.setUrl(url);
executed (the execution status of this line is deduced): httpRequest.setUrl(url);
-
631 -
632 bool ssl = url.scheme().toLower() == QLatin1String("https");
executed (the execution status of this line is deduced): bool ssl = url.scheme().toLower() == QLatin1String("https");
-
633 q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl);
executed (the execution status of this line is deduced): q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl);
-
634 httpRequest.setSsl(ssl);
executed (the execution status of this line is deduced): httpRequest.setSsl(ssl);
-
635 -
636 -
637#ifndef QT_NO_NETWORKPROXY -
638 QNetworkProxy transparentProxy, cacheProxy;
executed (the execution status of this line is deduced): QNetworkProxy transparentProxy, cacheProxy;
-
639 -
640 // FIXME the proxy stuff should be done in the HTTP thread -
641 foreach (const QNetworkProxy &p, managerPrivate->queryProxy(QNetworkProxyQuery(request.url()))) {
executed (the execution status of this line is deduced): for (QForeachContainer<__typeof__(managerPrivate->queryProxy(QNetworkProxyQuery(request.url())))> _container_(managerPrivate->queryProxy(QNetworkProxyQuery(request.url()))); !_container_.brk && _container_.i != _container_.e; __extension__ ({ ++_container_.brk; ++_container_.i; })) for (const QNetworkProxy &p = *_container_.i;; __extension__ ({--_container_.brk; break;})) {
-
642 // use the first proxy that works -
643 // for non-encrypted connections, any transparent or HTTP proxy -
644 // for encrypted, only transparent proxies -
645 if (!ssl
evaluated: !ssl
TRUEFALSE
yes
Evaluation Count:625
yes
Evaluation Count:92
92-625
646 && (p.capabilities() & QNetworkProxy::CachingCapability)
evaluated: (p.capabilities() & QNetworkProxy::CachingCapability)
TRUEFALSE
yes
Evaluation Count:60
yes
Evaluation Count:565
60-565
647 && (p.type() == QNetworkProxy::HttpProxy ||
evaluated: p.type() == QNetworkProxy::HttpProxy
TRUEFALSE
yes
Evaluation Count:49
yes
Evaluation Count:11
11-49
648 p.type() == QNetworkProxy::HttpCachingProxy)) {
evaluated: p.type() == QNetworkProxy::HttpCachingProxy
TRUEFALSE
yes
Evaluation Count:8
yes
Evaluation Count:3
3-8
649 cacheProxy = p;
executed (the execution status of this line is deduced): cacheProxy = p;
-
650 transparentProxy = QNetworkProxy::NoProxy;
executed (the execution status of this line is deduced): transparentProxy = QNetworkProxy::NoProxy;
-
651 break;
executed: break;
Execution Count:57
57
652 } -
653 if (p.isTransparentProxy()) {
evaluated: p.isTransparentProxy()
TRUEFALSE
yes
Evaluation Count:652
yes
Evaluation Count:8
8-652
654 transparentProxy = p;
executed (the execution status of this line is deduced): transparentProxy = p;
-
655 cacheProxy = QNetworkProxy::NoProxy;
executed (the execution status of this line is deduced): cacheProxy = QNetworkProxy::NoProxy;
-
656 break;
executed: break;
Execution Count:652
652
657 } -
658 }
executed: }
Execution Count:8
8
659 -
660 // check if at least one of the proxies -
661 if (transparentProxy.type() == QNetworkProxy::DefaultProxy &&
evaluated: transparentProxy.type() == QNetworkProxy::DefaultProxy
TRUEFALSE
yes
Evaluation Count:3
yes
Evaluation Count:709
3-709
662 cacheProxy.type() == QNetworkProxy::DefaultProxy) {
partially evaluated: cacheProxy.type() == QNetworkProxy::DefaultProxy
TRUEFALSE
yes
Evaluation Count:3
no
Evaluation Count:0
0-3
663 // unsuitable proxies -
664 QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
executed (the execution status of this line is deduced): QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
-
665 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
executed (the execution status of this line is deduced): QArgument<QNetworkReply::NetworkError >("QNetworkReply::NetworkError", QNetworkReply::ProxyNotFoundError),
-
666 Q_ARG(QString, q->QNetworkReplyHttpImpl::tr("No suitable proxy found")));
executed (the execution status of this line is deduced): QArgument<QString >("QString", QNetworkReplyHttpImpl::tr("No suitable proxy found")));
-
667 QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
executed (the execution status of this line is deduced): QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
-
668 return;
executed: return;
Execution Count:3
3
669 } -
670#endif -
671 -
672 -
673 bool loadedFromCache = false;
executed (the execution status of this line is deduced): bool loadedFromCache = false;
-
674 httpRequest.setPriority(convert(request.priority()));
executed (the execution status of this line is deduced): httpRequest.setPriority(convert(request.priority()));
-
675 -
676 switch (operation) { -
677 case QNetworkAccessManager::GetOperation: -
678 httpRequest.setOperation(QHttpNetworkRequest::Get);
executed (the execution status of this line is deduced): httpRequest.setOperation(QHttpNetworkRequest::Get);
-
679 loadedFromCache = loadFromCacheIfAllowed(httpRequest);
executed (the execution status of this line is deduced): loadedFromCache = loadFromCacheIfAllowed(httpRequest);
-
680 break;
executed: break;
Execution Count:493
493
681 -
682 case QNetworkAccessManager::HeadOperation: -
683 httpRequest.setOperation(QHttpNetworkRequest::Head);
executed (the execution status of this line is deduced): httpRequest.setOperation(QHttpNetworkRequest::Head);
-
684 loadedFromCache = loadFromCacheIfAllowed(httpRequest);
executed (the execution status of this line is deduced): loadedFromCache = loadFromCacheIfAllowed(httpRequest);
-
685 break;
executed: break;
Execution Count:26
26
686 -
687 case QNetworkAccessManager::PostOperation: -
688 invalidateCache();
executed (the execution status of this line is deduced): invalidateCache();
-
689 httpRequest.setOperation(QHttpNetworkRequest::Post);
executed (the execution status of this line is deduced): httpRequest.setOperation(QHttpNetworkRequest::Post);
-
690 createUploadByteDevice();
executed (the execution status of this line is deduced): createUploadByteDevice();
-
691 break;
executed: break;
Execution Count:142
142
692 -
693 case QNetworkAccessManager::PutOperation: -
694 invalidateCache();
executed (the execution status of this line is deduced): invalidateCache();
-
695 httpRequest.setOperation(QHttpNetworkRequest::Put);
executed (the execution status of this line is deduced): httpRequest.setOperation(QHttpNetworkRequest::Put);
-
696 createUploadByteDevice();
executed (the execution status of this line is deduced): createUploadByteDevice();
-
697 break;
executed: break;
Execution Count:35
35
698 -
699 case QNetworkAccessManager::DeleteOperation: -
700 invalidateCache();
executed (the execution status of this line is deduced): invalidateCache();
-
701 httpRequest.setOperation(QHttpNetworkRequest::Delete);
executed (the execution status of this line is deduced): httpRequest.setOperation(QHttpNetworkRequest::Delete);
-
702 break;
executed: break;
Execution Count:7
7
703 -
704 case QNetworkAccessManager::CustomOperation: -
705 invalidateCache(); // for safety reasons, we don't know what the operation does
executed (the execution status of this line is deduced): invalidateCache();
-
706 httpRequest.setOperation(QHttpNetworkRequest::Custom);
executed (the execution status of this line is deduced): httpRequest.setOperation(QHttpNetworkRequest::Custom);
-
707 createUploadByteDevice();
executed (the execution status of this line is deduced): createUploadByteDevice();
-
708 httpRequest.setCustomVerb(request.attribute(
executed (the execution status of this line is deduced): httpRequest.setCustomVerb(request.attribute(
-
709 QNetworkRequest::CustomVerbAttribute).toByteArray());
executed (the execution status of this line is deduced): QNetworkRequest::CustomVerbAttribute).toByteArray());
-
710 break;
executed: break;
Execution Count:6
6
711 -
712 default: -
713 break; // can't happen
never executed: break;
0
714 } -
715 -
716 if (loadedFromCache) {
evaluated: loadedFromCache
TRUEFALSE
yes
Evaluation Count:14
yes
Evaluation Count:695
14-695
717 return; // no need to send the request! :)
executed: return;
Execution Count:14
14
718 } -
719 -
720 QList<QByteArray> headers = request.rawHeaderList();
executed (the execution status of this line is deduced): QList<QByteArray> headers = request.rawHeaderList();
-
721 if (resumeOffset != 0) {
partially evaluated: resumeOffset != 0
TRUEFALSE
no
Evaluation Count:0
yes
Evaluation Count:695
0-695
722 if (headers.contains("Range")) {
never evaluated: headers.contains("Range")
0
723 // Need to adjust resume offset for user specified range -
724 -
725 headers.removeOne("Range");
never executed (the execution status of this line is deduced): headers.removeOne("Range");
-
726 -
727 // We've already verified that requestRange starts with "bytes=", see canResume. -
728 QByteArray requestRange = request.rawHeader("Range").mid(6);
never executed (the execution status of this line is deduced): QByteArray requestRange = request.rawHeader("Range").mid(6);
-
729 -
730 int index = requestRange.indexOf('-');
never executed (the execution status of this line is deduced): int index = requestRange.indexOf('-');
-
731 -
732 quint64 requestStartOffset = requestRange.left(index).toULongLong();
never executed (the execution status of this line is deduced): quint64 requestStartOffset = requestRange.left(index).toULongLong();
-
733 quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
never executed (the execution status of this line is deduced): quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
-
734 -
735 requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) +
never executed (the execution status of this line is deduced): requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) +
-
736 '-' + QByteArray::number(requestEndOffset);
never executed (the execution status of this line is deduced): '-' + QByteArray::number(requestEndOffset);
-
737 -
738 httpRequest.setHeaderField("Range", requestRange);
never executed (the execution status of this line is deduced): httpRequest.setHeaderField("Range", requestRange);
-
739 } else {
never executed: }
0
740 httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
never executed (the execution status of this line is deduced): httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
-
741 }
never executed: }
0
742 } -
743 -
744 foreach (const QByteArray &header, headers)
executed (the execution status of this line is deduced): for (QForeachContainer<__typeof__(headers)> _container_(headers); !_container_.brk && _container_.i != _container_.e; __extension__ ({ ++_container_.brk; ++_container_.i; })) for (const QByteArray &header = *_container_.i;; __extension__ ({--_container_.brk; break;}))
-
745 httpRequest.setHeaderField(header, request.rawHeader(header));
executed: httpRequest.setHeaderField(header, request.rawHeader(header));
Execution Count:295
295
746 -
747 if (request.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true)
evaluated: request.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true
TRUEFALSE
yes
Evaluation Count:20
yes
Evaluation Count:675
20-675
748 httpRequest.setPipeliningAllowed(true);
executed: httpRequest.setPipeliningAllowed(true);
Execution Count:20
20
749 -
750 if (static_cast<QNetworkRequest::LoadControl>
evaluated: static_cast<QNetworkRequest::LoadControl> (request.attribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual
TRUEFALSE
yes
Evaluation Count:1
yes
Evaluation Count:694
1-694
751 (request.attribute(QNetworkRequest::AuthenticationReuseAttribute,
evaluated: static_cast<QNetworkRequest::LoadControl> (request.attribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual
TRUEFALSE
yes
Evaluation Count:1
yes
Evaluation Count:694
1-694
752 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual)
evaluated: static_cast<QNetworkRequest::LoadControl> (request.attribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual
TRUEFALSE
yes
Evaluation Count:1
yes
Evaluation Count:694
1-694
753 httpRequest.setWithCredentials(false);
executed: httpRequest.setWithCredentials(false);
Execution Count:1
1
754 -
755 -
756 // Create the HTTP thread delegate -
757 QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
executed (the execution status of this line is deduced): QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
-
758#ifndef QT_NO_BEARERMANAGEMENT -
759 delegate->networkSession = managerPrivate->getNetworkSession();
executed (the execution status of this line is deduced): delegate->networkSession = managerPrivate->getNetworkSession();
-
760#endif -
761 -
762 // For the synchronous HTTP, this is the normal way the delegate gets deleted -
763 // For the asynchronous HTTP this is a safety measure, the delegate deletes itself when HTTP is finished -
764 QObject::connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater()));
executed (the execution status of this line is deduced): QObject::connect(thread, "2""finished()", delegate, "1""deleteLater()");
-
765 -
766 // Set the properties it needs -
767 delegate->httpRequest = httpRequest;
executed (the execution status of this line is deduced): delegate->httpRequest = httpRequest;
-
768#ifndef QT_NO_NETWORKPROXY -
769 delegate->cacheProxy = cacheProxy;
executed (the execution status of this line is deduced): delegate->cacheProxy = cacheProxy;
-
770 delegate->transparentProxy = transparentProxy;
executed (the execution status of this line is deduced): delegate->transparentProxy = transparentProxy;
-
771#endif -
772 delegate->ssl = ssl;
executed (the execution status of this line is deduced): delegate->ssl = ssl;
-
773#ifndef QT_NO_SSL -
774 if (ssl)
evaluated: ssl
TRUEFALSE
yes
Evaluation Count:87
yes
Evaluation Count:608
87-608
775 delegate->incomingSslConfiguration = request.sslConfiguration();
executed: delegate->incomingSslConfiguration = request.sslConfiguration();
Execution Count:87
87
776#endif -
777 -
778 // Do we use synchronous HTTP? -
779 delegate->synchronous = synchronous;
executed (the execution status of this line is deduced): delegate->synchronous = synchronous;
-
780 -
781 // The authentication manager is used to avoid the BlockingQueuedConnection communication -
782 // from HTTP thread to user thread in some cases. -
783 delegate->authenticationManager = managerPrivate->authenticationManager;
executed (the execution status of this line is deduced): delegate->authenticationManager = managerPrivate->authenticationManager;
-
784 -
785 if (!synchronous) {
evaluated: !synchronous
TRUEFALSE
yes
Evaluation Count:619
yes
Evaluation Count:76
76-619
786 // Tell our zerocopy policy to the delegate -
787 QVariant downloadBufferMaximumSizeAttribute = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
executed (the execution status of this line is deduced): QVariant downloadBufferMaximumSizeAttribute = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
-
788 if (downloadBufferMaximumSizeAttribute.isValid()) {
evaluated: downloadBufferMaximumSizeAttribute.isValid()
TRUEFALSE
yes
Evaluation Count:3
yes
Evaluation Count:616
3-616
789 delegate->downloadBufferMaximumSize = downloadBufferMaximumSizeAttribute.toLongLong();
executed (the execution status of this line is deduced): delegate->downloadBufferMaximumSize = downloadBufferMaximumSizeAttribute.toLongLong();
-
790 } else {
executed: }
Execution Count:3
3
791 // If there is no MaximumDownloadBufferSizeAttribute set (which is for the majority -
792 // of QNetworkRequest) then we can assume we'll do it anyway for small HTTP replies. -
793 // This helps with performance and memory fragmentation. -
794 delegate->downloadBufferMaximumSize = 128*1024;
executed (the execution status of this line is deduced): delegate->downloadBufferMaximumSize = 128*1024;
-
795 }
executed: }
Execution Count:616
616
796 -
797 -
798 // These atomic integers are used for signal compression -
799 delegate->pendingDownloadData = pendingDownloadDataEmissions;
executed (the execution status of this line is deduced): delegate->pendingDownloadData = pendingDownloadDataEmissions;
-
800 delegate->pendingDownloadProgress = pendingDownloadProgressEmissions;
executed (the execution status of this line is deduced): delegate->pendingDownloadProgress = pendingDownloadProgressEmissions;
-
801 -
802 // Connect the signals of the delegate to us -
803 QObject::connect(delegate, SIGNAL(downloadData(QByteArray)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""downloadData(QByteArray)",
-
804 q, SLOT(replyDownloadData(QByteArray)),
executed (the execution status of this line is deduced): q, "1""replyDownloadData(QByteArray)",
-
805 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
806 QObject::connect(delegate, SIGNAL(downloadFinished()),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""downloadFinished()",
-
807 q, SLOT(replyFinished()),
executed (the execution status of this line is deduced): q, "1""replyFinished()",
-
808 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
809 QObject::connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)",
-
810 q, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)),
executed (the execution status of this line is deduced): q, "1""replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)",
-
811 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
812 QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""downloadProgress(qint64,qint64)",
-
813 q, SLOT(replyDownloadProgressSlot(qint64,qint64)),
executed (the execution status of this line is deduced): q, "1""replyDownloadProgressSlot(qint64,qint64)",
-
814 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
815 QObject::connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""error(QNetworkReply::NetworkError,QString)",
-
816 q, SLOT(httpError(QNetworkReply::NetworkError,QString)),
executed (the execution status of this line is deduced): q, "1""httpError(QNetworkReply::NetworkError,QString)",
-
817 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
818#ifndef QT_NO_SSL -
819 QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""sslConfigurationChanged(QSslConfiguration)",
-
820 q, SLOT(replySslConfigurationChanged(QSslConfiguration)),
executed (the execution status of this line is deduced): q, "1""replySslConfigurationChanged(QSslConfiguration)",
-
821 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
822#endif -
823 // Those need to report back, therefire BlockingQueuedConnection -
824 QObject::connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""authenticationRequired(QHttpNetworkRequest,QAuthenticator*)",
-
825 q, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
executed (the execution status of this line is deduced): q, "1""httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)",
-
826 Qt::BlockingQueuedConnection);
executed (the execution status of this line is deduced): Qt::BlockingQueuedConnection);
-
827#ifndef QT_NO_NETWORKPROXY -
828 QObject::connect(delegate, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)",
-
829 q, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
executed (the execution status of this line is deduced): q, "1""proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)",
-
830 Qt::BlockingQueuedConnection);
executed (the execution status of this line is deduced): Qt::BlockingQueuedConnection);
-
831#endif -
832#ifndef QT_NO_SSL -
833 QObject::connect(delegate, SIGNAL(sslErrors(QList<QSslError>,bool*,QList<QSslError>*)),
executed (the execution status of this line is deduced): QObject::connect(delegate, "2""sslErrors(QList<QSslError>,bool*,QList<QSslError>*)",
-
834 q, SLOT(replySslErrors(QList<QSslError>,bool*,QList<QSslError>*)),
executed (the execution status of this line is deduced): q, "1""replySslErrors(QList<QSslError>,bool*,QList<QSslError>*)",
-
835 Qt::BlockingQueuedConnection);
executed (the execution status of this line is deduced): Qt::BlockingQueuedConnection);
-
836#endif -
837 // This signal we will use to start the request. -
838 QObject::connect(q, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest()));
executed (the execution status of this line is deduced): QObject::connect(q, "2""startHttpRequest()", delegate, "1""startRequest()");
-
839 QObject::connect(q, SIGNAL(abortHttpRequest()), delegate, SLOT(abortRequest()));
executed (the execution status of this line is deduced): QObject::connect(q, "2""abortHttpRequest()", delegate, "1""abortRequest()");
-
840 -
841 // To throttle the connection. -
842 QObject::connect(q, SIGNAL(readBufferSizeChanged(qint64)), delegate, SLOT(readBufferSizeChanged(qint64)));
executed (the execution status of this line is deduced): QObject::connect(q, "2""readBufferSizeChanged(qint64)", delegate, "1""readBufferSizeChanged(qint64)");
-
843 QObject::connect(q, SIGNAL(readBufferFreed(qint64)), delegate, SLOT(readBufferFreed(qint64)));
executed (the execution status of this line is deduced): QObject::connect(q, "2""readBufferFreed(qint64)", delegate, "1""readBufferFreed(qint64)");
-
844 -
845 if (uploadByteDevice) {
evaluated: uploadByteDevice
TRUEFALSE
yes
Evaluation Count:138
yes
Evaluation Count:481
138-481
846 QNonContiguousByteDeviceThreadForwardImpl *forwardUploadDevice =
executed (the execution status of this line is deduced): QNonContiguousByteDeviceThreadForwardImpl *forwardUploadDevice =
-
847 new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size());
executed (the execution status of this line is deduced): new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size());
-
848 if (uploadByteDevice->isResetDisabled())
evaluated: uploadByteDevice->isResetDisabled()
TRUEFALSE
yes
Evaluation Count:1
yes
Evaluation Count:137
1-137
849 forwardUploadDevice->disableReset();
executed: forwardUploadDevice->disableReset();
Execution Count:1
1
850 forwardUploadDevice->setParent(delegate); // needed to make sure it is moved on moveToThread()
executed (the execution status of this line is deduced): forwardUploadDevice->setParent(delegate);
-
851 delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
executed (the execution status of this line is deduced): delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
-
852 -
853 // From main thread to user thread: -
854 QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)),
executed (the execution status of this line is deduced): QObject::connect(q, "2""haveUploadData(QByteArray,bool,qint64)",
-
855 forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection);
executed (the execution status of this line is deduced): forwardUploadDevice, "1""haveDataSlot(QByteArray,bool,qint64)", Qt::QueuedConnection);
-
856 QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
executed (the execution status of this line is deduced): QObject::connect(uploadByteDevice.data(), "2""readyRead()",
-
857 forwardUploadDevice, SIGNAL(readyRead()),
executed (the execution status of this line is deduced): forwardUploadDevice, "2""readyRead()",
-
858 Qt::QueuedConnection);
executed (the execution status of this line is deduced): Qt::QueuedConnection);
-
859 -
860 // From http thread to user thread: -
861 QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
executed (the execution status of this line is deduced): QObject::connect(forwardUploadDevice, "2""wantData(qint64)",
-
862 q, SLOT(wantUploadDataSlot(qint64)));
executed (the execution status of this line is deduced): q, "1""wantUploadDataSlot(qint64)");
-
863 QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
executed (the execution status of this line is deduced): QObject::connect(forwardUploadDevice, "2""processedData(qint64)",
-
864 q, SLOT(sentUploadDataSlot(qint64)));
executed (the execution status of this line is deduced): q, "1""sentUploadDataSlot(qint64)");
-
865 QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
executed (the execution status of this line is deduced): QObject::connect(forwardUploadDevice, "2""resetData(bool*)",
-
866 q, SLOT(resetUploadDataSlot(bool*)),
executed (the execution status of this line is deduced): q, "1""resetUploadDataSlot(bool*)",
-
867 Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
executed (the execution status of this line is deduced): Qt::BlockingQueuedConnection);
-
868 }
executed: }
Execution Count:138
138
869 } else if (synchronous) {
executed: }
Execution Count:619
partially evaluated: synchronous
TRUEFALSE
yes
Evaluation Count:76
no
Evaluation Count:0
0-619
870 QObject::connect(q, SIGNAL(startHttpRequestSynchronously()), delegate, SLOT(startRequestSynchronously()), Qt::BlockingQueuedConnection);
executed (the execution status of this line is deduced): QObject::connect(q, "2""startHttpRequestSynchronously()", delegate, "1""startRequestSynchronously()", Qt::BlockingQueuedConnection);
-
871 -
872 if (uploadByteDevice) {
evaluated: uploadByteDevice
TRUEFALSE
yes
Evaluation Count:41
yes
Evaluation Count:35
35-41
873 // For the synchronous HTTP use case the use thread (this one here) is blocked -
874 // so we cannot use the asynchronous upload architecture. -
875 // We therefore won't use the QNonContiguousByteDeviceThreadForwardImpl but directly -
876 // use the uploadByteDevice provided to us by the QNetworkReplyImpl. -
877 // The code that is in start() makes sure it is safe to use from a thread -
878 // since it only wraps a QRingBuffer -
879 delegate->httpRequest.setUploadByteDevice(uploadByteDevice.data());
executed (the execution status of this line is deduced): delegate->httpRequest.setUploadByteDevice(uploadByteDevice.data());
-
880 }
executed: }
Execution Count:41
41
881 }
executed: }
Execution Count:76
76
882 -
883 -
884 // Move the delegate to the http thread -
885 delegate->moveToThread(thread);
executed (the execution status of this line is deduced): delegate->moveToThread(thread);
-
886 // This call automatically moves the uploadDevice too for the asynchronous case. -
887 -
888 // Prepare timers for progress notifications -
889 downloadProgressSignalChoke.start();
executed (the execution status of this line is deduced): downloadProgressSignalChoke.start();
-
890 uploadProgressSignalChoke.invalidate();
executed (the execution status of this line is deduced): uploadProgressSignalChoke.invalidate();
-
891 -
892 // Send an signal to the delegate so it starts working in the other thread -
893 if (synchronous) {
evaluated: synchronous
TRUEFALSE
yes
Evaluation Count:76
yes
Evaluation Count:619
76-619
894 emit q->startHttpRequestSynchronously(); // This one is BlockingQueuedConnection, so it will return when all work is done
executed (the execution status of this line is deduced): q->startHttpRequestSynchronously();
-
895 -
896 if (delegate->incomingErrorCode != QNetworkReply::NoError) {
evaluated: delegate->incomingErrorCode != QNetworkReply::NoError
TRUEFALSE
yes
Evaluation Count:13
yes
Evaluation Count:63
13-63
897 replyDownloadMetaData
executed (the execution status of this line is deduced): replyDownloadMetaData
-
898 (delegate->incomingHeaders,
executed (the execution status of this line is deduced): (delegate->incomingHeaders,
-
899 delegate->incomingStatusCode,
executed (the execution status of this line is deduced): delegate->incomingStatusCode,
-
900 delegate->incomingReasonPhrase,
executed (the execution status of this line is deduced): delegate->incomingReasonPhrase,
-
901 delegate->isPipeliningUsed,
executed (the execution status of this line is deduced): delegate->isPipeliningUsed,
-
902 QSharedPointer<char>(),
executed (the execution status of this line is deduced): QSharedPointer<char>(),
-
903 delegate->incomingContentLength);
executed (the execution status of this line is deduced): delegate->incomingContentLength);
-
904 replyDownloadData(delegate->synchronousDownloadData);
executed (the execution status of this line is deduced): replyDownloadData(delegate->synchronousDownloadData);
-
905 httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
executed (the execution status of this line is deduced): httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
-
906 } else {
executed: }
Execution Count:13
13
907 replyDownloadMetaData
executed (the execution status of this line is deduced): replyDownloadMetaData
-
908 (delegate->incomingHeaders,
executed (the execution status of this line is deduced): (delegate->incomingHeaders,
-
909 delegate->incomingStatusCode,
executed (the execution status of this line is deduced): delegate->incomingStatusCode,
-
910 delegate->incomingReasonPhrase,
executed (the execution status of this line is deduced): delegate->incomingReasonPhrase,
-
911 delegate->isPipeliningUsed,
executed (the execution status of this line is deduced): delegate->isPipeliningUsed,
-
912 QSharedPointer<char>(),
executed (the execution status of this line is deduced): QSharedPointer<char>(),
-
913 delegate->incomingContentLength);
executed (the execution status of this line is deduced): delegate->incomingContentLength);
-
914 replyDownloadData(delegate->synchronousDownloadData);
executed (the execution status of this line is deduced): replyDownloadData(delegate->synchronousDownloadData);
-
915 }
executed: }
Execution Count:63
63
916 -
917 thread->quit();
executed (the execution status of this line is deduced): thread->quit();
-
918 thread->wait(5000);
executed (the execution status of this line is deduced): thread->wait(5000);
-
919 if (thread->isFinished())
partially evaluated: thread->isFinished()
TRUEFALSE
yes
Evaluation Count:76
no
Evaluation Count:0
0-76
920 delete thread;
executed: delete thread;
Execution Count:76
76
921 else -
922 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
never executed: QObject::connect(thread, "2""finished()", thread, "1""deleteLater()");
0
923 -
924 finished();
executed (the execution status of this line is deduced): finished();
-
925 } else {
executed: }
Execution Count:76
76
926 emit q->startHttpRequest(); // Signal to the HTTP thread and go back to user.
executed (the execution status of this line is deduced): q->startHttpRequest();
-
927 }
executed: }
Execution Count:619
619
928} -
929 -
930void QNetworkReplyHttpImplPrivate::invalidateCache() -
931{ -
932 QAbstractNetworkCache *nc = managerPrivate->networkCache; -
933 if (nc) -
934 nc->remove(request.url()); -
935} -
936 -
937void QNetworkReplyHttpImplPrivate::initCacheSaveDevice() -
938{ -
939 Q_Q(QNetworkReplyHttpImpl); -
940 -
941 // The disk cache does not support partial content, so don't even try to -
942 // save any such content into the cache. -
943 if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) { -
944 cacheEnabled = false; -
945 return; -
946 } -
947 -
948 // save the meta data -
949 QNetworkCacheMetaData metaData; -
950 metaData.setUrl(url); -
951 metaData = fetchCacheMetaData(metaData); -
952 -
953 // save the redirect request also in the cache -
954 QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute); -
955 if (redirectionTarget.isValid()) { -
956 QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes(); -
957 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget); -
958 metaData.setAttributes(attributes); -
959 } -
960 -
961 cacheSaveDevice = managerPrivate->networkCache->prepare(metaData); -
962 -
963 if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) { -
964 if (cacheSaveDevice && !cacheSaveDevice->isOpen()) -
965 qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- " -
966 "class %s probably needs to be fixed", -
967 managerPrivate->networkCache->metaObject()->className()); -
968 -
969 managerPrivate->networkCache->remove(url); -
970 cacheSaveDevice = 0; -
971 cacheEnabled = false; -
972 } -
973} -
974 -
975void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d) -
976{ -
977 Q_Q(QNetworkReplyHttpImpl); -
978 -
979 // If we're closed just ignore this data -
980 if (!q->isOpen()) -
981 return; -
982 -
983 int pendingSignals = (int)pendingDownloadDataEmissions->fetchAndAddAcquire(-1) - 1; -
984 -
985 if (pendingSignals > 0) { -
986 // Some more signal emissions to this slot are pending. -
987 // Instead of writing the downstream data, we wait -
988 // and do it in the next call we get -
989 // (signal comppression) -
990 pendingDownloadData.append(d); -
991 return; -
992 } -
993 -
994 pendingDownloadData.append(d); -
995 d.clear(); -
996 // We need to usa a copy for calling writeDownstreamData as we could -
997 // possibly recurse into this this function when we call -
998 // appendDownstreamDataSignalEmissions because the user might call -
999 // processEvents() or spin an event loop when this occur. -
1000 QByteDataBuffer pendingDownloadDataCopy = pendingDownloadData; -
1001 pendingDownloadData.clear(); -
1002 -
1003 if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice) { -
1004 initCacheSaveDevice(); -
1005 } -
1006 -
1007 qint64 bytesWritten = 0; -
1008 for (int i = 0; i < pendingDownloadDataCopy.bufferCount(); i++) { -
1009 QByteArray const &item = pendingDownloadDataCopy[i]; -
1010 -
1011 if (cacheSaveDevice) -
1012 cacheSaveDevice->write(item.constData(), item.size()); -
1013 downloadMultiBuffer.append(item); -
1014 -
1015 bytesWritten += item.size(); -
1016 } -
1017 pendingDownloadDataCopy.clear(); -
1018 -
1019 bytesDownloaded += bytesWritten; -
1020 -
1021 -
1022 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); -
1023 if (preMigrationDownloaded != Q_INT64_C(-1)) -
1024 totalSize = totalSize.toLongLong() + preMigrationDownloaded; -
1025 -
1026 emit q->readyRead(); -
1027 // emit readyRead before downloadProgress incase this will cause events to be -
1028 // processed and we get into a recursive call (as in QProgressDialog). -
1029 if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) { -
1030 downloadProgressSignalChoke.restart(); -
1031 emit q->downloadProgress(bytesDownloaded, -
1032 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); -
1033 } -
1034 -
1035} -
1036 -
1037void QNetworkReplyHttpImplPrivate::replyFinished() -
1038{ -
1039 // We are already loading from cache, we still however -
1040 // got this signal because it was posted already -
1041 if (loadingFromCache) -
1042 return; -
1043 -
1044 finished(); -
1045} -
1046 -
1047void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode) -
1048{ -
1049 Q_Q(QNetworkReplyHttpImpl); -
1050 switch (statusCode) { -
1051 case 301: // Moved Permanently -
1052 case 302: // Found -
1053 case 303: // See Other -
1054 case 307: // Temporary Redirect -
1055 // What do we do about the caching of the HTML note? -
1056 // The response to a 303 MUST NOT be cached, while the response to -
1057 // all of the others is cacheable if the headers indicate it to be -
1058 QByteArray header = q->rawHeader("location"); -
1059 QUrl url = QUrl(QString::fromUtf8(header)); -
1060 if (!url.isValid()) -
1061 url = QUrl(QLatin1String(header)); -
1062 q->setAttribute(QNetworkRequest::RedirectionTargetAttribute, url); -
1063 } -
1064} -
1065 -
1066void QNetworkReplyHttpImplPrivate::replyDownloadMetaData -
1067 (QList<QPair<QByteArray,QByteArray> > hm, -
1068 int sc,QString rp,bool pu, -
1069 QSharedPointer<char> db, -
1070 qint64 contentLength) -
1071{ -
1072 Q_Q(QNetworkReplyHttpImpl); -
1073 Q_UNUSED(contentLength); -
1074 -
1075 statusCode = sc; -
1076 reasonPhrase = rp; -
1077 -
1078 // Download buffer -
1079 if (!db.isNull()) { -
1080 downloadBufferPointer = db; -
1081 downloadZerocopyBuffer = downloadBufferPointer.data(); -
1082 downloadBufferCurrentSize = 0; -
1083 q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<char> > (downloadBufferPointer)); -
1084 } -
1085 -
1086 q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu); -
1087 -
1088 // reconstruct the HTTP header -
1089 QList<QPair<QByteArray, QByteArray> > headerMap = hm; -
1090 QList<QPair<QByteArray, QByteArray> >::ConstIterator it = headerMap.constBegin(), -
1091 end = headerMap.constEnd(); -
1092 for (; it != end; ++it) { -
1093 QByteArray value = q->rawHeader(it->first); -
1094 if (!value.isEmpty()) { -
1095 if (qstricmp(it->first.constData(), "set-cookie") == 0) -
1096 value += '\n'; -
1097 else -
1098 value += ", "; -
1099 } -
1100 value += it->second; -
1101 q->setRawHeader(it->first, value); -
1102 } -
1103 -
1104 q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); -
1105 q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); -
1106 -
1107 // is it a redirection? -
1108 checkForRedirect(statusCode); -
1109 -
1110 if (statusCode >= 500 && statusCode < 600) { -
1111 QAbstractNetworkCache *nc = managerPrivate->networkCache; -
1112 if (nc) { -
1113 QNetworkCacheMetaData metaData = nc->metaData(request.url()); -
1114 QNetworkHeadersPrivate cacheHeaders; -
1115 cacheHeaders.setAllRawHeaders(metaData.rawHeaders()); -
1116 QNetworkHeadersPrivate::RawHeadersList::ConstIterator it; -
1117 it = cacheHeaders.findRawHeader("Cache-Control"); -
1118 bool mustReValidate = false; -
1119 if (it != cacheHeaders.rawHeaders.constEnd()) { -
1120 QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second); -
1121 if (cacheControl.contains("must-revalidate")) -
1122 mustReValidate = true; -
1123 } -
1124 if (!mustReValidate && sendCacheContents(metaData)) -
1125 return; -
1126 } -
1127 } -
1128 -
1129 if (statusCode == 304) { -
1130#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) -
1131 qDebug() << "Received a 304 from" << url(); -
1132#endif -
1133 QAbstractNetworkCache *nc = managerPrivate->networkCache; -
1134 if (nc) { -
1135 QNetworkCacheMetaData oldMetaData = nc->metaData(request.url()); -
1136 QNetworkCacheMetaData metaData = fetchCacheMetaData(oldMetaData); -
1137 if (oldMetaData != metaData) -
1138 nc->updateMetaData(metaData); -
1139 if (sendCacheContents(metaData)) -
1140 return; -
1141 } -
1142 } -
1143 -
1144 -
1145 if (statusCode != 304 && statusCode != 303) { -
1146 if (!isCachingEnabled()) -
1147 setCachingEnabled(true); -
1148 } -
1149 -
1150 metaDataChanged(); -
1151} -
1152 -
1153void QNetworkReplyHttpImplPrivate::replyDownloadProgressSlot(qint64 bytesReceived, qint64 bytesTotal) -
1154{ -
1155 Q_Q(QNetworkReplyHttpImpl); -
1156 -
1157 // If we're closed just ignore this data -
1158 if (!q->isOpen()) -
1159 return; -
1160 -
1161 // we can be sure here that there is a download buffer -
1162 -
1163 int pendingSignals = (int)pendingDownloadProgressEmissions->fetchAndAddAcquire(-1) - 1; -
1164 if (pendingSignals > 0) { -
1165 // Let's ignore this signal and look at the next one coming in -
1166 // (signal comppression) -
1167 return; -
1168 } -
1169 -
1170 if (!q->isOpen()) -
1171 return; -
1172 -
1173 if (cacheEnabled && isCachingAllowed() && bytesReceived == bytesTotal) { -
1174 // Write everything in one go if we use a download buffer. might be more performant. -
1175 initCacheSaveDevice(); -
1176 // need to check again if cache enabled and device exists -
1177 if (cacheSaveDevice && cacheEnabled) -
1178 cacheSaveDevice->write(downloadZerocopyBuffer, bytesTotal); -
1179 // FIXME where is it closed? -
1180 } -
1181 -
1182 bytesDownloaded = bytesReceived; -
1183 -
1184 downloadBufferCurrentSize = bytesReceived; -
1185 -
1186 // Only emit readyRead when actual data is there -
1187 // emit readyRead before downloadProgress incase this will cause events to be -
1188 // processed and we get into a recursive call (as in QProgressDialog). -
1189 if (bytesDownloaded > 0) -
1190 emit q->readyRead(); -
1191 if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) { -
1192 downloadProgressSignalChoke.restart(); -
1193 emit q->downloadProgress(bytesDownloaded, bytesTotal); -
1194 } -
1195} -
1196 -
1197void QNetworkReplyHttpImplPrivate::httpAuthenticationRequired(const QHttpNetworkRequest &request, -
1198 QAuthenticator *auth) -
1199{ -
1200 managerPrivate->authenticationRequired(auth, q_func(), synchronous, url, &urlForLastAuthentication, request.withCredentials()); -
1201} -
1202 -
1203#ifndef QT_NO_NETWORKPROXY -
1204void QNetworkReplyHttpImplPrivate::proxyAuthenticationRequired(const QNetworkProxy &proxy, -
1205 QAuthenticator *authenticator) -
1206{ -
1207 managerPrivate->proxyAuthenticationRequired(proxy, synchronous, authenticator, &lastProxyAuthentication); -
1208} -
1209#endif -
1210 -
1211void QNetworkReplyHttpImplPrivate::httpError(QNetworkReply::NetworkError errorCode, -
1212 const QString &errorString) -
1213{ -
1214#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) -
1215 qDebug() << "http error!" << errorCode << errorString; -
1216#endif -
1217 -
1218 // FIXME? -
1219 error(errorCode, errorString); -
1220} -
1221 -
1222#ifndef QT_NO_SSL -
1223void QNetworkReplyHttpImplPrivate::replySslErrors( -
1224 const QList<QSslError> &list, bool *ignoreAll, QList<QSslError> *toBeIgnored) -
1225{ -
1226 Q_Q(QNetworkReplyHttpImpl); -
1227 emit q->sslErrors(list); -
1228 // Check if the callback set any ignore and return this here to http thread -
1229 if (pendingIgnoreAllSslErrors) -
1230 *ignoreAll = true; -
1231 if (!pendingIgnoreSslErrorsList.isEmpty()) -
1232 *toBeIgnored = pendingIgnoreSslErrorsList; -
1233} -
1234 -
1235void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfiguration &sslConfiguration) -
1236{ -
1237 // Receiving the used SSL configuration from the HTTP thread -
1238 this->sslConfiguration = sslConfiguration; -
1239} -
1240#endif -
1241 -
1242// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread -
1243void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r) -
1244{ -
1245 *r = uploadByteDevice->reset(); -
1246} -
1247 -
1248// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread -
1249void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount) -
1250{ -
1251 uploadByteDevice->advanceReadPointer(amount); -
1252} -
1253 -
1254// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread -
1255void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize) -
1256{ -
1257 Q_Q(QNetworkReplyHttpImpl); -
1258 -
1259 // call readPointer -
1260 qint64 currentUploadDataLength = 0; -
1261 char *data = const_cast<char*>(uploadByteDevice->readPointer(maxSize, currentUploadDataLength)); -
1262 // Let's make a copy of this data -
1263 QByteArray dataArray(data, currentUploadDataLength); -
1264 -
1265 // Communicate back to HTTP thread -
1266 emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); -
1267} -
1268 -
1269/* -
1270 A simple web page that can be used to test us: http://www.procata.com/cachetest/ -
1271 */ -
1272bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData &metaData) -
1273{ -
1274 Q_Q(QNetworkReplyHttpImpl); -
1275 -
1276 setCachingEnabled(false); -
1277 if (!metaData.isValid()) -
1278 return false; -
1279 -
1280 QAbstractNetworkCache *nc = managerPrivate->networkCache; -
1281 Q_ASSERT(nc); -
1282 QIODevice *contents = nc->data(url); -
1283 if (!contents) { -
1284#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) -
1285 qDebug() << "Can not send cache, the contents are 0" << url; -
1286#endif -
1287 return false; -
1288 } -
1289 contents->setParent(q); -
1290 -
1291 QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes(); -
1292 int status = attributes.value(QNetworkRequest::HttpStatusCodeAttribute).toInt(); -
1293 if (status < 100) -
1294 status = 200; // fake it -
1295 -
1296 q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, status); -
1297 q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute)); -
1298 q->setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true); -
1299 -
1300 QNetworkCacheMetaData::RawHeaderList rawHeaders = metaData.rawHeaders(); -
1301 QNetworkCacheMetaData::RawHeaderList::ConstIterator it = rawHeaders.constBegin(), -
1302 end = rawHeaders.constEnd(); -
1303 for ( ; it != end; ++it) -
1304 setRawHeader(it->first, it->second); -
1305 -
1306 checkForRedirect(status); -
1307 -
1308 cacheLoadDevice = contents; -
1309 q->connect(cacheLoadDevice, SIGNAL(readyRead()), SLOT(_q_cacheLoadReadyRead())); -
1310 q->connect(cacheLoadDevice, SIGNAL(readChannelFinished()), SLOT(_q_cacheLoadReadyRead())); -
1311 -
1312 // This needs to be emitted in the event loop because it can be reached at -
1313 // the direct code path of qnam.get(...) before the user has a chance -
1314 // to connect any signals. -
1315 QMetaObject::invokeMethod(q, "metaDataChanged", Qt::QueuedConnection); -
1316 QMetaObject::invokeMethod(q, "_q_cacheLoadReadyRead", Qt::QueuedConnection); -
1317 -
1318 -
1319#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) -
1320 qDebug() << "Successfully sent cache:" << url << contents->size() << "bytes"; -
1321#endif -
1322 -
1323 // Set the following flag so we can ignore some signals from HTTP thread -
1324 // that would still come -
1325 loadingFromCache = true; -
1326 return true; -
1327} -
1328 -
1329QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNetworkCacheMetaData &oldMetaData) const -
1330{ -
1331 Q_Q(const QNetworkReplyHttpImpl); -
1332 -
1333 QNetworkCacheMetaData metaData = oldMetaData; -
1334 -
1335 QNetworkHeadersPrivate cacheHeaders; -
1336 cacheHeaders.setAllRawHeaders(metaData.rawHeaders()); -
1337 QNetworkHeadersPrivate::RawHeadersList::ConstIterator it; -
1338 -
1339 QList<QByteArray> newHeaders = q->rawHeaderList(); -
1340 foreach (QByteArray header, newHeaders) { -
1341 QByteArray originalHeader = header; -
1342 header = header.toLower(); -
1343 bool hop_by_hop = -
1344 (header == "connection" -
1345 || header == "keep-alive" -
1346 || header == "proxy-authenticate" -
1347 || header == "proxy-authorization" -
1348 || header == "te" -
1349 || header == "trailers" -
1350 || header == "transfer-encoding" -
1351 || header == "upgrade"); -
1352 if (hop_by_hop) -
1353 continue; -
1354 -
1355 // for 4.6.0, we were planning to not store the date header in the -
1356 // cached resource; through that we planned to reduce the number -
1357 // of writes to disk when using a QNetworkDiskCache (i.e. don't -
1358 // write to disk when only the date changes). -
1359 // However, without the date we cannot calculate the age of the page -
1360 // anymore. -
1361 //if (header == "date") -
1362 //continue; -
1363 -
1364 // Don't store Warning 1xx headers -
1365 if (header == "warning") { -
1366 QByteArray v = q->rawHeader(header); -
1367 if (v.length() == 3 -
1368 && v[0] == '1' -
1369 && v[1] >= '0' && v[1] <= '9' -
1370 && v[2] >= '0' && v[2] <= '9') -
1371 continue; -
1372 } -
1373 -
1374 it = cacheHeaders.findRawHeader(header); -
1375 if (it != cacheHeaders.rawHeaders.constEnd()) { -
1376 // Match the behavior of Firefox and assume Cache-Control: "no-transform" -
1377 if (header == "content-encoding" -
1378 || header == "content-range" -
1379 || header == "content-type") -
1380 continue; -
1381 -
1382 // For MS servers that send "Content-Length: 0" on 304 responses -
1383 // ignore this too -
1384 if (header == "content-length") -
1385 continue; -
1386 } -
1387 -
1388#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) -
1389 QByteArray n = rawHeader(header); -
1390 QByteArray o; -
1391 if (it != cacheHeaders.rawHeaders.constEnd()) -
1392 o = (*it).second; -
1393 if (n != o && header != "date") { -
1394 qDebug() << "replacing" << header; -
1395 qDebug() << "new" << n; -
1396 qDebug() << "old" << o; -
1397 } -
1398#endif -
1399 cacheHeaders.setRawHeader(originalHeader, q->rawHeader(header)); -
1400 } -
1401 metaData.setRawHeaders(cacheHeaders.rawHeaders); -
1402 -
1403 bool checkExpired = true; -
1404 -
1405 QHash<QByteArray, QByteArray> cacheControl; -
1406 it = cacheHeaders.findRawHeader("Cache-Control"); -
1407 if (it != cacheHeaders.rawHeaders.constEnd()) { -
1408 cacheControl = parseHttpOptionHeader(it->second); -
1409 QByteArray maxAge = cacheControl.value("max-age"); -
1410 if (!maxAge.isEmpty()) { -
1411 checkExpired = false; -
1412 QDateTime dt = QDateTime::currentDateTime(); -
1413 dt = dt.addSecs(maxAge.toInt()); -
1414 metaData.setExpirationDate(dt); -
1415 } -
1416 } -
1417 if (checkExpired) { -
1418 it = cacheHeaders.findRawHeader("expires"); -
1419 if (it != cacheHeaders.rawHeaders.constEnd()) { -
1420 QDateTime expiredDateTime = QNetworkHeadersPrivate::fromHttpDate(it->second); -
1421 metaData.setExpirationDate(expiredDateTime); -
1422 } -
1423 } -
1424 -
1425 it = cacheHeaders.findRawHeader("last-modified"); -
1426 if (it != cacheHeaders.rawHeaders.constEnd()) -
1427 metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(it->second)); -
1428 -
1429 bool canDiskCache; -
1430 // only cache GET replies by default, all other replies (POST, PUT, DELETE) -
1431 // are not cacheable by default (according to RFC 2616 section 9) -
1432 if (httpRequest.operation() == QHttpNetworkRequest::Get) { -
1433 -
1434 canDiskCache = true; -
1435 // 14.32 -
1436 // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client -
1437 // had sent "Cache-Control: no-cache". -
1438 it = cacheHeaders.findRawHeader("pragma"); -
1439 if (it != cacheHeaders.rawHeaders.constEnd() -
1440 && it->second == "no-cache") -
1441 canDiskCache = false; -
1442 -
1443 // HTTP/1.1. Check the Cache-Control header -
1444 if (cacheControl.contains("no-cache")) -
1445 canDiskCache = false; -
1446 else if (cacheControl.contains("no-store")) -
1447 canDiskCache = false; -
1448 -
1449 // responses to POST might be cacheable -
1450 } else if (httpRequest.operation() == QHttpNetworkRequest::Post) { -
1451 -
1452 canDiskCache = false; -
1453 // some pages contain "expires:" and "cache-control: no-cache" field, -
1454 // so we only might cache POST requests if we get "cache-control: max-age ..." -
1455 if (cacheControl.contains("max-age")) -
1456 canDiskCache = true; -
1457 -
1458 // responses to PUT and DELETE are not cacheable -
1459 } else { -
1460 canDiskCache = false; -
1461 } -
1462 -
1463 metaData.setSaveToDisk(canDiskCache); -
1464 QNetworkCacheMetaData::AttributesMap attributes; -
1465 if (statusCode != 304) { -
1466 // update the status code -
1467 attributes.insert(QNetworkRequest::HttpStatusCodeAttribute, statusCode); -
1468 attributes.insert(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); -
1469 } else { -
1470 // this is a redirection, keep the attributes intact -
1471 attributes = oldMetaData.attributes(); -
1472 } -
1473 metaData.setAttributes(attributes); -
1474 return metaData; -
1475} -
1476 -
1477bool QNetworkReplyHttpImplPrivate::canResume() const -
1478{ -
1479 Q_Q(const QNetworkReplyHttpImpl); -
1480 -
1481 // Only GET operation supports resuming. -
1482 if (operation != QNetworkAccessManager::GetOperation) -
1483 return false; -
1484 -
1485 // Can only resume if server/resource supports Range header. -
1486 QByteArray acceptRangesheaderName("Accept-Ranges"); -
1487 if (!q->hasRawHeader(acceptRangesheaderName) || q->rawHeader(acceptRangesheaderName) == "none") -
1488 return false; -
1489 -
1490 // We only support resuming for byte ranges. -
1491 if (request.hasRawHeader("Range")) { -
1492 QByteArray range = request.rawHeader("Range"); -
1493 if (!range.startsWith("bytes=")) -
1494 return false; -
1495 } -
1496 -
1497 // If we're using a download buffer then we don't support resuming/migration -
1498 // right now. Too much trouble. -
1499 if (downloadZerocopyBuffer) -
1500 return false; -
1501 -
1502 return true; -
1503} -
1504 -
1505void QNetworkReplyHttpImplPrivate::setResumeOffset(quint64 offset) -
1506{ -
1507 resumeOffset = offset; -
1508} -
1509 -
1510/*! -
1511 Starts the backend. Returns true if the backend is started. Returns false if the backend -
1512 could not be started due to an unopened or roaming session. The caller should recall this -
1513 function once the session has been opened or the roaming process has finished. -
1514*/ -
1515bool QNetworkReplyHttpImplPrivate::start() -
1516{ -
1517#ifndef QT_NO_BEARERMANAGEMENT -
1518 QSharedPointer<QNetworkSession> networkSession(managerPrivate->getNetworkSession()); -
1519 if (!networkSession) { -
1520#endif -
1521 postRequest(); -
1522 return true; -
1523#ifndef QT_NO_BEARERMANAGEMENT -
1524 } -
1525 -
1526 // This is not ideal. -
1527 const QString host = url.host(); -
1528 if (host == QLatin1String("localhost") || -
1529 QHostAddress(host).isLoopback()) { -
1530 // Don't need an open session for localhost access. -
1531 postRequest(); -
1532 return true; -
1533 } -
1534 -
1535 if (networkSession->isOpen() && -
1536 networkSession->state() == QNetworkSession::Connected) { -
1537 Q_Q(QNetworkReplyHttpImpl); -
1538 QObject::connect(networkSession.data(), SIGNAL(usagePoliciesChanged(QNetworkSession::UsagePolicies)), -
1539 q, SLOT(_q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies))); -
1540 postRequest(); -
1541 return true; -
1542 } -
1543 -
1544 return false; -
1545#endif -
1546} -
1547 -
1548void QNetworkReplyHttpImplPrivate::_q_startOperation() -
1549{ -
1550 Q_Q(QNetworkReplyHttpImpl); -
1551 -
1552 // ensure this function is only being called once -
1553 if (state == Working) { -
1554 qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); -
1555 return; -
1556 } -
1557 state = Working; -
1558 -
1559#ifndef QT_NO_BEARERMANAGEMENT -
1560 // Do not start background requests if they are not allowed by session policy -
1561 QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession()); -
1562 QVariant isBackground = request.attribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(false)); -
1563 if (isBackground.toBool() && session && session->usagePolicies().testFlag(QNetworkSession::NoBackgroundTrafficPolicy)) { -
1564 QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection, -
1565 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::BackgroundRequestNotAllowedError), -
1566 Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Background request not allowed."))); -
1567 QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection); -
1568 return; -
1569 } -
1570#endif -
1571 -
1572 if (!start()) { -
1573#ifndef QT_NO_BEARERMANAGEMENT -
1574 // backend failed to start because the session state is not Connected. -
1575 // QNetworkAccessManager will call reply->backend->start() again for us when the session -
1576 // state changes. -
1577 state = WaitingForSession; -
1578 -
1579 if (session) { -
1580 QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)), -
1581 q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection); -
1582 -
1583 if (!session->isOpen()) { -
1584 session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground); -
1585 session->open(); -
1586 } -
1587 } else { -
1588 qWarning("Backend is waiting for QNetworkSession to connect, but there is none!"); -
1589 QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection, -
1590 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError), -
1591 Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error."))); -
1592 QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection); -
1593 return; -
1594 } -
1595#else -
1596 qWarning("Backend start failed"); -
1597 QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection, -
1598 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::UnknownNetworkError), -
1599 Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "backend start error."))); -
1600 QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection); -
1601 return; -
1602#endif -
1603 } -
1604 -
1605 if (synchronous) { -
1606 state = Finished; -
1607 q_func()->setFinished(true); -
1608 } else { -
1609 if (state != Finished) { -
1610 -
1611 } -
1612 } -
1613} -
1614 -
1615void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead() -
1616{ -
1617 Q_Q(QNetworkReplyHttpImpl); -
1618 -
1619 if (state != Working) -
1620 return; -
1621 if (!cacheLoadDevice || !q->isOpen() || !cacheLoadDevice->bytesAvailable()) -
1622 return; -
1623 -
1624 // FIXME Optimize to use zerocopy download buffer if it is a QBuffer. -
1625 // Needs to be done where sendCacheContents() (?) of HTTP is emitting -
1626 // metaDataChanged ? -
1627 -
1628 -
1629 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); -
1630 -
1631 // emit readyRead before downloadProgress incase this will cause events to be -
1632 // processed and we get into a recursive call (as in QProgressDialog). -
1633 -
1634 // This readyRead() goes to the user. The user then may or may not read() anything. -
1635 emit q->readyRead(); -
1636 if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) { -
1637 downloadProgressSignalChoke.restart(); -
1638 emit q->downloadProgress(bytesDownloaded, -
1639 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); -
1640 } -
1641 -
1642 // If there are still bytes available in the cacheLoadDevice then the user did not read -
1643 // in response to the readyRead() signal. This means we have to load from the cacheLoadDevice -
1644 // and buffer that stuff. This is needed to be able to properly emit finished() later. -
1645 while (cacheLoadDevice->bytesAvailable()) { -
1646 downloadMultiBuffer.append(cacheLoadDevice->readAll()); -
1647 } -
1648 -
1649 if (cacheLoadDevice->isSequential()) { -
1650 // check if end and we can read the EOF -1 -
1651 char c; -
1652 qint64 actualCount = cacheLoadDevice->read(&c, 1); -
1653 if (actualCount < 0) { -
1654 cacheLoadDevice->deleteLater(); -
1655 cacheLoadDevice = 0; -
1656 QMetaObject::invokeMethod(q, "_q_finished", Qt::QueuedConnection); -
1657 } else if (actualCount == 1) { -
1658 // This is most probably not happening since most QIODevice returned something proper for bytesAvailable() -
1659 // and had already been "emptied". -
1660 cacheLoadDevice->ungetChar(c); -
1661 } -
1662 } else if ((!cacheLoadDevice->isSequential() && cacheLoadDevice->atEnd())) { -
1663 // This codepath is in case the cache device is a QBuffer, e.g. from QNetworkDiskCache. -
1664 cacheLoadDevice->deleteLater(); -
1665 cacheLoadDevice = 0; -
1666 QMetaObject::invokeMethod(q, "_q_finished", Qt::QueuedConnection); -
1667 } -
1668 -
1669} -
1670 -
1671 -
1672void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingDataFinished() -
1673{ -
1674 Q_Q(QNetworkReplyHttpImpl); -
1675 -
1676 // make sure this is only called once, ever. -
1677 //_q_bufferOutgoingData may call it or the readChannelFinished emission -
1678 if (state != Buffering) -
1679 return; -
1680 -
1681 // disconnect signals -
1682 QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); -
1683 QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); -
1684 -
1685 // finally, start the request -
1686 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); -
1687} -
1688 -
1689void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingData() -
1690{ -
1691 Q_Q(QNetworkReplyHttpImpl); -
1692 -
1693 if (!outgoingDataBuffer) { -
1694 // first call, create our buffer -
1695 outgoingDataBuffer = QSharedPointer<QRingBuffer>(new QRingBuffer()); -
1696 -
1697 QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); -
1698 QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); -
1699 } -
1700 -
1701 qint64 bytesBuffered = 0; -
1702 qint64 bytesToBuffer = 0; -
1703 -
1704 // read data into our buffer -
1705 forever { -
1706 bytesToBuffer = outgoingData->bytesAvailable(); -
1707 // unknown? just try 2 kB, this also ensures we always try to read the EOF -
1708 if (bytesToBuffer <= 0) -
1709 bytesToBuffer = 2*1024; -
1710 -
1711 char *dst = outgoingDataBuffer->reserve(bytesToBuffer); -
1712 bytesBuffered = outgoingData->read(dst, bytesToBuffer); -
1713 -
1714 if (bytesBuffered == -1) { -
1715 // EOF has been reached. -
1716 outgoingDataBuffer->chop(bytesToBuffer); -
1717 -
1718 _q_bufferOutgoingDataFinished(); -
1719 break; -
1720 } else if (bytesBuffered == 0) { -
1721 // nothing read right now, just wait until we get called again -
1722 outgoingDataBuffer->chop(bytesToBuffer); -
1723 -
1724 break; -
1725 } else { -
1726 // don't break, try to read() again -
1727 outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered); -
1728 } -
1729 } -
1730} -
1731 -
1732#ifndef QT_NO_BEARERMANAGEMENT -
1733void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected() -
1734{ -
1735 Q_Q(QNetworkReplyHttpImpl); -
1736 -
1737 if (!manager) -
1738 return; -
1739 -
1740 QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession(); -
1741 if (!session) -
1742 return; -
1743 -
1744 if (session->state() != QNetworkSession::Connected) -
1745 return; -
1746 -
1747 switch (state) { -
1748 case QNetworkReplyImplPrivate::Buffering: -
1749 case QNetworkReplyImplPrivate::Working: -
1750 case QNetworkReplyImplPrivate::Reconnecting: -
1751 // Migrate existing downloads to new network connection. -
1752 migrateBackend(); -
1753 break; -
1754 case QNetworkReplyImplPrivate::WaitingForSession: -
1755 // Start waiting requests. -
1756 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); -
1757 break; -
1758 default: -
1759 ; -
1760 } -
1761} -
1762 -
1763void QNetworkReplyHttpImplPrivate::_q_networkSessionFailed() -
1764{ -
1765 // Abort waiting and working replies. -
1766 if (state == WaitingForSession || state == Working) { -
1767 state = Working; -
1768 QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession()); -
1769 QString errorStr; -
1770 if (session) -
1771 errorStr = session->errorString(); -
1772 else -
1773 errorStr = QCoreApplication::translate("QNetworkReply", "Network session error."); -
1774 error(QNetworkReplyImpl::NetworkSessionFailedError, errorStr); -
1775 finished(); -
1776 } -
1777} -
1778 -
1779void QNetworkReplyHttpImplPrivate::_q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies newPolicies) -
1780{ -
1781 if (request.attribute(QNetworkRequest::BackgroundRequestAttribute).toBool()) { -
1782 if (newPolicies & QNetworkSession::NoBackgroundTrafficPolicy) { -
1783 // Abort waiting and working replies. -
1784 if (state == WaitingForSession || state == Working) { -
1785 state = Working; -
1786 error(QNetworkReply::BackgroundRequestNotAllowedError, -
1787 QCoreApplication::translate("QNetworkReply", "Background request not allowed.")); -
1788 finished(); -
1789 } -
1790 // ### if canResume(), then we could resume automatically -
1791 } -
1792 } -
1793 -
1794} -
1795#endif -
1796 -
1797 -
1798// need to have this function since the reply is a private member variable -
1799// and the special backends need to access this. -
1800void QNetworkReplyHttpImplPrivate::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal) -
1801{ -
1802 Q_Q(QNetworkReplyHttpImpl); -
1803 if (isFinished) -
1804 return; -
1805 -
1806 //choke signal emissions, except the first and last signals which are unconditional -
1807 if (uploadProgressSignalChoke.isValid()) { -
1808 if (bytesSent != bytesTotal && uploadProgressSignalChoke.elapsed() < progressSignalInterval) { -
1809 return; -
1810 } -
1811 uploadProgressSignalChoke.restart(); -
1812 } else { -
1813 uploadProgressSignalChoke.start(); -
1814 } -
1815 -
1816 emit q->uploadProgress(bytesSent, bytesTotal); -
1817} -
1818 -
1819QNonContiguousByteDevice* QNetworkReplyHttpImplPrivate::createUploadByteDevice() -
1820{ -
1821 Q_Q(QNetworkReplyHttpImpl); -
1822 -
1823 if (outgoingDataBuffer) -
1824 uploadByteDevice = QSharedPointer<QNonContiguousByteDevice>(QNonContiguousByteDeviceFactory::create(outgoingDataBuffer)); -
1825 else if (outgoingData) { -
1826 uploadByteDevice = QSharedPointer<QNonContiguousByteDevice>(QNonContiguousByteDeviceFactory::create(outgoingData)); -
1827 } else { -
1828 return 0; -
1829 } -
1830 -
1831 bool bufferDisallowed = -
1832 request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, -
1833 QVariant(false)) == QVariant(true); -
1834 if (bufferDisallowed) -
1835 uploadByteDevice->disableReset(); -
1836 -
1837 // We want signal emissions only for normal asynchronous uploads -
1838 if (!synchronous) -
1839 QObject::connect(uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)), -
1840 q, SLOT(emitReplyUploadProgress(qint64,qint64))); -
1841 -
1842 return uploadByteDevice.data(); -
1843} -
1844 -
1845void QNetworkReplyHttpImplPrivate::_q_finished() -
1846{ -
1847 // This gets called queued, just forward to real call then -
1848 finished(); -
1849} -
1850 -
1851void QNetworkReplyHttpImplPrivate::finished() -
1852{ -
1853 Q_Q(QNetworkReplyHttpImpl); -
1854 -
1855 if (state == Finished || state == Aborted || state == WaitingForSession) -
1856 return; -
1857 -
1858 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); -
1859 if (preMigrationDownloaded != Q_INT64_C(-1)) -
1860 totalSize = totalSize.toLongLong() + preMigrationDownloaded; -
1861 -
1862 if (manager) { -
1863#ifndef QT_NO_BEARERMANAGEMENT -
1864 QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession(); -
1865 if (session && session->state() == QNetworkSession::Roaming && -
1866 state == Working && errorCode != QNetworkReply::OperationCanceledError) { -
1867 // only content with a known size will fail with a temporary network failure error -
1868 if (!totalSize.isNull()) { -
1869 if (bytesDownloaded != totalSize) { -
1870 if (migrateBackend()) { -
1871 // either we are migrating or the request is finished/aborted -
1872 if (state == Reconnecting || state == WaitingForSession) { -
1873 return; // exit early if we are migrating. -
1874 } -
1875 } else { -
1876 error(QNetworkReply::TemporaryNetworkFailureError, -
1877 QNetworkReply::tr("Temporary network failure.")); -
1878 } -
1879 } -
1880 } -
1881 } -
1882#endif -
1883 } -
1884 -
1885 state = Finished; -
1886 q->setFinished(true); -
1887 -
1888 if (totalSize.isNull() || totalSize == -1) { -
1889 emit q->downloadProgress(bytesDownloaded, bytesDownloaded); -
1890 } else { -
1891 emit q->downloadProgress(bytesDownloaded, totalSize.toLongLong()); -
1892 } -
1893 -
1894 if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer)) -
1895 emit q->uploadProgress(0, 0); -
1896 -
1897 // if we don't know the total size of or we received everything save the cache -
1898 if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize) -
1899 completeCacheSave(); -
1900 -
1901 emit q->readChannelFinished(); -
1902 emit q->finished(); -
1903} -
1904 -
1905void QNetworkReplyHttpImplPrivate::_q_error(QNetworkReplyImpl::NetworkError code, const QString &errorMessage) -
1906{ -
1907 this->error(code, errorMessage); -
1908} -
1909 -
1910 -
1911void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, const QString &errorMessage) -
1912{ -
1913 Q_Q(QNetworkReplyHttpImpl); -
1914 // Can't set and emit multiple errors. -
1915 if (errorCode != QNetworkReply::NoError) { -
1916 qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once."); -
1917 return; -
1918 } -
1919 -
1920 errorCode = code; -
1921 q->setErrorString(errorMessage); -
1922 -
1923 // note: might not be a good idea, since users could decide to delete us -
1924 // which would delete the backend too... -
1925 // maybe we should protect the backend -
1926 emit q->error(code); -
1927} -
1928 -
1929void QNetworkReplyHttpImplPrivate::metaDataChanged() -
1930{ -
1931 // FIXME merge this with replyDownloadMetaData(); ? -
1932 -
1933 Q_Q(QNetworkReplyHttpImpl); -
1934 // 1. do we have cookies? -
1935 // 2. are we allowed to set them? -
1936 if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && manager -
1937 && (static_cast<QNetworkRequest::LoadControl> -
1938 (request.attribute(QNetworkRequest::CookieSaveControlAttribute, -
1939 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic)) { -
1940 QList<QNetworkCookie> cookies = -
1941 qvariant_cast<QList<QNetworkCookie> >(cookedHeaders.value(QNetworkRequest::SetCookieHeader)); -
1942 QNetworkCookieJar *jar = manager->cookieJar(); -
1943 if (jar) -
1944 jar->setCookiesFromUrl(cookies, url); -
1945 } -
1946 emit q->metaDataChanged(); -
1947} -
1948 -
1949/* -
1950 Migrates the backend of the QNetworkReply to a new network connection if required. Returns -
1951 true if the reply is migrated or it is not required; otherwise returns false. -
1952*/ -
1953bool QNetworkReplyHttpImplPrivate::migrateBackend() -
1954{ -
1955 Q_Q(QNetworkReplyHttpImpl); -
1956 -
1957 // Network reply is already finished or aborted, don't need to migrate. -
1958 if (state == Finished || state == Aborted) -
1959 return true; -
1960 -
1961 // Backend does not support resuming download. -
1962 if (!canResume()) -
1963 return false; -
1964 -
1965 // Request has outgoing data, not migrating. -
1966 if (outgoingData) -
1967 return false; -
1968 -
1969 // Request is serviced from the cache, don't need to migrate. -
1970 if (cacheLoadDevice) -
1971 return true; -
1972 -
1973 state = Reconnecting; -
1974 -
1975 cookedHeaders.clear(); -
1976 rawHeaders.clear(); -
1977 -
1978 preMigrationDownloaded = bytesDownloaded; -
1979 -
1980 setResumeOffset(bytesDownloaded); -
1981 -
1982 emit q->abortHttpRequest(); -
1983 -
1984 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); -
1985 -
1986 return true; -
1987} -
1988 -
1989 -
1990void QNetworkReplyHttpImplPrivate::createCache() -
1991{ -
1992 // check if we can save and if we're allowed to -
1993 if (!managerPrivate->networkCache -
1994 || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool()) -
1995 return; -
1996 cacheEnabled = true; -
1997} -
1998 -
1999bool QNetworkReplyHttpImplPrivate::isCachingEnabled() const -
2000{ -
2001 return (cacheEnabled && managerPrivate->networkCache != 0); -
2002} -
2003 -
2004void QNetworkReplyHttpImplPrivate::setCachingEnabled(bool enable) -
2005{ -
2006 if (!enable && !cacheEnabled) -
2007 return; // nothing to do -
2008 if (enable && cacheEnabled) -
2009 return; // nothing to do either! -
2010 -
2011 if (enable) { -
2012 if (bytesDownloaded) { -
2013 qDebug() << "setCachingEnabled: " << bytesDownloaded << " bytesDownloaded"; -
2014 // refuse to enable in this case -
2015 qCritical("QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written"); -
2016 return; -
2017 } -
2018 -
2019 createCache(); -
2020 } else { -
2021 // someone told us to turn on, then back off? -
2022 // ok... but you should make up your mind -
2023 qDebug("QNetworkReplyImpl: setCachingEnabled(true) called after setCachingEnabled(false)"); -
2024 managerPrivate->networkCache->remove(url); -
2025 cacheSaveDevice = 0; -
2026 cacheEnabled = false; -
2027 } -
2028} -
2029 -
2030bool QNetworkReplyHttpImplPrivate::isCachingAllowed() const -
2031{ -
2032 return operation == QNetworkAccessManager::GetOperation || operation == QNetworkAccessManager::HeadOperation; -
2033} -
2034 -
2035void QNetworkReplyHttpImplPrivate::completeCacheSave() -
2036{ -
2037 if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) { -
2038 managerPrivate->networkCache->remove(url); -
2039 } else if (cacheEnabled && cacheSaveDevice) { -
2040 managerPrivate->networkCache->insert(cacheSaveDevice); -
2041 } -
2042 cacheSaveDevice = 0; -
2043 cacheEnabled = false; -
2044} -
2045 -
2046QT_END_NAMESPACE -
2047 -
2048#endif // QT_NO_HTTP -
2049 -
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial