summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp39
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h2
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp88
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h3
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp5
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp7
-rw-r--r--src/network/socket/qabstractsocket.cpp2
-rw-r--r--src/network/ssl/qssl.cpp7
-rw-r--r--src/network/ssl/qssl.h4
-rw-r--r--src/network/ssl/qsslconfiguration.cpp4
-rw-r--r--src/network/ssl/qsslconfiguration_p.h2
-rw-r--r--src/network/ssl/qsslsocket.cpp32
-rw-r--r--src/network/ssl/qsslsocket.h3
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp45
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h4
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp14
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h4
17 files changed, 216 insertions, 49 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 3502113..29ae5b0 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -487,7 +487,7 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
-void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
{
Q_ASSERT(socket);
@@ -500,8 +500,7 @@ void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socke
prepareRequest(messagePair);
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
- channels[i].sendRequest();
- return;
+ return true;
}
if (!lowPriorityQueue.isEmpty()) {
@@ -511,9 +510,9 @@ void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socke
prepareRequest(messagePair);
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
- channels[i].sendRequest();
- return;
+ return true;
}
+ return false;
}
// this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
@@ -765,7 +764,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
//resend the necessary ones.
for (int i = 0; i < channelCount; ++i) {
- if (channels[i].resendCurrent) {
+ if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
channels[i].resendCurrent = false;
channels[i].state = QHttpNetworkConnectionChannel::IdleState;
@@ -784,17 +783,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// try to get a free AND connected socket
for (int i = 0; i < channelCount; ++i) {
if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
- dequeueAndSendRequest(channels[i].socket);
- }
- }
-
- // return fast if there is nothing to do
- if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
- return;
- // try to get a free unconnected socket
- for (int i = 0; i < channelCount; ++i) {
- if (!channels[i].reply && !channels[i].isSocketBusy()) {
- dequeueAndSendRequest(channels[i].socket);
+ if (dequeueRequest(channels[i].socket))
+ channels[i].sendRequest();
}
}
@@ -811,6 +801,21 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < channelCount; i++)
if (channels[i].socket->state() == QAbstractSocket::ConnectedState)
fillPipeline(channels[i].socket);
+
+ // If there is not already any connected channels we need to connect a new one.
+ // We do not pair the channel with the request until we know if it is
+ // connected or not. This is to reuse connected channels before we connect new once.
+ int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count();
+ for (int i = 0; i < channelCount; ++i) {
+ if (channels[i].socket->state() == QAbstractSocket::ConnectingState)
+ queuedRequest--;
+ if ( queuedRequest <=0 )
+ break;
+ if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
+ channels[i].ensureConnection();
+ queuedRequest--;
+ }
+ }
}
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index d4748c1..874ea22 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -161,7 +161,7 @@ public:
QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request);
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
- void dequeueAndSendRequest(QAbstractSocket *socket);
+ bool dequeueRequest(QAbstractSocket *socket);
void prepareRequest(HttpMessagePair &request);
void fillPipeline(QAbstractSocket *socket);
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 41bc64a..6564b4b 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -91,8 +91,10 @@ void QHttpNetworkConnectionChannel::init()
#else
socket = new QTcpSocket;
#endif
+#ifndef QT_NO_NETWORKPROXY
// Set by QNAM anyway, but let's be safe here
socket->setProxy(QNetworkProxy::NoProxy);
+#endif
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
@@ -145,10 +147,12 @@ void QHttpNetworkConnectionChannel::init()
void QHttpNetworkConnectionChannel::close()
{
- socket->blockSignals(true);
+ if (socket->state() == QAbstractSocket::UnconnectedState)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else
+ state = QHttpNetworkConnectionChannel::ClosingState;
+
socket->close();
- socket->blockSignals(false);
- state = QHttpNetworkConnectionChannel::IdleState;
}
@@ -500,6 +504,7 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
// called when unexpectedly reading a -1 or when data is expected but socket is closed
void QHttpNetworkConnectionChannel::handleUnexpectedEOF()
{
+ Q_ASSERT(reply);
if (reconnectAttempts <= 0) {
// too many errors reading/receiving/parsing the status, close the socket and emit error
requeueCurrentlyPipelinedRequests();
@@ -522,7 +527,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// resend this request after we receive the disconnected signal
if (socketState == QAbstractSocket::ClosingState) {
- resendCurrent = true;
+ if (reply)
+ resendCurrent = true;
return false;
}
@@ -582,13 +588,15 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
#endif
} else {
// In case of no proxy we can use the Unbuffered QTcpSocket
+#ifndef QT_NO_NETWORKPROXY
if (connection->d_func()->networkProxy.type() == QNetworkProxy::NoProxy
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
+#endif
socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered);
// For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
socket->setReadBufferSize(1*1024);
-
+#ifndef QT_NO_NETWORKPROXY
} else {
socket->connectToHost(connectHost, connectPort);
@@ -597,6 +605,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// here and there.
socket->setReadBufferSize(64*1024);
}
+#endif
}
return false;
}
@@ -644,6 +653,7 @@ bool QHttpNetworkConnectionChannel::expand(bool dataComplete)
void QHttpNetworkConnectionChannel::allDone()
{
+ Q_ASSERT(reply);
#ifndef QT_NO_COMPRESS
// expand the whole data.
if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) {
@@ -679,7 +689,8 @@ void QHttpNetworkConnectionChannel::allDone()
reconnectAttempts = 2;
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
- this->state = QHttpNetworkConnectionChannel::IdleState;
+ if (state != QHttpNetworkConnectionChannel::ClosingState)
+ state = QHttpNetworkConnectionChannel::IdleState;
// 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
@@ -729,7 +740,8 @@ void QHttpNetworkConnectionChannel::allDone()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else if (alreadyPipelinedRequests.isEmpty()) {
if (connectionCloseEnabled)
- close();
+ if (socket->state() != QAbstractSocket::UnconnectedState)
+ close();
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
@@ -737,6 +749,7 @@ void QHttpNetworkConnectionChannel::allDone()
void QHttpNetworkConnectionChannel::detectPipeliningSupport()
{
+ Q_ASSERT(reply);
// detect HTTP Pipelining support
QByteArray serverHeaderField;
if (
@@ -820,6 +833,7 @@ void QHttpNetworkConnectionChannel::handleStatus()
bool QHttpNetworkConnectionChannel::resetUploadData()
{
+ Q_ASSERT(reply);
QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
if (!uploadByteDevice)
return true;
@@ -877,7 +891,8 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
{
requeueCurrentlyPipelinedRequests();
close();
- resendCurrent = true;
+ if (reply)
+ resendCurrent = true;
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
@@ -905,15 +920,18 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
//private slots
void QHttpNetworkConnectionChannel::_q_readyRead()
{
- // We got a readyRead but no bytes are available..
- // This happens for the Unbuffered QTcpSocket
- // Also check if socket is in ConnectedState since
- // this function may also be invoked via the event loop.
if (socket->state() == QAbstractSocket::ConnectedState && socket->bytesAvailable() == 0) {
+ // We got a readyRead but no bytes are available..
+ // This happens for the Unbuffered QTcpSocket
+ // Also check if socket is in ConnectedState since
+ // this function may also be invoked via the event loop.
char c;
qint64 ret = socket->peek(&c, 1);
if (ret < 0) {
- socket->disconnectFromHost();
+ _q_error(socket->error());
+ // We still need to handle the reply so it emits its signals etc.
+ if (reply)
+ _q_receiveReply();
return;
}
}
@@ -936,6 +954,12 @@ void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
void QHttpNetworkConnectionChannel::_q_disconnected()
{
+ if (state == QHttpNetworkConnectionChannel::ClosingState) {
+ state = QHttpNetworkConnectionChannel::IdleState;
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
+ }
+
// read the available data before closing
if (isSocketWaiting() || isSocketReading()) {
if (reply) {
@@ -973,10 +997,10 @@ void QHttpNetworkConnectionChannel::_q_connected()
//channels[i].reconnectAttempts = 2;
if (!pendingEncrypt) {
state = QHttpNetworkConnectionChannel::IdleState;
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
if (reply)
sendRequest();
- else
- close();
}
}
@@ -1004,8 +1028,20 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
}
+ } else if (state == QHttpNetworkConnectionChannel::ReadingState) {
+ if (!reply->d_func()->expectContent()) {
+ // No content expected, this is a valid way to have the connection closed by the server
+ return;
+ }
+ if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
+ // There was no content-length header and it's not chunked encoding,
+ // so this is a valid way to have the connection closed by the server
+ return;
+ }
+ // ok, we got a disconnect even though we did not expect it
+ errorCode = QNetworkReply::RemoteHostClosedError;
} else {
- return;
+ errorCode = QNetworkReply::RemoteHostClosedError;
}
break;
case QAbstractSocket::SocketTimeoutError:
@@ -1030,9 +1066,13 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
QPointer<QHttpNetworkConnection> that = connection;
QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
+ // Need to dequeu the request so that we can emit the error.
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
if (reply) {
reply->d_func()->errorString = errorString;
emit reply->finishedWithError(errorCode, errorString);
+ reply = 0;
}
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
@@ -1044,7 +1084,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
#ifndef QT_NO_NETWORKPROXY
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
{
- connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
+ // Need to dequeue the request before we can emit the error.
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
+ if (reply)
+ connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
}
#endif
@@ -1060,7 +1104,10 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
return; // ### error
state = QHttpNetworkConnectionChannel::IdleState;
pendingEncrypt = false;
- sendRequest();
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
+ if (reply)
+ sendRequest();
}
void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
@@ -1071,7 +1118,10 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
// Also pause the connection because socket notifiers may fire while an user
// dialog is displaying
connection->d_func()->pauseConnection();
- emit reply->sslErrors(errors);
+ if (pendingEncrypt && !reply)
+ connection->d_func()->dequeueRequest(socket);
+ if (reply)
+ emit reply->sslErrors(errors);
connection->d_func()->resumeConnection();
}
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 8cbc689..893d75e 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -95,7 +95,8 @@ public:
WritingState = 2, // writing the data
WaitingState = 4, // waiting for reply
ReadingState = 8, // reading the reply
- BusyState = (ConnectingState|WritingState|WaitingState|ReadingState)
+ ClosingState = 16,
+ BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|ClosingState)
};
QAbstractSocket *socket;
bool ssl;
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index 4908e0a..a031cd0 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -233,6 +233,11 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest,
return;
}
+ // The disk cache API does not currently support partial content retrieval.
+ // That is why we don't use the disk cache for any such requests.
+ if (request().hasRawHeader("Range"))
+ return;
+
QAbstractNetworkCache *nc = networkCache();
if (!nc)
return; // no local cache
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 485f449..1c9fa3e 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -514,6 +514,13 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice()
{
Q_Q(QNetworkReplyImpl);
+ // The disk cache does not support partial content, so don't even try to
+ // save any such content into the cache.
+ if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) {
+ cacheEnabled = false;
+ return;
+ }
+
// save the meta data
QNetworkCacheMetaData metaData;
metaData.setUrl(url);
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 2a942cc..c7c2e82 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -2210,6 +2210,8 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
} else if (readBytes < 0) {
d->socketError = d->socketEngine->error();
setErrorString(d->socketEngine->errorString());
+ d->resetSocketLayer();
+ d->state = QAbstractSocket::UnconnectedState;
} else if (!d->socketEngine->isReadNotificationEnabled()) {
// Only do this when there was no error
d->socketEngine->setReadNotificationEnabled(true);
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index e9e7d21..5594296 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -101,12 +101,17 @@ QT_BEGIN_NAMESPACE
Describes the protocol of the cipher.
- \value SslV3 SSLv3 - the default protocol.
+ \value SslV3 SSLv3
\value SslV2 SSLv2
\value TlsV1 TLSv1
\value UnknownProtocol The cipher's protocol cannot be determined.
\value AnyProtocol The socket understands SSLv2, SSLv3, and TLSv1. This
value is used by QSslSocket only.
+ \value TlsV1SslV3 On the client side, this will send
+ a TLS 1.0 Client Hello, enabling TLSv1 and SSLv3 connections.
+ On the server side, this will enable both SSLv3 and TLSv1 connections.
+ \value SecureProtocols The default option, using protocols known to be secure;
+ currently behaves like TlsV1SslV3.
Note: most servers using SSL understand both versions (2 and 3),
but it is recommended to use the latest version only for security
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index 4c035fd..24dbb09 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -75,8 +75,10 @@ namespace QSsl {
enum SslProtocol {
SslV3,
SslV2,
- TlsV1,
+ TlsV1, // ### Qt 5: rename to TlsV1_0 or so
AnyProtocol,
+ TlsV1SslV3,
+ SecureProtocols,
UnknownProtocol = -1
};
}
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 3592226..150f77e 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -213,7 +213,7 @@ bool QSslConfiguration::isNull() const
*/
QSsl::SslProtocol QSslConfiguration::protocol() const
{
- return d ? d->protocol : QSsl::SslV3;
+ return d ? d->protocol : QSsl::SecureProtocols;
}
/*!
@@ -518,7 +518,7 @@ void QSslConfiguration::setCaCertificates(const QList<QSslCertificate> &certific
\list
\o no local certificate and no private key
- \o protocol SSLv3
+ \o protocol SecureProtocols (meaning either TLS 1.0 or SSL 3 will be used)
\o the system's default CA certificate list
\o the cipher list equal to the list of the SSL libraries'
supported SSL ciphers
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index b039e69..a5af51a 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -80,7 +80,7 @@ class QSslConfigurationPrivate: public QSharedData
{
public:
QSslConfigurationPrivate()
- : protocol(QSsl::SslV3),
+ : protocol(QSsl::SecureProtocols),
peerVerifyMode(QSslSocket::AutoVerifyPeer),
peerVerifyDepth(0)
{ }
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 61f27fe..98e2dc5 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -56,7 +56,7 @@
QSslSocket establishes a secure, encrypted TCP connection you can
use for transmitting encrypted data. It can operate in both client
and server mode, and it supports modern SSL protocols, including
- SSLv3 and TLSv1. By default, QSslSocket uses SSLv3, but you can
+ SSLv3 and TLSv1. By default, QSslSocket uses TLSv1, but you can
change the SSL protocol by calling setProtocol() as long as you do
it before the handshake has started.
@@ -552,7 +552,7 @@ bool QSslSocket::isEncrypted() const
}
/*!
- Returns the socket's SSL protocol. By default, \l QSsl::SslV3 is used.
+ Returns the socket's SSL protocol. By default, \l QSsl::SecureProtocols is used.
\sa setProtocol()
*/
@@ -659,6 +659,34 @@ void QSslSocket::setPeerVerifyDepth(int depth)
}
/*!
+ \since 4.8
+
+ Returns the different hostname for the certificate validation, as set by
+ setPeerVerifyName or by connectToHostEncrypted.
+
+ \sa setPeerVerifyName(), connectToHostEncrypted()
+*/
+QString QSslSocket::peerVerifyName() const
+{
+ Q_D(const QSslSocket);
+ return d->verificationPeerName;
+}
+
+/*!
+ \since 4.8
+
+ Sets a different hostname for the certificate validation instead of the one used for the TCP
+ connection.
+
+ \sa connectToHostEncrypted()
+*/
+void QSslSocket::setPeerVerifyName(const QString &hostName)
+{
+ Q_D(QSslSocket);
+ d->verificationPeerName = hostName;
+}
+
+/*!
\reimp
Returns the number of decrypted bytes that are immediately available for
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index 703a1fb..648fd8c 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -106,6 +106,9 @@ public:
int peerVerifyDepth() const;
void setPeerVerifyDepth(int depth);
+ QString peerVerifyName() const;
+ void setPeerVerifyName(const QString &hostName);
+
// From QIODevice
qint64 bytesAvailable() const;
qint64 bytesToWrite() const;
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 83714ed..c1b1712 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -60,6 +60,12 @@
#include <QtCore/qvarlengtharray.h>
#include <QLibrary> // for loading the security lib for the CA store
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+// Symbian does not seem to have the symbol for SNI defined
+#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
+#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
+#endif
+#endif
QT_BEGIN_NAMESPACE
#if defined(Q_OS_MAC)
@@ -253,6 +259,8 @@ init_context:
case QSsl::SslV3:
ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());
break;
+ case QSsl::SecureProtocols: // SslV2 will be disabled below
+ case QSsl::TlsV1SslV3: // SslV2 will be disabled below
case QSsl::AnyProtocol:
default:
ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
@@ -278,7 +286,11 @@ init_context:
}
// Enable all bug workarounds.
- q_SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) {
+ q_SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
+ } else {
+ q_SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ }
// Initialize ciphers
QByteArray cipherString;
@@ -313,9 +325,18 @@ init_context:
q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
}
}
+
+ bool addExpiredCerts = true;
+#if defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
+ //On Leopard SSL does not work if we add the expired certificates.
+ if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_5)
+ addExpiredCerts = false;
+#endif
// now add the expired certs
- foreach (const QSslCertificate &caCertificate, expiredCerts) {
- q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+ if (addExpiredCerts) {
+ foreach (const QSslCertificate &caCertificate, expiredCerts) {
+ q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+ }
}
if (s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
@@ -386,6 +407,24 @@ init_context:
return false;
}
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+ if ((configuration.protocol == QSsl::TlsV1SslV3 ||
+ configuration.protocol == QSsl::TlsV1 ||
+ configuration.protocol == QSsl::SecureProtocols ||
+ configuration.protocol == QSsl::AnyProtocol) &&
+ client && q_SSLeay() >= 0x00090806fL) {
+ // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
+ QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
+ if (tlsHostName.isEmpty())
+ tlsHostName = hostName;
+ QByteArray ace = QUrl::toAce(tlsHostName);
+ if (!ace.isEmpty()) {
+ if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.constData()))
+ qWarning("could not set SSL_CTRL_SET_TLSEXT_HOSTNAME, Server Name Indication disabled");
+ }
+ }
+#endif
+
// Clear the session.
q_SSL_clear(ssl);
errorList.clear();
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 5a7963e..ca49fab 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -79,6 +79,10 @@
#include <openssl/x509_vfy.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+#include <openssl/tls1.h>
+#endif
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
typedef _STACK STACK;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index b9a05f3..b1310cc 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -208,6 +208,9 @@ DEFINEFUNC(long, SSL_get_verify_result, SSL *a, a, return -1, return)
DEFINEFUNC(int, SSL_library_init, void, DUMMYARG, return -1, return)
DEFINEFUNC(void, SSL_load_error_strings, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, const void *parg, parg, return -1, return)
+#endif
DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
@@ -263,6 +266,7 @@ DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c,
DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
+DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
#ifdef Q_OS_SYMBIAN
#define RESOLVEFUNC(func, ordinal, lib) \
@@ -586,6 +590,9 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_library_init, 137, libs.first )
RESOLVEFUNC(SSL_load_error_strings, 139, libs.first )
RESOLVEFUNC(SSL_new, 140, libs.first )
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+ RESOLVEFUNC(SSL_ctrl, 95, libs.first )
+#endif
RESOLVEFUNC(SSL_read, 143, libs.first )
RESOLVEFUNC(SSL_set_accept_state, 148, libs.first )
RESOLVEFUNC(SSL_set_bio, 149, libs.first )
@@ -600,6 +607,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSLv3_server_method, 197, libs.first )
RESOLVEFUNC(SSLv23_server_method, 191, libs.first )
RESOLVEFUNC(TLSv1_server_method, 200, libs.first )
+ RESOLVEFUNC(SSL_CTX_load_verify_locations, 34, libs.first )
RESOLVEFUNC(X509_NAME_oneline, 1830, libs.second )
RESOLVEFUNC(X509_PUBKEY_get, 1844, libs.second )
RESOLVEFUNC(X509_STORE_free, 1939, libs.second )
@@ -631,7 +639,7 @@ bool q_resolveOpenSslSymbols()
#endif
RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf, 1153, libs.second )
RESOLVEFUNC(OPENSSL_add_all_algorithms_conf, 1152, libs.second )
- RESOLVEFUNC(SSL_CTX_load_verify_locations, 34, libs.second )
+ RESOLVEFUNC(SSLeay, 1504, libs.second )
#else // Q_OS_SYMBIAN
#ifdef SSLEAY_MACROS
RESOLVEFUNC(ASN1_dup)
@@ -711,6 +719,9 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_library_init)
RESOLVEFUNC(SSL_load_error_strings)
RESOLVEFUNC(SSL_new)
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+ RESOLVEFUNC(SSL_ctrl)
+#endif
RESOLVEFUNC(SSL_read)
RESOLVEFUNC(SSL_set_accept_state)
RESOLVEFUNC(SSL_set_bio)
@@ -757,6 +768,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf)
RESOLVEFUNC(OPENSSL_add_all_algorithms_conf)
RESOLVEFUNC(SSL_CTX_load_verify_locations)
+ RESOLVEFUNC(SSLeay)
#endif // Q_OS_SYMBIAN
symbolsResolved = true;
delete libs.first;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index c05dfe11..49830ac 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -316,6 +316,9 @@ long q_SSL_get_verify_result(SSL *a);
int q_SSL_library_init();
void q_SSL_load_error_strings();
SSL *q_SSL_new(SSL_CTX *a);
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+long q_SSL_ctrl(SSL *ssl,int cmd, long larg, const void *parg);
+#endif
int q_SSL_read(SSL *a, void *b, int c);
void q_SSL_set_bio(SSL *a, BIO *b, BIO *c);
void q_SSL_set_accept_state(SSL *a);
@@ -413,6 +416,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
void q_OPENSSL_add_all_algorithms_noconf();
void q_OPENSSL_add_all_algorithms_conf();
int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
+long q_SSLeay();
// Helper function
class QDateTime;