toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <windows.h>
     7 #include <ras.h>
     8 #include <wininet.h>
    10 #include "mozilla/ArrayUtils.h"
    11 #include "mozilla/Attributes.h"
    12 #include "nsISystemProxySettings.h"
    13 #include "nsIServiceManager.h"
    14 #include "mozilla/ModuleUtils.h"
    15 #include "nsPrintfCString.h"
    16 #include "nsNetUtil.h"
    17 #include "nsISupportsPrimitives.h"
    18 #include "nsIURI.h"
    20 class nsWindowsSystemProxySettings MOZ_FINAL : public nsISystemProxySettings
    21 {
    22 public:
    23     NS_DECL_THREADSAFE_ISUPPORTS
    24     NS_DECL_NSISYSTEMPROXYSETTINGS
    26     nsWindowsSystemProxySettings() {};
    27     nsresult Init();
    29 private:
    30     ~nsWindowsSystemProxySettings() {};
    32     bool MatchOverride(const nsACString& aHost);
    33     bool PatternMatch(const nsACString& aHost, const nsACString& aOverride);
    34 };
    36 NS_IMPL_ISUPPORTS(nsWindowsSystemProxySettings, nsISystemProxySettings)
    38 NS_IMETHODIMP
    39 nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
    40 {
    41   *aMainThreadOnly = false;
    42   return NS_OK;
    43 }
    46 nsresult
    47 nsWindowsSystemProxySettings::Init()
    48 {
    49     return NS_OK;
    50 }
    52 static void SetProxyResult(const char* aType, const nsACString& aHostPort,
    53                            nsACString& aResult)
    54 {
    55     aResult.AssignASCII(aType);
    56     aResult.Append(' ');
    57     aResult.Append(aHostPort);
    58 }
    60 static void SetProxyResultDirect(nsACString& aResult)
    61 {
    62     // For whatever reason, a proxy is not to be used.
    63     aResult.AssignASCII("DIRECT");
    64 }
    66 static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags,
    67                                    nsAString& aValue)
    68 {
    69     DWORD connFlags = 0;
    70     WCHAR connName[RAS_MaxEntryName + 1];
    71     MOZ_SEH_TRY {
    72         InternetGetConnectedStateExW(&connFlags, connName,
    73                                      mozilla::ArrayLength(connName), 0);
    74     } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
    75         return NS_ERROR_FAILURE;
    76     }
    78     INTERNET_PER_CONN_OPTIONW options[2];
    79     options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI;
    80     options[1].dwOption = aOption;
    82     INTERNET_PER_CONN_OPTION_LISTW list;
    83     list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
    84     list.pszConnection = connFlags & INTERNET_CONNECTION_MODEM ?
    85                          connName : nullptr;
    86     list.dwOptionCount = mozilla::ArrayLength(options);
    87     list.dwOptionError = 0;
    88     list.pOptions = options;
    90     unsigned long size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
    91     if (!InternetQueryOptionW(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION,
    92                               &list, &size)) {
    93         if (GetLastError() != ERROR_INVALID_PARAMETER) {
    94             return NS_ERROR_FAILURE;
    95         }
    96         options[0].dwOption = INTERNET_PER_CONN_FLAGS;
    97         size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
    98         MOZ_SEH_TRY {
    99             if (!InternetQueryOptionW(nullptr,
   100                                       INTERNET_OPTION_PER_CONNECTION_OPTION,
   101                                       &list, &size)) {
   102                 return NS_ERROR_FAILURE;
   103             }
   104         } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
   105             return NS_ERROR_FAILURE;
   106         }
   107     }
   109     aFlags = options[0].Value.dwValue;
   110     aValue.Assign(options[1].Value.pszValue);
   111     GlobalFree(options[1].Value.pszValue);
   113     return NS_OK;
   114 }
   116 bool
   117 nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost)
   118 {
   119     nsresult rv;
   120     uint32_t flags = 0;
   121     nsAutoString buf;
   123     rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf);
   124     if (NS_FAILED(rv))
   125         return false;
   127     NS_ConvertUTF16toUTF8 cbuf(buf);
   129     nsAutoCString host(aHost);
   130     int32_t start = 0;
   131     int32_t end = cbuf.Length();
   133     // Windows formats its proxy override list in the form:
   134     // server;server;server where 'server' is a server name pattern or IP
   135     // address, or "<local>". "<local>" must be translated to
   136     // "localhost;127.0.0.1".
   137     // In a server name pattern, a '*' character matches any substring and
   138     // all other characters must match themselves; the whole pattern must match
   139     // the whole hostname.
   140     while (true) {
   141         int32_t delimiter = cbuf.FindCharInSet(" ;", start);
   142         if (delimiter == -1)
   143             delimiter = end;
   145         if (delimiter != start) {
   146             const nsAutoCString override(Substring(cbuf, start,
   147                                                    delimiter - start));
   148             if (override.EqualsLiteral("<local>")) {
   149                 // This override matches local addresses.
   150                 if (host.EqualsLiteral("localhost") ||
   151                     host.EqualsLiteral("127.0.0.1"))
   152                     return true;
   153             } else if (PatternMatch(host, override)) {
   154                 return true;
   155             }
   156         }
   158         if (delimiter == end)
   159             break;
   160         start = ++delimiter;
   161     }
   163     return false;
   164 }
   166 bool
   167 nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost,
   168                                            const nsACString& aOverride)
   169 {
   170     nsAutoCString host(aHost);
   171     nsAutoCString override(aOverride);
   172     int32_t overrideLength = override.Length();
   173     int32_t tokenStart = 0;
   174     int32_t offset = 0;
   175     bool star = false;
   177     while (tokenStart < overrideLength) {
   178         int32_t tokenEnd = override.FindChar('*', tokenStart);
   179         if (tokenEnd == tokenStart) {
   180             star = true;
   181             tokenStart++;
   182             // If the character following the '*' is a '.' character then skip
   183             // it so that "*.foo.com" allows "foo.com".
   184             if (override.FindChar('.', tokenStart) == tokenStart)
   185                 tokenStart++;
   186         } else {
   187             if (tokenEnd == -1)
   188                 tokenEnd = overrideLength;
   189             nsAutoCString token(Substring(override, tokenStart,
   190                                           tokenEnd - tokenStart));
   191             offset = host.Find(token, offset);
   192             if (offset == -1 || (!star && offset))
   193                 return false;
   194             star = false;
   195             tokenStart = tokenEnd;
   196             offset += token.Length();
   197         }
   198     }
   200     return (star || (offset == host.Length()));
   201 }
   203 nsresult
   204 nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult)
   205 {
   206     nsresult rv;
   207     uint32_t flags = 0;
   208     nsAutoString buf;
   210     rv = ReadInternetOption(INTERNET_PER_CONN_AUTOCONFIG_URL, flags, buf);
   211     if (!(flags & PROXY_TYPE_AUTO_PROXY_URL)) {
   212         aResult.Truncate();
   213         return rv;
   214     }
   216     if (NS_SUCCEEDED(rv))
   217         aResult = NS_ConvertUTF16toUTF8(buf);
   218     return rv;
   219 }
   221 nsresult
   222 nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
   223                                              const nsACString & aScheme,
   224                                              const nsACString & aHost,
   225                                              const int32_t      aPort,
   226                                              nsACString & aResult)
   227 {
   228     nsresult rv;
   229     uint32_t flags = 0;
   230     nsAutoString buf;
   232     rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf);
   233     if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) {
   234         SetProxyResultDirect(aResult);
   235         return NS_OK;
   236     }
   238     if (MatchOverride(aHost)) {
   239         SetProxyResultDirect(aResult);
   240         return NS_OK;
   241     }
   243     NS_ConvertUTF16toUTF8 cbuf(buf);
   245     nsAutoCString prefix;
   246     ToLowerCase(aScheme, prefix);
   248     prefix.Append('=');
   250     nsAutoCString specificProxy;
   251     nsAutoCString defaultProxy;
   252     nsAutoCString socksProxy;
   253     int32_t start = 0;
   254     int32_t end = cbuf.Length();
   256     while (true) {
   257         int32_t delimiter = cbuf.FindCharInSet(" ;", start);
   258         if (delimiter == -1)
   259             delimiter = end;
   261         if (delimiter != start) {
   262             const nsAutoCString proxy(Substring(cbuf, start,
   263                                                 delimiter - start));
   264             if (proxy.FindChar('=') == -1) {
   265                 // If a proxy name is listed by itself, it is used as the
   266                 // default proxy for any protocols that do not have a specific
   267                 // proxy specified.
   268                 // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
   269                 defaultProxy = proxy;
   270             } else if (proxy.Find(prefix) == 0) {
   271                 // To list a proxy for a specific protocol, the string must
   272                 // follow the format "<protocol>=<protocol>://<proxy_name>".
   273                 // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
   274                 specificProxy = Substring(proxy, prefix.Length());
   275                 break;
   276             } else if (proxy.Find("socks=") == 0) {
   277                 // SOCKS proxy.
   278                 socksProxy = Substring(proxy, 5); // "socks=" length.
   279             }
   280         }
   282         if (delimiter == end)
   283             break;
   284         start = ++delimiter;
   285     }
   287     if (!specificProxy.IsEmpty())
   288         SetProxyResult("PROXY", specificProxy, aResult); // Protocol-specific proxy.
   289     else if (!defaultProxy.IsEmpty())
   290         SetProxyResult("PROXY", defaultProxy, aResult); // Default proxy.
   291     else if (!socksProxy.IsEmpty())
   292         SetProxyResult("SOCKS", socksProxy, aResult); // SOCKS proxy.
   293     else
   294         SetProxyResultDirect(aResult); // Direct connection.
   296     return NS_OK;
   297 }
   299 #define NS_WINDOWSSYSTEMPROXYSERVICE_CID  /* 4e22d3ea-aaa2-436e-ada4-9247de57d367 */\
   300     { 0x4e22d3ea, 0xaaa2, 0x436e, \
   301         {0xad, 0xa4, 0x92, 0x47, 0xde, 0x57, 0xd3, 0x67 } }
   303 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsSystemProxySettings, Init)
   304 NS_DEFINE_NAMED_CID(NS_WINDOWSSYSTEMPROXYSERVICE_CID);
   306 static const mozilla::Module::CIDEntry kSysProxyCIDs[] = {
   307     { &kNS_WINDOWSSYSTEMPROXYSERVICE_CID, false, nullptr, nsWindowsSystemProxySettingsConstructor },
   308     { nullptr }
   309 };
   311 static const mozilla::Module::ContractIDEntry kSysProxyContracts[] = {
   312     { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_WINDOWSSYSTEMPROXYSERVICE_CID },
   313     { nullptr }
   314 };
   316 static const mozilla::Module kSysProxyModule = {
   317     mozilla::Module::kVersion,
   318     kSysProxyCIDs,
   319     kSysProxyContracts
   320 };
   322 NSMODULE_DEFN(nsWindowsProxyModule) = &kSysProxyModule;

mercurial