toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,322 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include <windows.h>
    1.10 +#include <ras.h>
    1.11 +#include <wininet.h>
    1.12 +
    1.13 +#include "mozilla/ArrayUtils.h"
    1.14 +#include "mozilla/Attributes.h"
    1.15 +#include "nsISystemProxySettings.h"
    1.16 +#include "nsIServiceManager.h"
    1.17 +#include "mozilla/ModuleUtils.h"
    1.18 +#include "nsPrintfCString.h"
    1.19 +#include "nsNetUtil.h"
    1.20 +#include "nsISupportsPrimitives.h"
    1.21 +#include "nsIURI.h"
    1.22 +
    1.23 +class nsWindowsSystemProxySettings MOZ_FINAL : public nsISystemProxySettings
    1.24 +{
    1.25 +public:
    1.26 +    NS_DECL_THREADSAFE_ISUPPORTS
    1.27 +    NS_DECL_NSISYSTEMPROXYSETTINGS
    1.28 +
    1.29 +    nsWindowsSystemProxySettings() {};
    1.30 +    nsresult Init();
    1.31 +
    1.32 +private:
    1.33 +    ~nsWindowsSystemProxySettings() {};
    1.34 +
    1.35 +    bool MatchOverride(const nsACString& aHost);
    1.36 +    bool PatternMatch(const nsACString& aHost, const nsACString& aOverride);
    1.37 +};
    1.38 +
    1.39 +NS_IMPL_ISUPPORTS(nsWindowsSystemProxySettings, nsISystemProxySettings)
    1.40 +
    1.41 +NS_IMETHODIMP
    1.42 +nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
    1.43 +{
    1.44 +  *aMainThreadOnly = false;
    1.45 +  return NS_OK;
    1.46 +}
    1.47 +
    1.48 +
    1.49 +nsresult
    1.50 +nsWindowsSystemProxySettings::Init()
    1.51 +{
    1.52 +    return NS_OK;
    1.53 +}
    1.54 +
    1.55 +static void SetProxyResult(const char* aType, const nsACString& aHostPort,
    1.56 +                           nsACString& aResult)
    1.57 +{
    1.58 +    aResult.AssignASCII(aType);
    1.59 +    aResult.Append(' ');
    1.60 +    aResult.Append(aHostPort);
    1.61 +}
    1.62 +
    1.63 +static void SetProxyResultDirect(nsACString& aResult)
    1.64 +{
    1.65 +    // For whatever reason, a proxy is not to be used.
    1.66 +    aResult.AssignASCII("DIRECT");
    1.67 +}
    1.68 +
    1.69 +static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags,
    1.70 +                                   nsAString& aValue)
    1.71 +{
    1.72 +    DWORD connFlags = 0;
    1.73 +    WCHAR connName[RAS_MaxEntryName + 1];
    1.74 +    MOZ_SEH_TRY {
    1.75 +        InternetGetConnectedStateExW(&connFlags, connName,
    1.76 +                                     mozilla::ArrayLength(connName), 0);
    1.77 +    } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
    1.78 +        return NS_ERROR_FAILURE;
    1.79 +    }
    1.80 +
    1.81 +    INTERNET_PER_CONN_OPTIONW options[2];
    1.82 +    options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI;
    1.83 +    options[1].dwOption = aOption;
    1.84 +
    1.85 +    INTERNET_PER_CONN_OPTION_LISTW list;
    1.86 +    list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
    1.87 +    list.pszConnection = connFlags & INTERNET_CONNECTION_MODEM ?
    1.88 +                         connName : nullptr;
    1.89 +    list.dwOptionCount = mozilla::ArrayLength(options);
    1.90 +    list.dwOptionError = 0;
    1.91 +    list.pOptions = options;
    1.92 +
    1.93 +    unsigned long size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
    1.94 +    if (!InternetQueryOptionW(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION,
    1.95 +                              &list, &size)) {
    1.96 +        if (GetLastError() != ERROR_INVALID_PARAMETER) {
    1.97 +            return NS_ERROR_FAILURE;
    1.98 +        }
    1.99 +        options[0].dwOption = INTERNET_PER_CONN_FLAGS;
   1.100 +        size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
   1.101 +        MOZ_SEH_TRY {
   1.102 +            if (!InternetQueryOptionW(nullptr,
   1.103 +                                      INTERNET_OPTION_PER_CONNECTION_OPTION,
   1.104 +                                      &list, &size)) {
   1.105 +                return NS_ERROR_FAILURE;
   1.106 +            }
   1.107 +        } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
   1.108 +            return NS_ERROR_FAILURE;
   1.109 +        }
   1.110 +    }
   1.111 +
   1.112 +    aFlags = options[0].Value.dwValue;
   1.113 +    aValue.Assign(options[1].Value.pszValue);
   1.114 +    GlobalFree(options[1].Value.pszValue);
   1.115 +
   1.116 +    return NS_OK;
   1.117 +}
   1.118 +
   1.119 +bool
   1.120 +nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost)
   1.121 +{
   1.122 +    nsresult rv;
   1.123 +    uint32_t flags = 0;
   1.124 +    nsAutoString buf;
   1.125 +
   1.126 +    rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf);
   1.127 +    if (NS_FAILED(rv))
   1.128 +        return false;
   1.129 +
   1.130 +    NS_ConvertUTF16toUTF8 cbuf(buf);
   1.131 +
   1.132 +    nsAutoCString host(aHost);
   1.133 +    int32_t start = 0;
   1.134 +    int32_t end = cbuf.Length();
   1.135 +
   1.136 +    // Windows formats its proxy override list in the form:
   1.137 +    // server;server;server where 'server' is a server name pattern or IP
   1.138 +    // address, or "<local>". "<local>" must be translated to
   1.139 +    // "localhost;127.0.0.1".
   1.140 +    // In a server name pattern, a '*' character matches any substring and
   1.141 +    // all other characters must match themselves; the whole pattern must match
   1.142 +    // the whole hostname.
   1.143 +    while (true) {
   1.144 +        int32_t delimiter = cbuf.FindCharInSet(" ;", start);
   1.145 +        if (delimiter == -1)
   1.146 +            delimiter = end;
   1.147 +
   1.148 +        if (delimiter != start) {
   1.149 +            const nsAutoCString override(Substring(cbuf, start,
   1.150 +                                                   delimiter - start));
   1.151 +            if (override.EqualsLiteral("<local>")) {
   1.152 +                // This override matches local addresses.
   1.153 +                if (host.EqualsLiteral("localhost") ||
   1.154 +                    host.EqualsLiteral("127.0.0.1"))
   1.155 +                    return true;
   1.156 +            } else if (PatternMatch(host, override)) {
   1.157 +                return true;
   1.158 +            }
   1.159 +        }
   1.160 +
   1.161 +        if (delimiter == end)
   1.162 +            break;
   1.163 +        start = ++delimiter;
   1.164 +    }
   1.165 +
   1.166 +    return false;
   1.167 +}
   1.168 +
   1.169 +bool
   1.170 +nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost,
   1.171 +                                           const nsACString& aOverride)
   1.172 +{
   1.173 +    nsAutoCString host(aHost);
   1.174 +    nsAutoCString override(aOverride);
   1.175 +    int32_t overrideLength = override.Length();
   1.176 +    int32_t tokenStart = 0;
   1.177 +    int32_t offset = 0;
   1.178 +    bool star = false;
   1.179 +
   1.180 +    while (tokenStart < overrideLength) {
   1.181 +        int32_t tokenEnd = override.FindChar('*', tokenStart);
   1.182 +        if (tokenEnd == tokenStart) {
   1.183 +            star = true;
   1.184 +            tokenStart++;
   1.185 +            // If the character following the '*' is a '.' character then skip
   1.186 +            // it so that "*.foo.com" allows "foo.com".
   1.187 +            if (override.FindChar('.', tokenStart) == tokenStart)
   1.188 +                tokenStart++;
   1.189 +        } else {
   1.190 +            if (tokenEnd == -1)
   1.191 +                tokenEnd = overrideLength;
   1.192 +            nsAutoCString token(Substring(override, tokenStart,
   1.193 +                                          tokenEnd - tokenStart));
   1.194 +            offset = host.Find(token, offset);
   1.195 +            if (offset == -1 || (!star && offset))
   1.196 +                return false;
   1.197 +            star = false;
   1.198 +            tokenStart = tokenEnd;
   1.199 +            offset += token.Length();
   1.200 +        }
   1.201 +    }
   1.202 +
   1.203 +    return (star || (offset == host.Length()));
   1.204 +}
   1.205 +
   1.206 +nsresult
   1.207 +nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult)
   1.208 +{
   1.209 +    nsresult rv;
   1.210 +    uint32_t flags = 0;
   1.211 +    nsAutoString buf;
   1.212 +
   1.213 +    rv = ReadInternetOption(INTERNET_PER_CONN_AUTOCONFIG_URL, flags, buf);
   1.214 +    if (!(flags & PROXY_TYPE_AUTO_PROXY_URL)) {
   1.215 +        aResult.Truncate();
   1.216 +        return rv;
   1.217 +    }
   1.218 +
   1.219 +    if (NS_SUCCEEDED(rv))
   1.220 +        aResult = NS_ConvertUTF16toUTF8(buf);
   1.221 +    return rv;
   1.222 +}
   1.223 +
   1.224 +nsresult
   1.225 +nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
   1.226 +                                             const nsACString & aScheme,
   1.227 +                                             const nsACString & aHost,
   1.228 +                                             const int32_t      aPort,
   1.229 +                                             nsACString & aResult)
   1.230 +{
   1.231 +    nsresult rv;
   1.232 +    uint32_t flags = 0;
   1.233 +    nsAutoString buf;
   1.234 +
   1.235 +    rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf);
   1.236 +    if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) {
   1.237 +        SetProxyResultDirect(aResult);
   1.238 +        return NS_OK;
   1.239 +    }
   1.240 +
   1.241 +    if (MatchOverride(aHost)) {
   1.242 +        SetProxyResultDirect(aResult);
   1.243 +        return NS_OK;
   1.244 +    }
   1.245 +
   1.246 +    NS_ConvertUTF16toUTF8 cbuf(buf);
   1.247 +
   1.248 +    nsAutoCString prefix;
   1.249 +    ToLowerCase(aScheme, prefix);
   1.250 +
   1.251 +    prefix.Append('=');
   1.252 +
   1.253 +    nsAutoCString specificProxy;
   1.254 +    nsAutoCString defaultProxy;
   1.255 +    nsAutoCString socksProxy;
   1.256 +    int32_t start = 0;
   1.257 +    int32_t end = cbuf.Length();
   1.258 +
   1.259 +    while (true) {
   1.260 +        int32_t delimiter = cbuf.FindCharInSet(" ;", start);
   1.261 +        if (delimiter == -1)
   1.262 +            delimiter = end;
   1.263 +
   1.264 +        if (delimiter != start) {
   1.265 +            const nsAutoCString proxy(Substring(cbuf, start,
   1.266 +                                                delimiter - start));
   1.267 +            if (proxy.FindChar('=') == -1) {
   1.268 +                // If a proxy name is listed by itself, it is used as the
   1.269 +                // default proxy for any protocols that do not have a specific
   1.270 +                // proxy specified.
   1.271 +                // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
   1.272 +                defaultProxy = proxy;
   1.273 +            } else if (proxy.Find(prefix) == 0) {
   1.274 +                // To list a proxy for a specific protocol, the string must
   1.275 +                // follow the format "<protocol>=<protocol>://<proxy_name>".
   1.276 +                // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
   1.277 +                specificProxy = Substring(proxy, prefix.Length());
   1.278 +                break;
   1.279 +            } else if (proxy.Find("socks=") == 0) {
   1.280 +                // SOCKS proxy.
   1.281 +                socksProxy = Substring(proxy, 5); // "socks=" length.
   1.282 +            }
   1.283 +        }
   1.284 +
   1.285 +        if (delimiter == end)
   1.286 +            break;
   1.287 +        start = ++delimiter;
   1.288 +    }
   1.289 +
   1.290 +    if (!specificProxy.IsEmpty())
   1.291 +        SetProxyResult("PROXY", specificProxy, aResult); // Protocol-specific proxy.
   1.292 +    else if (!defaultProxy.IsEmpty())
   1.293 +        SetProxyResult("PROXY", defaultProxy, aResult); // Default proxy.
   1.294 +    else if (!socksProxy.IsEmpty())
   1.295 +        SetProxyResult("SOCKS", socksProxy, aResult); // SOCKS proxy.
   1.296 +    else
   1.297 +        SetProxyResultDirect(aResult); // Direct connection.
   1.298 +
   1.299 +    return NS_OK;
   1.300 +}
   1.301 +
   1.302 +#define NS_WINDOWSSYSTEMPROXYSERVICE_CID  /* 4e22d3ea-aaa2-436e-ada4-9247de57d367 */\
   1.303 +    { 0x4e22d3ea, 0xaaa2, 0x436e, \
   1.304 +        {0xad, 0xa4, 0x92, 0x47, 0xde, 0x57, 0xd3, 0x67 } }
   1.305 +
   1.306 +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsSystemProxySettings, Init)
   1.307 +NS_DEFINE_NAMED_CID(NS_WINDOWSSYSTEMPROXYSERVICE_CID);
   1.308 +
   1.309 +static const mozilla::Module::CIDEntry kSysProxyCIDs[] = {
   1.310 +    { &kNS_WINDOWSSYSTEMPROXYSERVICE_CID, false, nullptr, nsWindowsSystemProxySettingsConstructor },
   1.311 +    { nullptr }
   1.312 +};
   1.313 +
   1.314 +static const mozilla::Module::ContractIDEntry kSysProxyContracts[] = {
   1.315 +    { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_WINDOWSSYSTEMPROXYSERVICE_CID },
   1.316 +    { nullptr }
   1.317 +};
   1.318 +
   1.319 +static const mozilla::Module kSysProxyModule = {
   1.320 +    mozilla::Module::kVersion,
   1.321 +    kSysProxyCIDs,
   1.322 +    kSysProxyContracts
   1.323 +};
   1.324 +
   1.325 +NSMODULE_DEFN(nsWindowsProxyModule) = &kSysProxyModule;

mercurial