/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtNetwork module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia 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. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qnetworkreply.h" | |
#include "qnetworkreply_p.h" | |
#include <QtNetwork/qsslconfiguration.h> | |
QT_BEGIN_NAMESPACE | |
QNetworkReplyPrivate::QNetworkReplyPrivate() | |
: readBufferMaxSize(0), | |
operation(QNetworkAccessManager::UnknownOperation), | |
errorCode(QNetworkReply::NoError) | |
{ | |
// set the default attribute values | |
attributes.insert(QNetworkRequest::ConnectionEncryptedAttribute, false); | |
} | |
/*! | |
\class QNetworkReply | |
\since 4.4 | |
\brief The QNetworkReply class contains the data and headers for a request | |
sent with QNetworkAccessManager | |
\reentrant | |
\ingroup network | |
\inmodule QtNetwork | |
The QNetworkReply class contains the data and meta data related to | |
a request posted with QNetworkAccessManager. Like QNetworkRequest, | |
it contains a URL and headers (both in parsed and raw form), some | |
information about the reply's state and the contents of the reply | |
itself. | |
QNetworkReply is a sequential-access QIODevice, which means that | |
once data is read from the object, it no longer kept by the | |
device. It is therefore the application's responsibility to keep | |
this data if it needs to. Whenever more data is received from the | |
network and processed, the readyRead() signal is emitted. | |
The downloadProgress() signal is also emitted when data is | |
received, but the number of bytes contained in it may not | |
represent the actual bytes received, if any transformation is done | |
to the contents (for example, decompressing and removing the | |
protocol overhead). | |
Even though QNetworkReply is a QIODevice connected to the contents | |
of the reply, it also emits the uploadProgress() signal, which | |
indicates the progress of the upload for operations that have such | |
content. | |
\note Do not delete the object in the slot connected to the | |
error() or finished() signal. Use deleteLater(). | |
\sa QNetworkRequest, QNetworkAccessManager | |
*/ | |
/*! | |
\enum QNetworkReply::NetworkError | |
Indicates all possible error conditions found during the | |
processing of the request. | |
\value NoError no error condition. | |
\note When the HTTP protocol returns a redirect no error will be | |
reported. You can check if there is a redirect with the | |
QNetworkRequest::RedirectionTargetAttribute attribute. | |
\value ConnectionRefusedError the remote server refused the | |
connection (the server is not accepting requests) | |
\value RemoteHostClosedError the remote server closed the | |
connection prematurely, before the entire reply was received and | |
processed | |
\value HostNotFoundError the remote host name was not found | |
(invalid hostname) | |
\value TimeoutError the connection to the remote server | |
timed out | |
\value OperationCanceledError the operation was canceled via calls | |
to abort() or close() before it was finished. | |
\value SslHandshakeFailedError the SSL/TLS handshake failed and the | |
encrypted channel could not be established. The sslErrors() signal | |
should have been emitted. | |
\value TemporaryNetworkFailureError the connection was broken due | |
to disconnection from the network, however the system has initiated | |
roaming to another access point. The request should be resubmitted | |
and will be processed as soon as the connection is re-established. | |
\value ProxyConnectionRefusedError the connection to the proxy | |
server was refused (the proxy server is not accepting requests) | |
\value ProxyConnectionClosedError the proxy server closed the | |
connection prematurely, before the entire reply was received and | |
processed | |
\value ProxyNotFoundError the proxy host name was not | |
found (invalid proxy hostname) | |
\value ProxyTimeoutError the connection to the proxy | |
timed out or the proxy did not reply in time to the request sent | |
\value ProxyAuthenticationRequiredError the proxy requires | |
authentication in order to honour the request but did not accept | |
any credentials offered (if any) | |
\value ContentAccessDenied the access to the remote | |
content was denied (similar to HTTP error 401) | |
\value ContentOperationNotPermittedError the operation requested | |
on the remote content is not permitted | |
\value ContentNotFoundError the remote content was not | |
found at the server (similar to HTTP error 404) | |
\value AuthenticationRequiredError the remote server requires | |
authentication to serve the content but the credentials provided | |
were not accepted (if any) | |
\value ContentReSendError the request needed to be sent | |
again, but this failed for example because the upload data | |
could not be read a second time. | |
\value ProtocolUnknownError the Network Access API cannot | |
honor the request because the protocol is not known | |
\value ProtocolInvalidOperationError the requested operation is | |
invalid for this protocol | |
\value UnknownNetworkError an unknown network-related | |
error was detected | |
\value UnknownProxyError an unknown proxy-related error | |
was detected | |
\value UnknownContentError an unknown error related to | |
the remote content was detected | |
\value ProtocolFailure a breakdown in protocol was | |
detected (parsing error, invalid or unexpected responses, etc.) | |
\sa error() | |
*/ | |
/*! | |
\fn void QNetworkReply::sslErrors(const QList<QSslError> &errors) | |
This signal is emitted if the SSL/TLS session encountered errors | |
during the set up, including certificate verification errors. The | |
\a errors parameter contains the list of errors. | |
To indicate that the errors are not fatal and that the connection | |
should proceed, the ignoreSslErrors() function should be called | |
from the slot connected to this signal. If it is not called, the | |
SSL session will be torn down before any data is exchanged | |
(including the URL). | |
This signal can be used to display an error message to the user | |
indicating that security may be compromised and display the | |
SSL settings (see sslConfiguration() to obtain it). If the user | |
decides to proceed after analyzing the remote certificate, the | |
slot should call ignoreSslErrors(). | |
\sa QSslSocket::sslErrors(), QNetworkAccessManager::sslErrors(), | |
sslConfiguration(), ignoreSslErrors() | |
*/ | |
/*! | |
\fn void QNetworkReply::metaDataChanged() | |
\omit FIXME: Update name? \endomit | |
This signal is emitted whenever the metadata in this reply | |
changes. metadata is any information that is not the content | |
(data) itself, including the network headers. In the majority of | |
cases, the metadata will be known fully by the time the first | |
byte of data is received. However, it is possible to receive | |
updates of headers or other metadata during the processing of the | |
data. | |
\sa header(), rawHeaderList(), rawHeader(), hasRawHeader() | |
*/ | |
/*! | |
\fn void QNetworkReply::finished() | |
This signal is emitted when the reply has finished | |
processing. After this signal is emitted, there will be no more | |
updates to the reply's data or metadata. | |
Unless close() has been called, the reply will be still be opened | |
for reading, so the data can be retrieved by calls to read() or | |
readAll(). In particular, if no calls to read() were made as a | |
result of readyRead(), a call to readAll() will retrieve the full | |
contents in a QByteArray. | |
This signal is emitted in tandem with | |
QNetworkAccessManager::finished() where that signal's reply | |
parameter is this object. | |
\note Do not delete the object in the slot connected to this | |
signal. Use deleteLater(). | |
You can also use isFinished() to check if a QNetworkReply | |
has finished even before you receive the finished() signal. | |
\sa QNetworkAccessManager::finished(), isFinished() | |
*/ | |
/*! | |
\fn void QNetworkReply::error(QNetworkReply::NetworkError code) | |
This signal is emitted when the reply detects an error in | |
processing. The finished() signal will probably follow, indicating | |
that the connection is over. | |
The \a code parameter contains the code of the error that was | |
detected. Call errorString() to obtain a textual representation of | |
the error condition. | |
\note Do not delete the object in the slot connected to this | |
signal. Use deleteLater(). | |
\sa error(), errorString() | |
*/ | |
/*! | |
\fn void QNetworkReply::uploadProgress(qint64 bytesSent, qint64 bytesTotal) | |
This signal is emitted to indicate the progress of the upload part | |
of this network request, if there's any. If there's no upload | |
associated with this request, this signal will not be emitted. | |
The \a bytesSent | |
parameter indicates the number of bytes uploaded, while \a | |
bytesTotal indicates the total number of bytes to be uploaded. If | |
the number of bytes to be uploaded could not be determined, \a | |
bytesTotal will be -1. | |
The upload is finished when \a bytesSent is equal to \a | |
bytesTotal. At that time, \a bytesTotal will not be -1. | |
\sa downloadProgress() | |
*/ | |
/*! | |
\fn void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) | |
This signal is emitted to indicate the progress of the download | |
part of this network request, if there's any. If there's no | |
download associated with this request, this signal will be emitted | |
once with 0 as the value of both \a bytesReceived and \a | |
bytesTotal. | |
The \a bytesReceived parameter indicates the number of bytes | |
received, while \a bytesTotal indicates the total number of bytes | |
expected to be downloaded. If the number of bytes to be downloaded | |
is not known, \a bytesTotal will be -1. | |
The download is finished when \a bytesReceived is equal to \a | |
bytesTotal. At that time, \a bytesTotal will not be -1. | |
Note that the values of both \a bytesReceived and \a bytesTotal | |
may be different from size(), the total number of bytes | |
obtained through read() or readAll(), or the value of the | |
header(ContentLengthHeader). The reason for that is that there may | |
be protocol overhead or the data may be compressed during the | |
download. | |
\sa uploadProgress(), bytesAvailable() | |
*/ | |
/*! | |
\fn void QNetworkReply::abort() | |
Aborts the operation immediately and close down any network | |
connections still open. Uploads still in progress are also | |
aborted. | |
\sa close() | |
*/ | |
/*! | |
Creates a QNetworkReply object with parent \a parent. | |
You cannot directly instantiate QNetworkReply objects. Use | |
QNetworkAccessManager functions to do that. | |
*/ | |
QNetworkReply::QNetworkReply(QObject *parent) | |
: QIODevice(*new QNetworkReplyPrivate, parent) | |
{ | |
} | |
/*! | |
\internal | |
*/ | |
QNetworkReply::QNetworkReply(QNetworkReplyPrivate &dd, QObject *parent) | |
: QIODevice(dd, parent) | |
{ | |
} | |
/*! | |
Disposes of this reply and frees any resources associated with | |
it. If any network connections are still open, they will be | |
closed. | |
\sa abort(), close() | |
*/ | |
QNetworkReply::~QNetworkReply() | |
{ | |
} | |
/*! | |
Closes this device for reading. Unread data is discarded, but the | |
network resources are not discarded until they are finished. In | |
particular, if any upload is in progress, it will continue until | |
it is done. | |
The finished() signal is emitted when all operations are over and | |
the network resources are freed. | |
\sa abort(), finished() | |
*/ | |
void QNetworkReply::close() | |
{ | |
QIODevice::close(); | |
} | |
/*! | |
\internal | |
*/ | |
bool QNetworkReply::isSequential() const | |
{ | |
return true; | |
} | |
/*! | |
Returns the size of the read buffer, in bytes. | |
\sa setReadBufferSize() | |
*/ | |
qint64 QNetworkReply::readBufferSize() const | |
{ | |
return d_func()->readBufferMaxSize; | |
} | |
/*! | |
Sets the size of the read buffer to be \a size bytes. The read | |
buffer is the buffer that holds data that is being downloaded off | |
the network, before it is read with QIODevice::read(). Setting the | |
buffer size to 0 will make the buffer unlimited in size. | |
QNetworkReply will try to stop reading from the network once this | |
buffer is full (i.e., bytesAvailable() returns \a size or more), | |
thus causing the download to throttle down as well. If the buffer | |
is not limited in size, QNetworkReply will try to download as fast | |
as possible from the network. | |
Unlike QAbstractSocket::setReadBufferSize(), QNetworkReply cannot | |
guarantee precision in the read buffer size. That is, | |
bytesAvailable() can return more than \a size. | |
\sa readBufferSize() | |
*/ | |
void QNetworkReply::setReadBufferSize(qint64 size) | |
{ | |
Q_D(QNetworkReply); | |
d->readBufferMaxSize = size; | |
} | |
/*! | |
Returns the QNetworkAccessManager that was used to create this | |
QNetworkReply object. Initially, it is also the parent object. | |
*/ | |
QNetworkAccessManager *QNetworkReply::manager() const | |
{ | |
return d_func()->manager; | |
} | |
/*! | |
Returns the request that was posted for this reply. In special, | |
note that the URL for the request may be different than that of | |
the reply. | |
\sa QNetworkRequest::url(), url(), setRequest() | |
*/ | |
QNetworkRequest QNetworkReply::request() const | |
{ | |
return d_func()->request; | |
} | |
/*! | |
Returns the operation that was posted for this reply. | |
\sa setOperation() | |
*/ | |
QNetworkAccessManager::Operation QNetworkReply::operation() const | |
{ | |
return d_func()->operation; | |
} | |
/*! | |
Returns the error that was found during the processing of this | |
request. If no error was found, returns NoError. | |
\sa setError() | |
*/ | |
QNetworkReply::NetworkError QNetworkReply::error() const | |
{ | |
return d_func()->errorCode; | |
} | |
/*! | |
\since 4.6 | |
Returns true when the reply has finished or was aborted. | |
\sa isRunning() | |
*/ | |
bool QNetworkReply::isFinished() const | |
{ | |
return d_func()->isFinished(); | |
} | |
/*! | |
\since 4.6 | |
Returns true when the request is still processing and the | |
reply has not finished or was aborted yet. | |
\sa isFinished() | |
*/ | |
bool QNetworkReply::isRunning() const | |
{ | |
return !isFinished(); | |
} | |
/*! | |
Returns the URL of the content downloaded or uploaded. Note that | |
the URL may be different from that of the original request. | |
\sa request(), setUrl(), QNetworkRequest::url() | |
*/ | |
QUrl QNetworkReply::url() const | |
{ | |
return d_func()->url; | |
} | |
/*! | |
Returns the value of the known header \a header, if that header | |
was sent by the remote server. If the header was not sent, returns | |
an invalid QVariant. | |
\sa rawHeader(), setHeader(), QNetworkRequest::header() | |
*/ | |
QVariant QNetworkReply::header(QNetworkRequest::KnownHeaders header) const | |
{ | |
return d_func()->cookedHeaders.value(header); | |
} | |
/*! | |
Returns true if the raw header of name \a headerName was sent by | |
the remote server | |
\sa rawHeader() | |
*/ | |
bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const | |
{ | |
Q_D(const QNetworkReply); | |
return d->findRawHeader(headerName) != d->rawHeaders.constEnd(); | |
} | |
/*! | |
Returns the raw contents of the header \a headerName as sent by | |
the remote server. If there is no such header, returns an empty | |
byte array, which may be indistinguishable from an empty | |
header. Use hasRawHeader() to verify if the server sent such | |
header field. | |
\sa setRawHeader(), hasRawHeader(), header() | |
*/ | |
QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const | |
{ | |
Q_D(const QNetworkReply); | |
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it = | |
d->findRawHeader(headerName); | |
if (it != d->rawHeaders.constEnd()) | |
return it->second; | |
return QByteArray(); | |
} | |
/*! \typedef QNetworkReply::RawHeaderPair | |
RawHeaderPair is a QPair<QByteArray, QByteArray> where the first | |
QByteArray is the header name and the second is the header. | |
*/ | |
/*! | |
Returns a list of raw header pairs. | |
*/ | |
const QList<QNetworkReply::RawHeaderPair>& QNetworkReply::rawHeaderPairs() const | |
{ | |
Q_D(const QNetworkReply); | |
return d->rawHeaders; | |
} | |
/*! | |
Returns a list of headers fields that were sent by the remote | |
server, in the order that they were sent. Duplicate headers are | |
merged together and take place of the latter duplicate. | |
*/ | |
QList<QByteArray> QNetworkReply::rawHeaderList() const | |
{ | |
return d_func()->rawHeadersKeys(); | |
} | |
/*! | |
Returns the attribute associated with the code \a code. If the | |
attribute has not been set, it returns an invalid QVariant (type QVariant::Null). | |
You can expect the default values listed in | |
QNetworkRequest::Attribute to be applied to the values returned by | |
this function. | |
\sa setAttribute(), QNetworkRequest::Attribute | |
*/ | |
QVariant QNetworkReply::attribute(QNetworkRequest::Attribute code) const | |
{ | |
return d_func()->attributes.value(code); | |
} | |
#ifndef QT_NO_OPENSSL | |
/*! | |
Returns the SSL configuration and state associated with this | |
reply, if SSL was used. It will contain the remote server's | |
certificate, its certificate chain leading to the Certificate | |
Authority as well as the encryption ciphers in use. | |
The peer's certificate and its certificate chain will be known by | |
the time sslErrors() is emitted, if it's emitted. | |
*/ | |
QSslConfiguration QNetworkReply::sslConfiguration() const | |
{ | |
QSslConfiguration config; | |
// determine if we support this extension | |
int id = metaObject()->indexOfMethod("sslConfigurationImplementation()"); | |
if (id != -1) { | |
void *arr[] = { &config, 0 }; | |
const_cast<QNetworkReply *>(this)->qt_metacall(QMetaObject::InvokeMetaMethod, id, arr); | |
} | |
return config; | |
} | |
/*! | |
Sets the SSL configuration for the network connection associated | |
with this request, if possible, to be that of \a config. | |
*/ | |
void QNetworkReply::setSslConfiguration(const QSslConfiguration &config) | |
{ | |
if (config.isNull()) | |
return; | |
int id = metaObject()->indexOfMethod("setSslConfigurationImplementation(QSslConfiguration)"); | |
if (id != -1) { | |
QSslConfiguration copy(config); | |
void *arr[] = { 0, © }; | |
qt_metacall(QMetaObject::InvokeMetaMethod, id, arr); | |
} | |
} | |
/*! | |
\overload | |
\since 4.6 | |
If this function is called, the SSL errors given in \a errors | |
will be ignored. | |
Note that you can set the expected certificate in the SSL error: | |
If, for instance, you want to issue a request to a server that uses | |
a self-signed certificate, consider the following snippet: | |
\snippet doc/src/snippets/code/src_network_access_qnetworkreply.cpp 0 | |
Multiple calls to this function will replace the list of errors that | |
were passed in previous calls. | |
You can clear the list of errors you want to ignore by calling this | |
function with an empty list. | |
\sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors() | |
*/ | |
void QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) | |
{ | |
// do this cryptic trick, because we could not add a virtual method to this class later on | |
// since that breaks binary compatibility | |
int id = metaObject()->indexOfMethod("ignoreSslErrorsImplementation(QList<QSslError>)"); | |
if (id != -1) { | |
QList<QSslError> copy(errors); | |
void *arr[] = { 0, © }; | |
qt_metacall(QMetaObject::InvokeMetaMethod, id, arr); | |
} | |
} | |
#endif | |
/*! | |
If this function is called, SSL errors related to network | |
connection will be ignored, including certificate validation | |
errors. | |
Note that calling this function without restraint may pose a | |
security risk for your application. Use it with care. | |
This function can be called from the slot connected to the | |
sslErrors() signal, which indicates which errors were | |
found. | |
\sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors() | |
*/ | |
void QNetworkReply::ignoreSslErrors() | |
{ | |
} | |
/*! | |
\internal | |
*/ | |
qint64 QNetworkReply::writeData(const char *, qint64) | |
{ | |
return -1; // you can't write | |
} | |
/*! | |
Sets the associated operation for this object to be \a | |
operation. This value will be returned by operation(). | |
Note: the operation should be set when this object is created and | |
not changed again. | |
\sa operation(), setRequest() | |
*/ | |
void QNetworkReply::setOperation(QNetworkAccessManager::Operation operation) | |
{ | |
Q_D(QNetworkReply); | |
d->operation = operation; | |
} | |
/*! | |
Sets the associated request for this object to be \a request. This | |
value will be returned by request(). | |
Note: the request should be set when this object is created and | |
not changed again. | |
\sa request(), setOperation() | |
*/ | |
void QNetworkReply::setRequest(const QNetworkRequest &request) | |
{ | |
Q_D(QNetworkReply); | |
d->request = request; | |
} | |
/*! | |
Sets the error condition to be \a errorCode. The human-readable | |
message is set with \a errorString. | |
Calling setError() does not emit the error(QNetworkReply::NetworkError) | |
signal. | |
\sa error(), errorString() | |
*/ | |
void QNetworkReply::setError(NetworkError errorCode, const QString &errorString) | |
{ | |
Q_D(QNetworkReply); | |
d->errorCode = errorCode; | |
setErrorString(errorString); // in QIODevice | |
} | |
/*! | |
Sets the URL being processed to be \a url. Normally, the URL | |
matches that of the request that was posted, but for a variety of | |
reasons it can be different (for example, a file path being made | |
absolute or canonical). | |
\sa url(), request(), QNetworkRequest::url() | |
*/ | |
void QNetworkReply::setUrl(const QUrl &url) | |
{ | |
Q_D(QNetworkReply); | |
d->url = url; | |
} | |
/*! | |
Sets the known header \a header to be of value \a value. The | |
corresponding raw form of the header will be set as well. | |
\sa header(), setRawHeader(), QNetworkRequest::setHeader() | |
*/ | |
void QNetworkReply::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) | |
{ | |
Q_D(QNetworkReply); | |
d->setCookedHeader(header, value); | |
} | |
/*! | |
Sets the raw header \a headerName to be of value \a value. If \a | |
headerName was previously set, it is overridden. Multiple HTTP | |
headers of the same name are functionally equivalent to one single | |
header with the values concatenated, separated by commas. | |
If \a headerName matches a known header, the value \a value will | |
be parsed and the corresponding parsed form will also be set. | |
\sa rawHeader(), header(), setHeader(), QNetworkRequest::setRawHeader() | |
*/ | |
void QNetworkReply::setRawHeader(const QByteArray &headerName, const QByteArray &value) | |
{ | |
Q_D(QNetworkReply); | |
d->setRawHeader(headerName, value); | |
} | |
/*! | |
Sets the attribute \a code to have value \a value. If \a code was | |
previously set, it will be overridden. If \a value is an invalid | |
QVariant, the attribute will be unset. | |
\sa attribute(), QNetworkRequest::setAttribute() | |
*/ | |
void QNetworkReply::setAttribute(QNetworkRequest::Attribute code, const QVariant &value) | |
{ | |
Q_D(QNetworkReply); | |
if (value.isValid()) | |
d->attributes.insert(code, value); | |
else | |
d->attributes.remove(code); | |
} | |
QT_END_NAMESPACE |