src/network/kernel/qnetworkproxy_mac.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtNetwork module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qnetworkproxy.h"
       
    43 
       
    44 #ifndef QT_NO_NETWORKPROXY
       
    45 
       
    46 #include <CoreFoundation/CoreFoundation.h>
       
    47 #include <SystemConfiguration/SystemConfiguration.h>
       
    48 
       
    49 #include <QtCore/QRegExp>
       
    50 #include <QtCore/QStringList>
       
    51 #include <QtCore/qendian.h>
       
    52 #include <QtCore/qstringlist.h>
       
    53 #include "private/qcore_mac_p.h"
       
    54 
       
    55 /*
       
    56  * MacOS X has a proxy configuration module in System Preferences (on
       
    57  * MacOS X 10.5, it's in Network, Advanced), where one can set the
       
    58  * proxy settings for:
       
    59  *
       
    60  * \list
       
    61  *   \o FTP proxy
       
    62  *   \o Web Proxy (HTTP)
       
    63  *   \o Secure Web Proxy (HTTPS)
       
    64  *   \o Streaming Proxy (RTSP)
       
    65  *   \o SOCKS Proxy
       
    66  *   \o Gopher Proxy
       
    67  *   \o URL for Automatic Proxy Configuration (PAC scripts)
       
    68  *   \o Bypass list (by default: *.local, 169.254/16)
       
    69  * \endlist
       
    70  *
       
    71  * The matching configuration can be obtained by calling SCDynamicStoreCopyProxies
       
    72  * (from <SystemConfiguration/SCDynamicStoreCopySpecific.h>). See
       
    73  * Apple's documentation:
       
    74  *
       
    75  * http://developer.apple.com/DOCUMENTATION/Networking/Reference/SysConfig/SCDynamicStoreCopySpecific/CompositePage.html#//apple_ref/c/func/SCDynamicStoreCopyProxies
       
    76  *
       
    77  */
       
    78 
       
    79 QT_BEGIN_NAMESPACE
       
    80 
       
    81 static bool isHostExcluded(CFDictionaryRef dict, const QString &host)
       
    82 {
       
    83     if (host.isEmpty())
       
    84         return true;
       
    85 
       
    86     bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':'));
       
    87     CFNumberRef excludeSimples;
       
    88     if (isSimple &&
       
    89         (excludeSimples = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesExcludeSimpleHostnames))) {
       
    90         int enabled;
       
    91         if (CFNumberGetValue(excludeSimples, kCFNumberIntType, &enabled) && enabled)
       
    92             return true;
       
    93     }
       
    94 
       
    95     QHostAddress ipAddress;
       
    96     bool isIpAddress = ipAddress.setAddress(host);
       
    97 
       
    98     // not a simple host name
       
    99     // does it match the list of exclusions?
       
   100     CFArrayRef exclusionList = (CFArrayRef)CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList);
       
   101     if (!exclusionList)
       
   102         return false;
       
   103 
       
   104     CFIndex size = CFArrayGetCount(exclusionList);
       
   105     for (CFIndex i = 0; i < size; ++i) {
       
   106         CFStringRef cfentry = (CFStringRef)CFArrayGetValueAtIndex(exclusionList, i);
       
   107         QString entry = QCFString::toQString(cfentry);
       
   108 
       
   109         if (isIpAddress && ipAddress.isInSubnet(QHostAddress::parseSubnet(entry))) {
       
   110             return true;        // excluded
       
   111         } else {
       
   112             // do wildcard matching
       
   113             QRegExp rx(entry, Qt::CaseInsensitive, QRegExp::Wildcard);
       
   114             if (rx.exactMatch(host))
       
   115                 return true;
       
   116         }
       
   117     }
       
   118 
       
   119     // host was not excluded
       
   120     return false;
       
   121 }
       
   122 
       
   123 static QNetworkProxy proxyFromDictionary(CFDictionaryRef dict, QNetworkProxy::ProxyType type,
       
   124                                          CFStringRef enableKey, CFStringRef hostKey,
       
   125                                          CFStringRef portKey)
       
   126 {
       
   127     CFNumberRef protoEnabled;
       
   128     CFNumberRef protoPort;
       
   129     CFStringRef protoHost;
       
   130     if (enableKey
       
   131         && (protoEnabled = (CFNumberRef)CFDictionaryGetValue(dict, enableKey))
       
   132         && (protoHost = (CFStringRef)CFDictionaryGetValue(dict, hostKey))
       
   133         && (protoPort = (CFNumberRef)CFDictionaryGetValue(dict, portKey))) {
       
   134         int enabled;
       
   135         if (CFNumberGetValue(protoEnabled, kCFNumberIntType, &enabled) && enabled) {
       
   136             QString host = QCFString::toQString(protoHost);
       
   137 
       
   138             int port;
       
   139             CFNumberGetValue(protoPort, kCFNumberIntType, &port);
       
   140 
       
   141             return QNetworkProxy(type, host, port);
       
   142         }
       
   143     }
       
   144 
       
   145     // proxy not enabled
       
   146     return QNetworkProxy();
       
   147 }
       
   148 
       
   149 QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
       
   150 {
       
   151     QList<QNetworkProxy> result;
       
   152 
       
   153     // obtain a dictionary to the proxy settings:
       
   154     CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
       
   155     if (!dict) {
       
   156         qWarning("QNetworkProxyFactory::systemProxyForQuery: SCDynamicStoreCopyProxies returned NULL");
       
   157         return result;          // failed
       
   158     }
       
   159 
       
   160     if (isHostExcluded(dict, query.peerHostName()))
       
   161         return result;          // no proxy for this host
       
   162 
       
   163     // is there a PAC enabled? If so, use it first.
       
   164     CFNumberRef pacEnabled;
       
   165     if ((pacEnabled = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigEnable))) {
       
   166         int enabled;
       
   167         if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
       
   168             // PAC is enabled
       
   169             CFStringRef pacUrl =
       
   170                 (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
       
   171             QString url = QCFString::toQString(pacUrl);
       
   172 
       
   173             // ### TODO: Use PAC somehow
       
   174         }
       
   175     }
       
   176 
       
   177     // no PAC, decide which proxy we're looking for based on the query
       
   178     bool isHttps = false;
       
   179     QString protocol = query.protocolTag().toLower();
       
   180 
       
   181     // try the protocol-specific proxy
       
   182     QNetworkProxy protocolSpecificProxy;
       
   183     if (protocol == QLatin1String("ftp")) {
       
   184         protocolSpecificProxy =
       
   185             proxyFromDictionary(dict, QNetworkProxy::FtpCachingProxy,
       
   186                                 kSCPropNetProxiesFTPEnable,
       
   187                                 kSCPropNetProxiesFTPProxy,
       
   188                                 kSCPropNetProxiesFTPPort);
       
   189     } else if (protocol == QLatin1String("http")) {
       
   190         protocolSpecificProxy =
       
   191             proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
       
   192                                 kSCPropNetProxiesHTTPEnable,
       
   193                                 kSCPropNetProxiesHTTPProxy,
       
   194                                 kSCPropNetProxiesHTTPPort);
       
   195     } else if (protocol == QLatin1String("https")) {
       
   196         isHttps = true;
       
   197         protocolSpecificProxy =
       
   198             proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
       
   199                                 kSCPropNetProxiesHTTPSEnable,
       
   200                                 kSCPropNetProxiesHTTPSProxy,
       
   201                                 kSCPropNetProxiesHTTPSPort);
       
   202     }
       
   203     if (protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy)
       
   204         result << protocolSpecificProxy;
       
   205 
       
   206     // let's add SOCKSv5 if present too
       
   207     QNetworkProxy socks5 = proxyFromDictionary(dict, QNetworkProxy::Socks5Proxy,
       
   208                                                kSCPropNetProxiesSOCKSEnable,
       
   209                                                kSCPropNetProxiesSOCKSProxy,
       
   210                                                kSCPropNetProxiesSOCKSPort);
       
   211     if (socks5.type() != QNetworkProxy::DefaultProxy)
       
   212         result << socks5;
       
   213 
       
   214     // let's add the HTTPS proxy if present (and if we haven't added
       
   215     // yet)
       
   216     if (!isHttps) {
       
   217         QNetworkProxy https = proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
       
   218                                                   kSCPropNetProxiesHTTPSEnable,
       
   219                                                   kSCPropNetProxiesHTTPSProxy,
       
   220                                                   kSCPropNetProxiesHTTPSPort);
       
   221         if (https.type() != QNetworkProxy::DefaultProxy && https != protocolSpecificProxy)
       
   222             result << https;
       
   223     }
       
   224 
       
   225     return result;
       
   226 }
       
   227 
       
   228 QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
       
   229 {
       
   230     QList<QNetworkProxy> result = macQueryInternal(query);
       
   231     if (result.isEmpty())
       
   232         result << QNetworkProxy::NoProxy;
       
   233 
       
   234     return result;
       
   235 }
       
   236 
       
   237 #endif
       
   238 
       
   239 QT_END_NAMESPACE