diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 10 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply.cpp | 23 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply_p.h | 1 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessftpbackend.cpp | 5 | ||||
-rw-r--r-- | src/network/access/qnetworkcookie.cpp | 2 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface_win.cpp | 2 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface_win_p.h | 3 | ||||
-rw-r--r-- | src/network/kernel/qnetworkproxy_win.cpp | 48 | ||||
-rw-r--r-- | src/network/socket/qabstractsocket.cpp | 11 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine.cpp | 13 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 8 | ||||
-rw-r--r-- | src/network/socket/qudpsocket.cpp | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols.cpp | 26 |
13 files changed, 140 insertions, 16 deletions
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index d4931bd207..6e33836feb 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -733,14 +733,8 @@ void QHttpNetworkConnectionChannel::allDone() } } else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) { // this is weird. we had nothing pipelined but still bytes available. better close it. - //if (socket->bytesAvailable() > 0) - // close(); - // - // FIXME - // We do not close it anymore now, but should introduce this again after having fixed - // the chunked decoder in QHttpNetworkReply to read the whitespace after the last chunk. - // (Currently this is worked around by readStatus in the QHttpNetworkReply ignoring - // leading whitespace. + close(); + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } else if (alreadyPipelinedRequests.isEmpty()) { if (connectionCloseEnabled) diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 85463ee210..39204163f2 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -257,6 +257,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) chunkedTransferEncoding(false), connectionCloseEnabled(true), forceConnectionCloseEnabled(false), + lastChunkRead(false), currentChunkSize(0), currentChunkRead(0), connection(0), autoDecompress(false), responseData(), requestIsPrepared(false) ,pipeliningUsed(false), downstreamLimited(false) @@ -277,6 +278,7 @@ void QHttpNetworkReplyPrivate::clearHttpLayerInformation() totalProgress = 0; currentChunkSize = 0; currentChunkRead = 0; + lastChunkRead = false; connectionCloseEnabled = true; #ifndef QT_NO_COMPRESS if (autoDecompress) @@ -721,7 +723,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, Q { qint64 bytes = 0; while (socket->bytesAvailable()) { - if (currentChunkRead >= currentChunkSize) { + if (!lastChunkRead && currentChunkRead >= currentChunkSize) { // For the first chunk and when we're done with a chunk currentChunkSize = 0; currentChunkRead = 0; @@ -744,8 +746,23 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, Q break; } // if the chunk size is 0, end of the stream - if (currentChunkSize == 0) { - state = AllDoneState; + if (currentChunkSize == 0 || lastChunkRead) { + lastChunkRead = true; + // try to read the "\r\n" after the chunk + char crlf[2]; + qint64 haveRead = socket->read(crlf, 2); + if (haveRead > 0) + bytes += haveRead; + + if ((haveRead == 2 && crlf[0] == '\r' && crlf[1] == '\n') || (haveRead == 1 && crlf[0] == '\n')) + state = AllDoneState; + else if (haveRead == 1 && crlf[0] == '\r') + break; // Still waiting for the last \n + else if (haveRead > 0) { + // If we read something else then CRLF, we need to close the channel. + forceConnectionCloseEnabled = true; + state = AllDoneState; + } break; } diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 04e4569457..97fefc6e1b 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -217,6 +217,7 @@ public: bool chunkedTransferEncoding; bool connectionCloseEnabled; bool forceConnectionCloseEnabled; + bool lastChunkRead; qint64 currentChunkSize; qint64 currentChunkRead; QPointer<QHttpNetworkConnection> connection; diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index 42201aa9a3..4aa491db0c 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -223,6 +223,7 @@ void QNetworkAccessFtpBackend::ftpDone() if (ftp->state() == QFtp::Connected) { // the login did not succeed QUrl newUrl = url(); + QString userInfo = newUrl.userInfo(); newUrl.setUserInfo(QString()); setUrl(newUrl); @@ -236,6 +237,10 @@ void QNetworkAccessFtpBackend::ftpDone() return; } + // Re insert the user info so that we can remove the cache entry. + newUrl.setUserInfo(userInfo); + setUrl(newUrl); + error(QNetworkReply::AuthenticationRequiredError, tr("Logging in to %1 failed: authentication required") .arg(url().host())); diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index 0dbfdb2f0c..7174acc31e 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -606,7 +606,7 @@ static bool checkStaticArray(int &val, const QByteArray &dateString, int at, con val = j; return true; } - i += strlen(str) + 1; + i += int(strlen(str)) + 1; ++j; } } diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index a311af7686..8e3b5ce7c0 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -182,6 +182,8 @@ static QList<QNetworkInterfacePrivate *> interfaceListingWinXP() iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning; if ((ptr->Flags & IP_ADAPTER_NO_MULTICAST) == 0) iface->flags |= QNetworkInterface::CanMulticast; + if (ptr->IfType == IF_TYPE_PPP) + iface->flags |= QNetworkInterface::IsPointToPoint; iface->name = QString::fromLocal8Bit(ptr->AdapterName); iface->friendlyName = QString::fromWCharArray(ptr->FriendlyName); diff --git a/src/network/kernel/qnetworkinterface_win_p.h b/src/network/kernel/qnetworkinterface_win_p.h index 73e5c625ec..303f4d3690 100644 --- a/src/network/kernel/qnetworkinterface_win_p.h +++ b/src/network/kernel/qnetworkinterface_win_p.h @@ -94,6 +94,9 @@ QT_BEGIN_NAMESPACE # define MIB_IF_TYPE_LOOPBACK 24 # define MIB_IF_TYPE_SLIP 28 +// definitions from Ipifcons.h +#define IF_TYPE_PPP 23 + #endif // copied from qnativesocketengine_win.cpp struct qt_in6_addr { diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp index 4f1dece4a9..a17f547742 100644 --- a/src/network/kernel/qnetworkproxy_win.cpp +++ b/src/network/kernel/qnetworkproxy_win.cpp @@ -113,13 +113,49 @@ typedef HINTERNET (WINAPI * PtrWinHttpOpen)(LPCWSTR, DWORD, LPCWSTR, LPCWSTR,DWO typedef BOOL (WINAPI * PtrWinHttpGetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*); typedef BOOL (WINAPI * PtrWinHttpGetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*); typedef BOOL (WINAPI * PtrWinHttpCloseHandle)(HINTERNET); +typedef SC_HANDLE (WINAPI * PtrOpenSCManager)(LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, DWORD dwDesiredAccess); +typedef BOOL (WINAPI * PtrEnumServicesStatusEx)(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType, DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, + LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName); +typedef BOOL (WINAPI * PtrCloseServiceHandle)(SC_HANDLE hSCObject); static PtrWinHttpGetProxyForUrl ptrWinHttpGetProxyForUrl = 0; static PtrWinHttpOpen ptrWinHttpOpen = 0; static PtrWinHttpGetDefaultProxyConfiguration ptrWinHttpGetDefaultProxyConfiguration = 0; static PtrWinHttpGetIEProxyConfigForCurrentUser ptrWinHttpGetIEProxyConfigForCurrentUser = 0; static PtrWinHttpCloseHandle ptrWinHttpCloseHandle = 0; +static PtrOpenSCManager ptrOpenSCManager = 0; +static PtrEnumServicesStatusEx ptrEnumServicesStatusEx = 0; +static PtrCloseServiceHandle ptrCloseServiceHandle = 0; +static bool currentProcessIsService() +{ + if (!ptrOpenSCManager || !ptrEnumServicesStatusEx|| !ptrCloseServiceHandle) + return false; + + SC_HANDLE hSCM = ptrOpenSCManager(0, 0, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); + if (!hSCM) + return false; + + ULONG bufSize = 0; + ULONG nbServices = 0; + if (ptrEnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_ACTIVE, 0, bufSize, &bufSize, &nbServices, 0, 0)) + return false; //error case + + LPENUM_SERVICE_STATUS_PROCESS info = reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESS>(malloc(bufSize)); + bool foundService = false; + if (ptrEnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_ACTIVE, (LPBYTE)info, bufSize, &bufSize, &nbServices, 0, 0)) { + DWORD currProcId = GetCurrentProcessId(); + for (ULONG i = 0; i < nbServices && !foundService; i++) { + if (info[i].ServiceStatusProcess.dwProcessId == currProcId) + foundService = true; + } + } + + ptrCloseServiceHandle(hSCM); + free(info); + return foundService; +} + static QStringList splitSpaceSemicolon(const QString &source) { QStringList list; @@ -364,10 +400,14 @@ void QWindowsSystemProxy::init() ptrWinHttpGetProxyForUrl = (PtrWinHttpGetProxyForUrl)lib.resolve("WinHttpGetProxyForUrl"); ptrWinHttpGetDefaultProxyConfiguration = (PtrWinHttpGetDefaultProxyConfiguration)lib.resolve("WinHttpGetDefaultProxyConfiguration"); ptrWinHttpGetIEProxyConfigForCurrentUser = (PtrWinHttpGetIEProxyConfigForCurrentUser)lib.resolve("WinHttpGetIEProxyConfigForCurrentUser"); + ptrOpenSCManager = (PtrOpenSCManager) QSystemLibrary(L"advapi32").resolve("OpenSCManagerW"); + ptrEnumServicesStatusEx = (PtrEnumServicesStatusEx) QSystemLibrary(L"advapi32").resolve("EnumServicesStatusExW"); + ptrCloseServiceHandle = (PtrCloseServiceHandle) QSystemLibrary(L"advapi32").resolve("CloseServiceHandle"); // Try to obtain the Internet Explorer configuration. WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig; - if (ptrWinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig)) { + const bool hasIEConfig = ptrWinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig); + if (hasIEConfig) { if (ieProxyConfig.lpszAutoConfigUrl) { autoConfigUrl = QString::fromWCharArray(ieProxyConfig.lpszAutoConfigUrl); GlobalFree(ieProxyConfig.lpszAutoConfigUrl); @@ -383,9 +423,13 @@ void QWindowsSystemProxy::init() proxyBypass = splitSpaceSemicolon(QString::fromWCharArray(ieProxyConfig.lpszProxyBypass)); GlobalFree(ieProxyConfig.lpszProxyBypass); } - } else { + } + + if (!hasIEConfig || + (currentProcessIsService() && proxyServerList.isEmpty() && proxyBypass.isEmpty())) { // no user configuration // attempt to get the default configuration instead + // that config will serve as default if WPAD fails WINHTTP_PROXY_INFO proxyInfo; if (ptrWinHttpGetDefaultProxyConfiguration(&proxyInfo) && proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) { diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index af22b20b21..0c4eed8de9 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -1984,7 +1984,16 @@ bool QAbstractSocket::waitForConnected(int msecs) d->_q_startConnecting(QHostInfoPrivate::fromName(d->hostName, networkSession)); } else #endif - d->_q_startConnecting(QHostInfo::fromName(d->hostName)); + { + QHostAddress temp; + if (temp.setAddress(d->hostName)) { + QHostInfo info; + info.setAddresses(QList<QHostAddress>() << temp); + d->_q_startConnecting(info); + } else { + d->_q_startConnecting(QHostInfo::fromName(d->hostName)); + } + } } if (state() == UnconnectedState) return false; // connect not im progress anymore! diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index a34b19f7ef..8fac3613c0 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -637,6 +637,19 @@ bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false); Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false); Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false); + + // if the user binds a socket to an IPv6 address (or QHostAddress::Any) and + // then attempts to join an IPv4 multicast group, this won't work on + // Windows. In order to make this cross-platform, we warn & fail on all + // platforms. + if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol && + (d->socketProtocol == QAbstractSocket::IPv6Protocol || + d->socketProtocol == QAbstractSocket::AnyIPProtocol)) { + qWarning("QAbstractSocket: cannot bind to QHostAddress::Any (or an IPv6 address) and join an IPv4 multicast group"); + qWarning("QAbstractSocket: bind to QHostAddress::AnyIPv4 instead if you want to do this"); + return false; + } + return d->nativeJoinMulticastGroup(groupAddress, iface); } diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 295d3961a8..7cd8e1bff3 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -321,7 +321,13 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt } case QNativeSocketEngine::AddressReusable: #if defined(SO_REUSEPORT) - n = SO_REUSEPORT; + // on OS X, SO_REUSEADDR isn't sufficient to allow multiple binds to the + // same port (which is useful for multicast UDP). SO_REUSEPORT is, but + // we most definitely do not want to use this for TCP. See QTBUG-6305. + if (socketType == QAbstractSocket::UdpSocket) + n = SO_REUSEPORT; + else + n = SO_REUSEADDR; #else n = SO_REUSEADDR; #endif diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index ec751c289e..23c1956ec5 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -178,6 +178,10 @@ QUdpSocket::~QUdpSocket() interface chosen by the operating system. The socket must be in BoundState, otherwise an error occurs. + Note that if you are attempting to join an IPv4 group, your socket must not + be bound using IPv6 (or in dual mode, using QHostAddress::Any). You must use + QHostAddress::AnyIPv4 instead. + This function returns true if successful; otherwise it returns false and sets the socket error accordingly. diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index aa25215755..b5374d13cd 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -53,6 +53,9 @@ #if defined(Q_OS_UNIX) #include <QtCore/qdir.h> #endif +#ifdef Q_OS_LINUX +#include <link.h> +#endif QT_BEGIN_NAMESPACE @@ -347,6 +350,23 @@ static bool libGreaterThan(const QString &lhs, const QString &rhs) return true; } +#ifdef Q_OS_LINUX +static int dlIterateCallback(struct dl_phdr_info *info, size_t size, void *data) +{ + if (size < sizeof (info->dlpi_addr) + sizeof (info->dlpi_name)) + return 1; + QSet<QString> *paths = (QSet<QString> *)data; + QString path = QString::fromLocal8Bit(info->dlpi_name); + if (!path.isEmpty()) { + QFileInfo fi(path); + path = fi.absolutePath(); + if (!path.isEmpty()) + paths->insert(path); + } + return 0; +} +#endif + static QStringList findAllLibSsl() { QStringList paths; @@ -358,6 +378,12 @@ static QStringList findAllLibSsl() .split(QLatin1Char(':'), QString::SkipEmptyParts); # endif paths << QLatin1String("/lib") << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib"); +#ifdef Q_OS_LINUX + // discover paths of already loaded libraries + QSet<QString> loadedPaths; + dl_iterate_phdr(dlIterateCallback, &loadedPaths); + paths.append(loadedPaths.toList()); +#endif QStringList foundSsls; foreach (const QString &path, paths) { |