From 90520cd834d84f2b091fea94f1d44bc6cb863420 Mon Sep 17 00:00:00 2001 From: Aron Rosenberg Date: Wed, 4 Apr 2012 16:41:27 -0700 Subject: Automatically query for Mac Proxy Server credentials Add support for automatically searching the Mac System Preferences for proxy server username/password. If a user has put credentials in the SystemPreferences->Network->Interface->Proxies area, we will now look in the KeyChain for those files. This will automatically pop up a Permissions dialog from the OS if valid credentials were found which match the server we are trying to access. Task-Number: QTBUG-22033 Change-Id: Ic7952afab4d16a65a87bb2f97a928c1c91167fe7 Reviewed-by: Shane Kearns --- src/network/access/access.pri | 2 + src/network/access/qnetworkaccessmanager.cpp | 70 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'src/network/access') diff --git a/src/network/access/access.pri b/src/network/access/access.pri index e0a0253b6c..590a37bf15 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -65,3 +65,5 @@ SOURCES += \ access/qhttpmultipart.cpp include($$PWD/../../3rdparty/zlib_dependency.pri) + +mac:LIBS_PRIVATE += -framework Security diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 397bb0535e..3a69ec4056 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -82,6 +82,64 @@ Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend) Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend) #endif +#ifdef Q_OS_MAC + +#include +#include +#include + +bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password) +{ + OSStatus err; + SecKeychainItemRef itemRef; + bool retValue = false; + SecProtocolType protocolType = kSecProtocolTypeAny; + if (scheme.compare(QLatin1String("ftp"),Qt::CaseInsensitive)==0) { + protocolType = kSecProtocolTypeFTP; + } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0) { + protocolType = kSecProtocolTypeHTTP; + } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0) { + protocolType = kSecProtocolTypeHTTPS; + } + QByteArray proxyHostnameUtf8(proxyHostname.toUtf8()); + err = SecKeychainFindInternetPassword(NULL, + proxyHostnameUtf8.length(), proxyHostnameUtf8.constData(), + 0,NULL, + 0, NULL, + 0, NULL, + 0, + protocolType, + kSecAuthenticationTypeAny, + 0, NULL, + &itemRef); + if (err == noErr) { + + SecKeychainAttribute attr; + SecKeychainAttributeList attrList; + UInt32 length; + void *outData; + + attr.tag = kSecAccountItemAttr; + attr.length = 0; + attr.data = NULL; + + attrList.count = 1; + attrList.attr = &attr; + + if (SecKeychainItemCopyContent(itemRef, NULL, &attrList, &length, &outData) == noErr) { + username = QString::fromUtf8((const char*)attr.data, attr.length); + password = QString::fromUtf8((const char*)outData, length); + SecKeychainItemFreeContent(&attrList,outData); + retValue = true; + } + CFRelease(itemRef); + } + return retValue; +} +#endif + + + static void ensureInitialized() { #ifndef QT_NO_FTP @@ -1117,6 +1175,18 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authen return; } } +#ifdef Q_OS_MAC + //now we try to get the username and password from keychain + //if not successful signal will be emitted + QString username; + QString password; + if (getProxyAuth(proxy.hostName(),reply->request().url().scheme(),username,password)) { + authenticator->setUser(username); + authenticator->setPassword(password); + authenticationManager->cacheProxyCredentials(proxy, authenticator); + return; + } +#endif // if we emit a signal here in synchronous mode, the user might spin // an event loop, which might recurse and lead to problems -- cgit v1.2.3 From 3c0fdefc318eeeb019b3727962bea7ba7ea236d2 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 12 Apr 2012 17:28:37 +0100 Subject: Fix autotest failures in QAbstractNetworkCache The cache expiration calculation was previously removed to avoid calculating it every time an object is fetched from the cache. This is because the expiration date is calculated from max-age or expires headers when the object is added to the cache. However this broke the case where the server only provides a last-modified header. In this case, the expiration date needs to be checked at fetch time in order to add the warning if the object is >24h old. Change-Id: Iad381da0f91c27ac603abbaa94f268700ad2297f Reviewed-by: Thiago Macieira --- src/network/access/qnetworkreplyhttpimpl.cpp | 118 ++++++++++++++------------- 1 file changed, 60 insertions(+), 58 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index a914ee3f04..101e1aa222 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -513,69 +513,71 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h QDateTime currentDateTime = QDateTime::currentDateTime(); QDateTime expirationDate = metaData.expirationDate(); -#if 0 - /* - * age_value - * is the value of Age: header received by the cache with - * this response. - * date_value - * is the value of the origin server's Date: header - * request_time - * is the (local) time when the cache made the request - * that resulted in this cached response - * response_time - * is the (local) time when the cache received the - * response - * now - * is the current (local) time - */ - int age_value = 0; - it = cacheHeaders.findRawHeader("age"); - if (it != cacheHeaders.rawHeaders.constEnd()) - age_value = it->second.toInt(); - - QDateTime dateHeader; - int date_value = 0; - it = cacheHeaders.findRawHeader("date"); - if (it != cacheHeaders.rawHeaders.constEnd()) { - dateHeader = QNetworkHeadersPrivate::fromHttpDate(it->second); - date_value = dateHeader.toTime_t(); - } - - int now = currentDateTime.toUTC().toTime_t(); - int request_time = now; - int response_time = now; + bool response_is_fresh; + if (!expirationDate.isValid()) { + /* + * age_value + * is the value of Age: header received by the cache with + * this response. + * date_value + * is the value of the origin server's Date: header + * request_time + * is the (local) time when the cache made the request + * that resulted in this cached response + * response_time + * is the (local) time when the cache received the + * response + * now + * is the current (local) time + */ + int age_value = 0; + it = cacheHeaders.findRawHeader("age"); + if (it != cacheHeaders.rawHeaders.constEnd()) + age_value = it->second.toInt(); - // Algorithm from RFC 2616 section 13.2.3 - int apparent_age = qMax(0, response_time - date_value); - int corrected_received_age = qMax(apparent_age, age_value); - int response_delay = response_time - request_time; - int corrected_initial_age = corrected_received_age + response_delay; - int resident_time = now - response_time; - int current_age = corrected_initial_age + resident_time; + QDateTime dateHeader; + int date_value = 0; + it = cacheHeaders.findRawHeader("date"); + if (it != cacheHeaders.rawHeaders.constEnd()) { + dateHeader = QNetworkHeadersPrivate::fromHttpDate(it->second); + date_value = dateHeader.toTime_t(); + } - // RFC 2616 13.2.4 Expiration Calculations - if (!expirationDate.isValid()) { - if (lastModified.isValid()) { - int diff = currentDateTime.secsTo(lastModified); - expirationDate = lastModified; - expirationDate.addSecs(diff / 10); - if (httpRequest.headerField("Warning").isEmpty()) { - QDateTime dt; - dt.setTime_t(current_age); - if (dt.daysTo(currentDateTime) > 1) - httpRequest.setHeaderField("Warning", "113"); + int now = currentDateTime.toUTC().toTime_t(); + int request_time = now; + int response_time = now; + + // Algorithm from RFC 2616 section 13.2.3 + int apparent_age = qMax(0, response_time - date_value); + int corrected_received_age = qMax(apparent_age, age_value); + int response_delay = response_time - request_time; + int corrected_initial_age = corrected_received_age + response_delay; + int resident_time = now - response_time; + int current_age = corrected_initial_age + resident_time; + + // RFC 2616 13.2.4 Expiration Calculations + if (!expirationDate.isValid()) { + if (lastModified.isValid()) { + int diff = currentDateTime.secsTo(lastModified); + expirationDate = lastModified; + expirationDate.addSecs(diff / 10); + if (httpRequest.headerField("Warning").isEmpty()) { + QDateTime dt; + dt.setTime_t(current_age); + if (dt.daysTo(currentDateTime) > 1) + httpRequest.setHeaderField("Warning", "113"); + } } } - } - // the cache-saving code below sets the expirationDate with date+max_age - // if "max-age" is present, or to Expires otherwise - int freshness_lifetime = dateHeader.secsTo(expirationDate); - bool response_is_fresh = (freshness_lifetime > current_age); -#else - bool response_is_fresh = currentDateTime.secsTo(expirationDate) >= 0; -#endif + // the cache-saving code below sets the expirationDate with date+max_age + // if "max-age" is present, or to Expires otherwise + int freshness_lifetime = dateHeader.secsTo(expirationDate); + response_is_fresh = (freshness_lifetime > current_age); + } else { + // expiration date was calculated earlier (e.g. when storing object to the cache) + response_is_fresh = currentDateTime.secsTo(expirationDate) >= 0; + } if (!response_is_fresh) return false; -- cgit v1.2.3