Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qhttpnetworkreply.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:network-protocol
4
7
8#ifndef QT_NO_SSL
9# include <QtNetwork/qsslkey.h>
10# include <QtNetwork/qsslcipher.h>
11# include <QtNetwork/qsslconfiguration.h>
12#endif
13
14#include <private/qdecompresshelper_p.h>
15
17
18using namespace Qt::StringLiterals;
19
20QHttpNetworkReply::QHttpNetworkReply(const QUrl &url, QObject *parent)
21 : QObject(*new QHttpNetworkReplyPrivate(url), parent)
22{
23}
24
25QHttpNetworkReply::~QHttpNetworkReply()
26{
27 Q_D(QHttpNetworkReply);
28 if (d->connection) {
29 d->connection->d_func()->removeReply(this);
30 }
31}
32
33QUrl QHttpNetworkReply::url() const
34{
35 return d_func()->url;
36}
37void QHttpNetworkReply::setUrl(const QUrl &url)
38{
39 Q_D(QHttpNetworkReply);
40 d->url = url;
41}
42
43QUrl QHttpNetworkReply::redirectUrl() const
44{
45 return d_func()->redirectUrl;
46}
47
48void QHttpNetworkReply::setRedirectUrl(const QUrl &url)
49{
50 Q_D(QHttpNetworkReply);
51 d->redirectUrl = url;
52}
53
54bool QHttpNetworkReply::isHttpRedirect(int statusCode)
55{
56 return (statusCode == 301 || statusCode == 302 || statusCode == 303
57 || statusCode == 305 || statusCode == 307 || statusCode == 308);
58}
59
60qint64 QHttpNetworkReply::contentLength() const
61{
62 return d_func()->contentLength();
63}
64
65void QHttpNetworkReply::setContentLength(qint64 length)
66{
67 Q_D(QHttpNetworkReply);
68 d->setContentLength(length);
69}
70
71QHttpHeaders QHttpNetworkReply::header() const
72{
73 return d_func()->parser.headers();
74}
75
76QByteArray QHttpNetworkReply::headerField(QByteArrayView name, const QByteArray &defaultValue) const
77{
78 return d_func()->headerField(name, defaultValue);
79}
80
81void QHttpNetworkReply::setHeaderField(const QByteArray &name, const QByteArray &data)
82{
83 Q_D(QHttpNetworkReply);
84 d->setHeaderField(name, data);
85}
86
87void QHttpNetworkReply::appendHeaderField(const QByteArray &name, const QByteArray &data)
88{
89 Q_D(QHttpNetworkReply);
90 d->appendHeaderField(name, data);
91}
92
93void QHttpNetworkReply::parseHeader(QByteArrayView header)
94{
95 Q_D(QHttpNetworkReply);
96 d->parseHeader(header);
97}
98
99QHttpNetworkRequest QHttpNetworkReply::request() const
100{
101 return d_func()->request;
102}
103
104void QHttpNetworkReply::setRequest(const QHttpNetworkRequest &request)
105{
106 Q_D(QHttpNetworkReply);
107 d->request = request;
108 d->ssl = request.isSsl();
109}
110
111int QHttpNetworkReply::statusCode() const
112{
113 return d_func()->parser.getStatusCode();
114}
115
116void QHttpNetworkReply::setStatusCode(int code)
117{
118 Q_D(QHttpNetworkReply);
119 d->parser.setStatusCode(code);
120}
121
122QString QHttpNetworkReply::errorString() const
123{
124 return d_func()->errorString;
125}
126
127QNetworkReply::NetworkError QHttpNetworkReply::errorCode() const
128{
129 return d_func()->httpErrorCode;
130}
131
132QString QHttpNetworkReply::reasonPhrase() const
133{
134 return d_func()->parser.getReasonPhrase();
135}
136
137void QHttpNetworkReply::setReasonPhrase(const QString &reason)
138{
139 d_func()->parser.setReasonPhrase(reason);
140}
141
142void QHttpNetworkReply::setErrorString(const QString &error)
143{
144 Q_D(QHttpNetworkReply);
145 d->errorString = error;
146}
147
148int QHttpNetworkReply::majorVersion() const
149{
150 return d_func()->parser.getMajorVersion();
151}
152
153int QHttpNetworkReply::minorVersion() const
154{
155 return d_func()->parser.getMinorVersion();
156}
157
158void QHttpNetworkReply::setMajorVersion(int version)
159{
160 d_func()->parser.setMajorVersion(version);
161}
162
163void QHttpNetworkReply::setMinorVersion(int version)
164{
165 d_func()->parser.setMinorVersion(version);
166}
167
168qint64 QHttpNetworkReply::bytesAvailable() const
169{
170 Q_D(const QHttpNetworkReply);
171 if (d->connection)
172 return d->connection->d_func()->uncompressedBytesAvailable(*this);
173 else
174 return -1;
175}
176
177qint64 QHttpNetworkReply::bytesAvailableNextBlock() const
178{
179 Q_D(const QHttpNetworkReply);
180 if (d->connection)
181 return d->connection->d_func()->uncompressedBytesAvailableNextBlock(*this);
182 else
183 return -1;
184}
185
186bool QHttpNetworkReply::readAnyAvailable() const
187{
188 Q_D(const QHttpNetworkReply);
189 return (d->responseData.bufferCount() > 0);
190}
191
192QByteArray QHttpNetworkReply::readAny()
193{
194 Q_D(QHttpNetworkReply);
195 if (d->responseData.bufferCount() == 0)
196 return QByteArray();
197
198 // we'll take the last buffer, so schedule another read from http
199 if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
200 d->connection->d_func()->readMoreLater(this);
201 return d->responseData.read();
202}
203
204QByteArray QHttpNetworkReply::readAll()
205{
206 Q_D(QHttpNetworkReply);
207 return d->responseData.readAll();
208}
209
210QByteArray QHttpNetworkReply::read(qint64 amount)
211{
212 Q_D(QHttpNetworkReply);
213 return d->responseData.read(amount);
214}
215
216
217qint64 QHttpNetworkReply::sizeNextBlock()
218{
219 Q_D(QHttpNetworkReply);
220 return d->responseData.sizeNextBlock();
221}
222
223void QHttpNetworkReply::setDownstreamLimited(bool dsl)
224{
225 Q_D(QHttpNetworkReply);
226 d->downstreamLimited = dsl;
227 d->connection->d_func()->readMoreLater(this);
228}
229
230void QHttpNetworkReply::setReadBufferSize(qint64 size)
231{
232 Q_D(QHttpNetworkReply);
233 d->readBufferMaxSize = size;
234}
235
236bool QHttpNetworkReply::supportsUserProvidedDownloadBuffer()
237{
238 Q_D(QHttpNetworkReply);
239 return !d->isChunked() && !d->autoDecompress &&
240 d->bodyLength > 0 && d->parser.getStatusCode() == 200;
241}
242
243void QHttpNetworkReply::setUserProvidedDownloadBuffer(char* b)
244{
245 Q_D(QHttpNetworkReply);
246 if (supportsUserProvidedDownloadBuffer())
247 d->userProvidedDownloadBuffer = b;
248}
249
250char* QHttpNetworkReply::userProvidedDownloadBuffer()
251{
252 Q_D(QHttpNetworkReply);
253 return d->userProvidedDownloadBuffer;
254}
255
256void QHttpNetworkReply::abort()
257{
258 Q_D(QHttpNetworkReply);
259 d->state = QHttpNetworkReplyPrivate::Aborted;
260}
261
262bool QHttpNetworkReply::isAborted() const
263{
264 return d_func()->state == QHttpNetworkReplyPrivate::Aborted;
265}
266
267bool QHttpNetworkReply::isFinished() const
268{
269 return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;
270}
271
272bool QHttpNetworkReply::isPipeliningUsed() const
273{
274 return d_func()->pipeliningUsed;
275}
276
277bool QHttpNetworkReply::isHttp2Used() const
278{
279 return d_func()->h2Used;
280}
281
282void QHttpNetworkReply::setHttp2WasUsed(bool h2)
283{
284 d_func()->h2Used = h2;
285}
286
287qint64 QHttpNetworkReply::removedContentLength() const
288{
289 return d_func()->removedContentLength;
290}
291
292bool QHttpNetworkReply::isRedirecting() const
293{
294 return d_func()->isRedirecting();
295}
296
297QHttpNetworkConnection* QHttpNetworkReply::connection()
298{
299 return d_func()->connection;
300}
301
302
303QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
304 : QHttpNetworkHeaderPrivate(newUrl)
305 , state(NothingDoneState)
306 , ssl(false),
307 bodyLength(0), contentRead(0), totalProgress(0),
308 chunkedTransferEncoding(false),
309 connectionCloseEnabled(true),
310 forceConnectionCloseEnabled(false),
311 lastChunkRead(false),
312 currentChunkSize(0), currentChunkRead(0), readBufferMaxSize(0),
313 totallyUploadedData(0),
314 removedContentLength(-1),
315 connection(nullptr),
316 autoDecompress(false), responseData(), requestIsPrepared(false)
317 ,pipeliningUsed(false), h2Used(false), downstreamLimited(false)
318 ,userProvidedDownloadBuffer(nullptr)
319
320{
321 QString scheme = newUrl.scheme();
322 if (scheme == "preconnect-http"_L1 || scheme == "preconnect-https"_L1)
323 // make sure we do not close the socket after preconnecting
324 connectionCloseEnabled = false;
325}
326
327QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() = default;
328
329void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
330{
331 state = NothingDoneState;
332 bodyLength = 0;
333 contentRead = 0;
334 totalProgress = 0;
335 currentChunkSize = 0;
336 currentChunkRead = 0;
337 lastChunkRead = false;
338 connectionCloseEnabled = true;
339 parser.clear();
340}
341
342// TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
343void QHttpNetworkReplyPrivate::clear()
344{
345 connection = nullptr;
346 connectionChannel = nullptr;
347 autoDecompress = false;
348 clearHttpLayerInformation();
349}
350
351// QHttpNetworkReplyPrivate
352qint64 QHttpNetworkReplyPrivate::bytesAvailable() const
353{
354 return (state != ReadingDataState ? 0 : fragment.size());
355}
356
357bool QHttpNetworkReplyPrivate::isCompressed() const
358{
359 return QDecompressHelper::isSupportedEncoding(headerField("content-encoding"));
360}
361
362bool QHttpNetworkReply::isCompressed() const
363{
364 Q_D(const QHttpNetworkReply);
365 return d->isCompressed();
366}
367
368void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
369{
370 // The header "Content-Encoding = gzip" is retained.
371 // Content-Length is removed since the actual one sent by the server is for compressed data
372 constexpr auto name = QByteArrayView("content-length");
373 QByteArray contentLength = parser.firstHeaderField(name);
374 bool parseOk = false;
375 qint64 value = contentLength.toLongLong(&parseOk);
376 if (parseOk) {
377 removedContentLength = value;
378 parser.removeHeaderField(name);
379 }
380}
381
382qint64 QHttpNetworkReplyPrivate::readStatus(QIODevice *socket)
383{
384 if (fragment.isEmpty()) {
385 // reserve bytes for the status line. This is better than always append() which reallocs the byte array
386 fragment.reserve(32);
387 }
388
389 qint64 bytes = 0;
390 char c;
391 qint64 haveRead = 0;
392
393 do {
394 haveRead = socket->read(&c, 1);
395 if (haveRead == -1)
396 return -1; // unexpected EOF
397 else if (haveRead == 0)
398 break; // read more later
399 else if (haveRead == 1 && fragment.size() == 0 && (c == 11 || c == '\n' || c == '\r' || c == ' ' || c == 31))
400 continue; // Ignore all whitespace that was trailing froma previous request on that socket
401
402 bytes++;
403
404 // allow both CRLF & LF (only) line endings
405 if (c == '\n') {
406 // remove the CR at the end
407 if (fragment.endsWith('\r')) {
408 fragment.truncate(fragment.size()-1);
409 }
410 bool ok = parseStatus(fragment);
411 state = ReadingHeaderState;
412 fragment.clear();
413 if (!ok) {
414 return -1;
415 }
416 break;
417 } else {
418 fragment.append(c);
419 }
420
421 // is this a valid reply?
422 if (fragment.size() == 5 && !fragment.startsWith("HTTP/")) {
423 fragment.clear();
424 return -1;
425 }
426 } while (haveRead == 1);
427
428 return bytes;
429}
430
431bool QHttpNetworkReplyPrivate::parseStatus(QByteArrayView status)
432{
433 return parser.parseStatus(status);
434}
435
436qint64 QHttpNetworkReplyPrivate::readHeader(QIODevice *socket)
437{
438 if (fragment.isEmpty()) {
439 // according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
440 // block is 381 bytes.
441 // reserve bytes. This is better than always append() which reallocs the byte array.
442 fragment.reserve(512);
443 }
444
445 qint64 bytes = 0;
446 char c = 0;
447 bool allHeaders = false;
448 qint64 haveRead = 0;
449 do {
450 haveRead = socket->read(&c, 1);
451 if (haveRead == 0) {
452 // read more later
453 break;
454 } else if (haveRead == -1) {
455 // connection broke down
456 return -1;
457 } else {
458 fragment.append(c);
459 bytes++;
460
461 if (c == '\n') {
462 // check for possible header endings. As per HTTP rfc,
463 // the header endings will be marked by CRLFCRLF. But
464 // we will allow CRLFCRLF, CRLFLF, LFCRLF, LFLF
465 if (fragment.endsWith("\n\r\n")
466 || fragment.endsWith("\n\n"))
467 allHeaders = true;
468
469 // there is another case: We have no headers. Then the fragment equals just the line ending
470 if ((fragment.size() == 2 && fragment.endsWith("\r\n"))
471 || (fragment.size() == 1 && fragment.endsWith("\n")))
472 allHeaders = true;
473 }
474 }
475 } while (!allHeaders && haveRead > 0);
476
477 // we received all headers now parse them
478 if (allHeaders) {
479 parseHeader(fragment);
480 state = ReadingDataState;
481 fragment.clear(); // next fragment
482 bodyLength = contentLength(); // cache the length
483
484 // cache isChunked() since it is called often
485 chunkedTransferEncoding = headerField("transfer-encoding").toLower().contains("chunked");
486
487 // cache isConnectionCloseEnabled since it is called often
488 QByteArray connectionHeaderField = headerField("connection");
489 // check for explicit indication of close or the implicit connection close of HTTP/1.0
490 connectionCloseEnabled = (connectionHeaderField.toLower().contains("close") ||
491 headerField("proxy-connection").toLower().contains("close")) ||
492 (parser.getMajorVersion() == 1 && parser.getMinorVersion() == 0 &&
493 (connectionHeaderField.isEmpty() && !headerField("proxy-connection").toLower().contains("keep-alive")));
494 }
495 return bytes;
496}
497
498void QHttpNetworkReplyPrivate::parseHeader(QByteArrayView header)
499{
500 parser.parseHeaders(header);
501}
502
503void QHttpNetworkReplyPrivate::appendHeaderField(const QByteArray &name, const QByteArray &data)
504{
505 parser.appendHeaderField(name, data);
506}
507
508bool QHttpNetworkReplyPrivate::isChunked()
509{
510 return chunkedTransferEncoding;
511}
512
513bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
514{
515 return connectionCloseEnabled || forceConnectionCloseEnabled;
516}
517
518// note this function can only be used for non-chunked, non-compressed with
519// known content length
520qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QIODevice *socket, char *b)
521{
522 // This first read is to flush the buffer inside the socket
523 qint64 haveRead = 0;
524 haveRead = socket->read(b, bodyLength - contentRead);
525 if (haveRead == -1) {
526 return -1;
527 }
528 contentRead += haveRead;
529
530 if (contentRead == bodyLength) {
531 state = AllDoneState;
532 }
533
534 return haveRead;
535}
536
537// note this function can only be used for non-chunked, non-compressed with
538// known content length
539qint64 QHttpNetworkReplyPrivate::readBodyFast(QIODevice *socket, QByteDataBuffer *rb)
540{
541
542 qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
543 if (readBufferMaxSize)
544 toBeRead = qMin(toBeRead, readBufferMaxSize);
545
546 if (!toBeRead)
547 return 0;
548
549 QByteArray bd;
550 bd.resize(toBeRead);
551 qint64 haveRead = socket->read(bd.data(), toBeRead);
552 if (haveRead == -1) {
553 bd.clear();
554 return 0; // ### error checking here;
555 }
556 bd.resize(haveRead);
557
558 rb->append(bd);
559
560 if (contentRead + haveRead == bodyLength) {
561 state = AllDoneState;
562 }
563
564 contentRead += haveRead;
565 return haveRead;
566}
567
568
569qint64 QHttpNetworkReplyPrivate::readBody(QIODevice *socket, QByteDataBuffer *out)
570{
571 qint64 bytes = 0;
572
573 if (isChunked()) {
574 // chunked transfer encoding (rfc 2616, sec 3.6)
575 bytes += readReplyBodyChunked(socket, out);
576 } else if (bodyLength > 0) {
577 // we have a Content-Length
578 bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
579 if (contentRead + bytes == bodyLength)
580 state = AllDoneState;
581 } else {
582 // no content length. just read what's possible
583 bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
584 }
585 contentRead += bytes;
586 return bytes;
587}
588
589qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *socket, QByteDataBuffer *out, qint64 size)
590{
591 // FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
592 qint64 bytes = 0;
593 Q_ASSERT(socket);
594 Q_ASSERT(out);
595
596 int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
597
598 if (readBufferMaxSize)
599 toBeRead = qMin<qint64>(toBeRead, readBufferMaxSize);
600
601 while (toBeRead > 0) {
602 QByteArray byteData;
603 byteData.resize(toBeRead);
604 qint64 haveRead = socket->read(byteData.data(), byteData.size());
605 if (haveRead <= 0) {
606 // ### error checking here
607 byteData.clear();
608 return bytes;
609 }
610
611 byteData.resize(haveRead);
612 out->append(byteData);
613 bytes += haveRead;
614 size -= haveRead;
615
616 toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
617 }
618 return bytes;
619
620}
621
622qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *socket, QByteDataBuffer *out)
623{
624 qint64 bytes = 0;
625 while (socket->bytesAvailable()) {
626
627 if (readBufferMaxSize && (bytes > readBufferMaxSize))
628 break;
629
630 if (!lastChunkRead && currentChunkRead >= currentChunkSize) {
631 // For the first chunk and when we're done with a chunk
632 currentChunkSize = 0;
633 currentChunkRead = 0;
634 if (bytes) {
635 // After a chunk
636 char crlf[2];
637 // read the "\r\n" after the chunk
638 qint64 haveRead = socket->read(crlf, 2);
639 // FIXME: This code is slightly broken and not optimal. What if the 2 bytes are not available yet?!
640 // For nice reasons (the toLong in getChunkSize accepting \n at the beginning
641 // it right now still works, but we should definitely fix this.
642
643 if (haveRead != 2)
644 return bytes; // FIXME
645 bytes += haveRead;
646 }
647 // Note that chunk size gets stored in currentChunkSize, what is returned is the bytes read
648 bytes += getChunkSize(socket, &currentChunkSize);
649 if (currentChunkSize == -1)
650 break;
651 }
652 // if the chunk size is 0, end of the stream
653 if (currentChunkSize == 0 || lastChunkRead) {
654 lastChunkRead = true;
655 // try to read the "\r\n" after the chunk
656 char crlf[2];
657 qint64 haveRead = socket->read(crlf, 2);
658 if (haveRead > 0)
659 bytes += haveRead;
660
661 if ((haveRead == 2 && crlf[0] == '\r' && crlf[1] == '\n') || (haveRead == 1 && crlf[0] == '\n'))
662 state = AllDoneState;
663 else if (haveRead == 1 && crlf[0] == '\r')
664 break; // Still waiting for the last \n
665 else if (haveRead > 0) {
666 // If we read something else then CRLF, we need to close the channel.
667 forceConnectionCloseEnabled = true;
668 state = AllDoneState;
669 }
670 break;
671 }
672
673 // otherwise, try to begin reading this chunk / to read what is missing for this chunk
674 qint64 haveRead = readReplyBodyRaw (socket, out, currentChunkSize - currentChunkRead);
675 currentChunkRead += haveRead;
676 bytes += haveRead;
677
678 // ### error checking here
679
680 }
681 return bytes;
682}
683
684qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *socket, qint64 *chunkSize)
685{
686 qint64 bytes = 0;
687 char crlf[2];
688 *chunkSize = -1;
689
690 int bytesAvailable = socket->bytesAvailable();
691 // FIXME rewrite to permanent loop without bytesAvailable
692 while (bytesAvailable > bytes) {
693 qint64 sniffedBytes = socket->peek(crlf, 2);
694 int fragmentSize = fragment.size();
695
696 // check the next two bytes for a "\r\n", skip blank lines
697 if ((fragmentSize && sniffedBytes == 2 && crlf[0] == '\r' && crlf[1] == '\n')
698 ||(fragmentSize > 1 && fragment.endsWith('\r') && crlf[0] == '\n'))
699 {
700 bytes += socket->read(crlf, 1); // read the \r or \n
701 if (crlf[0] == '\r')
702 bytes += socket->read(crlf, 1); // read the \n
703 bool ok = false;
704 // ignore the chunk-extension
705 const auto fragmentView = QByteArrayView(fragment).mid(0, fragment.indexOf(';')).trimmed();
706 *chunkSize = fragmentView.toLong(&ok, 16);
707 fragment.clear();
708 break; // size done
709 } else {
710 // read the fragment to the buffer
711 char c = 0;
712 qint64 haveRead = socket->read(&c, 1);
713 if (haveRead < 0) {
714 return -1; // FIXME
715 }
716 bytes += haveRead;
717 fragment.append(c);
718 }
719 }
720
721 return bytes;
722}
723
724bool QHttpNetworkReplyPrivate::isRedirecting() const
725{
726 // We're in the process of redirecting - if the HTTP status code says so and
727 // followRedirect is switched on
728 return (QHttpNetworkReply::isHttpRedirect(parser.getStatusCode())
729 && request.isFollowRedirects());
730}
731
732bool QHttpNetworkReplyPrivate::shouldEmitSignals()
733{
734 // for 401 & 407 don't emit the data signals. Content along with these
735 // responses are sent only if the authentication fails.
736 return parser.getStatusCode() != 401 && parser.getStatusCode() != 407;
737}
738
739bool QHttpNetworkReplyPrivate::expectContent()
740{
741 int statusCode = parser.getStatusCode();
742 // check whether we can expect content after the headers (rfc 2616, sec4.4)
743 if ((statusCode >= 100 && statusCode < 200)
744 || statusCode == 204 || statusCode == 304)
745 return false;
746 if (request.operation() == QHttpNetworkRequest::Head)
747 return false; // no body expected for HEAD request
748 qint64 expectedContentLength = contentLength();
749 if (expectedContentLength == 0)
750 return false;
751 if (expectedContentLength == -1 && bodyLength == 0) {
752 // The content-length header was stripped, but its value was 0.
753 // This would be the case for an explicitly zero-length compressed response.
754 return false;
755 }
756 return true;
757}
758
759void QHttpNetworkReplyPrivate::eraseData()
760{
761 responseData.clear();
762}
763
764
765// SSL support below
766#ifndef QT_NO_SSL
767
768QSslConfiguration QHttpNetworkReply::sslConfiguration() const
769{
770 Q_D(const QHttpNetworkReply);
771
772 if (!d->connectionChannel)
773 return QSslConfiguration();
774
775 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(d->connectionChannel->socket);
776 if (!sslSocket)
777 return QSslConfiguration();
778
779 return sslSocket->sslConfiguration();
780}
781
782void QHttpNetworkReply::setSslConfiguration(const QSslConfiguration &config)
783{
784 Q_D(QHttpNetworkReply);
785 if (d->connection)
786 d->connection->setSslConfiguration(config);
787}
788
789void QHttpNetworkReply::ignoreSslErrors()
790{
791 Q_D(QHttpNetworkReply);
792 if (d->connection)
793 d->connection->ignoreSslErrors();
794}
795
796void QHttpNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
797{
798 Q_D(QHttpNetworkReply);
799 if (d->connection)
800 d->connection->ignoreSslErrors(errors);
801}
802
803
804#endif //QT_NO_SSL
805
806
807QT_END_NAMESPACE
808
809#include "moc_qhttpnetworkreply_p.cpp"