[Pkg-owncloud-commits] [owncloud-client] 428/484: Qt: Add Windows-specific patches OBS, also a QNAM fix

Sandro Knauß hefee-guest at moszumanska.debian.org
Wed Dec 16 00:38:16 UTC 2015


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository owncloud-client.

commit 2d604cee256ef555c85985b86f1b3cfe0b47ddf2
Author: Daniel Molkentin <danimo at owncloud.com>
Date:   Wed Nov 25 22:35:57 2015 +0100

    Qt: Add Windows-specific patches OBS, also a QNAM fix
---
 ...-Network-Fix-up-previous-corruption-patch.patch | 434 +++++++++++++++++++++
 ...losed-http-sockets-pass-as-valid-connecti.patch | 121 ++++++
 ...it-system-proxy-if-internet-settings-chan.patch | 152 ++++++++
 ...not-crash-if-SSL-context-is-gone-after-ro.patch |  32 ++
 admin/qt/patches/README.md                         |   9 +-
 5 files changed, 745 insertions(+), 3 deletions(-)

diff --git a/admin/qt/patches/0007-X-Network-Fix-up-previous-corruption-patch.patch b/admin/qt/patches/0007-X-Network-Fix-up-previous-corruption-patch.patch
new file mode 100644
index 0000000..4e2fe41
--- /dev/null
+++ b/admin/qt/patches/0007-X-Network-Fix-up-previous-corruption-patch.patch
@@ -0,0 +1,434 @@
+From eae0cb09f1310e755c2aff7c1112f7a6c09d7a53 Mon Sep 17 00:00:00 2001
+From: Markus Goetz <markus at woboq.com>
+Date: Fri, 19 Jun 2015 15:35:34 +0200
+Subject: [PATCH] Network: Fix up previous corruption patch
+
+This is a fix-up for cff39fba10ffc10ee4dcfdc66ff6528eb26462d3.
+That patch lead to some internal state issues that lead to the QTBUG-47048
+or to QNetworkReply objects erroring with "Connection Closed" when
+the server closed the Keep-Alive connection.
+
+This patch changes the QNAM socket slot connections to be DirectConnection.
+We don't close the socket anymore in slots where it is anyway in a closed state
+afterwards. This prevents event/stack recursions.
+We also flush QSslSocket/QTcpSocket receive buffers when receiving a disconnect
+so that the developer always gets the full decrypted data from the buffers.
+
+[ChangeLog][QtNetwork] Fix HTTP issues with "Unknown Error" and "Connection Closed"
+[ChangeLog][QtNetwork][Sockets] Read OS/encrypted read buffers when connection
+closed by server.
+
+Change-Id: Ib4d6a2d0d988317e3a5356f36e8dbcee4590beed
+Task-number: QTBUG-47048
+Reviewed-by: Kai Koehne <kai.koehne at theqtcompany.com>
+Reviewed-by: Richard J. Moore <rich at kde.org>
+---
+ src/network/access/qhttpnetworkconnection.cpp      |   1 -
+ .../access/qhttpnetworkconnectionchannel.cpp       | 108 +++++++++++++--------
+ .../access/qhttpnetworkconnectionchannel_p.h       |   1 +
+ src/network/access/qhttpnetworkreply.cpp           |   2 +-
+ src/network/access/qhttpprotocolhandler.cpp        |   1 -
+ src/network/socket/qabstractsocket.cpp             |   7 +-
+ src/network/ssl/qsslsocket.cpp                     |   8 ++
+ src/network/ssl/qsslsocket_openssl.cpp             |   7 ++
+ .../access/qnetworkreply/tst_qnetworkreply.cpp     |   9 +-
+ 9 files changed, 94 insertions(+), 50 deletions(-)
+
+diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
+index 365ce55..543c70e 100644
+--- a/src/network/access/qhttpnetworkconnection.cpp
++++ b/src/network/access/qhttpnetworkconnection.cpp
+@@ -917,7 +917,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
+     for (int i = 0; i < channelCount; ++i) {
+         if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
+             channels[i].resendCurrent = false;
+-            channels[i].state = QHttpNetworkConnectionChannel::IdleState;
+
+             // if this is not possible, error will be emitted and connection terminated
+             if (!channels[i].resetUploadData())
+diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
+index 49c6793..e2f6307 100644
+--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
++++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
+@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
+
+ // TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+
++// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
++// connection times out)
++// We use 3 because we can get a _q_error 3 times depending on the timing:
++static const int reconnectAttemptsDefault = 3;
++
+ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
+     : socket(0)
+     , ssl(false)
+@@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
+     , resendCurrent(false)
+     , lastStatus(0)
+     , pendingEncrypt(false)
+-    , reconnectAttempts(2)
++    , reconnectAttempts(reconnectAttemptsDefault)
+     , authMethod(QAuthenticatorPrivate::None)
+     , proxyAuthMethod(QAuthenticatorPrivate::None)
+     , authenticationCredentialsSent(false)
+@@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
+     socket->setProxy(QNetworkProxy::NoProxy);
+ #endif
+
+-    // We want all signals (except the interactive ones) be connected as QueuedConnection
+-    // because else we're falling into cases where we recurse back into the socket code
+-    // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
+-    // is safer.
++    // After some back and forth in all the last years, this is now a DirectConnection because otherwise
++    // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
++    // which behave slightly differently on Windows vs Linux
+     QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
+                      this, SLOT(_q_bytesWritten(qint64)),
+-                     Qt::QueuedConnection);
++                     Qt::DirectConnection);
+     QObject::connect(socket, SIGNAL(connected()),
+                      this, SLOT(_q_connected()),
+-                     Qt::QueuedConnection);
++                     Qt::DirectConnection);
+     QObject::connect(socket, SIGNAL(readyRead()),
+                      this, SLOT(_q_readyRead()),
+-                     Qt::QueuedConnection);
++                     Qt::DirectConnection);
+
+     // The disconnected() and error() signals may already come
+     // while calling connectToHost().
+@@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
+     qRegisterMetaType<QAbstractSocket::SocketError>();
+     QObject::connect(socket, SIGNAL(disconnected()),
+                      this, SLOT(_q_disconnected()),
+-                     Qt::QueuedConnection);
++                     Qt::DirectConnection);
+     QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+                      this, SLOT(_q_error(QAbstractSocket::SocketError)),
+-                     Qt::QueuedConnection);
++                     Qt::DirectConnection);
+
+
+ #ifndef QT_NO_NETWORKPROXY
+@@ -147,13 +151,13 @@ void QHttpNetworkConnectionChannel::init()
+         // won't be a sslSocket if encrypt is false
+         QObject::connect(sslSocket, SIGNAL(encrypted()),
+                          this, SLOT(_q_encrypted()),
+-                         Qt::QueuedConnection);
++                         Qt::DirectConnection);
+         QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
+                          this, SLOT(_q_sslErrors(QList<QSslError>)),
+                          Qt::DirectConnection);
+         QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
+                          this, SLOT(_q_encryptedBytesWritten(qint64)),
+-                         Qt::QueuedConnection);
++                         Qt::DirectConnection);
+
+         if (ignoreAllSslErrors)
+             sslSocket->ignoreSslErrors();
+@@ -397,7 +401,7 @@ void QHttpNetworkConnectionChannel::allDone()
+
+     // reset the reconnection attempts after we receive a complete reply.
+     // in case of failures, each channel will attempt two reconnects before emitting error.
+-    reconnectAttempts = 2;
++    reconnectAttempts = reconnectAttemptsDefault;
+
+     // now the channel can be seen as free/idle again, all signal emissions for the reply have been done
+     if (state != QHttpNetworkConnectionChannel::ClosingState)
+@@ -651,6 +655,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
+         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ }
+
++void QHttpNetworkConnectionChannel::resendCurrentRequest()
++{
++    requeueCurrentlyPipelinedRequests();
++    if (reply)
++        resendCurrent = true;
++    if (qobject_cast<QHttpNetworkConnection*>(connection))
++        QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
++}
++
+ bool QHttpNetworkConnectionChannel::isSocketBusy() const
+ {
+     return (state & QHttpNetworkConnectionChannel::BusyState);
+@@ -694,8 +707,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
+         return;
+     }
+
+-    // read the available data before closing
+-    if (isSocketWaiting() || isSocketReading()) {
++    // read the available data before closing (also done in _q_error for other codepaths)
++    if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
+         if (reply) {
+             state = QHttpNetworkConnectionChannel::ReadingState;
+             _q_receiveReply();
+@@ -707,7 +720,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
+     state = QHttpNetworkConnectionChannel::IdleState;
+
+     requeueCurrentlyPipelinedRequests();
+-    close();
++
++    pendingEncrypt = false;
+ }
+
+
+@@ -789,11 +803,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
+         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) {
++        // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
++        // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
++        // The reconnectAttempts handling catches the cases where we can re-send the request.
++        if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
++            // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
++            // is sent on them. No need to error the other replies below. Just bail out here.
++            // The _q_disconnected will handle the possibly pipelined replies
++            return;
++        } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
++            // Try to reconnect/resend before sending an error.
++            // While "Reading" the _q_disconnected() will handle this.
+             if (reconnectAttempts-- > 0) {
+-                closeAndResendCurrentRequest();
++                resendCurrentRequest();
+                 return;
+             } else {
+                 errorCode = QNetworkReply::RemoteHostClosedError;
+@@ -818,24 +840,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
+                 // we can ignore the readbuffersize as the data is already
+                 // in memory and we will not receive more data on the socket.
+                 reply->setReadBufferSize(0);
++                reply->setDownstreamLimited(false);
+                 _q_receiveReply();
+-#ifndef QT_NO_SSL
+-                if (ssl) {
+-                    // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
+-                    // So we need to check this if the socket is a QSslSocket. When the socket is flushed
+-                    // it will force a decrypt of the encrypted data in the plainsocket.
+-                    QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
+-                    qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
+-                    while (sslSocket->encryptedBytesAvailable()) {
+-                        sslSocket->flush();
+-                        _q_receiveReply();
+-                        qint64 afterFlush = sslSocket->encryptedBytesAvailable();
+-                        if (afterFlush == beforeFlush)
+-                            break;
+-                        beforeFlush = afterFlush;
+-                    }
++                if (!reply) {
++                    // No more reply assigned after the previous call? Then it had been finished successfully.
++                    requeueCurrentlyPipelinedRequests();
++                    state = QHttpNetworkConnectionChannel::IdleState;
++                    QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
++                    return;
+                 }
+-#endif
+             }
+
+             errorCode = QNetworkReply::RemoteHostClosedError;
+@@ -846,7 +859,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
+     case QAbstractSocket::SocketTimeoutError:
+         // try to reconnect/resend before sending an error.
+         if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
+-            closeAndResendCurrentRequest();
++            resendCurrentRequest();
+             return;
+         }
+         errorCode = QNetworkReply::TimeoutError;
+@@ -860,7 +873,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
+     case QAbstractSocket::ProxyConnectionClosedError:
+         // try to reconnect/resend before sending an error.
+         if (reconnectAttempts-- > 0) {
+-            closeAndResendCurrentRequest();
++            resendCurrentRequest();
+             return;
+         }
+         errorCode = QNetworkReply::ProxyConnectionClosedError;
+@@ -868,7 +881,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
+     case QAbstractSocket::ProxyConnectionTimeoutError:
+         // try to reconnect/resend before sending an error.
+         if (reconnectAttempts-- > 0) {
+-            closeAndResendCurrentRequest();
++            resendCurrentRequest();
+             return;
+         }
+         errorCode = QNetworkReply::ProxyTimeoutError;
+@@ -916,8 +929,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
+     // send the next request
+     QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
+
+-    if (that) //signal emission triggered event loop
+-        close();
++    if (that) {
++        //signal emission triggered event loop
++        if (!socket)
++            state = QHttpNetworkConnectionChannel::IdleState;
++        else if (socket->state() == QAbstractSocket::UnconnectedState)
++            state = QHttpNetworkConnectionChannel::IdleState;
++        else
++            state = QHttpNetworkConnectionChannel::ClosingState;
++
++        // pendingEncrypt must only be true in between connected and encrypted states
++        pendingEncrypt = false;
++    }
+ }
+
+ #ifndef QT_NO_NETWORKPROXY
+@@ -941,7 +964,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
+
+ void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
+ {
+-    sendRequest();
++    if (reply)
++        sendRequest();
+ }
+
+ #ifndef QT_NO_SSL
+diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
+index 231fe11..a834b7d 100644
+--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
++++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
+@@ -169,6 +169,7 @@ public:
+
+     void handleUnexpectedEOF();
+     void closeAndResendCurrentRequest();
++    void resendCurrentRequest();
+
+     bool isSocketBusy() const;
+     bool isSocketWriting() const;
+diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
+index 55863a3..8b71bd8 100644
+--- a/src/network/access/qhttpnetworkreply.cpp
++++ b/src/network/access/qhttpnetworkreply.cpp
+@@ -191,7 +191,7 @@ QByteArray QHttpNetworkReply::readAny()
+         return QByteArray();
+
+     // we'll take the last buffer, so schedule another read from http
+-    if (d->downstreamLimited && d->responseData.bufferCount() == 1)
++    if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
+         d->connection->d_func()->readMoreLater(this);
+     return d->responseData.read();
+ }
+diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
+index 3357948..380aaac 100644
+--- a/src/network/access/qhttpprotocolhandler.cpp
++++ b/src/network/access/qhttpprotocolhandler.cpp
+@@ -250,7 +250,6 @@ bool QHttpProtocolHandler::sendRequest()
+     if (!m_reply) {
+         // heh, how should that happen!
+         qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
+-        m_channel->state = QHttpNetworkConnectionChannel::IdleState;
+         return false;
+     }
+
+diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
+index 2666771..0e82d4a 100644
+--- a/src/network/socket/qabstractsocket.cpp
++++ b/src/network/socket/qabstractsocket.cpp
+@@ -768,6 +768,7 @@ bool QAbstractSocketPrivate::canReadNotification()
+ void QAbstractSocketPrivate::canCloseNotification()
+ {
+     Q_Q(QAbstractSocket);
++    // Note that this method is only called on Windows. Other platforms close in the canReadNotification()
+
+ #if defined (QABSTRACTSOCKET_DEBUG)
+     qDebug("QAbstractSocketPrivate::canCloseNotification()");
+@@ -777,7 +778,11 @@ void QAbstractSocketPrivate::canCloseNotification()
+     if (isBuffered) {
+         // Try to read to the buffer, if the read fail we can close the socket.
+         newBytes = buffer.size();
+-        if (!readFromSocket()) {
++        qint64 oldReadBufferMaxSize = readBufferMaxSize;
++        readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
++        bool hadReadFromSocket = readFromSocket();
++        readBufferMaxSize = oldReadBufferMaxSize;
++        if (!hadReadFromSocket) {
+             q->disconnectFromHost();
+             return;
+         }
+diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
+index c1fab94..2b9e923 100644
+--- a/src/network/ssl/qsslsocket.cpp
++++ b/src/network/ssl/qsslsocket.cpp
+@@ -2294,6 +2294,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
+     qCDebug(lcSsl) << "\tstate =" << q->state();
+     qCDebug(lcSsl) << "\terrorString =" << q->errorString();
+ #endif
++    // this moves encrypted bytes from plain socket into our buffer
++    if (plainSocket->bytesAvailable()) {
++        qint64 tmpReadBufferMaxSize = readBufferMaxSize;
++        readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
++        transmit();
++        readBufferMaxSize = tmpReadBufferMaxSize;
++    }
++
+     q->setSocketError(plainSocket->error());
+     q->setErrorString(plainSocket->errorString());
+     emit q->error(error);
+diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
+index ac4336a..94655fe 100644
+--- a/src/network/ssl/qsslsocket_openssl.cpp
++++ b/src/network/ssl/qsslsocket_openssl.cpp
+@@ -1419,6 +1419,13 @@ void QSslSocketBackendPrivate::disconnected()
+ {
+     if (plainSocket->bytesAvailable() <= 0)
+         destroySslContext();
++    else {
++        // Move all bytes into the plain buffer
++        qint64 tmpReadBufferMaxSize = readBufferMaxSize;
++        readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
++        transmit();
++        readBufferMaxSize = tmpReadBufferMaxSize;
++    }
+     //if there is still buffered data in the plain socket, don't destroy the ssl context yet.
+     //it will be destroyed when the socket is deleted.
+ }
+diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+index d2edf67..138f528 100644
+--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
++++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+@@ -1051,7 +1051,7 @@ protected:
+         // clean up QAbstractSocket's residue:
+         while (client->bytesToWrite() > 0) {
+             qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
+-            if (!client->waitForBytesWritten(2000)) {
++            if (!client->waitForBytesWritten(10000)) {
+                 qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
+                 return;
+             }
+@@ -1071,7 +1071,7 @@ protected:
+             measuredSentBytes += writeNextData(client, bytesToWrite);
+
+             while (client->bytesToWrite() > 0) {
+-                if (!client->waitForBytesWritten(2000)) {
++                if (!client->waitForBytesWritten(10000)) {
+                     qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
+                     return;
+                 }
+@@ -7946,7 +7946,7 @@ public slots:
+         m_receivedData += data;
+         if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
+             m_parsedHeaders = true;
+-            QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
++            QTimer::singleShot(qrand()%60, this, SLOT(closeDelayed())); // simulate random network latency
+             // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
+             // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
+             // This test catches that.
+@@ -8052,11 +8052,12 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
+
+             // get the request started and the incoming socket connected
+             QTestEventLoop::instance().enterLoop(10);
++            QVERIFY(!QTestEventLoop::instance().timeout());
+
+             //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
+
+             // Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
+-            QVERIFY(server.m_correctUploads > 5);
++            QVERIFY(server.m_correctUploads > 2);
+             // Because actually important is that we don't get any corruption:
+             QCOMPARE(server.m_corruptUploads, 0);
+
+--
+1.9.1
diff --git a/admin/qt/patches/0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch b/admin/qt/patches/0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
new file mode 100644
index 0000000..c883e3d
--- /dev/null
+++ b/admin/qt/patches/0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
@@ -0,0 +1,121 @@
+From 0df5d079290b4c3b13e58e9397fabdc1dfdba96b Mon Sep 17 00:00:00 2001
+From: Ulf Hermann <ulf.hermann at theqtcompany.com>
+Date: Fri, 25 Sep 2015 13:23:46 +0200
+Subject: [PATCH] Don't let closed http sockets pass as valid connections
+
+A QAbstractSocket can be close()'d at any time, independently of its
+current connection state. being closed means that we cannot use it to
+read or write data, but internally it might still have some data to
+send or receive, for example to an http server. We can even get a
+connected() signal after close()'ing the socket.
+
+We need to catch this condition and mark any pending data not yet
+written to the socket for resending.
+
+Task-number: QTBUG-48326
+Change-Id: I6f61c35f2c567f2a138f8cfe9ade7fd1ec039be6
+Reviewed-by: Simon Hausmann <simon.hausmann at theqtcompany.com>
+---
+ .../access/qhttpnetworkconnectionchannel.cpp       |  7 ++-
+ .../tst_qhttpnetworkconnection.cpp                 | 54 ++++++++++++++++++++++
+ 2 files changed, 60 insertions(+), 1 deletion(-)
+
+diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
+index 293909c..b4eda34 100644
+--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
++++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
+@@ -272,7 +272,12 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
+     QAbstractSocket::SocketState socketState = socket->state();
+
+     // resend this request after we receive the disconnected signal
+-    if (socketState == QAbstractSocket::ClosingState) {
++    // If !socket->isOpen() then we have already called close() on the socket, but there was still a
++    // pending connectToHost() for which we hadn't seen a connected() signal, yet. The connected()
++    // has now arrived (as indicated by socketState != ClosingState), but we cannot send anything on
++    // such a socket anymore.
++    if (socketState == QAbstractSocket::ClosingState ||
++            (socketState != QAbstractSocket::UnconnectedState && !socket->isOpen())) {
+         if (reply)
+             resendCurrent = true;
+         return false;
+diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
+index 5d072af..0d188a8 100644
+--- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
++++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
+@@ -36,6 +36,7 @@
+ #include "private/qhttpnetworkconnection_p.h"
+ #include "private/qnoncontiguousbytedevice_p.h"
+ #include <QAuthenticator>
++#include <QTcpServer>
+
+ #include "../../../network-settings.h"
+
+@@ -106,6 +107,8 @@ private Q_SLOTS:
+
+     void getAndThenDeleteObject();
+     void getAndThenDeleteObject_data();
++
++    void overlappingCloseAndWrite();
+ };
+
+ tst_QHttpNetworkConnection::tst_QHttpNetworkConnection()
+@@ -1112,6 +1115,57 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject()
+     }
+ }
+
++class TestTcpServer : public QTcpServer
++{
++    Q_OBJECT
++public:
++    TestTcpServer() : errorCodeReports(0)
++    {
++        connect(this, &QTcpServer::newConnection, this, &TestTcpServer::onNewConnection);
++        QVERIFY(listen(QHostAddress::LocalHost));
++    }
++
++    int errorCodeReports;
++
++public slots:
++    void onNewConnection()
++    {
++        QTcpSocket *socket = nextPendingConnection();
++        if (!socket)
++            return;
++        // close socket instantly!
++        connect(socket, &QTcpSocket::readyRead, socket, &QTcpSocket::close);
++    }
++
++    void onReply(QNetworkReply::NetworkError code)
++    {
++        QCOMPARE(code, QNetworkReply::RemoteHostClosedError);
++        ++errorCodeReports;
++    }
++};
++
++void tst_QHttpNetworkConnection::overlappingCloseAndWrite()
++{
++    // server accepts connections, but closes the socket instantly
++    TestTcpServer server;
++    QNetworkAccessManager accessManager;
++
++    // ten requests are scheduled. All should result in an RemoteHostClosed...
++    QUrl url;
++    url.setScheme(QStringLiteral("http"));
++    url.setHost(server.serverAddress().toString());
++    url.setPort(server.serverPort());
++    for (int i = 0; i < 10; ++i) {
++        QNetworkRequest request(url);
++        QNetworkReply *reply = accessManager.get(request);
++        // Not using Qt5 connection syntax here because of overly baroque syntax to discern between
++        // different error() methods.
++        QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
++                         &server, SLOT(onReply(QNetworkReply::NetworkError)));
++    }
++
++    QTRY_COMPARE(server.errorCodeReports, 10);
++}
+
+
+ QTEST_MAIN(tst_QHttpNetworkConnection)
+--
+1.9.1
diff --git a/admin/qt/patches/0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch b/admin/qt/patches/0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch
new file mode 100644
index 0000000..814c4d1
--- /dev/null
+++ b/admin/qt/patches/0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch
@@ -0,0 +1,152 @@
+From ae9d3f4c6c1a732788cd1f24c6a928cee16c3991 Mon Sep 17 00:00:00 2001
+From: Daniel Molkentin <daniel at molkentin.de>
+Date: Tue, 27 Jan 2015 16:58:32 +0100
+Subject: [PATCH] Win32: Re-init system proxy if internet settings change
+
+Because Proxy Auto Configuration performs DNS lookups,
+the proxy settings are being cached. For long-running
+programs this means that once users switch e.g. from or
+to company networks with a proxy, they instantly will
+lose connectivity because we cache the old setting.
+
+To remedy this, we monitor the Registry (locations
+courtesy of Chromium's platform support) for changes
+in its settings, and requery for the current proxy in
+that case.
+
+Task-number: QTBUG-3470
+Task-number: QTBUG-29990
+Change-Id: Id25a51387bcd232c5f879cea0371038986d0e2de
+Reviewed-by: Oliver Wolff <oliver.wolff at theqtcompany.com>
+---
+ src/network/kernel/qnetworkproxy_win.cpp | 86 +++++++++++++++++++++++++++++++-
+ 1 file changed, 84 insertions(+), 2 deletions(-)
+
+diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
+index da2c020..f7741ce 100644
+--- a/src/network/kernel/qnetworkproxy_win.cpp
++++ b/src/network/kernel/qnetworkproxy_win.cpp
+@@ -345,12 +345,66 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
+     return removeDuplicateProxies(result);
+ }
+
++#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
++namespace {
++class QRegistryWatcher {
++public:
++    void addLocation(HKEY hive, const QString& path)
++    {
++        HKEY openedKey;
++        if (RegOpenKeyEx(hive, reinterpret_cast<const wchar_t*>(path.utf16()), 0, KEY_READ, &openedKey) != ERROR_SUCCESS)
++            return;
++
++        const DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
++                REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY;
++
++        // Watch the registry key for a change of value.
++        HANDLE handle = CreateEvent(NULL, true, false, NULL);
++        if (RegNotifyChangeKeyValue(openedKey, true, filter, handle, true) != ERROR_SUCCESS) {
++            CloseHandle(handle);
++            return;
++        }
++        m_watchEvents.append(handle);
++        m_registryHandles.append(openedKey);
++    }
++
++    bool hasChanged() const {
++        return !isEmpty() &&
++               WaitForMultipleObjects(m_watchEvents.size(), m_watchEvents.data(), false, 0) < WAIT_OBJECT_0 + m_watchEvents.size();
++    }
++
++    bool isEmpty() const {
++        return m_watchEvents.isEmpty();
++    }
++
++    void clear() {
++        foreach (HANDLE event, m_watchEvents)
++            CloseHandle(event);
++        foreach (HKEY key, m_registryHandles)
++            RegCloseKey(key);
++
++        m_watchEvents.clear();
++        m_registryHandles.clear();
++    }
++
++    ~QRegistryWatcher() {
++        clear();
++    }
++
++private:
++    QVector<HANDLE> m_watchEvents;
++    QVector<HKEY> m_registryHandles;
++};
++} // namespace
++#endif // !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
++
+ class QWindowsSystemProxy
+ {
+ public:
+     QWindowsSystemProxy();
+     ~QWindowsSystemProxy();
+     void init();
++    void reset();
+
+     QMutex mutex;
+
+@@ -361,7 +415,9 @@ public:
+     QStringList proxyServerList;
+     QStringList proxyBypass;
+     QList<QNetworkProxy> defaultResult;
+-
++#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
++    QRegistryWatcher proxySettingsWatcher;
++#endif
+     bool initialized;
+     bool functional;
+     bool isAutoConfig;
+@@ -381,16 +437,42 @@ QWindowsSystemProxy::~QWindowsSystemProxy()
+         ptrWinHttpCloseHandle(hHttpSession);
+ }
+
++void QWindowsSystemProxy::reset()
++{
++    autoConfigUrl.clear();
++    proxyServerList.clear();
++    proxyBypass.clear();
++    defaultResult.clear();
++    defaultResult << QNetworkProxy::NoProxy;
++    functional = false;
++    isAutoConfig = false;
++}
++
+ void QWindowsSystemProxy::init()
+ {
+-    if (initialized)
++    bool proxySettingsChanged = false;
++#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
++    proxySettingsChanged = proxySettingsWatcher.hasChanged();
++#endif
++
++    if (initialized && !proxySettingsChanged)
+         return;
+     initialized = true;
+
++    reset();
++
+ #ifdef Q_OS_WINCE
+     // Windows CE does not have any of the following API
+     return;
+ #else
++
++#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
++    proxySettingsWatcher.clear(); // needs reset to trigger a new detection
++    proxySettingsWatcher.addLocation(HKEY_CURRENT_USER,  QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
++    proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
++    proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
++#endif
++
+     // load the winhttp.dll library
+     QSystemLibrary lib(L"winhttp");
+     if (!lib.load())
+--
+1.9.1
diff --git a/admin/qt/patches/0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch b/admin/qt/patches/0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch
new file mode 100644
index 0000000..6669179
--- /dev/null
+++ b/admin/qt/patches/0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch
@@ -0,0 +1,32 @@
+From c1a67e7dc3a6f8876efa32cdbabbfde1c5a37bc6 Mon Sep 17 00:00:00 2001
+From: Daniel Molkentin <daniel at molkentin.de>
+Date: Tue, 31 Mar 2015 17:43:44 +0200
+Subject: [PATCH] Windows: Do not crash if SSL context is gone after root cert
+ lookup
+
+On Windows, we perform an extra certificate lookup for root CAs that
+are not in Windows' (minimal) root store. This check can take up to
+15 seconds. The SSL context can already be gone once we return. Hence
+we now check for a non-null SSL context on Windows before proceeding.
+
+Change-Id: I1951569d9b17da33fa604f7c9d8b33255acf200d
+Reviewed-by: Richard J. Moore <rich at kde.org>
+---
+ src/network/ssl/qsslsocket_openssl.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
+index 0e1a3e5..b132aec 100644
+--- a/src/network/ssl/qsslsocket_openssl.cpp
++++ b/src/network/ssl/qsslsocket_openssl.cpp
+@@ -1281,7 +1281,7 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi
+     if (plainSocket)
+         plainSocket->resume();
+     paused = false;
+-    if (checkSslErrors())
++    if (checkSslErrors() && ssl)
+         continueHandshake();
+ }
+
+--
+1.9.1
diff --git a/admin/qt/patches/README.md b/admin/qt/patches/README.md
index 466a6c7..5705069 100644
--- a/admin/qt/patches/README.md
+++ b/admin/qt/patches/README.md
@@ -18,17 +18,20 @@ purpose is outlined in each patches' front matter.
 ### Part of Qt v5.4.2 and later
 * 0004-Cocoa-Fix-systray-SVG-icons.patch
 * 0005-OSX-Fix-disapearing-tray-icon.patch
-  (TODO: actual patch slighly differs)
 * 0007-QNAM-Fix-upload-corruptions-when-server-closes-conne.patch
-  (TODO: Actual patch on build machine spans over two commit but is identical)
+* 0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch
+
+### Part of Qt v5.5.0 and later
+* 0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch
 
 ### Part of Qt v5.5.1 and later
+* 0007-X-Network-Fix-up-previous-corruption-patch.patch
 * 0008-QNAM-Fix-reply-deadlocks-on-server-closing-connectio.patch
-  (TODO: actual patch has different name)
 * 0014-Fix-SNI-for-TlsV1_0OrLater-TlsV1_1OrLater-and-TlsV1_.patch
 
 ### Upstreamed but not in any release yet (as of 2015-11-16)
 * 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
+* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
 * 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
 * 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
 * 0013-Make-UnknownAccessibility-not-block-requests.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git



More information about the Pkg-owncloud-commits mailing list