diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 1 | ||||
-rw-r--r-- | src/network/kernel/qnetworkproxy.cpp | 47 | ||||
-rw-r--r-- | src/network/kernel/qnetworkproxy.h | 4 | ||||
-rw-r--r-- | src/network/kernel/qnetworkproxy_win.cpp | 182 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate.cpp | 2 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 7 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols_p.h | 1 |
8 files changed, 203 insertions, 43 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index c65edb6673..397bb0535e 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1185,6 +1185,7 @@ void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) if (manager->d_func()->httpThread) { // The thread will deleteLater() itself from its finished() signal manager->d_func()->httpThread->quit(); + manager->d_func()->httpThread->wait(5000); manager->d_func()->httpThread = 0; } } @@ -1194,6 +1195,7 @@ QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate() if (httpThread) { // The thread will deleteLater() itself from its finished() signal httpThread->quit(); + httpThread->wait(5000); httpThread = 0; } } diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 1f456746ae..a914ee3f04 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -904,6 +904,7 @@ void QNetworkReplyHttpImplPrivate::postRequest() // End the thread. It will delete itself from the finished() signal thread->quit(); + thread->wait(5000); finished(); } else { diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 0281eaf48b..feef74e737 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -224,8 +224,10 @@ #include "private/qsocks5socketengine_p.h" #include "private/qhttpsocketengine_p.h" #include "qauthenticator.h" +#include "qdebug.h" #include "qhash.h" #include "qmutex.h" +#include "qstringlist.h" #include "qurl.h" #ifndef QT_NO_BEARERMANAGEMENT @@ -1508,6 +1510,51 @@ QList<QNetworkProxy> QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuer return globalNetworkProxy()->proxyForQuery(query); } +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QNetworkProxy &proxy) +{ + QNetworkProxy::ProxyType type = proxy.type(); + switch (type) { + case QNetworkProxy::NoProxy: + debug << "NoProxy "; + break; + case QNetworkProxy::DefaultProxy: + debug << "DefaultProxy "; + break; + case QNetworkProxy::Socks5Proxy: + debug << "Socks5Proxy "; + break; + case QNetworkProxy::HttpProxy: + debug << "HttpProxy "; + break; + case QNetworkProxy::HttpCachingProxy: + debug << "HttpCachingProxy "; + break; + case QNetworkProxy::FtpCachingProxy: + debug << "FtpCachingProxy "; + break; + default: + debug << "Unknown proxy " << int(type); + break; + } + debug << "\"" << proxy.hostName() << ":" << proxy.port() << "\" "; + QNetworkProxy::Capabilities caps = proxy.capabilities(); + QStringList scaps; + if (caps & QNetworkProxy::TunnelingCapability) + scaps << QStringLiteral("Tunnel"); + if (caps & QNetworkProxy::ListeningCapability) + scaps << QStringLiteral("Listen"); + if (caps & QNetworkProxy::UdpTunnelingCapability) + scaps << QStringLiteral("UDP"); + if (caps & QNetworkProxy::CachingCapability) + scaps << QStringLiteral("Caching"); + if (caps & QNetworkProxy::HostNameLookupCapability) + scaps << QStringLiteral("NameLookup"); + debug << "[" << scaps.join(QStringLiteral(" ")) << "]"; + return debug; +} +#endif + QT_END_NAMESPACE #endif // QT_NO_NETWORKPROXY diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h index 8f961c43ac..805f5cdb5c 100644 --- a/src/network/kernel/qnetworkproxy.h +++ b/src/network/kernel/qnetworkproxy.h @@ -203,6 +203,10 @@ public: static QList<QNetworkProxy> systemProxyForQuery(const QNetworkProxyQuery &query = QNetworkProxyQuery()); }; +#ifndef QT_NO_DEBUG_STREAM +Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxy &proxy); +#endif + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp index 33ae4a6a14..4f1dece4a9 100644 --- a/src/network/kernel/qnetworkproxy_win.cpp +++ b/src/network/kernel/qnetworkproxy_win.cpp @@ -103,6 +103,7 @@ typedef struct { #define WINHTTP_ERROR_BASE 12000 #define ERROR_WINHTTP_LOGIN_FAILURE (WINHTTP_ERROR_BASE + 15) +#define ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT (WINHTTP_ERROR_BASE + 167) #define ERROR_WINHTTP_AUTODETECTION_FAILED (WINHTTP_ERROR_BASE + 180) QT_BEGIN_NAMESPACE @@ -146,7 +147,7 @@ static QStringList splitSpaceSemicolon(const QString &source) static bool isBypassed(const QString &host, const QStringList &bypassList) { if (host.isEmpty()) - return true; + return false; bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':')); @@ -171,6 +172,51 @@ static bool isBypassed(const QString &host, const QStringList &bypassList) return false; } +static QList<QNetworkProxy> filterProxyListByCapabilities(const QList<QNetworkProxy> &proxyList, const QNetworkProxyQuery &query) +{ + QNetworkProxy::Capabilities requiredCaps; + switch (query.queryType()) { + case QNetworkProxyQuery::TcpSocket: + requiredCaps = QNetworkProxy::TunnelingCapability; + break; + case QNetworkProxyQuery::UdpSocket: + requiredCaps = QNetworkProxy::UdpTunnelingCapability; + break; + case QNetworkProxyQuery::TcpServer: + requiredCaps = QNetworkProxy::ListeningCapability; + break; + default: + return proxyList; + break; + } + QList<QNetworkProxy> result; + foreach (const QNetworkProxy& proxy, proxyList) { + if (proxy.capabilities() & requiredCaps) + result.append(proxy); + } + return result; +} + +static QList<QNetworkProxy> removeDuplicateProxies(const QList<QNetworkProxy> &proxyList) +{ + QList<QNetworkProxy> result; + foreach (QNetworkProxy proxy, proxyList) { + bool append = true; + for (int i=0; i < result.count(); i++) { + if (proxy.hostName() == result.at(i).hostName() + && proxy.port() == result.at(i).port()) { + append = false; + // HttpProxy trumps FtpCachingProxy or HttpCachingProxy on the same host/port + if (proxy.type() == QNetworkProxy::HttpProxy) + result[i] = proxy; + } + } + if (append) + result.append(proxy); + } + return result; +} + static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, const QStringList &proxyList) { // Reference documentation from Microsoft: @@ -179,38 +225,46 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con // According to the website, the proxy server list is // one or more of the space- or semicolon-separated strings in the format: // ([<scheme>=][<scheme>"://"]<server>[":"<port>]) + // The first scheme relates to the protocol tag + // The second scheme, if present, overrides the proxy type QList<QNetworkProxy> result; + QHash<QString, QNetworkProxy> taggedProxies; + const QString requiredTag = query.protocolTag(); + bool checkTags = !requiredTag.isEmpty() && query.queryType() != QNetworkProxyQuery::TcpServer; //windows tags are only for clients foreach (const QString &entry, proxyList) { int server = 0; + QNetworkProxy::ProxyType proxyType = QNetworkProxy::HttpProxy; + quint16 port = 8080; + int pos = entry.indexOf(QLatin1Char('=')); + QStringRef scheme; + QStringRef protocolTag; if (pos != -1) { - QStringRef scheme = entry.leftRef(pos); - if (scheme != query.protocolTag()) - continue; - + scheme = protocolTag = entry.leftRef(pos); server = pos + 1; } - - QNetworkProxy::ProxyType proxyType = QNetworkProxy::HttpProxy; - quint16 port = 8080; - pos = entry.indexOf(QLatin1String("://"), server); if (pos != -1) { - QStringRef scheme = entry.midRef(server, pos - server); + scheme = entry.midRef(server, pos - server); + server = pos + 3; + } + + if (!scheme.isEmpty()) { if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) { // no-op // defaults are above } else if (scheme == QLatin1String("socks") || scheme == QLatin1String("socks5")) { proxyType = QNetworkProxy::Socks5Proxy; port = 1080; + } else if (scheme == QLatin1String("ftp")) { + proxyType = QNetworkProxy::FtpCachingProxy; + port = 2121; } else { // unknown proxy type continue; } - - server = pos + 3; } pos = entry.indexOf(QLatin1Char(':'), server); @@ -226,9 +280,32 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con } result << QNetworkProxy(proxyType, entry.mid(server, pos - server), port); + if (!protocolTag.isEmpty()) + taggedProxies.insert(protocolTag.toString(), result.last()); } - return result; + if (checkTags && taggedProxies.contains(requiredTag)) { + if (query.queryType() == QNetworkProxyQuery::UrlRequest) { + result.clear(); + result.append(taggedProxies.value(requiredTag)); + return result; + } else { + result.prepend(taggedProxies.value(requiredTag)); + } + } + if (!checkTags || requiredTag != QLatin1String("http")) { + // if there are different http proxies for http and https, prefer the https one (more likely to be capable of CONNECT) + QNetworkProxy httpProxy = taggedProxies.value(QLatin1String("http")); + QNetworkProxy httpsProxy = taggedProxies.value(QLatin1String("http")); + if (httpProxy != httpsProxy && httpProxy.type() == QNetworkProxy::HttpProxy && httpsProxy.type() == QNetworkProxy::HttpProxy) { + for (int i = 0; i < result.count(); i++) { + if (httpProxy == result.at(i)) + result[i].setType(QNetworkProxy::HttpCachingProxy); + } + } + } + result = filterProxyListByCapabilities(result, query); + return removeDuplicateProxies(result); } class QWindowsSystemProxy @@ -306,14 +383,27 @@ void QWindowsSystemProxy::init() proxyBypass = splitSpaceSemicolon(QString::fromWCharArray(ieProxyConfig.lpszProxyBypass)); GlobalFree(ieProxyConfig.lpszProxyBypass); } + } else { + // no user configuration + // attempt to get the default configuration instead + WINHTTP_PROXY_INFO proxyInfo; + if (ptrWinHttpGetDefaultProxyConfiguration(&proxyInfo) && + proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) { + // we got information from the registry + // overwrite the IE configuration, if any + + proxyBypass = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxyBypass)); + proxyServerList = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxy)); + } + + if (proxyInfo.lpszProxy) + GlobalFree(proxyInfo.lpszProxy); + if (proxyInfo.lpszProxyBypass) + GlobalFree(proxyInfo.lpszProxyBypass); } hHttpSession = NULL; if (ieProxyConfig.fAutoDetect || !autoConfigUrl.isEmpty()) { - // using proxy autoconfiguration - proxyServerList.clear(); - proxyBypass.clear(); - // open the handle and obtain the options hHttpSession = ptrWinHttpOpen(L"Qt System Proxy access/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, @@ -326,6 +416,9 @@ void QWindowsSystemProxy::init() isAutoConfig = true; memset(&autoProxyOptions, 0, sizeof autoProxyOptions); autoProxyOptions.fAutoLogonIfChallenged = false; + //Although it is possible to specify dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT | WINHTTP_AUTOPROXY_CONFIG_URL + //this has poor performance (WPAD is attempted for every url, taking 2.5 seconds per interface, + //before the configured pac file is used) if (ieProxyConfig.fAutoDetect) { autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | @@ -334,23 +427,6 @@ void QWindowsSystemProxy::init() autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; autoProxyOptions.lpszAutoConfigUrl = (LPCWSTR)autoConfigUrl.utf16(); } - } else { - // not auto-detected - // attempt to get the static configuration instead - WINHTTP_PROXY_INFO proxyInfo; - if (ptrWinHttpGetDefaultProxyConfiguration(&proxyInfo) && - proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) { - // we got information from the registry - // overwrite the IE configuration, if any - - proxyBypass = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxyBypass)); - proxyServerList = splitSpaceSemicolon(QString::fromWCharArray(proxyInfo.lpszProxy)); - } - - if (proxyInfo.lpszProxy) - GlobalFree(proxyInfo.lpszProxy); - if (proxyInfo.lpszProxyBypass) - GlobalFree(proxyInfo.lpszProxyBypass); } functional = isAutoConfig || !proxyServerList.isEmpty(); @@ -390,6 +466,25 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro DWORD getProxyError = GetLastError(); if (!getProxySucceeded + && (ERROR_WINHTTP_AUTODETECTION_FAILED == getProxyError)) { + // WPAD failed + if (sp->autoConfigUrl.isEmpty()) { + //No config file could be retrieved on the network. + //Don't search for it next time again. + sp->isAutoConfig = false; + } else { + //pac file URL is specified as well, try using that + sp->autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + sp->autoProxyOptions.lpszAutoConfigUrl = (LPCWSTR)sp->autoConfigUrl.utf16(); + getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession, + (LPCWSTR)url.toString().utf16(), + &sp->autoProxyOptions, + &proxyInfo); + getProxyError = GetLastError(); + } + } + + if (!getProxySucceeded && (ERROR_WINHTTP_LOGIN_FAILURE == getProxyError)) { // We first tried without AutoLogon, because this might prevent caching the result. // But now we've to enable it (http://msdn.microsoft.com/en-us/library/aa383153%28v=VS.85%29.aspx) @@ -401,6 +496,13 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro getProxyError = GetLastError(); } + if (!getProxySucceeded + && (ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT == getProxyError)) { + // PAC file url is not connectable, or server returned error (e.g. http 404) + //Don't search for it next time again. + sp->isAutoConfig = false; + } + if (getProxySucceeded) { // yes, we got a config for this URL QString proxyBypass = QString::fromWCharArray(proxyInfo.lpszProxyBypass); @@ -410,20 +512,14 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro if (proxyInfo.lpszProxyBypass) GlobalFree(proxyInfo.lpszProxyBypass); + if (proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) + return sp->defaultResult; //i.e. the PAC file result was "DIRECT" if (isBypassed(query.peerHostName(), splitSpaceSemicolon(proxyBypass))) return sp->defaultResult; return parseServerList(query, proxyServerList); } - // GetProxyForUrl failed - - if (ERROR_WINHTTP_AUTODETECTION_FAILED == getProxyError) { - //No config file could be retrieved on the network. - //Don't search for it next time again. - sp->isAutoConfig = false; - } - - return sp->defaultResult; + // GetProxyForUrl failed, fall back to static configuration } // static configuration diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index a9573bf1d8..65634a3cb7 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -1161,6 +1161,8 @@ static const char *certificate_blacklist[] = { "07:27:14:a9", "Digisign Server ID (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Verizon CyberTrust "4c:0e:63:6a", "Digisign Server ID - (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Entrust + "72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0", "UTN-USERFirst-Hardware", // comodogate test certificate + "41", "MD5 Collisions Inc. (http://www.phreedom.org/md5)", // http://www.phreedom.org/research/rogue-ca/ 0 }; diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 20ad82407c..df60a0fcce 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -338,6 +338,13 @@ init_context: long options = setupOpenSslOptions(configuration.protocol, configuration.sslOptions); q_SSL_CTX_set_options(ctx, options); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + // Tell OpenSSL to release memory early + // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html + if (q_SSLeay() >= 0x10000000L) + q_SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + // Initialize ciphers QByteArray cipherString; int first = true; diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 758763523f..b0d748692f 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -411,6 +411,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length); bp,(char *)x,enc,kstr,klen,cb,u) #endif #define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) +#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) #define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st) #define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i) #define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st)) |