1
1
/****************************************************************************
3
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
4
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
7
** This file is part of the QtNetwork module of the Qt Toolkit.
8
9
** $QT_BEGIN_LICENSE:LGPL$
10
** Licensees holding valid Qt Commercial licenses may use this file in
11
** accordance with the Qt Commercial License Agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Nokia.
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
13
** contained in the Technology Preview License Agreement accompanying
15
16
** GNU Lesser General Public License Usage
16
17
** Alternatively, this file may be used under the terms of the GNU Lesser
20
21
** ensure the GNU Lesser General Public License version 2.1 requirements
21
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
** In addition, as a special exception, Nokia gives you certain
24
** additional rights. These rights are described in the Nokia Qt LGPL
25
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28
** GNU General Public License Usage
29
** Alternatively, this file may be used under the terms of the GNU
30
** General Public License version 3.0 as published by the Free Software
31
** Foundation and appearing in the file LICENSE.GPL included in the
32
** packaging of this file. Please review the following information to
33
** ensure the GNU General Public License version 3.0 requirements will be
34
** met: http://www.gnu.org/copyleft/gpl.html.
36
** If you are unsure which license is appropriate for your use, please
37
** contact the sales department at http://www.qtsoftware.com/contact.
24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights. These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
38
38
** $QT_END_LICENSE$
40
40
****************************************************************************/
163
163
Q_D(const QHttpNetworkReply);
164
164
if (d->connection)
165
return d->connection->d_func()->bytesAvailable(*this);
170
QByteArray QHttpNetworkReply::read(qint64 maxSize)
165
return d->connection->d_func()->uncompressedBytesAvailable(*this);
170
qint64 QHttpNetworkReply::bytesAvailableNextBlock() const
172
Q_D(const QHttpNetworkReply);
174
return d->connection->d_func()->uncompressedBytesAvailableNextBlock(*this);
179
QByteArray QHttpNetworkReply::readAny()
172
181
Q_D(QHttpNetworkReply);
175
d->connection->d_func()->read(*this, data, maxSize, false);
182
return d->responseData.read();
179
185
bool QHttpNetworkReply::isFinished() const
181
187
return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;
190
bool QHttpNetworkReply::isPipeliningUsed() const
192
return d_func()->pipeliningUsed;
186
196
QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
187
197
: QHttpNetworkHeaderPrivate(newUrl), state(NothingDoneState), statusCode(100),
188
198
majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
199
chunkedTransferEncoding(false),
200
connectionCloseEnabled(true),
201
forceConnectionCloseEnabled(false),
189
202
currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false),
190
autoDecompress(false), requestIsBuffering(false), requestIsPrepared(false)
203
autoDecompress(false), responseData(), requestIsPrepared(false)
204
,pipeliningUsed(false)
491
510
state = ReadingDataState;
492
511
fragment.clear(); // next fragment
493
512
bodyLength = contentLength(); // cache the length
514
// cache isChunked() since it is called often
515
chunkedTransferEncoding = headerField("transfer-encoding").toLower().contains("chunked");
517
// cache isConnectionCloseEnabled since it is called often
518
QByteArray connectionHeaderField = headerField("connection");
519
// check for explicit indication of close or the implicit connection close of HTTP/1.0
520
connectionCloseEnabled = (connectionHeaderField.toLower().contains("close") ||
521
headerField("proxy-connection").toLower().contains("close")) ||
522
(majorVersion == 1 && minorVersion == 0 && connectionHeaderField.isEmpty());
532
561
bool QHttpNetworkReplyPrivate::isChunked()
534
return headerField("transfer-encoding").toLower().contains("chunked");
537
bool QHttpNetworkReplyPrivate::connectionCloseEnabled()
539
return (headerField("connection").toLower().contains("close") ||
540
headerField("proxy-connection").toLower().contains("close"));
543
qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out)
563
return chunkedTransferEncoding;
566
bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
568
return connectionCloseEnabled || forceConnectionCloseEnabled;
571
// note this function can only be used for non-chunked, non-compressed with
572
// known content length
573
qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
575
qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
578
qint64 haveRead = socket->read(bd.data(), bd.size());
579
if (haveRead == -1) {
581
return 0; // ### error checking here;
587
if (contentRead + haveRead == bodyLength) {
588
state = AllDoneState;
591
contentRead += haveRead;
596
qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out)
545
598
qint64 bytes = 0;
546
599
if (isChunked()) {
547
bytes += transferChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6)
600
bytes += readReplyBodyChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6)
548
601
} else if (bodyLength > 0) { // we have a Content-Length
549
bytes += transferRaw(socket, out, bodyLength - contentRead);
602
bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
550
603
if (contentRead + bytes == bodyLength)
551
604
state = AllDoneState;
553
bytes += transferRaw(socket, out, socket->bytesAvailable());
606
bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
555
if (state == AllDoneState)
556
socket->readAll(); // Read the rest to clean (CRLF)
557
608
contentRead += bytes;
561
qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint64 size)
612
qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size)
563
614
qint64 bytes = 0;
567
618
int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable()));
568
QByteArray raw(toBeRead, 0);
570
qint64 read = in->read(raw.data(), raw.size());
573
// ### error checking here
574
qint64 written = out->write(raw.data(), read);
578
qDebug() << "### read" << read << "written" << written;
581
out->waitForBytesWritten(-1); // throttle
619
while (toBeRead > 0) {
621
byteData.resize(toBeRead);
622
qint64 haveRead = in->read(byteData.data(), byteData.size());
624
// ### error checking here
629
byteData.resize(haveRead);
630
out->append(byteData);
634
toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable()));
587
qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out)
640
qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out)
589
642
qint64 bytes = 0;
590
643
while (in->bytesAvailable()) { // while we can read from input
605
658
state = AllDoneState;
608
// otherwise, read data
609
qint64 readSize = qMin(in->bytesAvailable(), currentChunkSize - currentChunkRead);
610
QByteArray buffer(readSize, 0);
611
qint64 read = in->read(buffer.data(), readSize);
613
currentChunkRead += read;
614
qint64 written = out->write(buffer);
615
Q_UNUSED(written); // Avoid compile warning when building release
616
Q_ASSERT(read == written);
662
// otherwise, try to read what is missing for this chunk
663
qint64 haveRead = readReplyBodyRaw (in, out, currentChunkSize - currentChunkRead);
664
currentChunkRead += haveRead;
617
667
// ### error checking here
618
out->waitForBytesWritten(-1);
705
void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteArray &qba)
707
responseData.append(qba);
709
// clear the original! helps with implicit sharing and
710
// avoiding memcpy when the user is reading the data
714
void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteDataBuffer &data)
716
responseData.append(data);
718
// clear the original! helps with implicit sharing and
719
// avoiding memcpy when the user is reading the data
723
void QHttpNetworkReplyPrivate::appendCompressedReplyData(QByteDataBuffer &data)
725
// Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
726
// instead of one QByteArray.
727
for(int i = 0; i < data.bufferCount(); i++) {
728
QByteArray &byteData = data[i];
729
compressedData.append(byteData.constData(), byteData.size());
735
bool QHttpNetworkReplyPrivate::shouldEmitSignals()
737
// for 401 & 407 don't emit the data signals. Content along with these
738
// responses are send only if the authentication fails.
739
return (statusCode != 401 && statusCode != 407);
742
bool QHttpNetworkReplyPrivate::expectContent()
744
// check whether we can expect content after the headers (rfc 2616, sec4.4)
745
if ((statusCode >= 100 && statusCode < 200)
746
|| statusCode == 204 || statusCode == 304)
748
if (request.operation() == QHttpNetworkRequest::Head)
749
return !shouldEmitSignals();
750
if (contentLength() == 0)
755
void QHttpNetworkReplyPrivate::eraseData()
757
compressedData.clear();
758
responseData.clear();
655
762
// SSL support below
656
763
#ifndef QT_NO_OPENSSL