diff --git a/netwerk/base/public/Makefile.in b/netwerk/base/public/Makefile.in index 0fba2239df22..e4912f8ed16a 100644 --- a/netwerk/base/public/Makefile.in +++ b/netwerk/base/public/Makefile.in @@ -104,6 +104,7 @@ XPIDLSRCS = \ nsIStreamTransportService.idl \ nsIStreamLoader.idl \ nsISyncStreamListener.idl \ + nsISystemProxySettings.idl \ nsIUnicharStreamLoader.idl \ nsIStandardURL.idl \ nsINestedURI.idl \ diff --git a/netwerk/base/public/nsISystemProxySettings.idl b/netwerk/base/public/nsISystemProxySettings.idl new file mode 100644 index 000000000000..2dfd05c355a4 --- /dev/null +++ b/netwerk/base/public/nsISystemProxySettings.idl @@ -0,0 +1,61 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Novell code. + * + * The Initial Developer of the Original Code is Novell. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert O'Callahan (robert@ocallahan.org) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "nsIURI.idl" + +/** + * This interface allows the proxy code to use platform-specific proxy + * settings when the proxy preference is set to "automatic discovery". This service + * acts like a PAC parser to netwerk, but it will actually read the system settings and + * either return the proper proxy data from the autoconfig URL specified in the system proxy, + * or generate proxy data based on the system's manual proxy settings. + */ +[scriptable, uuid(a9f3ae38-b769-4e0b-9317-578388e326c9)] +interface nsISystemProxySettings : nsISupports +{ + /** + * If non-empty, use this PAC file. If empty, call getProxyForURI instead. + */ + readonly attribute AUTF8String PACURI; + + /** + * See nsIProxyAutoConfig::getProxyForURI; this function behaves exactly + * the same way. + */ + AUTF8String getProxyForURI(in nsIURI aURI); +}; diff --git a/netwerk/base/src/nsPACMan.h b/netwerk/base/src/nsPACMan.h index f977cd80d77c..ac8c0f5d5e0a 100644 --- a/netwerk/base/src/nsPACMan.h +++ b/netwerk/base/src/nsPACMan.h @@ -128,6 +128,14 @@ public: */ PRBool IsLoading() { return mLoader != nsnull; } + /** + * Returns true if the given URI matches the URI of our PAC file. + */ + PRBool IsPACURI(nsIURI *uri) { + PRBool result; + return mPACURI && NS_SUCCEEDED(mPACURI->Equals(uri, &result)) && result; + } + private: NS_DECL_NSISTREAMLOADEROBSERVER NS_DECL_NSIINTERFACEREQUESTOR @@ -162,14 +170,6 @@ private: */ void OnLoadFailure(); - /** - * Returns true if the given URI matches the URI of our PAC file. - */ - PRBool IsPACURI(nsIURI *uri) { - PRBool result; - return mPACURI && NS_SUCCEEDED(mPACURI->Equals(uri, &result)) && result; - } - private: nsCOMPtr mPAC; nsCOMPtr mPACURI; diff --git a/netwerk/base/src/nsProtocolProxyService.cpp b/netwerk/base/src/nsProtocolProxyService.cpp index 526b064e1a71..b8503b3ef8a7 100644 --- a/netwerk/base/src/nsProtocolProxyService.cpp +++ b/netwerk/base/src/nsProtocolProxyService.cpp @@ -404,6 +404,12 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, mProxyConfig = static_cast(type); reloadPAC = PR_TRUE; } + + if (mProxyConfig == eProxyConfig_System) { + mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); + } else { + mSystemProxySettings = nsnull; + } } if (!pref || !strcmp(pref, PROXY_PREF("http"))) @@ -461,8 +467,10 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, LoadHostFilters(tempString.get()); } - // We're done if not using PAC or WPAD - if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD) + // We're done if not using something that could give us a PAC URL + // (PAC, WPAD or System) + if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD && + mProxyConfig != eProxyConfig_System) return; // OK, we need to reload the PAC file if: @@ -477,17 +485,20 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, if (mProxyConfig == eProxyConfig_PAC) { prefBranch->GetCharPref(PROXY_PREF("autoconfig_url"), getter_Copies(tempString)); - } - else if (mProxyConfig == eProxyConfig_WPAD) { + } else { // We diverge from the WPAD spec here in that we don't walk the // hosts's FQDN, stripping components until we hit a TLD. Doing so // is dangerous in the face of an incomplete list of TLDs, and TLDs // get added over time. We could consider doing only a single // substitution of the first component, if that proves to help // compatibility. - tempString.AssignLiteral(WPAD_URL); + if (mSystemProxySettings) + mSystemProxySettings->GetPACURI(tempString); + else + tempString.AssignLiteral(WPAD_URL); } - ConfigureFromPAC(tempString); + if (!tempString.IsEmpty()) + ConfigureFromPAC(tempString); } } @@ -755,13 +766,16 @@ nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec) return NS_ERROR_OUT_OF_MEMORY; } - mFailedProxies.Clear(); - nsCOMPtr pacURI; nsresult rv = NS_NewURI(getter_AddRefs(pacURI), spec); if (NS_FAILED(rv)) return rv; + if (mPACMan->IsPACURI(pacURI)) + return NS_OK; + + mFailedProxies.Clear(); + return mPACMan->LoadPACFromURI(pacURI); } @@ -936,8 +950,10 @@ nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy, nsresult aStatus, nsIProxyInfo **aResult) { - // We only support failover when a PAC file is configured. - if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD) + // We only support failover when a PAC file is configured, either + // directly or via system settings + if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD && + mProxyConfig != eProxyConfig_System) return NS_ERROR_NOT_AVAILABLE; // Verify that |aProxy| is one of our nsProxyInfo objects. @@ -1234,15 +1250,37 @@ nsProtocolProxyService::Resolve_Internal(nsIURI *uri, if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) return NS_OK; // Can't proxy this (filters may not override) + if (mSystemProxySettings) { + nsCAutoString PACURI; + if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) && + !PACURI.IsEmpty()) { + // Switch to new PAC file if that setting has changed. If the setting + // hasn't changed, ConfigureFromPAC will exit early. + nsresult rv = ConfigureFromPAC(PACURI); + if (NS_FAILED(rv)) + return rv; + } else { + nsCAutoString proxy; + nsresult rv = mSystemProxySettings->GetProxyForURI(uri, proxy); + if (NS_SUCCEEDED(rv)) { + ProcessPACString(proxy, result); + return NS_OK; + } + // no proxy, stop search + return NS_OK; + } + } + // if proxies are enabled and this host:port combo is supposed to use a // proxy, check for a proxy. if (mProxyConfig == eProxyConfig_Direct || (mProxyConfig == eProxyConfig_Manual && !CanUseProxy(uri, info.defaultPort))) return NS_OK; - + // Proxy auto config magic... - if (mProxyConfig == eProxyConfig_PAC || mProxyConfig == eProxyConfig_WPAD) { + if (mProxyConfig == eProxyConfig_PAC || mProxyConfig == eProxyConfig_WPAD || + mProxyConfig == eProxyConfig_System) { // Do not query PAC now. *usePAC = PR_TRUE; return NS_OK; diff --git a/netwerk/base/src/nsProtocolProxyService.h b/netwerk/base/src/nsProtocolProxyService.h index 25de13a4f286..97bb49af8057 100644 --- a/netwerk/base/src/nsProtocolProxyService.h +++ b/netwerk/base/src/nsProtocolProxyService.h @@ -47,6 +47,7 @@ #include "nsIProtocolProxyService2.h" #include "nsIProtocolProxyFilter.h" #include "nsIProxyAutoConfig.h" +#include "nsISystemProxySettings.h" #include "nsIProxyInfo.h" #include "nsIObserver.h" #include "nsDataHashtable.h" @@ -315,6 +316,7 @@ protected: eProxyConfig_PAC, eProxyConfig_Direct4x, eProxyConfig_WPAD, + eProxyConfig_System, // use system proxy settings if available, otherwise DIRECT eProxyConfig_Last }; @@ -376,6 +378,7 @@ protected: PRBool mSOCKSProxyRemoteDNS; nsRefPtr mPACMan; // non-null if we are using PAC + nsCOMPtr mSystemProxySettings; PRTime mSessionStart; nsFailedProxyTable mFailedProxies; diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index f7218ded8eeb..9646da436f47 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -326,6 +326,10 @@ #define NS_INCREMENTALDOWNLOAD_CONTRACTID \ "@mozilla.org/network/incremental-download;1" +// component implementing nsISystemProxySettings. +#define NS_SYSTEMPROXYSETTINGS_CONTRACTID \ + "@mozilla.org/system-proxy-settings;1" + // service implementing nsIStreamTransportService #define NS_STREAMTRANSPORTSERVICE_CLASSNAME \ "nsStreamTransportService" diff --git a/toolkit/Makefile.in b/toolkit/Makefile.in index 3b561f11c54e..41aeb1e15db6 100644 --- a/toolkit/Makefile.in +++ b/toolkit/Makefile.in @@ -51,6 +51,10 @@ DIRS = \ themes \ $(NULL) +ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT))) +DIRS += system/unixproxy +endif + ifdef MOZ_CRASHREPORTER DIRS += crashreporter endif diff --git a/toolkit/library/libxul-config.mk b/toolkit/library/libxul-config.mk index d7ee2794648a..993d9a09f2ef 100644 --- a/toolkit/library/libxul-config.mk +++ b/toolkit/library/libxul-config.mk @@ -147,6 +147,14 @@ COMPONENT_LIBS += \ $(NULL) endif +ifdef MOZ_XUL +ifdef MOZ_ENABLE_GTK2 +COMPONENT_LIBS += \ + unixproxy \ + $(NULL) +endif +endif + ifdef MOZ_PERF_METRICS EXTRA_DSO_LIBS += mozutil_s endif diff --git a/toolkit/library/nsStaticXULComponents.cpp b/toolkit/library/nsStaticXULComponents.cpp index d5255419173a..3523c1df578b 100644 --- a/toolkit/library/nsStaticXULComponents.cpp +++ b/toolkit/library/nsStaticXULComponents.cpp @@ -262,6 +262,15 @@ #define XMLEXTRAS_MODULE #endif +#ifdef MOZ_XUL +#ifdef MOZ_ENABLE_GTK2 +#define UNIXPROXY_MODULE MODULE(nsUnixProxyModule) +#endif +#endif +#ifndef UNIXPROXY_MODULE +#define UNIXPROXY_MODULE +#endif + #define XUL_MODULES \ MODULE(xpconnect) \ MATHML_MODULES \ @@ -313,6 +322,7 @@ SPELLCHECK_MODULE \ XMLEXTRAS_MODULE \ LAYOUT_DEBUG_MODULE \ + UNIXPROXY_MODULE \ /* end of list */ #define MODULE(_name) \ diff --git a/toolkit/system/gnome/nsGConfService.cpp b/toolkit/system/gnome/nsGConfService.cpp index d8af2255a52c..9849b8c3bece 100644 --- a/toolkit/system/gnome/nsGConfService.cpp +++ b/toolkit/system/gnome/nsGConfService.cpp @@ -38,6 +38,10 @@ #include "nsGConfService.h" #include "nsStringAPI.h" +#include "nsCOMPtr.h" +#include "nsComponentManagerUtils.h" +#include "nsISupportsPrimitives.h" +#include "nsIMutableArray.h" #include @@ -123,6 +127,37 @@ nsGConfService::GetFloat(const nsACString &aKey, float* aResult) return NS_OK; } +NS_IMETHODIMP +nsGConfService::GetStringList(const nsACString &aKey, nsIArray** aResult) +{ + nsCOMPtr items(do_CreateInstance(NS_ARRAY_CONTRACTID)); + if (!items) + return NS_ERROR_OUT_OF_MEMORY; + + GError* error = nsnull; + GSList* list = gconf_client_get_list(mClient, PromiseFlatCString(aKey).get(), + GCONF_VALUE_STRING, &error); + if (error) { + g_error_free(error); + return NS_ERROR_FAILURE; + } + + for (GSList* l = list; l; l = l->next) { + nsCOMPtr obj(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID)); + if (!obj) { + g_slist_free(list); + return NS_ERROR_OUT_OF_MEMORY; + } + obj->SetData(NS_ConvertUTF8toUTF16((const char*)l->data)); + items->AppendElement(obj, PR_FALSE); + g_free(l->data); + } + + g_slist_free(list); + NS_ADDREF(*aResult = items); + return NS_OK; +} + NS_IMETHODIMP nsGConfService::SetBool(const nsACString &aKey, PRBool aValue) { diff --git a/toolkit/system/unixproxy/Makefile.in b/toolkit/system/unixproxy/Makefile.in new file mode 100644 index 000000000000..d0c02e362324 --- /dev/null +++ b/toolkit/system/unixproxy/Makefile.in @@ -0,0 +1,65 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Mozilla GNOME integration code. +# +# The Initial Developer of the Original Code is +# IBM Corporation. +# Portions created by the Initial Developer are Copyright (C) 2004 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brian Ryner +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = unixproxy +LIBRARY_NAME = unixproxy + +EXPORT_LIBRARY = 1 +IS_COMPONENT = 1 +MODULE_NAME = nsUnixProxyModule +GRE_MODULE = 1 +LIBXUL_LIBRARY = 1 + +REQUIRES = \ + xpcom \ + string \ + necko \ + mozgnome \ + $(NULL) + +CPPSRCS = \ + nsUnixSystemProxySettings.cpp \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp new file mode 100644 index 000000000000..5966fc1dd117 --- /dev/null +++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp @@ -0,0 +1,428 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert O'Callahan (robert@ocallahan.org) + * Michael Ventnor (m.ventnor@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISystemProxySettings.h" +#include "nsIGenericFactory.h" +#include "nsIServiceManager.h" +#include "nsIGConfService.h" +#include "nsIURI.h" +#include "nsReadableUtils.h" +#include "nsArrayUtils.h" +#include "prnetdb.h" +#include "prenv.h" +#include "nsPrintfCString.h" +#include "nsNetUtil.h" +#include "nsISupportsPrimitives.h" + +class nsUnixSystemProxySettings : public nsISystemProxySettings { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISYSTEMPROXYSETTINGS + + nsUnixSystemProxySettings() {} + nsresult Init(); + +private: + ~nsUnixSystemProxySettings() {} + + nsCOMPtr mGConf; + PRBool IsProxyMode(const char* aMode); + nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult); + nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, PRInt32 aPort, nsACString& aResult); +}; + +NS_IMPL_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings) + +nsresult +nsUnixSystemProxySettings::Init() +{ + mGConf = do_GetService(NS_GCONFSERVICE_CONTRACTID); + return NS_OK; +} + +PRBool +nsUnixSystemProxySettings::IsProxyMode(const char* aMode) +{ + nsCAutoString mode; + return NS_SUCCEEDED(mGConf->GetString(NS_LITERAL_CSTRING("/system/proxy/mode"), mode)) && + mode.EqualsASCII(aMode); +} + +nsresult +nsUnixSystemProxySettings::GetPACURI(nsACString& aResult) +{ + if (!mGConf || !IsProxyMode("auto")) { + // Return an empty string in this case + aResult.Truncate(); + return NS_OK; + } + + return mGConf->GetString(NS_LITERAL_CSTRING("/system/proxy/autoconfig_url"), + aResult); +} + +static PRBool +IsInNoProxyList(const nsACString& aHost, PRInt32 aPort, const char* noProxyVal) +{ + NS_ASSERTION(aPort >= 0, "Negative port?"); + + nsCAutoString noProxy(noProxyVal); + if (noProxy.EqualsLiteral("*")) + return PR_TRUE; + + noProxy.StripWhitespace(); + + nsReadingIterator pos; + nsReadingIterator end; + noProxy.BeginReading(pos); + noProxy.EndReading(end); + while (pos != end) { + nsReadingIterator last = pos; + nsReadingIterator nextPos; + if (FindCharInReadable(',', last, end)) { + nextPos = last; + ++nextPos; + } else { + last = end; + nextPos = end; + } + + nsReadingIterator colon = pos; + PRInt32 port = -1; + if (FindCharInReadable(':', colon, last)) { + ++colon; + nsDependentCSubstring portStr(colon, last); + nsCAutoString portStr2(portStr); // We need this for ToInteger. String API's suck. + PRInt32 err; + port = portStr2.ToInteger(&err); + if (NS_FAILED(err)) { + port = -2; // don't match any port, so we ignore this pattern + } + --colon; + } else { + colon = last; + } + + if (port == -1 || port == aPort) { + nsDependentCSubstring hostStr(pos, colon); + // By using StringEndsWith instead of an equality comparator, we can include sub-domains + if (StringEndsWith(aHost, hostStr, nsCaseInsensitiveCStringComparator())) + return PR_TRUE; + } + + pos = nextPos; + } + + return PR_FALSE; +} + +static void SetProxyResult(const char* aType, const nsACString& aHost, + PRInt32 aPort, nsACString& aResult) +{ + aResult.AppendASCII(aType); + aResult.Append(' '); + aResult.Append(aHost); + aResult.Append(':'); + aResult.Append(nsPrintfCString("%d", aPort)); +} + +static nsresult +GetProxyFromEnvironment(const nsACString& aScheme, + const nsACString& aHost, + PRInt32 aPort, + nsACString& aResult) +{ + nsCAutoString envVar; + envVar.Append(aScheme); + envVar.AppendLiteral("_proxy"); + const char* proxyVal = PR_GetEnv(envVar.get()); + if (!proxyVal) { + proxyVal = PR_GetEnv("all_proxy"); + if (!proxyVal) { + // Return failure so that the caller can detect the failure and + // fall back to other proxy detection (e.g., WPAD) + return NS_ERROR_FAILURE; + } + } + + const char* noProxyVal = PR_GetEnv("no_proxy"); + if (noProxyVal && IsInNoProxyList(aHost, aPort, noProxyVal)) { + aResult.AppendLiteral("DIRECT"); + return NS_OK; + } + + // Use our URI parser to crack the proxy URI + nsCOMPtr proxyURI; + nsresult rv = NS_NewURI(getter_AddRefs(proxyURI), proxyVal); + NS_ENSURE_SUCCESS(rv, rv); + + // Is there a way to specify "socks://" or something in these environment + // variables? I can't find any documentation. + PRBool isHTTP; + rv = proxyURI->SchemeIs("http", &isHTTP); + NS_ENSURE_SUCCESS(rv, rv); + if (!isHTTP) + return NS_ERROR_UNKNOWN_PROTOCOL; + + nsCAutoString proxyHost; + rv = proxyURI->GetHost(proxyHost); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 proxyPort; + rv = proxyURI->GetPort(&proxyPort); + NS_ENSURE_SUCCESS(rv, rv); + + SetProxyResult("PROXY", proxyHost, proxyPort, aResult); + return NS_OK; +} + +nsresult +nsUnixSystemProxySettings::SetProxyResultFromGConf(const char* aKeyBase, const char* aType, + nsACString& aResult) +{ + nsCAutoString hostKey; + hostKey.AppendASCII(aKeyBase); + hostKey.AppendLiteral("host"); + nsCAutoString host; + nsresult rv = mGConf->GetString(hostKey, host); + NS_ENSURE_SUCCESS(rv, rv); + if (host.IsEmpty()) + return NS_ERROR_FAILURE; + + nsCAutoString portKey; + portKey.AppendASCII(aKeyBase); + portKey.AppendLiteral("port"); + PRInt32 port; + rv = mGConf->GetInt(portKey, &port); + NS_ENSURE_SUCCESS(rv, rv); + + SetProxyResult(aType, host, port, aResult); + return NS_OK; +} + +/* copied from nsProtocolProxyService.cpp --- we should share this! */ +static void +proxy_MaskIPv6Addr(PRIPv6Addr &addr, PRUint16 mask_len) +{ + if (mask_len == 128) + return; + + if (mask_len > 96) { + addr.pr_s6_addr32[3] = PR_htonl( + PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len))); + } + else if (mask_len > 64) { + addr.pr_s6_addr32[3] = 0; + addr.pr_s6_addr32[2] = PR_htonl( + PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len))); + } + else if (mask_len > 32) { + addr.pr_s6_addr32[3] = 0; + addr.pr_s6_addr32[2] = 0; + addr.pr_s6_addr32[1] = PR_htonl( + PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len))); + } + else { + addr.pr_s6_addr32[3] = 0; + addr.pr_s6_addr32[2] = 0; + addr.pr_s6_addr32[1] = 0; + addr.pr_s6_addr32[0] = PR_htonl( + PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len))); + } +} + +static PRBool ConvertToIPV6Addr(const nsACString& aName, + PRIPv6Addr* aAddr) +{ + PRNetAddr addr; + if (PR_StringToNetAddr(PromiseFlatCString(aName).get(), &addr) != PR_SUCCESS) + return PR_FALSE; + + PRIPv6Addr ipv6; + // convert parsed address to IPv6 + if (addr.raw.family == PR_AF_INET) { + // convert to IPv4-mapped address + PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6); + } else if (addr.raw.family == PR_AF_INET6) { + // copy the address + memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr)); + } else { + return PR_FALSE; + } + + return PR_TRUE; +} + +static PRBool GConfIgnoreHost(const nsACString& aIgnore, + const nsACString& aHost) +{ + if (aIgnore.Equals(aHost, nsCaseInsensitiveCStringComparator())) + return PR_TRUE; + + if (aIgnore.First() == '*' && + StringEndsWith(aHost, nsDependentCSubstring(aIgnore, 1), + nsCaseInsensitiveCStringComparator())) + return PR_TRUE; + + PRInt32 mask = 128; + nsReadingIterator start; + nsReadingIterator slash; + nsReadingIterator end; + aIgnore.BeginReading(start); + aIgnore.BeginReading(slash); + aIgnore.EndReading(end); + if (FindCharInReadable('/', slash, end)) { + ++slash; + nsDependentCSubstring maskStr(slash, end); + nsCAutoString maskStr2(maskStr); + PRInt32 err; + mask = maskStr2.ToInteger(&err); + if (err != 0) { + mask = 128; + } + --slash; + } else { + slash = end; + } + + PRIPv6Addr ignoreAddr, hostAddr; + if (!ConvertToIPV6Addr(aIgnore, &ignoreAddr) || + !ConvertToIPV6Addr(aHost, &hostAddr)) + return PR_FALSE; + + proxy_MaskIPv6Addr(ignoreAddr, mask); + proxy_MaskIPv6Addr(hostAddr, mask); + + return memcmp(&ignoreAddr, &hostAddr, sizeof(PRIPv6Addr)) == 0; +} + +nsresult +nsUnixSystemProxySettings::GetProxyFromGConf(const nsACString& aScheme, + const nsACString& aHost, + PRInt32 aPort, + nsACString& aResult) +{ + PRBool masterProxySwitch = PR_FALSE; + mGConf->GetBool(NS_LITERAL_CSTRING("/system/http_proxy/use_http_proxy"), &masterProxySwitch); + if (!IsProxyMode("manual") || !masterProxySwitch) { + aResult.AppendLiteral("DIRECT"); + return NS_OK; + } + + nsCOMPtr ignoreList; + if (NS_SUCCEEDED(mGConf->GetStringList(NS_LITERAL_CSTRING("/system/http_proxy/ignore_hosts"), + getter_AddRefs(ignoreList))) && ignoreList) { + PRUint32 len = 0; + ignoreList->GetLength(&len); + for (PRUint32 i = 0; i < len; ++i) { + nsCOMPtr str = do_QueryElementAt(ignoreList, i); + if (str) { + nsAutoString s; + if (NS_SUCCEEDED(str->GetData(s)) && !s.IsEmpty()) { + if (GConfIgnoreHost(NS_ConvertUTF16toUTF8(s), aHost)) { + aResult.AppendLiteral("DIRECT"); + return NS_OK; + } + } + } + } + } + + PRBool useHttpProxyForAll = PR_FALSE; + // This setting sometimes doesn't exist, don't bail on failure + mGConf->GetBool(NS_LITERAL_CSTRING("/system/http_proxy/use_same_proxy"), &useHttpProxyForAll); + + nsresult rv; + if (!useHttpProxyForAll) { + rv = SetProxyResultFromGConf("/system/proxy/socks_", "SOCKS", aResult); + if (NS_SUCCEEDED(rv)) + return rv; + } + + if (aScheme.LowerCaseEqualsLiteral("http") || useHttpProxyForAll) { + rv = SetProxyResultFromGConf("/system/http_proxy/", "PROXY", aResult); + } else if (aScheme.LowerCaseEqualsLiteral("https")) { + rv = SetProxyResultFromGConf("/system/proxy/secure_", "PROXY", aResult); + } else if (aScheme.LowerCaseEqualsLiteral("ftp")) { + rv = SetProxyResultFromGConf("/system/proxy/ftp_", "PROXY", aResult); + } else { + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED(rv)) { + aResult.AppendLiteral("DIRECT"); + } + return NS_OK; +} + +nsresult +nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult) +{ + nsCAutoString scheme; + nsresult rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString host; + rv = aURI->GetHost(host); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 port; + rv = aURI->GetPort(&port); + NS_ENSURE_SUCCESS(rv, rv); + + if (!mGConf) + return GetProxyFromEnvironment(scheme, host, port, aResult); + + return GetProxyFromGConf(scheme, host, port, aResult); +} + +#define NS_UNIXSYSTEMPROXYSERVICE_CID /* 0fa3158c-d5a7-43de-9181-a285e74cf1d4 */\ + { 0x0fa3158c, 0xd5a7, 0x43de, \ + {0x91, 0x81, 0xa2, 0x85, 0xe7, 0x4c, 0xf1, 0xd4 } } + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUnixSystemProxySettings, Init) + +static const nsModuleComponentInfo components[] = { + { "Unix System Proxy Settings Service", + NS_UNIXSYSTEMPROXYSERVICE_CID, + NS_SYSTEMPROXYSETTINGS_CONTRACTID, + nsUnixSystemProxySettingsConstructor } +}; + +NS_IMPL_NSGETMODULE(nsUnixProxyModule, components) diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 380b5394d224..ca47e94a322d 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -661,6 +661,7 @@ MAKEFILES_xulapp=" toolkit/components/downloads/src/Makefile toolkit/components/filepicker/Makefile toolkit/system/gnome/Makefile + toolkit/system/unixproxy/Makefile toolkit/components/help/Makefile toolkit/components/history/Makefile toolkit/components/history/public/Makefile diff --git a/xpcom/system/nsIGConfService.idl b/xpcom/system/nsIGConfService.idl index fdd9399c0892..d1fceec636ff 100644 --- a/xpcom/system/nsIGConfService.idl +++ b/xpcom/system/nsIGConfService.idl @@ -37,8 +37,9 @@ * ***** END LICENSE BLOCK ***** */ #include "nsISupports.idl" +#include "nsIArray.idl" -[scriptable, uuid(01ac7b2e-c07c-465f-b35c-542eaef420a9)] +[scriptable, uuid(5009acae-6973-48c3-b6d6-52c692cc5d9d)] interface nsIGConfService : nsISupports { /* Basic registry access */ @@ -47,6 +48,12 @@ interface nsIGConfService : nsISupports long getInt(in AUTF8String key); float getFloat(in AUTF8String key); + /* + * Use this to return any list items in GConf, this will return + * an array of UTF16 nsISupportsString's. + */ + nsIArray getStringList(in AUTF8String key); + void setBool(in AUTF8String key, in boolean value); void setString(in AUTF8String key, in AUTF8String value); void setInt(in AUTF8String key, in long value);