summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorJason Barron <jbarron@trolltech.com>2009-08-06 06:38:11 (GMT)
committerJason Barron <jbarron@trolltech.com>2009-08-06 07:18:48 (GMT)
commit55c4f15df0d482c7d3d6c889b9fc132ed0bdd12a (patch)
tree99c01d7a4e0941f415e9a48f51faac94787b6cb0 /src/network
parent57ceb11ecf95032418712a686418116cf2398e7a (diff)
parentb008dfbd67176948f6fdf830dc99d23a538a6b9c (diff)
downloadQt-55c4f15df0d482c7d3d6c889b9fc132ed0bdd12a.zip
Qt-55c4f15df0d482c7d3d6c889b9fc132ed0bdd12a.tar.gz
Qt-55c4f15df0d482c7d3d6c889b9fc132ed0bdd12a.tar.bz2
Merge commit 'qt/master-stable'
Conflicts: configure.exe doc/src/classes/qnamespace.qdoc examples/examples.pro src/corelib/kernel/qcoreevent.cpp src/corelib/kernel/qobject.cpp src/gui/kernel/qapplication.cpp src/gui/kernel/qstandardgestures.h src/gui/kernel/qwidget.cpp
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp281
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h34
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp214
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h25
-rw-r--r--src/network/access/qhttpnetworkreply.cpp30
-rw-r--r--src/network/access/qhttpnetworkreply_p.h5
-rw-r--r--src/network/socket/qnet_unix_p.h2
7 files changed, 287 insertions, 304 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 20e4802..93d738c 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -89,58 +89,11 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
delete []channels;
}
-void QHttpNetworkConnectionPrivate::connectSignals(QAbstractSocket *socket)
-{
- Q_Q(QHttpNetworkConnection);
-
- QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
- q, SLOT(_q_bytesWritten(qint64)),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(connected()),
- q, SLOT(_q_connected()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(readyRead()),
- q, SLOT(_q_readyRead()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(disconnected()),
- q, SLOT(_q_disconnected()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
- q, SLOT(_q_error(QAbstractSocket::SocketError)),
- Qt::DirectConnection);
-#ifndef QT_NO_NETWORKPROXY
- QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
- q, SLOT(_q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
- Qt::DirectConnection);
-#endif
-
-#ifndef QT_NO_OPENSSL
- QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
- if (sslSocket) {
- // won't be a sslSocket if encrypt is false
- QObject::connect(sslSocket, SIGNAL(encrypted()),
- q, SLOT(_q_encrypted()),
- Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError>&)),
- q, SLOT(_q_sslErrors(const QList<QSslError>&)),
- Qt::DirectConnection);
- }
-#endif
-}
-
void QHttpNetworkConnectionPrivate::init()
{
- for (int i = 0; i < channelCount; ++i) {
-#ifndef QT_NO_OPENSSL
- if (encrypt)
- channels[i].socket = new QSslSocket;
- else
- channels[i].socket = new QTcpSocket;
-#else
- channels[i].socket = new QTcpSocket;
-#endif
-
- connectSignals(channels[i].socket);
+ for (int i = 0; i < channelCount; i++) {
+ channels[i].setConnection(this->q_func());
+ channels[i].init();
}
}
@@ -178,35 +131,6 @@ bool QHttpNetworkConnectionPrivate::isSocketReading(QAbstractSocket *socket) con
return (i != -1 && (channels[i].state & QHttpNetworkConnectionChannel::ReadingState));
}
-void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba)
-{
- reply.d_func()->responseData.append(qba);
-
- // clear the original! helps with implicit sharing and
- // avoiding memcpy when the user is reading the data
- qba.clear();
-}
-
-void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data)
-{
- reply.d_func()->responseData.append(data);
-
- // clear the original! helps with implicit sharing and
- // avoiding memcpy when the user is reading the data
- data.clear();
-}
-
-void QHttpNetworkConnectionPrivate::appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data)
-{
- // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
- // instead of one QByteArray.
- for(int i = 0; i < data.bufferCount(); i++) {
- QByteArray &byteData = data[i];
- reply.d_func()->compressedData.append(byteData.constData(), byteData.size());
- }
- data.clear();
-}
-
qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const
{
return reply.d_func()->responseData.byteAmount();
@@ -408,7 +332,7 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket)
QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice();
if (uploadByteDevice) {
// connect the signals so this function gets called again
- QObject::connect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead()));
+ QObject::connect(uploadByteDevice, SIGNAL(readyRead()), &channels[i], SLOT(_q_uploadDataReadyRead()));
channels[i].bytesTotal = channels[i].request.contentLength();
} else {
@@ -487,7 +411,7 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket)
{
QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice();
if (uploadByteDevice) {
- QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead()));
+ QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), &channels[i], SLOT(_q_uploadDataReadyRead()));
}
// ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
// this is needed if the sends an reply before we have finished sending the request. In that
@@ -566,7 +490,7 @@ bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetwork
if (ret >= retCheck) {
if (inflated.size()) {
reply->d_func()->totalProgress += inflated.size();
- appendUncompressedData(*reply, inflated);
+ reply->d_func()->appendUncompressedReplyData(inflated);
if (shouldEmitSignals(reply)) {
// important: At the point of this readyRead(), inflated must be cleared,
// else implicit sharing will trigger memcpy when the user is reading data!
@@ -687,9 +611,9 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN
bytes = reply->d_func()->readBody(socket, &byteDatas);
if (bytes) {
if (reply->d_func()->autoDecompress)
- appendCompressedData(*reply, byteDatas);
+ reply->d_func()->appendCompressedReplyData(byteDatas);
else
- appendUncompressedData(*reply, byteDatas);
+ reply->d_func()->appendUncompressedReplyData(byteDatas);
if (!reply->d_func()->autoDecompress) {
reply->d_func()->totalProgress += bytes;
@@ -1006,11 +930,7 @@ void QHttpNetworkConnectionPrivate::unqueueAndSendRequest(QAbstractSocket *socke
void QHttpNetworkConnectionPrivate::closeChannel(int channel)
{
- QAbstractSocket *socket = channels[channel].socket;
- socket->blockSignals(true);
- socket->close();
- socket->blockSignals(false);
- channels[channel].state = QHttpNetworkConnectionChannel::IdleState;
+ channels[channel].close();
}
void QHttpNetworkConnectionPrivate::resendCurrentRequest(QAbstractSocket *socket)
@@ -1104,53 +1024,6 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
}
-//private slots
-void QHttpNetworkConnectionPrivate::_q_readyRead()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- if (isSocketWaiting(socket) || isSocketReading(socket)) {
- int i = indexOf(socket);
- channels[i].state = QHttpNetworkConnectionChannel::ReadingState;
- if (channels[i].reply)
- receiveReply(socket, channels[i].reply);
- }
- // ### error
-}
-
-void QHttpNetworkConnectionPrivate::_q_bytesWritten(qint64 bytes)
-{
- Q_UNUSED(bytes);
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- // bytes have been written to the socket. write even more of them :)
- if (isSocketWriting(socket))
- sendRequest(socket);
- // otherwise we do nothing
-}
-
-void QHttpNetworkConnectionPrivate::_q_disconnected()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- // read the available data before closing
- int i = indexOf(socket);
- if (isSocketWaiting(socket) || isSocketReading(socket)) {
- channels[i].state = QHttpNetworkConnectionChannel::ReadingState;
- if (channels[i].reply)
- receiveReply(socket, channels[i].reply);
- } else if (channels[i].state == QHttpNetworkConnectionChannel::IdleState && channels[i].resendCurrent) {
- // re-sending request because the socket was in ClosingState
- QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
- }
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
-}
void QHttpNetworkConnectionPrivate::_q_startNextRequest()
{
@@ -1190,121 +1063,6 @@ void QHttpNetworkConnectionPrivate::_q_restartAuthPendingRequests()
}
}
-void QHttpNetworkConnectionPrivate::_q_connected()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
-
- // improve performance since we get the request sent by the kernel ASAP
- socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
-
- int i = indexOf(socket);
- // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
- //channels[i].reconnectAttempts = 2;
- if (!channels[i].pendingEncrypt) {
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- if (channels[i].reply)
- sendRequest(socket);
- else
- closeChannel(i);
- }
-}
-
-
-void QHttpNetworkConnectionPrivate::_q_error(QAbstractSocket::SocketError socketError)
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return;
- bool send2Reply = false;
- int i = indexOf(socket);
- QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
-
- switch (socketError) {
- case QAbstractSocket::HostNotFoundError:
- errorCode = QNetworkReply::HostNotFoundError;
- break;
- case QAbstractSocket::ConnectionRefusedError:
- errorCode = QNetworkReply::ConnectionRefusedError;
- break;
- case QAbstractSocket::RemoteHostClosedError:
- // try to reconnect/resend before sending an error.
- // while "Reading" the _q_disconnected() will handle this.
- if (channels[i].state != QHttpNetworkConnectionChannel::IdleState && channels[i].state != QHttpNetworkConnectionChannel::ReadingState) {
- if (channels[i].reconnectAttempts-- > 0) {
- resendCurrentRequest(socket);
- return;
- } else {
- send2Reply = true;
- errorCode = QNetworkReply::RemoteHostClosedError;
- }
- } else {
- return;
- }
- break;
- case QAbstractSocket::SocketTimeoutError:
- // try to reconnect/resend before sending an error.
- if (channels[i].state == QHttpNetworkConnectionChannel::WritingState && (channels[i].reconnectAttempts-- > 0)) {
- resendCurrentRequest(socket);
- return;
- }
- send2Reply = true;
- errorCode = QNetworkReply::TimeoutError;
- break;
- case QAbstractSocket::ProxyAuthenticationRequiredError:
- errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
- break;
- case QAbstractSocket::SslHandshakeFailedError:
- errorCode = QNetworkReply::SslHandshakeFailedError;
- break;
- default:
- // all other errors are treated as NetworkError
- errorCode = QNetworkReply::UnknownNetworkError;
- break;
- }
- QPointer<QObject> that = q;
- QString errorString = errorDetail(errorCode, socket);
- if (send2Reply) {
- if (channels[i].reply) {
- channels[i].reply->d_func()->errorString = errorString;
- // this error matters only to this reply
- emit channels[i].reply->finishedWithError(errorCode, errorString);
- }
- // send the next request
- QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
- } else {
- // the failure affects all requests.
- emit q->error(errorCode, errorString);
- }
- if (that) //signals make enter the event loop
- closeChannel(i);
-}
-
-#ifndef QT_NO_NETWORKPROXY
-void QHttpNetworkConnectionPrivate::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
-{
- Q_Q(QHttpNetworkConnection);
- emit q->proxyAuthenticationRequired(proxy, auth, q);
-}
-#endif
-
-void QHttpNetworkConnectionPrivate::_q_uploadDataReadyRead()
-{
- Q_Q(QHttpNetworkConnection);
- // upload data emitted readyRead()
- // find out which channel it is for
- QObject *sender = q->sender();
-
- for (int i = 0; i < channelCount; ++i) {
- if (sender == channels[i].request.uploadByteDevice()) {
- sendRequest(channels[i].socket);
- break;
- }
- }
-}
QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent)
: QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent)
@@ -1399,27 +1157,6 @@ QNetworkProxy QHttpNetworkConnection::transparentProxy() const
// SSL support below
#ifndef QT_NO_OPENSSL
-void QHttpNetworkConnectionPrivate::_q_encrypted()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- int i = indexOf(socket);
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- sendRequest(socket);
-}
-
-void QHttpNetworkConnectionPrivate::_q_sslErrors(const QList<QSslError> &errors)
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return;
- //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
- emit q->sslErrors(errors);
-}
-
QSslConfiguration QHttpNetworkConnectionPrivate::sslConfiguration(const QHttpNetworkReply &reply) const
{
if (!encrypt)
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index eb7a955..d8e21cd 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -138,23 +138,10 @@ private:
Q_DECLARE_SCOPED_PRIVATE(QHttpNetworkConnection)
Q_DISABLE_COPY(QHttpNetworkConnection)
friend class QHttpNetworkReply;
+ friend class QHttpNetworkConnectionChannel;
- Q_PRIVATE_SLOT(d_func(), void _q_bytesWritten(qint64))
- Q_PRIVATE_SLOT(d_func(), void _q_readyRead())
- Q_PRIVATE_SLOT(d_func(), void _q_disconnected())
Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
Q_PRIVATE_SLOT(d_func(), void _q_restartAuthPendingRequests())
- Q_PRIVATE_SLOT(d_func(), void _q_connected())
- Q_PRIVATE_SLOT(d_func(), void _q_error(QAbstractSocket::SocketError))
-#ifndef QT_NO_NETWORKPROXY
- Q_PRIVATE_SLOT(d_func(), void _q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))
-#endif
- Q_PRIVATE_SLOT(d_func(), void _q_uploadDataReadyRead())
-
-#ifndef QT_NO_OPENSSL
- Q_PRIVATE_SLOT(d_func(), void _q_encrypted())
- Q_PRIVATE_SLOT(d_func(), void _q_sslErrors(const QList<QSslError>&))
-#endif
};
@@ -169,7 +156,6 @@ public:
QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt);
~QHttpNetworkConnectionPrivate();
void init();
- void connectSignals(QAbstractSocket *socket);
enum { ChunkSize = 4096 };
@@ -189,18 +175,8 @@ public:
void copyCredentials(int fromChannel, QAuthenticator *auth, bool isProxy);
// private slots
- void _q_bytesWritten(qint64 bytes); // proceed sending
- void _q_readyRead(); // pending data to read
- void _q_disconnected(); // disconnected from host
void _q_startNextRequest(); // send the next request from the queue
void _q_restartAuthPendingRequests(); // send the currently blocked request
- void _q_connected(); // start sending request
- void _q_error(QAbstractSocket::SocketError); // error from socket
-#ifndef QT_NO_NETWORKPROXY
- void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy
-#endif
-
- void _q_uploadDataReadyRead();
void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
bool ensureConnection(QAbstractSocket *socket);
@@ -221,10 +197,6 @@ public:
bool pendingAuthSignal; // there is an incomplete authentication signal
bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal
- void appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba);
- void appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data);
- void appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data);
-
qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
qint64 compressedBytesAvailable(const QHttpNetworkReply &reply) const;
@@ -237,8 +209,6 @@ public:
inline bool expectContent(QHttpNetworkReply *reply);
#ifndef QT_NO_OPENSSL
- void _q_encrypted(); // start sending request (https)
- void _q_sslErrors(const QList<QSslError> &errors); // ssl errors from the socket
QSslConfiguration sslConfiguration(const QHttpNetworkReply &reply) const;
#endif
@@ -249,6 +219,8 @@ public:
//The request queues
QList<HttpMessagePair> highPriorityQueue;
QList<HttpMessagePair> lowPriorityQueue;
+
+ friend class QHttpNetworkConnectionChannel;
};
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index a04b530..6cd46fd 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -57,6 +57,220 @@ QT_BEGIN_NAMESPACE
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+void QHttpNetworkConnectionChannel::init()
+{
+#ifndef QT_NO_OPENSSL
+ if (connection->d_func()->encrypt)
+ socket = new QSslSocket;
+ else
+ socket = new QTcpSocket;
+#else
+ socket = new QTcpSocket;
+#endif
+
+ QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(_q_bytesWritten(qint64)),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(connected()),
+ this, SLOT(_q_connected()),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(readyRead()),
+ this, SLOT(_q_readyRead()),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(disconnected()),
+ this, SLOT(_q_disconnected()),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(_q_error(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+#ifndef QT_NO_NETWORKPROXY
+ QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
+ this, SLOT(_q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
+ Qt::DirectConnection);
+#endif
+
+#ifndef QT_NO_OPENSSL
+ QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
+ if (sslSocket) {
+ // won't be a sslSocket if encrypt is false
+ QObject::connect(sslSocket, SIGNAL(encrypted()),
+ this, SLOT(_q_encrypted()),
+ Qt::DirectConnection);
+ QObject::connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(_q_sslErrors(const QList<QSslError>&)),
+ Qt::DirectConnection);
+ }
+#endif
+}
+
+
+void QHttpNetworkConnectionChannel::close()
+{
+ socket->blockSignals(true);
+ socket->close();
+ socket->blockSignals(false);
+ state = QHttpNetworkConnectionChannel::IdleState;
+}
+
+
+//private slots
+void QHttpNetworkConnectionChannel::_q_readyRead()
+{
+ if (!socket)
+ return; // ### error
+ if (connection->d_func()->isSocketWaiting(socket) || connection->d_func()->isSocketReading(socket)) {
+ state = QHttpNetworkConnectionChannel::ReadingState;
+ if (reply)
+ connection->d_func()->receiveReply(socket, reply);
+ }
+ // ### error
+}
+
+void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
+{
+ Q_UNUSED(bytes);
+ if (!socket)
+ return; // ### error
+ // bytes have been written to the socket. write even more of them :)
+ if (connection->d_func()->isSocketWriting(socket))
+ connection->d_func()->sendRequest(socket);
+ // otherwise we do nothing
+}
+
+void QHttpNetworkConnectionChannel::_q_disconnected()
+{
+ if (!socket)
+ return; // ### error
+ // read the available data before closing
+ if (connection->d_func()->isSocketWaiting(socket) || connection->d_func()->isSocketReading(socket)) {
+ state = QHttpNetworkConnectionChannel::ReadingState;
+ if (reply)
+ connection->d_func()->receiveReply(socket, reply);
+ } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) {
+ // re-sending request because the socket was in ClosingState
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ }
+ state = QHttpNetworkConnectionChannel::IdleState;
+}
+
+
+void QHttpNetworkConnectionChannel::_q_connected()
+{
+ if (!socket)
+ return; // ### error
+
+ // improve performance since we get the request sent by the kernel ASAP
+ socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
+
+ // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
+ //channels[i].reconnectAttempts = 2;
+ if (!pendingEncrypt) {
+ state = QHttpNetworkConnectionChannel::IdleState;
+ if (reply)
+ connection->d_func()->sendRequest(socket);
+ else
+ close();
+ }
+}
+
+
+void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
+{
+ if (!socket)
+ return;
+ bool send2Reply = false;
+ QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
+
+ switch (socketError) {
+ case QAbstractSocket::HostNotFoundError:
+ errorCode = QNetworkReply::HostNotFoundError;
+ break;
+ case QAbstractSocket::ConnectionRefusedError:
+ errorCode = QNetworkReply::ConnectionRefusedError;
+ break;
+ case QAbstractSocket::RemoteHostClosedError:
+ // try to reconnect/resend before sending an error.
+ // while "Reading" the _q_disconnected() will handle this.
+ if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ if (reconnectAttempts-- > 0) {
+ connection->d_func()->resendCurrentRequest(socket);
+ return;
+ } else {
+ send2Reply = true;
+ errorCode = QNetworkReply::RemoteHostClosedError;
+ }
+ } else {
+ return;
+ }
+ break;
+ case QAbstractSocket::SocketTimeoutError:
+ // try to reconnect/resend before sending an error.
+ if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
+ connection->d_func()->resendCurrentRequest(socket);
+ return;
+ }
+ send2Reply = true;
+ errorCode = QNetworkReply::TimeoutError;
+ break;
+ case QAbstractSocket::ProxyAuthenticationRequiredError:
+ errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
+ break;
+ case QAbstractSocket::SslHandshakeFailedError:
+ errorCode = QNetworkReply::SslHandshakeFailedError;
+ break;
+ default:
+ // all other errors are treated as NetworkError
+ errorCode = QNetworkReply::UnknownNetworkError;
+ break;
+ }
+ QPointer<QObject> that = connection;
+ QString errorString = connection->d_func()->errorDetail(errorCode, socket);
+ if (send2Reply) {
+ if (reply) {
+ reply->d_func()->errorString = errorString;
+ // this error matters only to this reply
+ emit reply->finishedWithError(errorCode, errorString);
+ }
+ // send the next request
+ QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
+ } else {
+ // the failure affects all requests.
+ emit connection->error(errorCode, errorString);
+ }
+ if (that) //signal emission triggered event loop
+ close();
+}
+
+#ifndef QT_NO_NETWORKPROXY
+void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
+{
+ emit connection->proxyAuthenticationRequired(proxy, auth, connection);
+}
+#endif
+
+void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
+{
+ connection->d_func()->sendRequest(socket);
+}
+
+#ifndef QT_NO_OPENSSL
+void QHttpNetworkConnectionChannel::_q_encrypted()
+{
+ if (!socket)
+ return; // ### error
+ state = QHttpNetworkConnectionChannel::IdleState;
+ connection->d_func()->sendRequest(socket);
+}
+
+void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
+{
+ if (!socket)
+ return;
+ //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
+ emit connection->sslErrors(errors);
+}
+#endif
+
QT_END_NAMESPACE
#include "moc_qhttpnetworkconnectionchannel_p.cpp"
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index cbabc67..013e7a5 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -80,6 +80,7 @@ QT_BEGIN_NAMESPACE
class QHttpNetworkRequest;
class QHttpNetworkReply;
class QByteArray;
+class QHttpNetworkConnection;
class QHttpNetworkConnectionChannel : public QObject {
Q_OBJECT
@@ -117,7 +118,31 @@ public:
#ifndef QT_NO_OPENSSL
, ignoreAllSslErrors(false)
#endif
+ , connection(0)
{}
+
+ void setConnection(QHttpNetworkConnection *c) {connection = c;}
+ QHttpNetworkConnection *connection;
+
+ void init();
+ void close();
+
+ protected slots:
+ void _q_bytesWritten(qint64 bytes); // proceed sending
+ void _q_readyRead(); // pending data to read
+ void _q_disconnected(); // disconnected from host
+ void _q_connected(); // start sending request
+ void _q_error(QAbstractSocket::SocketError); // error from socket
+#ifndef QT_NO_NETWORKPROXY
+ void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy
+#endif
+
+ void _q_uploadDataReadyRead();
+
+#ifndef QT_NO_OPENSSL
+ void _q_encrypted(); // start sending request (https)
+ void _q_sslErrors(const QList<QSslError> &errors); // ssl errors from the socket
+#endif
};
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index c11b1a6..52672d5 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -685,6 +685,36 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *in, qint64 *chunkSize)
return bytes;
}
+void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteArray &qba)
+{
+ responseData.append(qba);
+
+ // clear the original! helps with implicit sharing and
+ // avoiding memcpy when the user is reading the data
+ qba.clear();
+}
+
+void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteDataBuffer &data)
+{
+ responseData.append(data);
+
+ // clear the original! helps with implicit sharing and
+ // avoiding memcpy when the user is reading the data
+ data.clear();
+}
+
+void QHttpNetworkReplyPrivate::appendCompressedReplyData(QByteDataBuffer &data)
+{
+ // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
+ // instead of one QByteArray.
+ for(int i = 0; i < data.bufferCount(); i++) {
+ QByteArray &byteData = data[i];
+ compressedData.append(byteData.constData(), byteData.size());
+ }
+ data.clear();
+}
+
+
// SSL support below
#ifndef QT_NO_OPENSSL
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 0982685..27c5860 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -149,6 +149,7 @@ private:
Q_DECLARE_SCOPED_PRIVATE(QHttpNetworkReply)
friend class QHttpNetworkConnection;
friend class QHttpNetworkConnectionPrivate;
+ friend class QHttpNetworkConnectionChannel;
};
@@ -171,6 +172,10 @@ public:
qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
+ void appendUncompressedReplyData(QByteArray &qba);
+ void appendUncompressedReplyData(QByteDataBuffer &data);
+ void appendCompressedReplyData(QByteDataBuffer &data);
+
qint64 bytesAvailable() const;
bool isChunked();
bool connectionCloseEnabled();
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
index f38c2fc..040b3ec 100644
--- a/src/network/socket/qnet_unix_p.h
+++ b/src/network/socket/qnet_unix_p.h
@@ -85,7 +85,7 @@ static inline int qt_safe_socket(int domain, int type, int protocol, int flags =
Q_ASSERT((flags & ~O_NONBLOCK) == 0);
register int fd;
-#ifdef SOCK_CLOEXEC
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
int newtype = type | SOCK_CLOEXEC;
if (flags & O_NONBLOCK)
newtype |= SOCK_NONBLOCK;