From 338da730e8bc23e227e26b094cba6bb6233c42de Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 25 Oct 2013 10:56:01 +0200 Subject: network: fix multi-phased NTLM authentication tested manually with internal NTLM proxy. Patch-by: Jonathan Lauvernier Change-Id: Ib3ed7aff12cb8d59ffc2b11ecc1c4fdc04acb368 Reviewed-by: Richard J. Moore --- src/network/kernel/qauthenticator.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/network') diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index e1a24a226f..8c16486878 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -189,7 +189,7 @@ QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other) d->realm = other.d->realm; d->method = other.d->method; d->options = other.d->options; - } else { + } else if (d->phase == QAuthenticatorPrivate::Start) { delete d; d = 0; } @@ -267,7 +267,8 @@ void QAuthenticator::detach() return; } - d->phase = QAuthenticatorPrivate::Start; + if (d->phase == QAuthenticatorPrivate::Done) + d->phase = QAuthenticatorPrivate::Start; } /*! -- cgit v1.2.3 From 0d7d5ff5d050537e33bc35d56c5214063821a1a4 Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Tue, 29 Oct 2013 00:07:56 +0800 Subject: Doc: Fix miscellaneous typos Change-Id: Iaf0dd8974c3ad78beffa995c596a76fb3e4cceab Reviewed-by: Jerome Pasion Reviewed-by: Kurt Pattyn --- src/network/bearer/qnetworkconfiguration.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/network') diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp index 8d34db19cd..a66b39f733 100644 --- a/src/network/bearer/qnetworkconfiguration.cpp +++ b/src/network/bearer/qnetworkconfiguration.cpp @@ -591,7 +591,6 @@ QNetworkConfiguration::BearerType QNetworkConfiguration::bearerTypeFamily() cons \li Value \row \li BearerUnknown - \li \li The session is based on an unknown or unspecified bearer type. The value of the string returned describes the bearer type. \row -- cgit v1.2.3 From 3655d71719a4746938f364bfe0d82c1609c3eacb Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 18 Jul 2013 18:20:42 +0200 Subject: Fix the network proxy code for windows to detect properly services This patch makes it so even sub processes of services are also detected to be running in the context of a service. With the previous code it would only detect that the current process is a service and not the sub processes. This fix makes sure we detect properly if the current process is running in the context of a service. This is important to detect properly the proxy configuration of the current user. Change-Id: I110dee62597aec3f8e2f6925166a428f72d14fd0 Reviewed-by: Joerg Bornemann Reviewed-by: Friedemann Kleint --- src/network/kernel/qnetworkproxy_win.cpp | 52 ++++++++++++-------------------- 1 file changed, 20 insertions(+), 32 deletions(-) (limited to 'src/network') diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp index f1893ae322..e16d7e557e 100644 --- a/src/network/kernel/qnetworkproxy_win.cpp +++ b/src/network/kernel/qnetworkproxy_win.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include "qnetworkfunctions_wince.h" /* @@ -115,48 +116,38 @@ 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; +#ifndef Q_OS_WINCE 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(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; + typedef BOOL (WINAPI *PtrGetUserName)(LPTSTR lpBuffer, LPDWORD lpnSize); + typedef BOOL (WINAPI *PtrLookupAccountName)(LPCTSTR lpSystemName, LPCTSTR lpAccountName, PSID Sid, + LPDWORD cbSid, LPTSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); + static PtrGetUserName ptrGetUserName = (PtrGetUserName)QSystemLibrary::resolve(QLatin1String("Advapi32"), "GetUserNameW"); + static PtrLookupAccountName ptrLookupAccountName = (PtrLookupAccountName)QSystemLibrary::resolve(QLatin1String("Advapi32"), "LookupAccountNameW"); + + if (ptrGetUserName && ptrLookupAccountName) { + wchar_t userName[UNLEN + 1] = L""; + DWORD size = UNLEN; + if (ptrGetUserName(userName, &size)) { + SID_NAME_USE type = SidTypeUser; + DWORD dummy = MAX_PATH; + wchar_t dummyStr[MAX_PATH] = L""; + PSID psid = 0; + if (ptrLookupAccountName(NULL, userName, &psid, &dummy, dummyStr, &dummy, &type)) + return type != SidTypeUser; //returns true if the current user is not a user } } - - ptrCloseServiceHandle(hSCM); - free(info); - return foundService; + return false; } +#endif // ! Q_OS_WINCE static QStringList splitSpaceSemicolon(const QString &source) { @@ -418,9 +409,6 @@ 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; -- cgit v1.2.3 From e469e667e39d638d3c4649b9793ee3eefe3c5784 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 31 Oct 2013 12:43:38 +0100 Subject: use the right scope "windows" only worked more or less by accident (it's the opposite of "console" and just happens to be the default on windows). Change-Id: Ib60c8ae5aea04f28207c05cc0005183dd6eb6244 Reviewed-by: Joerg Bornemann Reviewed-by: Thiago Macieira --- src/network/ssl/ssl.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/network') diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 0fe231357b..afb1df5aa4 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -45,5 +45,5 @@ android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp QMAKE_CXXFLAGS += $$OPENSSL_CFLAGS LIBS_PRIVATE += $$OPENSSL_LIBS - windows:LIBS += -lcrypt32 + win32: LIBS += -lcrypt32 } -- cgit v1.2.3 From 43684a20d044de6d4daac750809750777b68c9e5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 31 Oct 2013 13:34:10 +0100 Subject: use private linkage where possible Change-Id: Ie8eaa71bee87654c21218a23efd7e9d65b71f022 Reviewed-by: Joerg Bornemann Reviewed-by: Thiago Macieira --- src/network/kernel/kernel.pri | 2 +- src/network/socket/socket.pri | 2 +- src/network/ssl/ssl.pri | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/network') diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index a4a19988b3..97f52fdb6e 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -35,7 +35,7 @@ android { win32: { HEADERS += kernel/qnetworkinterface_win_p.h SOURCES += kernel/qdnslookup_win.cpp kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp - LIBS += -ldnsapi + LIBS_PRIVATE += -ldnsapi } integrity:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index 0204a92999..c0c6d750d9 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -40,7 +40,7 @@ win32:SOURCES += socket/qnativesocketengine_win.cpp \ socket/qlocalsocket_win.cpp \ socket/qlocalserver_win.cpp -win32:!wince*:LIBS += -ladvapi32 +win32:!wince*: LIBS_PRIVATE += -ladvapi32 wince*: { SOURCES -= socket/qlocalsocket_win.cpp \ diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index afb1df5aa4..eb8268515e 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -45,5 +45,5 @@ android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp QMAKE_CXXFLAGS += $$OPENSSL_CFLAGS LIBS_PRIVATE += $$OPENSSL_LIBS - win32: LIBS += -lcrypt32 + win32: LIBS_PRIVATE += -lcrypt32 } -- cgit v1.2.3 From 5c389cecd07a4659670e3fefa34d717762dc3af1 Mon Sep 17 00:00:00 2001 From: Jerome Pasion Date: Tue, 5 Nov 2013 13:03:33 +0100 Subject: Doc: Updated url variable in qdocconf files. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 5.2, the HTML output is in a flatter structure and when they are hosted in qt-project.org/doc, the documentation will be found at http://qt-project.org/doc/qt-$QT_VER The url variable is used by projects outside of Qt 5 which need to link to Qt 5 documentation, such as Qt Creator. Task-number: QTBUG-34584 Change-Id: Ifa55fcd9e402b0e184a41e316340e46aeb7101de Reviewed-by: Topi Reiniö Reviewed-by: Leena Miettinen --- src/network/doc/qtnetwork.qdocconf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/network') diff --git a/src/network/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf index f4779ae8fe..33d6c24461 100644 --- a/src/network/doc/qtnetwork.qdocconf +++ b/src/network/doc/qtnetwork.qdocconf @@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) project = QtNetwork description = Qt Network Reference Documentation -url = http://qt-project.org/doc/qt-$QT_VER/qtnetwork +url = http://qt-project.org/doc/qt-$QT_VER version = $QT_VERSION examplesinstallpath = network -- cgit v1.2.3 From fbcad545ce857923c709785cbb44f50c0a4f034c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sat, 26 Oct 2013 13:51:17 +0200 Subject: NSUrlConnection backend for QNetworkAccessManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for QNetworkAccessManager https REST on iOS, without adding a dependency on OpenSSL. The current limitations are: - Overriding server certificate trust issues (for example expired certificates) is not supported. - Usage on non-gui threads is not supported. NSurlConnection needs a CoreFoundation-based event loop, which Qt currently only provides when using QGuiApplication on the main thread. Change-Id: Ic6f74591d40c3b2248ab81db12647e432377cd4f Reviewed-by: Tor Arne Vestbø --- src/network/access/access.pri | 12 +- src/network/access/qnetworkaccessmanager.cpp | 10 + .../access/qnetworkreplynsurlconnectionimpl.mm | 449 +++++++++++++++++++++ .../access/qnetworkreplynsurlconnectionimpl_p.h | 89 ++++ 4 files changed, 558 insertions(+), 2 deletions(-) create mode 100644 src/network/access/qnetworkreplynsurlconnectionimpl.mm create mode 100644 src/network/access/qnetworkreplynsurlconnectionimpl_p.h (limited to 'src/network') diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 590a37bf15..aaaf05b551 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -64,6 +64,14 @@ SOURCES += \ access/qhttpthreaddelegate.cpp \ access/qhttpmultipart.cpp -include($$PWD/../../3rdparty/zlib_dependency.pri) +mac: LIBS_PRIVATE += -framework Security + +ios { + HEADERS += \ + access/qnetworkreplynsurlconnectionimpl_p.h -mac:LIBS_PRIVATE += -framework Security + OBJECTIVE_SOURCES += \ + access/qnetworkreplynsurlconnectionimpl.mm +} + +include($$PWD/../../3rdparty/zlib_dependency.pri) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 101e1a8c25..980b19b7e4 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -58,6 +58,10 @@ #include "qnetworkreplydataimpl_p.h" #include "qnetworkreplyfileimpl_p.h" +#if defined(Q_OS_IOS) && defined(QT_NO_SSL) +#include "qnetworkreplynsurlconnectionimpl_p.h" +#endif + #include "QtCore/qbuffer.h" #include "QtCore/qurl.h" #include "QtCore/qvector.h" @@ -1159,6 +1163,12 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera } } +// Use NSURLConnection for https on iOS when OpenSSL is disabled. +#if defined(Q_OS_IOS) && defined(QT_NO_SSL) + if (scheme == QLatin1String("https")) + return new QNetworkReplyNSURLConnectionImpl(this, request, op, outgoingData); +#endif + #ifndef QT_NO_HTTP // Since Qt 5 we use the new QNetworkReplyHttpImpl if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http") diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl.mm b/src/network/access/qnetworkreplynsurlconnectionimpl.mm new file mode 100644 index 0000000000..293a505912 --- /dev/null +++ b/src/network/access/qnetworkreplynsurlconnectionimpl.mm @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkreplynsurlconnectionimpl_p.h" + +#include "QtCore/qdatetime.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Network reply implementation using NSUrlConnection. +// +// Class/object structure: +// +// QNetworkReplyNSURLConnectionImpl +// |- QNetworkReplyNSURLConnectionImplPrivate +// |- (bytes read) +// |- (QIODevice and CFStream for async POST data transfer) +// |- NSURLConnection +// |- QtNSURLConnectionDelegate +// |- NSURLResponse/NSHTTPURLResponse +// |- (response data) +// +// The main entry point is the QNetworkReplyNSURLConnectionImpl constructor, which +// receives a network request from QNetworkAccessManager. The constructor +// creates a NSURLRequest and initiates a NSURLConnection with a QtNSURLConnectionDelegate. +// The delegate callbacks are then called asynchronously as the request completes. +// + +@class QtNSURLConnectionDelegate; +class QNetworkReplyNSURLConnectionImplPrivate: public QNetworkReplyPrivate +{ +public: + QNetworkReplyNSURLConnectionImplPrivate(); + virtual ~QNetworkReplyNSURLConnectionImplPrivate(); + + Q_DECLARE_PUBLIC(QNetworkReplyNSURLConnectionImpl) + NSURLConnection * urlConnection; + QtNSURLConnectionDelegate *urlConnectionDelegate; + qint64 bytesRead; + + // Sequental outgiong data streaming + QIODevice *outgoingData; + CFReadStreamRef readStream; + CFWriteStreamRef writeStream; + CFIndex transferBufferSize; + + // Forwarding functions to the public class. + void setFinished(); + void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value); + void setRawHeader(const QByteArray &headerName, const QByteArray &value); + void setError(QNetworkReply::NetworkError errorCode, const QString &errorString); +}; + +@interface QtNSURLConnectionDelegate : NSObject +{ + NSURLResponse *response; + NSMutableData *responseData; + QNetworkReplyNSURLConnectionImplPrivate * replyprivate; +} + +- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate ; +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_3_0) +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; +#endif +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError*)error; +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response; +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data; +- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; +- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse; +- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse; +- (void)connectionDidFinishLoading:(NSURLConnection*)connection; +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection; + +@end + +QNetworkReplyNSURLConnectionImplPrivate::QNetworkReplyNSURLConnectionImplPrivate() + : QNetworkReplyPrivate() + , urlConnection(0) + , urlConnectionDelegate(0) + , bytesRead(0) + , readStream(0) + , writeStream(0) + , transferBufferSize(4096) +{ +} + +QNetworkReplyNSURLConnectionImplPrivate::~QNetworkReplyNSURLConnectionImplPrivate() +{ + [urlConnection release]; + [urlConnectionDelegate release]; + if (readStream) + CFRelease(readStream); + if (writeStream) + CFRelease(writeStream); +} + +void QNetworkReplyNSURLConnectionImplPrivate::setFinished() +{ + q_func()->setFinished(true); +} + +void QNetworkReplyNSURLConnectionImplPrivate::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) +{ + q_func()->setHeader(header, value); +} + +void QNetworkReplyNSURLConnectionImplPrivate::setRawHeader(const QByteArray &headerName, const QByteArray &value) +{ + q_func()->setRawHeader(headerName, value); +} + +void QNetworkReplyNSURLConnectionImplPrivate::setError(QNetworkReply::NetworkError errorCode, const QString &errorString) +{ + q_func()->setError(errorCode, errorString); +} + +void QNetworkReplyNSURLConnectionImpl::readyReadOutgoingData() +{ + Q_D(QNetworkReplyNSURLConnectionImpl); + int bytesRead = 0; + do { + char data[d->transferBufferSize]; + bytesRead = d->outgoingData->read(data, d->transferBufferSize); + if (bytesRead <= 0) + break; + CFIndex bytesWritten = CFWriteStreamWrite(d->writeStream, reinterpret_cast(data), bytesRead); + if (bytesWritten != bytesRead) { + CFErrorRef err = CFWriteStreamCopyError(d->writeStream); + qWarning() << "QNetworkReplyNSURLConnectionImpl: CFWriteStreamWrite error" + << (err ? QString::number(CFErrorGetCode(err)) : QStringLiteral("")); + } + } while (bytesRead > 0); + + if (d->outgoingData->atEnd()) + CFWriteStreamClose(d->writeStream); +} + +@interface QtNSURLConnectionDelegate () + +@property (nonatomic, retain) NSURLResponse* response; +@property (nonatomic, retain) NSMutableData* responseData; + +@end + +@implementation QtNSURLConnectionDelegate + +@synthesize response; +@synthesize responseData; + +- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate +{ + if (self = [super init]) + replyprivate = a_replyPrivate; + return self; +} + +- (void)dealloc +{ + [response release]; + [responseData release]; + [super dealloc]; +} + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_3_0) +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + Q_UNUSED(connection) + Q_UNUSED(challenge) + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + SecTrustResultType resultType; + SecTrustEvaluate(serverTrust, &resultType); + if (resultType == kSecTrustResultUnspecified) { + // All good + [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; + } else if (resultType == kSecTrustResultRecoverableTrustFailure) { + // Certificate verification error, ask user + // ### TODO actually ask user + // (test site: https://testssl-expire.disig.sk/index.en.html) + qWarning() << "QNetworkReplyNSURLConnection: Certificate verification error handlig is" + << "not implemented. Connection will time out."; + } else { + // other error, which the default handler will handle + [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; + } + } + + [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; +} +#endif + +- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error +{ + Q_UNUSED(connection) + + QNetworkReply::NetworkError qtError = QNetworkReply::UnknownNetworkError; + if ([error domain] == NSURLErrorDomain) { + switch ([error code]) { + case NSURLErrorTimedOut: qtError = QNetworkReply::TimeoutError; break; + case NSURLErrorUnsupportedURL: qtError = QNetworkReply::ProtocolUnknownError; break; + case NSURLErrorCannotFindHost: qtError = QNetworkReply::HostNotFoundError; break; + case NSURLErrorCannotConnectToHost: qtError = QNetworkReply::ConnectionRefusedError; break; + case NSURLErrorNetworkConnectionLost: qtError = QNetworkReply::NetworkSessionFailedError; break; + case NSURLErrorDNSLookupFailed: qtError = QNetworkReply::HostNotFoundError; break; + case NSURLErrorNotConnectedToInternet: qtError = QNetworkReply::NetworkSessionFailedError; break; + case NSURLErrorUserAuthenticationRequired: qtError = QNetworkReply::AuthenticationRequiredError; break; + default: break; + } + } + + replyprivate->setError(qtError, QString::fromNSString([error localizedDescription])); +} + +- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)aResponse +{ + Q_UNUSED(connection) + self.response = aResponse; + self.responseData = [NSMutableData data]; + + // copy headers + if ([aResponse isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)aResponse; + NSDictionary *headers = [httpResponse allHeaderFields]; + for (NSString *key in headers) { + NSString *value = [headers objectForKey:key]; + replyprivate->setRawHeader(QString::fromNSString(key).toUtf8(), QString::fromNSString(value).toUtf8()); + } + } else { + if ([aResponse expectedContentLength] != NSURLResponseUnknownLength) + replyprivate->setHeader(QNetworkRequest::ContentLengthHeader, [aResponse expectedContentLength]); + } + + QMetaObject::invokeMethod(replyprivate->q_func(), "metaDataChanged", Qt::QueuedConnection); +} + +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data +{ + Q_UNUSED(connection) + [responseData appendData:data]; + + if ([response expectedContentLength] != NSURLResponseUnknownLength) { + QMetaObject::invokeMethod(replyprivate->q_func(), "downloadProgress", Qt::QueuedConnection, + Q_ARG(qint64, qint64([responseData length])), + Q_ARG(qint64, qint64([response expectedContentLength]))); + } + + QMetaObject::invokeMethod(replyprivate->q_func(), "readyRead", Qt::QueuedConnection); +} + +- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten + totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +{ + Q_UNUSED(connection) + Q_UNUSED(bytesWritten) + QMetaObject::invokeMethod(replyprivate->q_func(), "uploadProgress", Qt::QueuedConnection, + Q_ARG(qint64, qint64(totalBytesWritten)), + Q_ARG(qint64, qint64(totalBytesExpectedToWrite))); +} + +- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse +{ + Q_UNUSED(connection) + return cachedResponse; +} + +- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse +{ + Q_UNUSED(connection) + Q_UNUSED(redirectResponse) + return request; +} + +- (void)connectionDidFinishLoading:(NSURLConnection*)connection +{ + Q_UNUSED(connection) + replyprivate->setFinished(); + QMetaObject::invokeMethod(replyprivate->q_func(), "finished", Qt::QueuedConnection); +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection +{ + Q_UNUSED(connection) + return YES; +} + +@end + +QNetworkReplyNSURLConnectionImpl::~QNetworkReplyNSURLConnectionImpl() +{ +} + +QNetworkReplyNSURLConnectionImpl::QNetworkReplyNSURLConnectionImpl(QObject *parent, + const QNetworkRequest &request, const QNetworkAccessManager::Operation operation, QIODevice* outgoingData) + : QNetworkReply(*new QNetworkReplyNSURLConnectionImplPrivate(), parent) +{ + setRequest(request); + setUrl(request.url()); + setOperation(operation); + QNetworkReply::open(QIODevice::ReadOnly); + + QNetworkReplyNSURLConnectionImplPrivate *d = (QNetworkReplyNSURLConnectionImplPrivate*) d_func(); + + QUrl url = request.url(); + if (url.host() == QLatin1String("localhost")) + url.setHost(QString()); + + if (url.path().isEmpty()) + url.setPath(QLatin1String("/")); + setUrl(url); + + // Create a NSMutableURLRequest from QNetworkRequest + NSMutableURLRequest *nsRequest = [NSMutableURLRequest requestWithURL:request.url().toNSURL() + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:60.0]; + // copy headers + foreach (const QByteArray &header, request.rawHeaderList()) { + QByteArray headerValue = request.rawHeader(header); + [nsRequest addValue:QString::fromUtf8(headerValue).toNSString() + forHTTPHeaderField:QString::fromUtf8(header).toNSString()]; + } + + if (operation == QNetworkAccessManager::GetOperation) + [nsRequest setHTTPMethod:@"GET"]; + else if (operation == QNetworkAccessManager::PostOperation) + [nsRequest setHTTPMethod:@"POST"]; + else if (operation == QNetworkAccessManager::PutOperation) + [nsRequest setHTTPMethod:@"PUT"]; + else if (operation == QNetworkAccessManager::DeleteOperation) + [nsRequest setHTTPMethod:@"DELETE"]; + else + qWarning() << "QNetworkReplyNSURLConnection: Unsupported netork operation" << operation; + + if (outgoingData) { + d->outgoingData = outgoingData; + if (outgoingData->isSequential()) { + // set up streaming from outgoingData iodevice to request + CFStreamCreateBoundPair(kCFAllocatorDefault, &d->readStream, &d->writeStream, d->transferBufferSize); + CFWriteStreamOpen(d->writeStream); + [nsRequest setHTTPBodyStream:reinterpret_cast(d->readStream)]; + connect(outgoingData, SIGNAL(readyRead()), this, SLOT(readyReadOutgoingData())); + readyReadOutgoingData(); + } else { + // move all data at once + QByteArray data = outgoingData->readAll(); + [nsRequest setHTTPBody:[NSData dataWithBytes:data.constData() length:data.length()]]; + } + } + + // Create connection + d->urlConnectionDelegate = [[QtNSURLConnectionDelegate alloc] initWithQNetworkReplyNSURLConnectionImplPrivate:d]; + d->urlConnection = [[NSURLConnection alloc] initWithRequest:nsRequest delegate:d->urlConnectionDelegate]; + if (!d->urlConnection) { + // ### what type of error is an initWithRequest fail? + setError(QNetworkReply::ProtocolUnknownError, QStringLiteral("QNetworkReplyNSURLConnection internal error")); + } +} + +void QNetworkReplyNSURLConnectionImpl::close() +{ + // No-op? Network ops should continue (especially POSTs) + QNetworkReply::close(); +} + +void QNetworkReplyNSURLConnectionImpl::abort() +{ + Q_D(QNetworkReplyNSURLConnectionImpl); + [d->urlConnection cancel]; + QNetworkReply::close(); +} + +qint64 QNetworkReplyNSURLConnectionImpl::bytesAvailable() const +{ + Q_D(const QNetworkReplyNSURLConnectionImpl); + qint64 available = QNetworkReply::bytesAvailable() + + [[d->urlConnectionDelegate responseData] length] - + d->bytesRead; + + return available; +} + +bool QNetworkReplyNSURLConnectionImpl::isSequential() const +{ + return true; +} + +qint64 QNetworkReplyNSURLConnectionImpl::size() const +{ + Q_D(const QNetworkReplyNSURLConnectionImpl); + return [[d->urlConnectionDelegate responseData] length]; +} + +/*! + \internal +*/ +qint64 QNetworkReplyNSURLConnectionImpl::readData(char *data, qint64 maxlen) +{ + Q_D(QNetworkReplyNSURLConnectionImpl); + qint64 dataSize = [[d->urlConnectionDelegate responseData] length]; + qint64 canRead = qMin(maxlen, dataSize - d->bytesRead); + const char *sourceBase = static_cast([[d->urlConnectionDelegate responseData] bytes]); + memcpy(data, sourceBase + d->bytesRead, canRead); + d->bytesRead += canRead; + return canRead; +} + +QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl_p.h b/src/network/access/qnetworkreplynsurlconnectionimpl_p.h new file mode 100644 index 0000000000..967eb13246 --- /dev/null +++ b/src/network/access/qnetworkreplynsurlconnectionimpl_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETWORKREPLYNSURLCONNECTIONIMPL_H +#define QNETWORKREPLYNSURLCONNECTIONIMPL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Network Access API. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qnetworkreply.h" +#include "qnetworkreply_p.h" +#include "qnetworkaccessmanager.h" +#include +#include + +QT_BEGIN_NAMESPACE + + +class QNetworkReplyNSURLConnectionImplPrivate; +class QNetworkReplyNSURLConnectionImpl: public QNetworkReply +{ + Q_OBJECT +public: + QNetworkReplyNSURLConnectionImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op, QIODevice* outgoingData); + virtual ~QNetworkReplyNSURLConnectionImpl(); + virtual void abort(); + + // reimplemented from QNetworkReply + virtual void close(); + virtual qint64 bytesAvailable() const; + virtual bool isSequential () const; + qint64 size() const; + + virtual qint64 readData(char *data, qint64 maxlen); +public Q_SLOTS: + void readyReadOutgoingData(); + + Q_DECLARE_PRIVATE(QNetworkReplyNSURLConnectionImpl) +}; + +QT_END_NAMESPACE + +#endif // QNetworkReplyNSURLConnectionImpl_H -- cgit v1.2.3 From becdfa6fabb80d35e430a13835f01a6ff3f6cc73 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 6 Nov 2013 22:44:38 +0100 Subject: QSslConfiguration: rename [get]session() to [get]sessionTicket() to reflect the fact that this returns and sets the whole session ticket, and not just the session ID. Change-Id: I00fe2bc4197dbcd7a02b3ae4f2f84e3a2a7edad0 Reviewed-by: Richard J. Moore --- src/network/ssl/qssl.cpp | 2 +- src/network/ssl/qsslconfiguration.cpp | 24 ++++++++++++------------ src/network/ssl/qsslconfiguration.h | 4 ++-- src/network/ssl/qsslcontext.cpp | 4 ++-- src/network/ssl/qsslsocket.cpp | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/network') diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index ec771e1f49..5b7274e3e6 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -164,7 +164,7 @@ QT_BEGIN_NAMESPACE \value SslOptionDisableSessionSharing Disables SSL session sharing via the session ID handshake attribute. \value SslOptionDisableSessionPersistence Disables storing the SSL session - in ASN.1 format as returned by QSslConfiguration::session(). Enabling + in ASN.1 format as returned by QSslConfiguration::sessionTicket(). Enabling this feature adds memory overhead of approximately 1K per used session ticket. diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 8979c48d5d..4aad7c04c5 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -602,19 +602,19 @@ bool QSslConfiguration::testSslOption(QSsl::SslOption option) const \since 5.2 If QSsl::SslOptionDisableSessionPersistence was turned off, this - function returns the session used in the SSL handshake in ASN.1 - format, suitable to e.g. be persisted to disk. If no session was + function returns the session ticket used in the SSL handshake in ASN.1 + format, suitable to e.g. be persisted to disk. If no session ticket was used or QSsl::SslOptionDisableSessionPersistence was not turned off, this function returns an empty QByteArray. - \b{Note:} When persisting the session to disk or similar, be + \b{Note:} When persisting the session ticket to disk or similar, be careful not to expose the session to a potential attacker, as knowledge of the session allows for eavesdropping on data encrypted with the session parameters. - \sa setSession(), QSsl::SslOptionDisableSessionPersistence, setSslOption() + \sa setSessionTicket(), QSsl::SslOptionDisableSessionPersistence, setSslOption() */ -QByteArray QSslConfiguration::session() const +QByteArray QSslConfiguration::sessionTicket() const { return d->sslSession; } @@ -622,16 +622,16 @@ QByteArray QSslConfiguration::session() const /*! \since 5.2 - Sets the session to be used in an SSL handshake. + Sets the session ticket to be used in an SSL handshake. QSsl::SslOptionDisableSessionPersistence must be turned off - for this to work, and \a session must be in ASN.1 format - as returned by session(). + for this to work, and \a sessionTicket must be in ASN.1 format + as returned by sessionTicket(). - \sa session(), QSsl::SslOptionDisableSessionPersistence, setSslOption() + \sa sessionTicket(), QSsl::SslOptionDisableSessionPersistence, setSslOption() */ -void QSslConfiguration::setSession(const QByteArray &session) +void QSslConfiguration::setSessionTicket(const QByteArray &sessionTicket) { - d->sslSession = session; + d->sslSession = sessionTicket; } /*! @@ -645,7 +645,7 @@ void QSslConfiguration::setSession(const QByteArray &session) QSsl::SslOptionDisableSessionPersistence was not turned off, this function returns -1. - \sa session(), QSsl::SslOptionDisableSessionPersistence, setSslOption() + \sa sessionTicket(), QSsl::SslOptionDisableSessionPersistence, setSslOption() */ int QSslConfiguration::sessionTicketLifeTimeHint() const { diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 949ce70d4c..a48eceb63e 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -124,8 +124,8 @@ public: void setSslOption(QSsl::SslOption option, bool on); bool testSslOption(QSsl::SslOption option) const; - QByteArray session() const; - void setSession(const QByteArray &session); + QByteArray sessionTicket() const; + void setSessionTicket(const QByteArray &sessionTicket); int sessionTicketLifeTimeHint() const; static QSslConfiguration defaultConfiguration(); diff --git a/src/network/ssl/qsslcontext.cpp b/src/network/ssl/qsslcontext.cpp index 6d281c390d..037ee8c672 100644 --- a/src/network/ssl/qsslcontext.cpp +++ b/src/network/ssl/qsslcontext.cpp @@ -260,8 +260,8 @@ init_context: q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth()); // set persisted session if the user set it - if (!configuration.session().isEmpty()) - sslContext->setSessionASN1(configuration.session()); + if (!configuration.sessionTicket().isEmpty()) + sslContext->setSessionASN1(configuration.sessionTicket()); return sslContext; } diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 24843e9f92..38b493a769 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -903,7 +903,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.peerVerifyMode = configuration.peerVerifyMode(); d->configuration.protocol = configuration.protocol(); d->configuration.sslOptions = configuration.d->sslOptions; - d->configuration.sslSession = configuration.session(); + d->configuration.sslSession = configuration.sessionTicket(); d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint(); // if the CA certificates were set explicitly (either via -- cgit v1.2.3