summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp22
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h5
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp138
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h1
-rw-r--r--src/network/access/qhttpnetworkreply.cpp13
-rw-r--r--src/network/access/qhttpnetworkreply_p.h2
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp2
-rw-r--r--src/network/socket/qlocalsocket_p.h6
-rw-r--r--src/network/socket/qlocalsocket_win.cpp22
9 files changed, 130 insertions, 81 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index cc6a1c8..62aa2d7 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -404,6 +404,7 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor
QHttpNetworkReply *reply = new QHttpNetworkReply(request.url());
reply->setRequest(request);
reply->d_func()->connection = q;
+ reply->d_func()->connectionChannel = &channels[0]; // will have the correct one set later
HttpMessagePair pair = qMakePair(request, reply);
switch (request.priority()) {
@@ -688,14 +689,12 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (channels[i].resendCurrent) {
channels[i].resendCurrent = false;
channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- if (channels[i].reply) {
- // if this is not possible, error will be emitted and connection terminated
- if (!channels[i].resetUploadData())
- continue;
+ // if this is not possible, error will be emitted and connection terminated
+ if (!channels[i].resetUploadData())
+ continue;
- channels[i].sendRequest();
- }
+ channels[i].sendRequest();
}
}
@@ -861,17 +860,6 @@ QNetworkProxy QHttpNetworkConnection::transparentProxy() const
// SSL support below
#ifndef QT_NO_OPENSSL
-QSslConfiguration QHttpNetworkConnectionPrivate::sslConfiguration(const QHttpNetworkReply &reply) const
-{
- if (!encrypt)
- return QSslConfiguration();
-
- for (int i = 0; i < channelCount; ++i)
- if (channels[i].reply == &reply)
- return static_cast<QSslSocket *>(channels[0].socket)->sslConfiguration();
- return QSslConfiguration(); // pending or done request
-}
-
void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config)
{
Q_D(QHttpNetworkConnection);
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 03cf09c..823774e 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -210,11 +210,6 @@ public:
void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
-
-#ifndef QT_NO_OPENSSL
- QSslConfiguration sslConfiguration(const QHttpNetworkReply &reply) const;
-#endif
-
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy networkProxy;
void emitProxyAuthenticationRequired(const QHttpNetworkConnectionChannel *chan, const QNetworkProxy &proxy, QAuthenticator* auth);
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index b0e632a..dbee72a 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -124,6 +124,13 @@ void QHttpNetworkConnectionChannel::close()
bool QHttpNetworkConnectionChannel::sendRequest()
{
+ if (!reply) {
+ // heh, how should that happen!
+ qWarning() << "QHttpNetworkConnectionChannel::sendRequest() called without QHttpNetworkReply";
+ state = QHttpNetworkConnectionChannel::IdleState;
+ return false;
+ }
+
switch (state) {
case QHttpNetworkConnectionChannel::IdleState: { // write the header
if (!ensureConnection()) {
@@ -134,13 +141,13 @@ bool QHttpNetworkConnectionChannel::sendRequest()
}
written = 0; // excluding the header
bytesTotal = 0;
- if (reply) {
- reply->d_func()->clear();
- reply->d_func()->connection = connection;
- reply->d_func()->autoDecompress = request.d->autoDecompress;
- reply->d_func()->pipeliningUsed = false;
- }
- state = QHttpNetworkConnectionChannel::WritingState;
+
+ reply->d_func()->clear();
+ reply->d_func()->connection = connection;
+ reply->d_func()->connectionChannel = this;
+ reply->d_func()->autoDecompress = request.d->autoDecompress;
+ reply->d_func()->pipeliningUsed = false;
+
pendingEncrypt = false;
// if the url contains authentication parameters, use the new ones
// both channels will use the new authentication parameters
@@ -174,13 +181,15 @@ bool QHttpNetworkConnectionChannel::sendRequest()
QObject::connect(uploadByteDevice, SIGNAL(readyRead()),this, SLOT(_q_uploadDataReadyRead()));
bytesTotal = request.contentLength();
+
+ state = QHttpNetworkConnectionChannel::WritingState; // start writing data
+ sendRequest(); //recurse
} else {
- state = QHttpNetworkConnectionChannel::WaitingState;
- sendRequest();
- break;
+ state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
+ sendRequest(); //recurse
}
- // write the initial chunk together with the headers
- // fall through
+
+ break;
}
case QHttpNetworkConnectionChannel::WritingState:
{
@@ -190,7 +199,7 @@ bool QHttpNetworkConnectionChannel::sendRequest()
if (uploadByteDevice)
emit reply->dataSendProgress(written, bytesTotal);
state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
- sendRequest();
+ sendRequest(); // recurse
break;
}
@@ -278,51 +287,50 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
{
Q_ASSERT(socket);
+ if (!reply) {
+ // heh, how should that happen!
+ qWarning() << "QHttpNetworkConnectionChannel::_q_receiveReply() called without QHttpNetworkReply,"
+ << socket->bytesAvailable() << "bytes on socket.";
+ close();
+ return;
+ }
+
qint64 bytes = 0;
QAbstractSocket::SocketState socketState = socket->state();
// connection might be closed to signal the end of data
if (socketState == QAbstractSocket::UnconnectedState) {
- if (!socket->bytesAvailable()) {
- if (reply && reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
+ if (socket->bytesAvailable() <= 0) {
+ if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
+ // finish this reply. this case happens when the server did not send a content length
reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
allDone();
+ return;
} else {
- // try to reconnect/resend before sending an error.
- if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
- } else if (reply) {
- reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::RemoteHostClosedError, socket);
- emit reply->finishedWithError(QNetworkReply::RemoteHostClosedError, reply->d_func()->errorString);
- QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
- }
+ handleUnexpectedEOF();
+ return;
}
+ } else {
+ // socket not connected but still bytes for reading.. just continue in this function
}
}
// read loop for the response
while (socket->bytesAvailable()) {
- QHttpNetworkReplyPrivate::ReplyState state = reply ? reply->d_func()->state : QHttpNetworkReplyPrivate::AllDoneState;
+ QHttpNetworkReplyPrivate::ReplyState state = reply->d_func()->state;
switch (state) {
case QHttpNetworkReplyPrivate::NothingDoneState: {
// only eat whitespace on the first call
eatWhitespace();
state = reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
+ // fallthrough
}
case QHttpNetworkReplyPrivate::ReadingStatusState: {
qint64 statusBytes = reply->d_func()->readStatus(socket);
- if (statusBytes == -1 && reconnectAttempts <= 0) {
- // too many errors reading/receiving/parsing the status, close the socket and emit error
- close();
- reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::ProtocolFailure, socket);
- emit reply->finishedWithError(QNetworkReply::ProtocolFailure, reply->d_func()->errorString);
- QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
- break;
- } else if (statusBytes == -1) {
- reconnectAttempts--;
- reply->d_func()->clear();
- closeAndResendCurrentRequest();
- break;
+ if (statusBytes == -1) {
+ // connection broke while reading status. also handled if later _q_disconnected is called
+ handleUnexpectedEOF();
+ return;
}
bytes += statusBytes;
lastStatus = reply->d_func()->statusCode;
@@ -330,7 +338,13 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
}
case QHttpNetworkReplyPrivate::ReadingHeaderState: {
QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
- bytes += replyPrivate->readHeader(socket);
+ qint64 headerBytes = replyPrivate->readHeader(socket);
+ if (headerBytes == -1) {
+ // connection broke while reading headers. also handled if later _q_disconnected is called
+ handleUnexpectedEOF();
+ return;
+ }
+ bytes += headerBytes;
if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
if (replyPrivate->isGzipped() && replyPrivate->autoDecompress) {
// remove the Content-Length from header
@@ -417,8 +431,10 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
#endif
}
}
+ // still in ReadingDataState? This function will be called again by the socket's readyRead
if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState)
break;
+
// everything done, fall through
}
case QHttpNetworkReplyPrivate::AllDoneState:
@@ -430,6 +446,23 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
}
}
+// called when unexpectedly reading a -1 or when data is expected but socket is closed
+void QHttpNetworkConnectionChannel::handleUnexpectedEOF()
+{
+ if (reconnectAttempts <= 0) {
+ // too many errors reading/receiving/parsing the status, close the socket and emit error
+ requeueCurrentlyPipelinedRequests();
+ close();
+ reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::RemoteHostClosedError, socket);
+ emit reply->finishedWithError(QNetworkReply::RemoteHostClosedError, reply->d_func()->errorString);
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ } else {
+ reconnectAttempts--;
+ reply->d_func()->clear();
+ closeAndResendCurrentRequest();
+ }
+}
+
bool QHttpNetworkConnectionChannel::ensureConnection()
{
QAbstractSocket::SocketState socketState = socket->state();
@@ -556,7 +589,8 @@ void QHttpNetworkConnectionChannel::allDone()
handleStatus();
// ### at this point there should be no more data on the socket
// close if server requested
- if (reply->d_func()->isConnectionCloseEnabled())
+ bool connectionCloseEnabled = reply->d_func()->isConnectionCloseEnabled();
+ if (connectionCloseEnabled)
close();
// queue the finished signal, this is required since we might send new requests from
// slot connected to it. The socket will not fire readyRead signal, if we are already
@@ -567,14 +601,22 @@ void QHttpNetworkConnectionChannel::allDone()
// in case of failures, each channel will attempt two reconnects before emitting error.
reconnectAttempts = 2;
+ detectPipeliningSupport();
+
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
this->state = QHttpNetworkConnectionChannel::IdleState;
- detectPipeliningSupport();
+ // if it does not need to be sent again we can set it to 0
+ // the previous code did not do that and we had problems with accidental re-sending of a
+ // finished request.
+ // Note that this may trigger a segfault at some other point. But then we can fix the underlying
+ // problem.
+ if (!resendCurrent)
+ reply = 0;
// move next from pipeline to current request
if (!alreadyPipelinedRequests.isEmpty()) {
- if (resendCurrent || reply->d_func()->isConnectionCloseEnabled() || socket->state() != QAbstractSocket::ConnectedState) {
+ if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
// move the pipelined ones back to the main queue
requeueCurrentlyPipelinedRequests();
close();
@@ -730,12 +772,11 @@ void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
QHttpNetworkRequest &request = pair.first;
QHttpNetworkReply *reply = pair.second;
- if (reply) {
- reply->d_func()->clear();
- reply->d_func()->connection = connection;
- reply->d_func()->autoDecompress = request.d->autoDecompress;
- reply->d_func()->pipeliningUsed = true;
- }
+ reply->d_func()->clear();
+ reply->d_func()->connection = connection;
+ reply->d_func()->connectionChannel = this;
+ reply->d_func()->autoDecompress = request.d->autoDecompress;
+ reply->d_func()->pipeliningUsed = true;
#ifndef QT_NO_NETWORKPROXY
QByteArray header = QHttpNetworkRequestPrivate::header(request,
@@ -799,9 +840,10 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
{
// read the available data before closing
if (isSocketWaiting() || isSocketReading()) {
- state = QHttpNetworkConnectionChannel::ReadingState;
- if (reply)
+ if (reply) {
+ state = QHttpNetworkConnectionChannel::ReadingState;
_q_receiveReply();
+ }
} else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) {
// re-sending request because the socket was in ClosingState
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 75ab50d..5032d2b 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -157,6 +157,7 @@ public:
void requeueCurrentlyPipelinedRequests();
void detectPipeliningSupport();
+ void handleUnexpectedEOF();
void closeAndResendCurrentRequest();
void eatWhitespace();
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 512c045..984f557 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -230,6 +230,7 @@ void QHttpNetworkReplyPrivate::clear()
currentChunkRead = 0;
connectionCloseEnabled = true;
connection = 0;
+ connectionChannel = 0;
#ifndef QT_NO_COMPRESS
if (initInflate)
inflateEnd(&inflateStrm);
@@ -803,9 +804,15 @@ void QHttpNetworkReplyPrivate::eraseData()
QSslConfiguration QHttpNetworkReply::sslConfiguration() const
{
Q_D(const QHttpNetworkReply);
- if (d->connection)
- return d->connection->d_func()->sslConfiguration(*this);
- return QSslConfiguration();
+
+ if (!d->connectionChannel)
+ return QSslConfiguration();
+
+ QSslSocket *sslSocket = qobject_cast<QSslSocket*>(d->connectionChannel->socket);
+ if (!sslSocket)
+ return QSslConfiguration();
+
+ return sslSocket->sslConfiguration();
}
void QHttpNetworkReply::setSslConfiguration(const QSslConfiguration &config)
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index af9266b..fa240ec 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -86,6 +86,7 @@ static const unsigned char gz_magic[2] = {0x1f, 0x8b}; // gzip magic header
QT_BEGIN_NAMESPACE
class QHttpNetworkConnection;
+class QHttpNetworkConnectionChannel;
class QHttpNetworkRequest;
class QHttpNetworkConnectionPrivate;
class QHttpNetworkReplyPrivate;
@@ -218,6 +219,7 @@ public:
qint64 currentChunkSize;
qint64 currentChunkRead;
QPointer<QHttpNetworkConnection> connection;
+ QPointer<QHttpNetworkConnectionChannel> connectionChannel;
bool initInflate;
bool streamEnd;
#ifndef QT_NO_COMPRESS
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index c8f4e5b..dcd4e19 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -999,7 +999,7 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo
// of writes to disk when using a QNetworkDiskCache (i.e. don't
// write to disk when only the date changes).
// However, without the date we cannot calculate the age of the page
- // anymore. Consider a proper fix of that problem for 4.6.1.
+ // anymore.
//if (header == "date")
//continue;
diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h
index 081697b..0f1c23c 100644
--- a/src/network/socket/qlocalsocket_p.h
+++ b/src/network/socket/qlocalsocket_p.h
@@ -128,10 +128,8 @@ public:
void _q_stateChanged(QAbstractSocket::SocketState newState);
void _q_error(QAbstractSocket::SocketError newError);
#elif defined(Q_OS_WIN)
- ~QLocalSocketPrivate() {
- CloseHandle(overlapped.hEvent);
- }
-
+ ~QLocalSocketPrivate();
+ void destroyPipeHandles();
void setErrorString(const QString &function);
void _q_notified();
void _q_canWrite();
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index 1f94df6..3283bf2 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -110,6 +110,20 @@ QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
{
}
+QLocalSocketPrivate::~QLocalSocketPrivate()
+{
+ destroyPipeHandles();
+ CloseHandle(overlapped.hEvent);
+}
+
+void QLocalSocketPrivate::destroyPipeHandles()
+{
+ if (handle != INVALID_HANDLE_VALUE) {
+ DisconnectNamedPipe(handle);
+ CloseHandle(handle);
+ }
+}
+
void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
{
Q_D(QLocalSocket);
@@ -388,8 +402,7 @@ void QLocalSocket::close()
d->readSequenceStarted = false;
d->pendingReadyRead = false;
d->pipeClosed = false;
- DisconnectNamedPipe(d->handle);
- CloseHandle(d->handle);
+ d->destroyPipeHandles();
d->handle = INVALID_HANDLE_VALUE;
ResetEvent(d->overlapped.hEvent);
d->state = UnconnectedState;
@@ -524,7 +537,10 @@ bool QLocalSocket::waitForDisconnected(int msecs)
bool QLocalSocket::isValid() const
{
Q_D(const QLocalSocket);
- return (d->handle != INVALID_HANDLE_VALUE);
+ if (d->handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ return PeekNamedPipe(d->handle, NULL, 0, NULL, NULL, NULL);
}
bool QLocalSocket::waitForReadyRead(int msecs)