author | Ed Morley <emorley@mozilla.com> |
Thu, 13 Sep 2012 22:42:29 +0100 | |
changeset 113331 | e59b9b887c2586b05613a2f696e981544705a68a |
parent 113330 | 710e45d869208cc9f410423d85d300a218661fe3 |
child 113332 | 8daf8d51c827ea0e3c7c649d9bc7abf3b55e7242 |
push id | 1708 |
push user | akeybl@mozilla.com |
push date | Mon, 19 Nov 2012 21:10:21 +0000 |
treeherder | mozilla-beta@27b14fe50103 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 347307, 507578, 769764 |
milestone | 18.0a1 |
backs out | 3182f9d08c2dc22f4234616169366a887b800cf3 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -361,16 +361,18 @@ #ifdef MOZ_GTK2 @BINPATH@/components/nsFilePicker.manifest @BINPATH@/components/nsFilePicker.js #endif @BINPATH@/components/nsHelperAppDlg.manifest @BINPATH@/components/nsHelperAppDlg.js @BINPATH@/components/nsDownloadManagerUI.manifest @BINPATH@/components/nsDownloadManagerUI.js +@BINPATH@/components/nsProxyAutoConfig.manifest +@BINPATH@/components/nsProxyAutoConfig.js @BINPATH@/components/NetworkGeolocationProvider.manifest @BINPATH@/components/NetworkGeolocationProvider.js @BINPATH@/components/GPSDGeolocationProvider.manifest @BINPATH@/components/GPSDGeolocationProvider.js @BINPATH@/components/nsSidebar.manifest @BINPATH@/components/nsSidebar.js @BINPATH@/components/extensions.manifest @BINPATH@/components/addonManager.js
--- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -356,16 +356,18 @@ #ifdef MOZ_GTK2 @BINPATH@/components/nsFilePicker.manifest @BINPATH@/components/nsFilePicker.js #endif @BINPATH@/components/nsHelperAppDlg.manifest @BINPATH@/components/nsHelperAppDlg.js @BINPATH@/components/nsDownloadManagerUI.manifest @BINPATH@/components/nsDownloadManagerUI.js +@BINPATH@/components/nsProxyAutoConfig.manifest +@BINPATH@/components/nsProxyAutoConfig.js @BINPATH@/components/NetworkGeolocationProvider.manifest @BINPATH@/components/NetworkGeolocationProvider.js @BINPATH@/components/GPSDGeolocationProvider.manifest @BINPATH@/components/GPSDGeolocationProvider.js @BINPATH@/components/nsSidebar.manifest @BINPATH@/components/nsSidebar.js @BINPATH@/components/extensions.manifest @BINPATH@/components/addonManager.js
--- a/browser/installer/removed-files.in +++ b/browser/installer/removed-files.in @@ -82,18 +82,16 @@ components/dom_system_b2g.xpt components/uconvd.dll components/WeaveCrypto.js components/WeaveCrypto.manifest components/xmlextras.xpt components/xpcom.xpt components/xpti.dat components/xptitemp.dat components/nsMicrosummaryService.js -components/nsProxyAutoConfig.manifest -components/nsProxyAutoConfig.js D3DCompiler_42.dll d3dx9_42.dll defaults/pref/all.js defaults/pref/bug259708.js defaults/pref/bug307259.js defaults/pref/reporter.js defaults/pref/security-prefs.js defaults/pref/winpref.js @@ -918,17 +916,16 @@ xpicleanup@BIN_SUFFIX@ components/nsLoginInfo.js components/nsLoginManager.js components/nsLoginManagerPrompter.js components/nsPlacesAutoComplete.js components/nsPlacesDBFlush.js components/nsPlacesExpiration.js components/nsPrivateBrowsingService.js components/nsPrompter.js - components/nsProxyAutoConfig.manifest components/nsProxyAutoConfig.js components/nsSafebrowsingApplication.js components/nsSearchService.js components/nsSearchSuggestions.js components/nsSessionStartup.js components/nsSessionStore.js components/nsSetDefaultBrowser.js components/nsSidebar.js
--- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -26,17 +26,17 @@ #include "nsIUploadChannel.h" #include "nsIByteRangeRequest.h" #include "nsIStreamListener.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" #include "nsIURL.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" -#include "nsIProtocolProxyService2.h" +#include "nsIProtocolProxyService.h" #include "nsIStreamConverterService.h" #include "nsIFile.h" #if defined(XP_MACOSX) #include "nsILocalFileMac.h" #endif #include "nsIInputStream.h" #include "nsIIOService.h" #include "nsIURL.h" @@ -738,40 +738,34 @@ nsresult nsPluginHost::FindProxyForURL(c { if (!url || !result) { return NS_ERROR_INVALID_ARG; } nsresult res; nsCOMPtr<nsIURI> uriIn; nsCOMPtr<nsIProtocolProxyService> proxyService; - nsCOMPtr<nsIProtocolProxyService2> proxyService2; nsCOMPtr<nsIIOService> ioService; proxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &res); if (NS_FAILED(res) || !proxyService) return res; - proxyService2 = do_QueryInterface(proxyService, &res); - if (NS_FAILED(res) || !proxyService) - return res; - ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &res); if (NS_FAILED(res) || !ioService) return res; // make an nsURI from the argument url res = ioService->NewURI(nsDependentCString(url), nullptr, nullptr, getter_AddRefs(uriIn)); if (NS_FAILED(res)) return res; nsCOMPtr<nsIProxyInfo> pi; - // Remove this with bug 778201 - res = proxyService2->DeprecatedBlockingResolve(uriIn, 0, getter_AddRefs(pi)); + res = proxyService->Resolve(uriIn, 0, getter_AddRefs(pi)); if (NS_FAILED(res)) return res; nsAutoCString host, type; int32_t port = -1; // These won't fail, and even if they do... we'll be ok. if (pi) {
--- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -270,16 +270,18 @@ #ifdef MOZ_GTK2 @BINPATH@/components/nsFilePicker.manifest @BINPATH@/components/nsFilePicker.js #endif @BINPATH@/components/nsHelperAppDlg.manifest @BINPATH@/components/nsHelperAppDlg.js @BINPATH@/components/nsDownloadManagerUI.manifest @BINPATH@/components/nsDownloadManagerUI.js +@BINPATH@/components/nsProxyAutoConfig.manifest +@BINPATH@/components/nsProxyAutoConfig.js @BINPATH@/components/NetworkGeolocationProvider.manifest @BINPATH@/components/NetworkGeolocationProvider.js @BINPATH@/components/GPSDGeolocationProvider.manifest @BINPATH@/components/GPSDGeolocationProvider.js @BINPATH@/components/nsSidebar.manifest @BINPATH@/components/nsSidebar.js @BINPATH@/components/extensions.manifest @BINPATH@/components/addonManager.js
--- a/mobile/xul/installer/package-manifest.in +++ b/mobile/xul/installer/package-manifest.in @@ -337,16 +337,18 @@ #ifdef MOZ_GTK2 @BINPATH@/components/nsFilePicker.manifest @BINPATH@/components/nsFilePicker.js #endif @BINPATH@/components/nsHelperAppDlg.manifest @BINPATH@/components/nsHelperAppDlg.js @BINPATH@/components/nsDownloadManagerUI.manifest @BINPATH@/components/nsDownloadManagerUI.js +@BINPATH@/components/nsProxyAutoConfig.manifest +@BINPATH@/components/nsProxyAutoConfig.js @BINPATH@/components/NetworkGeolocationProvider.manifest @BINPATH@/components/NetworkGeolocationProvider.js @BINPATH@/components/GPSDGeolocationProvider.manifest @BINPATH@/components/GPSDGeolocationProvider.js @BINPATH@/components/nsSidebar.manifest @BINPATH@/components/nsSidebar.js @BINPATH@/components/extensions.manifest @BINPATH@/components/addonManager.js
--- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -1117,19 +1117,16 @@ pref("network.IDN.blacklist_chars", "\u0 // This preference specifies a list of domains for which DNS lookups will be // IPv4 only. Works around broken DNS servers which can't handle IPv6 lookups // and/or allows the user to disable IPv6 on a per-domain basis. See bug 68796. pref("network.dns.ipv4OnlyDomains", ""); // This preference can be used to turn off IPv6 name lookups. See bug 68796. pref("network.dns.disableIPv6", false); -// This preference can be used to turn off DNS prefetch. -pref("network.dns.disablePrefetch", false); - // This preference controls whether or not URLs with UTF-8 characters are // escaped. Set this preference to TRUE for strict RFC2396 conformance. pref("network.standard-url.escape-utf8", true); // This preference controls whether or not URLs are always encoded and sent as // UTF-8. pref("network.standard-url.encode-utf8", true);
--- a/netwerk/base/public/Makefile.in +++ b/netwerk/base/public/Makefile.in @@ -61,16 +61,17 @@ XPIDLSRCS = \ nsIPrivateBrowsingService.idl \ nsIProgressEventSink.idl \ nsIPrompt.idl \ nsIProtocolProxyService.idl \ nsIProtocolProxyService2.idl \ nsIProtocolProxyFilter.idl \ nsIProtocolProxyCallback.idl \ nsIProxiedProtocolHandler.idl \ + nsIProxyAutoConfig.idl \ nsIProxyInfo.idl \ nsITransport.idl \ nsISocketTransport.idl \ nsISocketTransportService.idl \ nsISpeculativeConnect.idl \ nsIServerSocket.idl \ nsIResumableChannel.idl \ nsIRequestObserverProxy.idl \
--- a/netwerk/base/public/nsIProtocolProxyService.idl +++ b/netwerk/base/public/nsIProtocolProxyService.idl @@ -12,20 +12,34 @@ interface nsIProtocolProxyFilter; interface nsIProxyInfo; interface nsIChannel; interface nsIURI; /** * nsIProtocolProxyService provides methods to access information about * various network proxies. */ -[scriptable, uuid(e77c642b-026f-41ce-9b23-f829a6e3f300)] +[scriptable, uuid(d7ec6237-162e-40f5-a2b4-46ccd5fa83c9)] interface nsIProtocolProxyService : nsISupports { - /** Flag 1 << 0 is unused **/ + /** + * This flag may be passed to the resolve method to request that it fail + * instead of block the calling thread. Proxy Auto Config (PAC) may + * perform a synchronous DNS query, which may not return immediately. So, + * calling resolve without this flag may result in locking up the calling + * thread for a lengthy period of time. + * + * By passing this flag to resolve, one can failover to asyncResolve to + * avoid locking up the calling thread if a PAC query is required. + * + * When this flag is passed to resolve, resolve may throw the exception + * NS_BASE_STREAM_WOULD_BLOCK to indicate that it failed due to this flag + * being present. + */ + const unsigned long RESOLVE_NON_BLOCKING = 1 << 0; /** * When the proxy configuration is manual this flag may be passed to the * resolve and asyncResolve methods to request to prefer the SOCKS proxy * to HTTP ones. */ const unsigned long RESOLVE_PREFER_SOCKS_PROXY = 1 << 1; @@ -58,46 +72,67 @@ interface nsIProtocolProxyService : nsIS /** * When the proxy configuration is manual this flag may be passed to the * resolve and asyncResolve methods to that all methods will be tunneled via * CONNECT through the http proxy. */ const unsigned long RESOLVE_ALWAYS_TUNNEL = (1 << 4); /** - * This method returns via callback a nsIProxyInfo instance that identifies - * a proxy to be used for loading the given URI. Otherwise, this method returns - * null indicating that a direct connection should be used. + * This method returns a nsIProxyInfo instance that identifies a proxy to + * be used for loading the given URI. Otherwise, this method returns null + * indicating that a direct connection should be used. + * + * @param aURI + * The URI to test. + * @param aFlags + * A bit-wise combination of the RESOLVE_ flags defined above. Pass + * 0 to specify the default behavior. Any additional bits that do + * not correspond to a RESOLVE_ flag are reserved for future use. + * + * NOTE: If this proxy is unavailable, getFailoverForProxy may be called + * to determine the correct secondary proxy to be used. + * + * NOTE: If the protocol handler for the given URI supports + * nsIProxiedProtocolHandler, then the nsIProxyInfo instance returned from + * resolve may be passed to the newProxiedChannel method to create a + * nsIChannel to the given URI that uses the specified proxy. + * + * NOTE: However, if the nsIProxyInfo type is "http", then it means that + * the given URI should be loaded using the HTTP protocol handler, which + * also supports nsIProxiedProtocolHandler. + * + * NOTE: If PAC is configured, and the PAC file has not yet been loaded, + * then this method will return a nsIProxyInfo instance with a type of + * "unknown" to indicate to the consumer that asyncResolve should be used + * to wait for the PAC file to finish loading. Otherwise, the consumer + * may choose to treat the result as type "direct" if desired. + * + * @see nsIProxiedProtocolHandler::newProxiedChannel + */ + nsIProxyInfo resolve(in nsIURI aURI, in unsigned long aFlags); + + /** + * This method is an asychronous version of the resolve method. Unlike + * resolve, this method is guaranteed not to block the calling thread + * waiting for DNS queries to complete. This method is intended as a + * substitute for resolve when the result is not needed immediately. * * @param aURI * The URI to test. * @param aFlags * A bit-wise combination of the RESOLVE_ flags defined above. Pass * 0 to specify the default behavior. Any additional bits that do * not correspond to a RESOLVE_ flag are reserved for future use. * @param aCallback * The object to be notified when the result is available. * * @return An object that can be used to cancel the asychronous operation. * If canceled, the cancelation status (aReason) will be forwarded * to the callback's onProxyAvailable method via the aStatus param. - * - * NOTE: If this proxy is unavailable, getFailoverForProxy may be called - * to determine the correct secondary proxy to be used. - * - * NOTE: If the protocol handler for the given URI supports - * nsIProxiedProtocolHandler, then the nsIProxyInfo instance returned from - * resolve may be passed to the newProxiedChannel method to create a - * nsIChannel to the given URI that uses the specified proxy. - * - * NOTE: However, if the nsIProxyInfo type is "http", then it means that - * the given URI should be loaded using the HTTP protocol handler, which - * also supports nsIProxiedProtocolHandler. - * - * @see nsIProxiedProtocolHandler::newProxiedChannel */ nsICancelable asyncResolve(in nsIURI aURI, in unsigned long aFlags, in nsIProtocolProxyCallback aCallback); /** * This method may be called to construct a nsIProxyInfo instance from * the given parameters. This method may be useful in conjunction with * nsISocketTransportService::createTransport for creating, for example,
--- a/netwerk/base/public/nsIProtocolProxyService2.idl +++ b/netwerk/base/public/nsIProtocolProxyService2.idl @@ -4,26 +4,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIProtocolProxyService.idl" /** * An extension of nsIProtocolProxyService */ -[scriptable, uuid(bed3702d-9374-4804-a20f-32baed8e2954)] +[scriptable, uuid(dbd9565d-29b1-437a-bff5-2fc339e2c5df)] interface nsIProtocolProxyService2 : nsIProtocolProxyService { /** * Call this method to cause the PAC file (if any is configured) to be * reloaded. The PAC file is loaded asynchronously. */ void reloadPAC(); - - /** - * This exists so Java(tm) can migrate to an asynchronous interface. - * Do not use this unless you are the plugin interface, and even then you - * ought to feel horribly guilty because you will create main thread jank. - * - * No documentation - it is deprecated! - **/ - nsIProxyInfo deprecatedBlockingResolve(in nsIURI aURI, in unsigned long aFlags); };
--- a/netwerk/base/public/nsIProxiedProtocolHandler.idl +++ b/netwerk/base/public/nsIProxiedProtocolHandler.idl @@ -4,31 +4,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIProtocolHandler.idl" interface nsIChannel; interface nsIURI; interface nsIProxyInfo; -[scriptable, uuid(2b63fe69-b0fc-48f2-a2df-adb795a4ce5c)] +[scriptable, uuid(0a24fed4-1dd2-11b2-a75c-9f8b9a8f9ba7)] interface nsIProxiedProtocolHandler : nsIProtocolHandler { /** Create a new channel with the given proxyInfo * - * @param uri the channel uri - * @param proxyInfo any proxy information that has already been determined, - * or null if channel should later determine the proxy on its own using - * proxyResolveFlags/proxyURI - * @param proxyResolveFlags used if the proxy is later determined - * from nsIProtocolProxyService::asyncResolve - * @param proxyURI used if the proxy is later determined from - * nsIProtocolProxyService::asyncResolve with this as the proxyURI name. - * Generally this is the same as uri (or null which has the same - * effect), except in the case of websockets which wants to bootstrap - * to an http:// channel but make its proxy determination based on - * a ws:// uri. */ - nsIChannel newProxiedChannel(in nsIURI uri, in nsIProxyInfo proxyInfo, - in unsigned long proxyResolveFlags, - in nsIURI proxyURI); + nsIChannel newProxiedChannel(in nsIURI uri, in nsIProxyInfo proxyInfo); };
new file mode 100644 --- /dev/null +++ b/netwerk/base/public/nsIProxyAutoConfig.idl @@ -0,0 +1,68 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/** + * The nsIProxyAutoConfig interface is used for setting arbitrary proxy + * configurations based on the specified URL. + * + * Note this interface wraps (at least in the implementation) the older + * hacks of proxy auto config. + * + * - Gagan Saksena 04/23/00 + */ + +[scriptable, uuid(a42619df-0a1c-46fb-8154-0e9b8f8f1ea8)] +interface nsIProxyAutoConfig : nsISupports +{ + /** + * This method initializes the object. This method may be called multiple + * times. If either parameter is an empty value, then the object is + * reset to its initial state. + * + * @param aPACURI + * URI used to fetch the PAC script. This is needed for properly + * constructing the JS sandbox used to evaluate the PAC script. + * @param aPACScript + * Javascript program text. + */ + void init(in ACString aPACURI, in AString aPACScript); + + /** + * Get the proxy string for the specified URI. The proxy string is + * given by the following: + * + * result = proxy-spec *( proxy-sep proxy-spec ) + * proxy-spec = direct-type | proxy-type LWS proxy-host [":" proxy-port] + * direct-type = "DIRECT" + * proxy-type = "PROXY" | "SOCKS" | "SOCKS4" | "SOCKS5" + * proxy-sep = ";" LWS + * proxy-host = hostname | ipv4-address-literal + * proxy-port = <any 16-bit unsigned integer> + * LWS = *( SP | HT ) + * SP = <US-ASCII SP, space (32)> + * HT = <US-ASCII HT, horizontal-tab (9)> + * + * NOTE: direct-type and proxy-type are case insensitive + * NOTE: SOCKS implies SOCKS4 + * + * Examples: + * "PROXY proxy1.foo.com:8080; PROXY proxy2.foo.com:8080; DIRECT" + * "SOCKS socksproxy" + * "DIRECT" + * + * XXX add support for IPv6 address literals. + * XXX quote whatever the official standard is for PAC. + * + * @param aTestURI + * The URI as an ASCII string to test. + * @param aTestHost + * The ASCII hostname to test. + * + * @return PAC result string as defined above. + */ + ACString getProxyForURI(in ACString aTestURI, in ACString aTestHost); +};
--- a/netwerk/base/public/nsISystemProxySettings.idl +++ b/netwerk/base/public/nsISystemProxySettings.idl @@ -8,36 +8,22 @@ /** * 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(971591cd-277e-409a-bbf6-0a79879cd307)] +[scriptable, uuid(a9f3ae38-b769-4e0b-9317-578388e326c9)] interface nsISystemProxySettings : nsISupports { /** - * Whether or not it is appropriate to execute getProxyForURI off the main thread. - * If that method can block (e.g. for WPAD as windows does) then it must be - * not mainThreadOnly to avoid creating main thread jank. The main thread only option is - * provided for implementations that do not block but use other main thread only - * functions such as dbus. - */ - readonly attribute bool mainThreadOnly; - - /** * If non-empty, use this PAC file. If empty, call getProxyForURI instead. */ readonly attribute AUTF8String PACURI; /** - * See ProxyAutoConfig::getProxyForURI; this function behaves similarly except - * a more relaxed return string is allowed that includes full urls instead of just - * host:port syntax. e.g. "PROXY http://www.foo.com:8080" instead of - * "PROXY www.foo.com:8080" + * See nsIProxyAutoConfig::getProxyForURI; this function behaves exactly + * the same way. */ - AUTF8String getProxyForURI(in AUTF8String testSpec, - in AUTF8String testScheme, - in AUTF8String testHost, - in int32_t testPort); + AUTF8String getProxyForURI(in nsIURI aURI); };
--- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -846,16 +846,50 @@ NS_GetReferrerFromChannel(nsIChannel *ch rv = chan->GetReferrer(referrer); if (NS_FAILED(rv)) *referrer = nullptr; } } return rv; } +#ifdef MOZILLA_INTERNAL_API +inline nsresult +NS_ExamineForProxy(const char *scheme, + const char *host, + int32_t port, + nsIProxyInfo **proxyInfo) +{ + nsresult rv; + nsCOMPtr<nsIProtocolProxyService> pps = + do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + nsAutoCString spec(scheme); + spec.Append("://"); + spec.Append(host); + spec.Append(':'); + spec.AppendInt(port); + // XXXXX - Under no circumstances whatsoever should any code which + // wants a uri do this. I do this here because I do not, in fact, + // actually want a uri (the dummy uris created here may not be + // syntactically valid for the specific protocol), and all we need + // is something which has a valid scheme, hostname, and a string + // to pass to PAC if needed - bbaetz + nsCOMPtr<nsIURI> uri = + do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + rv = uri->SetSpec(spec); + if (NS_SUCCEEDED(rv)) + rv = pps->Resolve(uri, 0, proxyInfo); + } + } + return rv; +} +#endif + inline nsresult NS_ParseContentType(const nsACString &rawContentType, nsCString &contentType, nsCString &contentCharset) { // contentCharset is left untouched if not present in rawContentType nsresult rv; nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv);
--- a/netwerk/base/src/Makefile.in +++ b/netwerk/base/src/Makefile.in @@ -61,21 +61,18 @@ CPPSRCS = \ nsNetAddr.cpp \ nsNetStrings.cpp \ nsBase64Encoder.cpp \ nsSerializationHelper.cpp \ nsDNSPrefetch.cpp \ RedirectChannelRegistrar.cpp \ nsPreloadedStream.cpp \ nsStreamListenerWrapper.cpp \ - ProxyAutoConfig.cpp \ $(NULL) -LOCAL_INCLUDES += -I$(topsrcdir)/dom/base - ifeq ($(MOZ_WIDGET_TOOLKIT),os2) CPPSRCS += nsURLHelperOS2.cpp else ifeq ($(MOZ_WIDGET_TOOLKIT),windows) CPPSRCS += nsURLHelperWin.cpp CPPSRCS += nsNativeConnectionHelper.cpp CPPSRCS += nsAutodialWin.cpp else @@ -95,16 +92,21 @@ ifdef MOZ_ENABLE_LIBCONIC endif ifdef MOZ_ENABLE_QTNETWORK CPPSRCS += nsAutodialQt.cpp LOCAL_INCLUDES += -I$(srcdir)/../../system/qt OS_INCLUDES += $(MOZ_QT_CFLAGS) endif endif +EXTRA_COMPONENTS = \ + $(srcdir)/nsProxyAutoConfig.js \ + $(srcdir)/nsProxyAutoConfig.manifest \ + $(NULL) + EXTRA_JS_MODULES = \ NetUtil.jsm \ $(NULL) # we don't want the shared lib, but we want to force the creation of a # static lib. FORCE_STATIC_LIB = 1
deleted file mode 100644 --- a/netwerk/base/src/ProxyAutoConfig.cpp +++ /dev/null @@ -1,790 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ProxyAutoConfig.h" -#include "nsICancelable.h" -#include "nsIDNSListener.h" -#include "nsIDNSRecord.h" -#include "nsIDNSService.h" -#include "nsNetUtil.h" -#include "nsThreadUtils.h" -#include "nsIConsoleService.h" -#include "nsJSUtils.h" -#include "prnetdb.h" -#include "nsITimer.h" - -namespace mozilla { -namespace net { - -// These are some global helper symbols the PAC format requires that we provide that -// are initialized as part of the global javascript context used for PAC evaluations. -// Additionally dnsResolve(host) and myIpAddress() are supplied in the same context -// but are implemented as c++ helpers. proxyAlert(msg) is similarly defined, but that -// is a gecko specific extension. - -static const char *sPacUtils = - "function dnsDomainIs(host, domain) {\n" - " return (host.length >= domain.length &&\n" - " host.substring(host.length - domain.length) == domain);\n" - "}\n" - "" - "function dnsDomainLevels(host) {\n" - " return host.split('.').length - 1;\n" - "}\n" - "" - "function convert_addr(ipchars) {\n" - " var bytes = ipchars.split('.');\n" - " var result = ((bytes[0] & 0xff) << 24) |\n" - " ((bytes[1] & 0xff) << 16) |\n" - " ((bytes[2] & 0xff) << 8) |\n" - " (bytes[3] & 0xff);\n" - " return result;\n" - "}\n" - "" - "function isInNet(ipaddr, pattern, maskstr) {\n" - " var test = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ipaddr);\n" - " if (test == null) {\n" - " ipaddr = dnsResolve(ipaddr);\n" - " if (ipaddr == null)\n" - " return false;\n" - " } else if (test[1] > 255 || test[2] > 255 || \n" - " test[3] > 255 || test[4] > 255) {\n" - " return false; // not an IP address\n" - " }\n" - " var host = convert_addr(ipaddr);\n" - " var pat = convert_addr(pattern);\n" - " var mask = convert_addr(maskstr);\n" - " return ((host & mask) == (pat & mask));\n" - " \n" - "}\n" - "" - "function isPlainHostName(host) {\n" - " return (host.search('\\\\.') == -1);\n" - "}\n" - "" - "function isResolvable(host) {\n" - " var ip = dnsResolve(host);\n" - " return (ip != null);\n" - "}\n" - "" - "function localHostOrDomainIs(host, hostdom) {\n" - " return (host == hostdom) ||\n" - " (hostdom.lastIndexOf(host + '.', 0) == 0);\n" - "}\n" - "" - "function shExpMatch(url, pattern) {\n" - " pattern = pattern.replace(/\\./g, '\\\\.');\n" - " pattern = pattern.replace(/\\*/g, '.*');\n" - " pattern = pattern.replace(/\\?/g, '.');\n" - " var newRe = new RegExp('^'+pattern+'$');\n" - " return newRe.test(url);\n" - "}\n" - "" - "var wdays = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};\n" - "var months = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};\n" - "" - "function weekdayRange() {\n" - " function getDay(weekday) {\n" - " if (weekday in wdays) {\n" - " return wdays[weekday];\n" - " }\n" - " return -1;\n" - " }\n" - " var date = new Date();\n" - " var argc = arguments.length;\n" - " var wday;\n" - " if (argc < 1)\n" - " return false;\n" - " if (arguments[argc - 1] == 'GMT') {\n" - " argc--;\n" - " wday = date.getUTCDay();\n" - " } else {\n" - " wday = date.getDay();\n" - " }\n" - " var wd1 = getDay(arguments[0]);\n" - " var wd2 = (argc == 2) ? getDay(arguments[1]) : wd1;\n" - " return (wd1 == -1 || wd2 == -1) ? false\n" - " : (wd1 <= wday && wday <= wd2);\n" - "}\n" - "" - "function dateRange() {\n" - " function getMonth(name) {\n" - " if (name in months) {\n" - " return months[name];\n" - " }\n" - " return -1;\n" - " }\n" - " var date = new Date();\n" - " var argc = arguments.length;\n" - " if (argc < 1) {\n" - " return false;\n" - " }\n" - " var isGMT = (arguments[argc - 1] == 'GMT');\n" - "\n" - " if (isGMT) {\n" - " argc--;\n" - " }\n" - " // function will work even without explict handling of this case\n" - " if (argc == 1) {\n" - " var tmp = parseInt(arguments[0]);\n" - " if (isNaN(tmp)) {\n" - " return ((isGMT ? date.getUTCMonth() : date.getMonth()) ==\n" - " getMonth(arguments[0]));\n" - " } else if (tmp < 32) {\n" - " return ((isGMT ? date.getUTCDate() : date.getDate()) == tmp);\n" - " } else { \n" - " return ((isGMT ? date.getUTCFullYear() : date.getFullYear()) ==\n" - " tmp);\n" - " }\n" - " }\n" - " var year = date.getFullYear();\n" - " var date1, date2;\n" - " date1 = new Date(year, 0, 1, 0, 0, 0);\n" - " date2 = new Date(year, 11, 31, 23, 59, 59);\n" - " var adjustMonth = false;\n" - " for (var i = 0; i < (argc >> 1); i++) {\n" - " var tmp = parseInt(arguments[i]);\n" - " if (isNaN(tmp)) {\n" - " var mon = getMonth(arguments[i]);\n" - " date1.setMonth(mon);\n" - " } else if (tmp < 32) {\n" - " adjustMonth = (argc <= 2);\n" - " date1.setDate(tmp);\n" - " } else {\n" - " date1.setFullYear(tmp);\n" - " }\n" - " }\n" - " for (var i = (argc >> 1); i < argc; i++) {\n" - " var tmp = parseInt(arguments[i]);\n" - " if (isNaN(tmp)) {\n" - " var mon = getMonth(arguments[i]);\n" - " date2.setMonth(mon);\n" - " } else if (tmp < 32) {\n" - " date2.setDate(tmp);\n" - " } else {\n" - " date2.setFullYear(tmp);\n" - " }\n" - " }\n" - " if (adjustMonth) {\n" - " date1.setMonth(date.getMonth());\n" - " date2.setMonth(date.getMonth());\n" - " }\n" - " if (isGMT) {\n" - " var tmp = date;\n" - " tmp.setFullYear(date.getUTCFullYear());\n" - " tmp.setMonth(date.getUTCMonth());\n" - " tmp.setDate(date.getUTCDate());\n" - " tmp.setHours(date.getUTCHours());\n" - " tmp.setMinutes(date.getUTCMinutes());\n" - " tmp.setSeconds(date.getUTCSeconds());\n" - " date = tmp;\n" - " }\n" - " return ((date1 <= date) && (date <= date2));\n" - "}\n" - "" - "function timeRange() {\n" - " var argc = arguments.length;\n" - " var date = new Date();\n" - " var isGMT= false;\n" - "" - " if (argc < 1) {\n" - " return false;\n" - " }\n" - " if (arguments[argc - 1] == 'GMT') {\n" - " isGMT = true;\n" - " argc--;\n" - " }\n" - "\n" - " var hour = isGMT ? date.getUTCHours() : date.getHours();\n" - " var date1, date2;\n" - " date1 = new Date();\n" - " date2 = new Date();\n" - "\n" - " if (argc == 1) {\n" - " return (hour == arguments[0]);\n" - " } else if (argc == 2) {\n" - " return ((arguments[0] <= hour) && (hour <= arguments[1]));\n" - " } else {\n" - " switch (argc) {\n" - " case 6:\n" - " date1.setSeconds(arguments[2]);\n" - " date2.setSeconds(arguments[5]);\n" - " case 4:\n" - " var middle = argc >> 1;\n" - " date1.setHours(arguments[0]);\n" - " date1.setMinutes(arguments[1]);\n" - " date2.setHours(arguments[middle]);\n" - " date2.setMinutes(arguments[middle + 1]);\n" - " if (middle == 2) {\n" - " date2.setSeconds(59);\n" - " }\n" - " break;\n" - " default:\n" - " throw 'timeRange: bad number of arguments'\n" - " }\n" - " }\n" - "\n" - " if (isGMT) {\n" - " date.setFullYear(date.getUTCFullYear());\n" - " date.setMonth(date.getUTCMonth());\n" - " date.setDate(date.getUTCDate());\n" - " date.setHours(date.getUTCHours());\n" - " date.setMinutes(date.getUTCMinutes());\n" - " date.setSeconds(date.getUTCSeconds());\n" - " }\n" - " return ((date1 <= date) && (date <= date2));\n" - "}\n" - ""; - -// sRunning is defined for the helper functions only while the -// Javascript engine is running and the PAC object cannot be deleted -// or reset. -static ProxyAutoConfig *sRunning = nullptr; - -// The PACResolver is used for dnsResolve() -class PACResolver MOZ_FINAL : public nsIDNSListener - , public nsITimerCallback -{ -public: - NS_DECL_ISUPPORTS - - PACResolver() - : mStatus(NS_ERROR_FAILURE) - { - } - - // nsIDNSListener - NS_IMETHODIMP OnLookupComplete(nsICancelable *request, - nsIDNSRecord *record, - nsresult status) - { - if (mTimer) { - mTimer->Cancel(); - mTimer = nullptr; - } - - mRequest = nullptr; - mStatus = status; - mResponse = record; - return NS_OK; - } - - // nsITimerCallback - NS_IMETHODIMP Notify(nsITimer *timer) - { - if (mRequest) - mRequest->Cancel(NS_ERROR_NET_TIMEOUT); - mTimer = nullptr; - return NS_OK; - } - - nsresult mStatus; - nsCOMPtr<nsICancelable> mRequest; - nsCOMPtr<nsIDNSRecord> mResponse; - nsCOMPtr<nsITimer> mTimer; -}; -NS_IMPL_THREADSAFE_ISUPPORTS2(PACResolver, nsIDNSListener, nsITimerCallback) - -static -void PACLogToConsole(nsString &aMessage) -{ - nsCOMPtr<nsIConsoleService> consoleService = - do_GetService(NS_CONSOLESERVICE_CONTRACTID); - if (!consoleService) - return; - - consoleService->LogStringMessage(aMessage.get()); -} - -// Javascript errors are logged to the main error console -static void -PACErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) -{ - nsString formattedMessage(NS_LITERAL_STRING("PAC Execution Error: ")); - formattedMessage += report->ucmessage; - formattedMessage += NS_LITERAL_STRING(" ["); - formattedMessage += report->uclinebuf; - formattedMessage += NS_LITERAL_STRING("]"); - PACLogToConsole(formattedMessage); -} - -// timeout of 0 means the normal necko timeout strategy, otherwise the dns request -// will be canceled after aTimeout milliseconds -static -JSBool PACResolve(const nsCString &aHostName, PRNetAddr *aNetAddr, - unsigned int aTimeout) -{ - if (!sRunning) { - NS_WARNING("PACResolve without a running ProxyAutoConfig object"); - return false; - } - - return sRunning->ResolveAddress(aHostName, aNetAddr, aTimeout); -} - -bool -ProxyAutoConfig::ResolveAddress(const nsCString &aHostName, - PRNetAddr *aNetAddr, - unsigned int aTimeout) -{ - nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); - if (!dns) - return false; - - nsRefPtr<PACResolver> helper = new PACResolver(); - - if (NS_FAILED(dns->AsyncResolve(aHostName, 0, helper, - NS_GetCurrentThread(), - getter_AddRefs(helper->mRequest)))) - return false; - - if (aTimeout && helper->mRequest) { - if (!mTimer) - mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - if (mTimer) { - mTimer->InitWithCallback(helper, aTimeout, nsITimer::TYPE_ONE_SHOT); - helper->mTimer = mTimer; - } - } - - // Spin the event loop of the pac thread until lookup is complete. - // nsPACman is responsible for keeping a queue and only allowing - // one PAC execution at a time even when it is called re-entrantly. - while (helper->mRequest) - NS_ProcessNextEvent(NS_GetCurrentThread()); - - if (NS_FAILED(helper->mStatus) || - NS_FAILED(helper->mResponse->GetNextAddr(0, aNetAddr))) - return false; - return true; -} - -static -bool PACResolveToString(const nsCString &aHostName, - nsCString &aDottedDecimal, - unsigned int aTimeout) -{ - PRNetAddr netAddr; - if (!PACResolve(aHostName, &netAddr, aTimeout)) - return false; - - char dottedDecimal[128]; - if (PR_NetAddrToString(&netAddr, dottedDecimal, sizeof(dottedDecimal)) != PR_SUCCESS) - return false; - - aDottedDecimal.Assign(dottedDecimal); - return true; -} - -// dnsResolve(host) javascript implementation -static -JSBool PACDnsResolve(JSContext *cx, unsigned int argc, jsval *vp) -{ - if (NS_IsMainThread()) { - NS_WARNING("DNS Resolution From PAC on Main Thread. How did that happen?"); - return false; - } - - JSString *arg1 = nullptr; - if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &arg1)) - return false; - - nsDependentJSString hostName; - nsAutoCString dottedDecimal; - - if (!hostName.init(cx, arg1)) - return false; - if (!PACResolveToString(NS_ConvertUTF16toUTF8(hostName), dottedDecimal, 0)) - return false; - - JSString *dottedDecimalString = JS_NewStringCopyZ(cx, dottedDecimal.get()); - JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString)); - return true; -} - -// myIpAddress() javascript implementation -static -JSBool PACMyIpAddress(JSContext *cx, unsigned int argc, jsval *vp) -{ - if (NS_IsMainThread()) { - NS_WARNING("DNS Resolution From PAC on Main Thread. How did that happen?"); - return false; - } - - if (!sRunning) { - NS_WARNING("PAC myIPAddress without a running ProxyAutoConfig object"); - return JS_FALSE; - } - - return sRunning->MyIPAddress(vp); -} - -// proxyAlert(msg) javascript implementation -static -JSBool PACProxyAlert(JSContext *cx, unsigned int argc, jsval *vp) -{ - JSString *arg1 = nullptr; - if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &arg1)) - return false; - - nsDependentJSString message; - if (!message.init(cx, arg1)) - return false; - - nsString alertMessage; - alertMessage.SetCapacity(32 + message.Length()); - alertMessage += NS_LITERAL_STRING("PAC-alert: "); - alertMessage += message; - PACLogToConsole(alertMessage); - - JS_SET_RVAL(cx, vp, JSVAL_VOID); /* return undefined */ - return true; -} - -static JSFunctionSpec PACGlobalFunctions[] = { - JS_FS("dnsResolve", PACDnsResolve, 1, 0), - JS_FS("myIpAddress", PACMyIpAddress, 0, 0), - JS_FS("proxyAlert", PACProxyAlert, 1, 0), - JS_FS_END -}; - -// JSRuntimeWrapper is a c++ object that manages the runtime and context -// for the JS engine used on the PAC thread. It is initialized and destroyed -// on the PAC thread. -class JSRuntimeWrapper -{ - public: - static JSRuntimeWrapper *Create() - { - JSRuntimeWrapper *entry = new JSRuntimeWrapper(); - - if (NS_FAILED(entry->Init())) { - delete entry; - return nullptr; - } - - return entry; - } - - JSContext *Context() const - { - return mContext; - } - - JSObject *Global() const - { - return mGlobal; - } - - ~JSRuntimeWrapper() - { - MOZ_COUNT_DTOR(JSRuntimeWrapper); - if (mContext) { - JS_DestroyContext(mContext); - } - - if (mRuntime) { - JS_DestroyRuntime(mRuntime); - } - } - - void SetOK() - { - mOK = true; - } - - bool IsOK() - { - return mOK; - } - -private: - static const unsigned sRuntimeHeapSize = 2 << 20; - - JSRuntime *mRuntime; - JSContext *mContext; - JSObject *mGlobal; - bool mOK; - - static JSClass sGlobalClass; - - JSRuntimeWrapper() - : mRuntime(nullptr), mContext(nullptr), mGlobal(nullptr), mOK(false) - { - MOZ_COUNT_CTOR(JSRuntimeWrapper); - } - - nsresult Init() - { - mRuntime = JS_NewRuntime(sRuntimeHeapSize); - NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY); - - mContext = JS_NewContext(mRuntime, 0); - NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY); - - JSAutoRequest ar(mContext); - - mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr); - NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY); - - JS_SetGlobalObject(mContext, mGlobal); - JS_InitStandardClasses(mContext, mGlobal); - - JS_SetVersion(mContext, JSVERSION_LATEST); - JS_SetErrorReporter(mContext, PACErrorReporter); - - if (!JS_DefineFunctions(mContext, mGlobal, PACGlobalFunctions)) - return NS_ERROR_FAILURE; - - return NS_OK; - } -}; - -JSClass JSRuntimeWrapper::sGlobalClass = { - "PACResolutionThreadGlobal", - JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub -}; - -nsresult -ProxyAutoConfig::Init(const nsCString &aPACURI, - const nsCString &aPACScript) -{ - mPACURI = aPACURI; - mPACScript = sPacUtils; - mPACScript.Append(aPACScript); - - if (!sRunning) - return SetupJS(); - - mJSNeedsSetup = true; - return NS_OK; -} - -nsresult -ProxyAutoConfig::SetupJS() -{ - mJSNeedsSetup = false; - NS_ABORT_IF_FALSE(!sRunning, "JIT is running"); - - delete mJSRuntime; - mJSRuntime = nullptr; - - if (mPACScript.IsEmpty()) - return NS_ERROR_FAILURE; - - mJSRuntime = JSRuntimeWrapper::Create(); - if (!mJSRuntime) - return NS_ERROR_FAILURE; - - JSAutoRequest ar(mJSRuntime->Context()); - - JSScript *script = JS_CompileScript(mJSRuntime->Context(), - mJSRuntime->Global(), - mPACScript.get(), mPACScript.Length(), - mPACURI.get(), 1); - if (!JS_ExecuteScript(mJSRuntime->Context(), mJSRuntime->Global(), script, nullptr)) { - nsString alertMessage(NS_LITERAL_STRING("PAC file failed to install from ")); - alertMessage += NS_ConvertUTF8toUTF16(mPACURI); - PACLogToConsole(alertMessage); - return NS_ERROR_FAILURE; - } - - mJSRuntime->SetOK(); - nsString alertMessage(NS_LITERAL_STRING("PAC file installed from ")); - alertMessage += NS_ConvertUTF8toUTF16(mPACURI); - PACLogToConsole(alertMessage); - - // we don't need these now - mPACScript.Truncate(); - mPACURI.Truncate(); - - return NS_OK; -} - -nsresult -ProxyAutoConfig::GetProxyForURI(const nsCString &aTestURI, - const nsCString &aTestHost, - nsACString &result) -{ - if (mJSNeedsSetup) - SetupJS(); - - if (!mJSRuntime || !mJSRuntime->IsOK()) - return NS_ERROR_NOT_AVAILABLE; - - JSContext *cx = mJSRuntime->Context(); - JSAutoRequest ar(cx); - - // the sRunning flag keeps a new PAC file from being installed - // while the event loop is spinning on a DNS function. Don't early return. - sRunning = this; - mRunningHost = aTestHost; - - nsresult rv = NS_ERROR_FAILURE; - JS::RootedString uriString(cx, JS_NewStringCopyZ(cx, aTestURI.get())); - JS::RootedString hostString(cx, JS_NewStringCopyZ(cx, aTestHost.get())); - - if (uriString && hostString) { - JS::RootedValue uriValue(cx, STRING_TO_JSVAL(uriString)); - JS::RootedValue hostValue(cx, STRING_TO_JSVAL(hostString)); - - jsval argv[2] = { uriValue, hostValue }; - jsval rval; - JSBool ok = JS_CallFunctionName(cx, mJSRuntime->Global(), - "FindProxyForURL", 2, argv, &rval); - - if (ok && rval.isString()) { - nsDependentJSString pacString; - if (pacString.init(cx, rval.toString())) { - CopyUTF16toUTF8(pacString, result); - rv = NS_OK; - } - } - } - - mRunningHost.Truncate(); - sRunning = nullptr; - return rv; -} - -void -ProxyAutoConfig::GC() -{ - if (!mJSRuntime || !mJSRuntime->IsOK()) - return; - - JS_MaybeGC(mJSRuntime->Context()); -} - -ProxyAutoConfig::~ProxyAutoConfig() -{ - MOZ_COUNT_DTOR(ProxyAutoConfig); - NS_ASSERTION(!mJSRuntime, - "~ProxyAutoConfig leaking JS runtime that " - "should have been deleted on pac thread"); -} - -void -ProxyAutoConfig::Shutdown() -{ - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread for shutdown"); - - if (sRunning || mShutdown) - return; - - mShutdown = true; - delete mJSRuntime; - mJSRuntime = nullptr; -} - -bool -ProxyAutoConfig::SrcAddress(const PRNetAddr *remoteAddress, nsCString &localAddress) -{ - PRFileDesc *fd; - fd = PR_OpenUDPSocket(remoteAddress->raw.family); - if (!fd) - return false; - - if (PR_Connect(fd, remoteAddress, 0) != PR_SUCCESS) { - PR_Close(fd); - return false; - } - - PRNetAddr localName; - if (PR_GetSockName(fd, &localName) != PR_SUCCESS) { - PR_Close(fd); - return false; - } - - PR_Close(fd); - - char dottedDecimal[128]; - if (PR_NetAddrToString(&localName, dottedDecimal, sizeof(dottedDecimal)) != PR_SUCCESS) - return false; - - localAddress.Assign(dottedDecimal); - - return true; -} - -// hostName is run through a dns lookup and then a udp socket is connected -// to the result. If that all works, the local IP address of the socket is -// returned to the javascript caller and true is returned from this function. -// otherwise false is returned. -bool -ProxyAutoConfig::MyIPAddressTryHost(const nsCString &hostName, - unsigned int timeout, - jsval *vp) -{ - PRNetAddr remoteAddress; - nsAutoCString localDottedDecimal; - JSContext *cx = mJSRuntime->Context(); - - if (PACResolve(hostName, &remoteAddress, timeout) && - SrcAddress(&remoteAddress, localDottedDecimal)) { - JSString *dottedDecimalString = - JS_NewStringCopyZ(cx, localDottedDecimal.get()); - JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString)); - return true; - } - return false; -} - -bool -ProxyAutoConfig::MyIPAddress(jsval *vp) -{ - nsAutoCString remoteDottedDecimal; - nsAutoCString localDottedDecimal; - JSContext *cx = mJSRuntime->Context(); - - // first, lookup the local address of a socket connected - // to the host of uri being resolved by the pac file. This is - // v6 safe.. but is the last step like that - if (MyIPAddressTryHost(mRunningHost, kTimeout, vp)) - return true; - - // next, look for a route to a public internet address that doesn't need DNS. - // This is the google anycast dns address, but it doesn't matter if it - // remains operable (as we don't contact it) as long as the address stays - // in commonly routed IP address space. - remoteDottedDecimal.AssignLiteral("8.8.8.8"); - if (MyIPAddressTryHost(remoteDottedDecimal, 0, vp)) - return true; - - // next, use the old algorithm based on the local hostname - nsAutoCString hostName; - nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); - if (dns && NS_SUCCEEDED(dns->GetMyHostName(hostName)) && - PACResolveToString(hostName, localDottedDecimal, kTimeout)) { - JSString *dottedDecimalString = - JS_NewStringCopyZ(cx, localDottedDecimal.get()); - JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString)); - return true; - } - - // next try a couple RFC 1918 variants.. maybe there is a - // local route - remoteDottedDecimal.AssignLiteral("192.168.0.1"); - if (MyIPAddressTryHost(remoteDottedDecimal, 0, vp)) - return true; - - // more RFC 1918 - remoteDottedDecimal.AssignLiteral("10.0.0.1"); - if (MyIPAddressTryHost(remoteDottedDecimal, 0, vp)) - return true; - - // who knows? let's fallback to localhost - localDottedDecimal.AssignLiteral("127.0.0.1"); - JSString *dottedDecimalString = - JS_NewStringCopyZ(cx, localDottedDecimal.get()); - JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString)); - return true; -} - -} // namespace mozilla -} // namespace mozilla::net
deleted file mode 100644 --- a/netwerk/base/src/ProxyAutoConfig.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef ProxyAutoConfig_h__ -#define ProxyAutoConfig_h__ - -#include "nsString.h" -#include "jsapi.h" -#include "prio.h" -#include "nsITimer.h" -#include "nsAutoPtr.h" - -namespace mozilla { namespace net { - -class JSRuntimeWrapper; - -// The ProxyAutoConfig class is meant to be created and run on a -// non main thread. It synchronously resolves PAC files by blocking that -// thread and running nested event loops. GetProxyForURI is not re-entrant. - -class ProxyAutoConfig { -public: - ProxyAutoConfig() - : mJSRuntime(nullptr) - , mJSNeedsSetup(false) - , mShutdown(false) - { - MOZ_COUNT_CTOR(ProxyAutoConfig); - } - ~ProxyAutoConfig(); - - nsresult Init(const nsCString &aPACURI, - const nsCString &aPACScript); - void Shutdown(); - void GC(); - bool MyIPAddress(jsval *vp); - bool ResolveAddress(const nsCString &aHostName, - PRNetAddr *aNetAddr, unsigned int aTimeout); - - /** - * Get the proxy string for the specified URI. The proxy string is - * given by the following: - * - * result = proxy-spec *( proxy-sep proxy-spec ) - * proxy-spec = direct-type | proxy-type LWS proxy-host [":" proxy-port] - * direct-type = "DIRECT" - * proxy-type = "PROXY" | "SOCKS" | "SOCKS4" | "SOCKS5" - * proxy-sep = ";" LWS - * proxy-host = hostname | ipv4-address-literal - * proxy-port = <any 16-bit unsigned integer> - * LWS = *( SP | HT ) - * SP = <US-ASCII SP, space (32)> - * HT = <US-ASCII HT, horizontal-tab (9)> - * - * NOTE: direct-type and proxy-type are case insensitive - * NOTE: SOCKS implies SOCKS4 - * - * Examples: - * "PROXY proxy1.foo.com:8080; PROXY proxy2.foo.com:8080; DIRECT" - * "SOCKS socksproxy" - * "DIRECT" - * - * XXX add support for IPv6 address literals. - * XXX quote whatever the official standard is for PAC. - * - * @param aTestURI - * The URI as an ASCII string to test. - * @param aTestHost - * The ASCII hostname to test. - * - * @param result - * result string as defined above. - */ - nsresult GetProxyForURI(const nsCString &aTestURI, - const nsCString &aTestHost, - nsACString &result); - -private: - const static unsigned int kTimeout = 1000; // ms to allow for myipaddress dns queries - - // used to compile the PAC file and setup the execution context - nsresult SetupJS(); - - bool SrcAddress(const PRNetAddr *remoteAddress, nsCString &localAddress); - bool MyIPAddressTryHost(const nsCString &hostName, unsigned int timeout, - jsval *vp); - - JSRuntimeWrapper *mJSRuntime; - bool mJSNeedsSetup; - bool mShutdown; - nsCString mPACScript; - nsCString mPACURI; - nsCString mRunningHost; - nsCOMPtr<nsITimer> mTimer; -}; - -}} // namespace mozilla::net - -#endif // ProxyAutoConfig_h__
--- a/netwerk/base/src/nsBaseChannel.cpp +++ b/netwerk/base/src/nsBaseChannel.cpp @@ -696,35 +696,32 @@ nsBaseChannel::OnStartRequest(nsIRequest // Now, the general type sniffers. Skip this if we have none. if ((mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) && gIOService->GetContentSniffers().Count() != 0) mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this)); SUSPEND_PUMP_FOR_SCOPE(); - if (mListener) // null in case of redirect - return mListener->OnStartRequest(this, mListenerContext); - return NS_OK; + return mListener->OnStartRequest(this, mListenerContext); } NS_IMETHODIMP nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status) { // If both mStatus and status are failure codes, we keep mStatus as-is since // that is consistent with our GetStatus and Cancel methods. if (NS_SUCCEEDED(mStatus)) mStatus = status; // Cause IsPending to return false. mPump = nullptr; - if (mListener) // null in case of redirect - mListener->OnStopRequest(this, mListenerContext, mStatus); + mListener->OnStopRequest(this, mListenerContext, mStatus); mListener = nullptr; mListenerContext = nullptr; // No need to suspend pump in this scope since we will not be receiving // any more events from it. if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
--- a/netwerk/base/src/nsIOService.cpp +++ b/netwerk/base/src/nsIOService.cpp @@ -34,19 +34,16 @@ #include "nsSimpleNestedURI.h" #include "nsNetUtil.h" #include "nsThreadUtils.h" #include "nsIPermissionManager.h" #include "nsTArray.h" #include "nsIConsoleService.h" #include "nsIUploadChannel2.h" #include "nsXULAppAPI.h" -#include "nsIProxiedChannel.h" -#include "nsIProtocolProxyCallback.h" -#include "nsICancelable.h" #include "mozilla/FunctionTimer.h" #if defined(XP_WIN) || defined(MOZ_PLATFORM_MAEMO) #include "nsNativeConnectionHelper.h" #endif #define PORT_PREF_PREFIX "network.security.ports." @@ -574,16 +571,41 @@ nsIOService::NewFileURI(nsIFile *file, n } NS_IMETHODIMP nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result) { return NewChannelFromURIWithProxyFlags(aURI, nullptr, 0, result); } +void +nsIOService::LookupProxyInfo(nsIURI *aURI, + nsIURI *aProxyURI, + uint32_t aProxyFlags, + nsCString *aScheme, + nsIProxyInfo **outPI) +{ + nsresult rv; + nsCOMPtr<nsIProxyInfo> pi; + + if (!mProxyService) { + mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID); + if (!mProxyService) + NS_WARNING("failed to get protocol proxy service"); + } + if (mProxyService) { + rv = mProxyService->Resolve(aProxyURI ? aProxyURI : aURI, aProxyFlags, + getter_AddRefs(pi)); + if (NS_FAILED(rv)) + pi = nullptr; + } + pi.forget(outPI); +} + + NS_IMETHODIMP nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI, nsIURI *aProxyURI, uint32_t aProxyFlags, nsIChannel **result) { nsresult rv; NS_ENSURE_ARG_POINTER(aURI); @@ -598,21 +620,36 @@ nsIOService::NewChannelFromURIWithProxyF if (NS_FAILED(rv)) return rv; uint32_t protoFlags; rv = handler->GetProtocolFlags(&protoFlags); if (NS_FAILED(rv)) return rv; - nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); - if (pph) - rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, result); - else - rv = handler->NewChannel(aURI, result); + // Talk to the PPS if the protocol handler allows proxying. Otherwise, + // skip this step. This allows us to lazily load the PPS at startup. + if (protoFlags & nsIProtocolHandler::ALLOWS_PROXY) { + nsCOMPtr<nsIProxyInfo> pi; + LookupProxyInfo(aURI, aProxyURI, aProxyFlags, &scheme, getter_AddRefs(pi)); + if (pi) { + nsAutoCString type; + if (NS_SUCCEEDED(pi->GetType(type)) && type.EqualsLiteral("http")) { + // we are going to proxy this channel using an http proxy + rv = GetProtocolHandler("http", getter_AddRefs(handler)); + if (NS_FAILED(rv)) + return rv; + } + nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); + if (pph) + return pph->NewProxiedChannel(aURI, pi, result); + } + } + + rv = handler->NewChannel(aURI, result); NS_ENSURE_SUCCESS(rv, rv); // Some extensions override the http protocol handler and provide their own // implementation. The channels returned from that implementation doesn't // seem to always implement the nsIUploadChannel2 interface, presumably // because it's a new interface. // Eventually we should remove this and simply require that http channels // implement the new interface. @@ -1170,84 +1207,40 @@ nsIOService::ExtractCharsetFromContentTy aCharsetStart, aCharsetEnd); if (*aHadCharset && *aCharsetStart == *aCharsetEnd) { *aHadCharset = false; } return NS_OK; } // nsISpeculativeConnect -class IOServiceProxyCallback MOZ_FINAL : public nsIProtocolProxyCallback +NS_IMETHODIMP +nsIOService::SpeculativeConnect(nsIURI *aURI, + nsIInterfaceRequestor *aCallbacks, + nsIEventTarget *aTarget) { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPROTOCOLPROXYCALLBACK - - IOServiceProxyCallback(nsIInterfaceRequestor *aCallbacks, - nsIEventTarget *aTarget, - nsIOService *aIOService) - : mCallbacks(aCallbacks) - , mTarget(aTarget) - , mIOService(aIOService) - { } - -private: - nsRefPtr<nsIInterfaceRequestor> mCallbacks; - nsRefPtr<nsIEventTarget> mTarget; - nsRefPtr<nsIOService> mIOService; -}; - -NS_IMPL_ISUPPORTS1(IOServiceProxyCallback, nsIProtocolProxyCallback) - -NS_IMETHODIMP -IOServiceProxyCallback::OnProxyAvailable(nsICancelable *request, nsIURI *aURI, - nsIProxyInfo *pi, nsresult status) -{ - // Checking proxy status for speculative connect - nsAutoCString type; - if (NS_SUCCEEDED(status) && pi && - NS_SUCCEEDED(pi->GetType(type)) && - !type.EqualsLiteral("direct")) { - // proxies dont do speculative connect - return NS_OK; - } - nsAutoCString scheme; nsresult rv = aURI->GetScheme(scheme); if (NS_FAILED(rv)) + return rv; + + // Check for proxy information. If there is a proxy configured then a + // speculative connect should not be performed because the potential + // reward is slim with tcp peers closely located to the browser. + nsCOMPtr<nsIProxyInfo> pi; + LookupProxyInfo(aURI, nullptr, 0, &scheme, getter_AddRefs(pi)); + if (pi) return NS_OK; nsCOMPtr<nsIProtocolHandler> handler; - rv = mIOService->GetProtocolHandler(scheme.get(), - getter_AddRefs(handler)); + rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); if (NS_FAILED(rv)) - return NS_OK; + return rv; nsCOMPtr<nsISpeculativeConnect> speculativeHandler = do_QueryInterface(handler); if (!speculativeHandler) return NS_OK; - speculativeHandler->SpeculativeConnect(aURI, - mCallbacks, - mTarget); - return NS_OK; + return speculativeHandler->SpeculativeConnect(aURI, + aCallbacks, + aTarget); } - -NS_IMETHODIMP -nsIOService::SpeculativeConnect(nsIURI *aURI, - nsIInterfaceRequestor *aCallbacks, - nsIEventTarget *aTarget) -{ - // Check for proxy information. If there is a proxy configured then a - // speculative connect should not be performed because the potential - // reward is slim with tcp peers closely located to the browser. - nsresult rv; - nsCOMPtr<nsIProtocolProxyService> pps = - do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsICancelable> cancelable; - nsRefPtr<IOServiceProxyCallback> callback = - new IOServiceProxyCallback(aCallbacks, aTarget, this); - return pps->AsyncResolve(aURI, 0, callback, getter_AddRefs(cancelable)); -}
--- a/netwerk/base/src/nsPACMan.cpp +++ b/netwerk/base/src/nsPACMan.cpp @@ -1,34 +1,31 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPACMan.h" #include "nsThreadUtils.h" +#include "nsIDNSService.h" +#include "nsIDNSListener.h" +#include "nsICancelable.h" #include "nsIAuthPrompt.h" #include "nsIPromptFactory.h" #include "nsIHttpChannel.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsNetUtil.h" +#include "nsAutoPtr.h" #include "nsCRT.h" #include "prmon.h" #include "nsIAsyncVerifyRedirectCallback.h" -#include "nsProxyRelease.h" //----------------------------------------------------------------------------- -using namespace mozilla; -using namespace mozilla::net; - -// The PAC thread does evaluations of both PAC files and -// nsISystemProxySettings because they can both block the calling thread and we -// don't want that on the main thread // Check to see if the underlying request was not an error page in the case of // a HTTP request. For other types of channels, just return true. static bool HttpRequestSucceeded(nsIStreamLoader *loader) { nsCOMPtr<nsIRequest> request; loader->GetRequest(getter_AddRefs(request)); @@ -39,305 +36,199 @@ HttpRequestSucceeded(nsIStreamLoader *lo if (httpChannel) httpChannel->GetRequestSucceeded(&result); return result; } //----------------------------------------------------------------------------- -// The ExecuteCallback runnable is triggered by -// nsPACManCallback::OnQueryComplete on the Main thread when its completion is -// discovered on the pac thread +// These objects are stored in nsPACMan::mPendingQ -class ExecuteCallback MOZ_FINAL : public nsRunnable +class PendingPACQuery MOZ_FINAL : public PRCList, + public nsIDNSListener { public: - ExecuteCallback(nsPACManCallback *aCallback, - nsresult status) - : mCallback(aCallback) - , mStatus(status) - { - } - - void SetPACString(const nsCString &pacString) - { - mPACString = pacString; - } - - void SetPACURL(const nsCString &pacURL) - { - mPACURL = pacURL; - } - - NS_IMETHODIMP Run() - { - mCallback->OnQueryComplete(mStatus, mPACString, mPACURL); - mCallback = nullptr; - return NS_OK; - } - -private: - nsRefPtr<nsPACManCallback> mCallback; - nsresult mStatus; - nsCString mPACString; - nsCString mPACURL; -}; - -//----------------------------------------------------------------------------- + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSLISTENER -// The PAC thread must be deleted from the main thread, this class -// acts as a proxy to do that, as the PACMan is reference counted -// and might be destroyed on either thread - -class ShutdownThread MOZ_FINAL : public nsRunnable -{ -public: - ShutdownThread(nsIThread *thread) - : mThread(thread) - { - } - - NS_IMETHODIMP Run() + PendingPACQuery(nsPACMan *pacMan, nsIURI *uri, nsPACManCallback *callback) + : mPACMan(pacMan) + , mURI(uri) + , mCallback(callback) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); - mThread->Shutdown(); - return NS_OK; - } - -private: - nsCOMPtr<nsIThread> mThread; -}; - -//----------------------------------------------------------------------------- - -// PACLoadComplete allows the PAC thread to tell the main thread that -// the javascript PAC file has been installed (perhaps unsuccessfully) -// and that there is no reason to queue executions anymore - -class PACLoadComplete MOZ_FINAL : public nsRunnable -{ -public: - PACLoadComplete(nsPACMan *aPACMan) - : mPACMan(aPACMan) - { + PR_INIT_CLIST(this); } - NS_IMETHODIMP Run() - { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); - mPACMan->mLoader = nullptr; - mPACMan->PostProcessPendingQ(); - return NS_OK; - } + nsresult Start(uint32_t flags); + void Complete(nsresult status, const nsCString &pacString); private: - nsRefPtr<nsPACMan> mPACMan; + nsPACMan *mPACMan; // weak reference + nsCOMPtr<nsIURI> mURI; + nsRefPtr<nsPACManCallback> mCallback; + nsCOMPtr<nsICancelable> mDNSRequest; }; -//----------------------------------------------------------------------------- +// This is threadsafe because we implement nsIDNSListener +NS_IMPL_THREADSAFE_ISUPPORTS1(PendingPACQuery, nsIDNSListener) -// ExecutePACThreadAction is used to proxy actions from the main -// thread onto the PAC thread. There are 3 options: process the queue, -// cancel the queue, and setup the javascript context with a new PAC file - -class ExecutePACThreadAction MOZ_FINAL : public nsRunnable +nsresult +PendingPACQuery::Start(uint32_t flags) { -public: - // by default we just process the queue - ExecutePACThreadAction(nsPACMan *aPACMan) - : mPACMan(aPACMan) - , mCancel(false) - , mSetupPAC(false) - { } + if (mDNSRequest) + return NS_OK; // already started - void CancelQueue (nsresult status) - { - mCancel = true; - mCancelStatus = status; - } - - void SetupPAC (const char *text, uint32_t datalen, nsCString &pacURI) - { - mSetupPAC = true; - mSetupPACData.Assign(text, datalen); - mSetupPACURI = pacURI; + nsresult rv; + nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + NS_WARNING("unable to get the DNS service"); + return rv; } - NS_IMETHODIMP Run() - { - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread"); - if (mCancel) { - mPACMan->CancelPendingQ(mCancelStatus); - mCancel = false; - return NS_OK; - } - - if (mSetupPAC) { - mSetupPAC = false; - - mPACMan->mPAC.Init(mSetupPACURI, - mSetupPACData); - - nsRefPtr<PACLoadComplete> runnable = new PACLoadComplete(mPACMan); - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - return NS_OK; - } - - mPACMan->ProcessPendingQ(); - return NS_OK; - } + nsAutoCString host; + rv = mURI->GetAsciiHost(host); + if (NS_FAILED(rv)) + return rv; -private: - nsRefPtr<nsPACMan> mPACMan; - - bool mCancel; - nsresult mCancelStatus; - - bool mSetupPAC; - nsCString mSetupPACData; - nsCString mSetupPACURI; -}; + rv = dns->AsyncResolve(host, flags, this, NS_GetCurrentThread(), + getter_AddRefs(mDNSRequest)); + if (NS_FAILED(rv)) + NS_WARNING("DNS AsyncResolve failed"); -//----------------------------------------------------------------------------- - -PendingPACQuery::PendingPACQuery(nsPACMan *pacMan, nsIURI *uri, - nsPACManCallback *callback, - bool mainThreadResponse) - : mPACMan(pacMan) - , mCallback(callback) - , mOnMainThreadOnly(mainThreadResponse) -{ - uri->GetAsciiSpec(mSpec); - uri->GetAsciiHost(mHost); - uri->GetScheme(mScheme); - uri->GetPort(&mPort); + return rv; } +// This may be called before or after OnLookupComplete void PendingPACQuery::Complete(nsresult status, const nsCString &pacString) { if (!mCallback) return; - nsRefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, status); - runnable->SetPACString(pacString); - if (mOnMainThreadOnly) - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - else - runnable->Run(); -} + + mCallback->OnQueryComplete(status, pacString); + mCallback = nullptr; -void -PendingPACQuery::UseAlternatePACFile(const nsCString &pacURL) -{ - if (!mCallback) - return; - - nsRefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, NS_OK); - runnable->SetPACURL(pacURL); - if (mOnMainThreadOnly) - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - else - runnable->Run(); + if (mDNSRequest) { + mDNSRequest->Cancel(NS_ERROR_ABORT); + mDNSRequest = nullptr; + } } NS_IMETHODIMP -PendingPACQuery::Run() +PendingPACQuery::OnLookupComplete(nsICancelable *request, + nsIDNSRecord *record, + nsresult status) { - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread"); - mPACMan->PostQuery(this); + // NOTE: we don't care about the results of this DNS query. We issued + // this DNS query just to pre-populate our DNS cache. + + mDNSRequest = nullptr; // break reference cycle + + // If we've already completed this query then do nothing. + if (!mCallback) + return NS_OK; + + // We're no longer pending, so we can remove ourselves. + PR_REMOVE_LINK(this); + + nsAutoCString pacString; + status = mPACMan->GetProxyForURI(mURI, pacString); + Complete(status, pacString); + + NS_RELEASE_THIS(); return NS_OK; } //----------------------------------------------------------------------------- nsPACMan::nsPACMan() : mLoadPending(false) , mShutdown(false) + , mScheduledReload(LL_MAXINT) , mLoadFailureCount(0) - , mInProgress(false) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "pacman must be created on main thread"); + PR_INIT_CLIST(&mPendingQ); } nsPACMan::~nsPACMan() { - if (mPACThread) { - if (NS_IsMainThread()) { - mPACThread->Shutdown(); - } - else { - nsRefPtr<ShutdownThread> runnable = new ShutdownThread(mPACThread); - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); - } - } - if (!NS_IsMainThread()) { - nsCOMPtr<nsIThread> mainThread; - NS_GetMainThread(getter_AddRefs(mainThread)); - - if (mPACURI) { - nsIURI *forgettable; - mPACURI.forget(&forgettable); - NS_ProxyRelease(mainThread, forgettable, false); - } - } - NS_ASSERTION(mLoader == nullptr, "pac man not shutdown properly"); - NS_ASSERTION(mPendingQ.isEmpty(), "pac man not shutdown properly"); + NS_ASSERTION(mPAC == nullptr, "pac man not shutdown properly"); + NS_ASSERTION(PR_CLIST_IS_EMPTY(&mPendingQ), "pac man not shutdown properly"); } void nsPACMan::Shutdown() { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "pacman must be shutdown on main thread"); CancelExistingLoad(); + ProcessPendingQ(NS_ERROR_ABORT); + + mPAC = nullptr; mShutdown = true; - PostCancelPendingQ(NS_ERROR_ABORT); +} + +nsresult +nsPACMan::GetProxyForURI(nsIURI *uri, nsACString &result) +{ + NS_ENSURE_STATE(!mShutdown); + + if (IsPACURI(uri)) { + result.Truncate(); + return NS_OK; + } + + MaybeReloadPAC(); + + if (IsLoading()) + return NS_ERROR_IN_PROGRESS; + if (!mPAC) + return NS_ERROR_NOT_AVAILABLE; + + nsAutoCString spec, host; + uri->GetAsciiSpec(spec); + uri->GetAsciiHost(host); + + return mPAC->GetProxyForURI(spec, host, result); } nsresult -nsPACMan::AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback, - bool mainThreadResponse) +nsPACMan::AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); - if (mShutdown) - return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_STATE(!mShutdown); + + MaybeReloadPAC(); + + PendingPACQuery *query = new PendingPACQuery(this, uri, callback); + if (!query) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(query); + PR_APPEND_LINK(query, &mPendingQ); - // Maybe Reload PAC - if (mPACURI && !mScheduledReload.IsNull() && - TimeStamp::Now() > mScheduledReload) - LoadPACFromURI(nullptr); + // If we're waiting for the PAC file to load, then delay starting the query. + // See OnStreamComplete. However, if this is the PAC URI then query right + // away since we know the result will be DIRECT. We could shortcut some code + // in this case by issuing the callback directly from here, but that would + // require extra code, so we just go through the usual async code path. + int isPACURI = IsPACURI(uri); - nsRefPtr<PendingPACQuery> query = - new PendingPACQuery(this, uri, callback, mainThreadResponse); + if (IsLoading() && !isPACURI) + return NS_OK; - if (IsPACURI(uri)) { - // deal with this directly instead of queueing it - query->Complete(NS_OK, EmptyCString()); - return NS_OK; + nsresult rv = query->Start(isPACURI ? 0 : nsIDNSService::RESOLVE_SPECULATE); + if (rv == NS_ERROR_DNS_LOOKUP_QUEUE_FULL && !isPACURI) { + query->OnLookupComplete(NULL, NULL, NS_OK); + rv = NS_OK; + } else if (NS_FAILED(rv)) { + NS_WARNING("failed to start PAC query"); + PR_REMOVE_LINK(query); + NS_RELEASE(query); } - return mPACThread->Dispatch(query, nsIEventTarget::DISPATCH_NORMAL); -} - -nsresult -nsPACMan::PostQuery(PendingPACQuery *query) -{ - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread"); - - if (mShutdown) { - query->Complete(NS_ERROR_NOT_AVAILABLE, EmptyCString()); - return NS_OK; - } - - // add a reference to the query while it is in the pending list - nsRefPtr<PendingPACQuery> addref(query); - mPendingQ.insertBack(addref.forget().get()); - ProcessPendingQ(); - return NS_OK; + return rv; } nsresult nsPACMan::LoadPACFromURI(nsIURI *pacURI) { NS_ENSURE_STATE(!mShutdown); NS_ENSURE_ARG(pacURI || mPACURI); @@ -360,34 +251,31 @@ nsPACMan::LoadPACFromURI(nsIURI *pacURI) mLoadPending = true; } CancelExistingLoad(); mLoader = loader; if (pacURI) { mPACURI = pacURI; - mPACURI->GetSpec(mPACURISpec); mLoadFailureCount = 0; // reset } - - // reset to Null - mScheduledReload = TimeStamp(); + mScheduledReload = LL_MAXINT; + mPAC = nullptr; return NS_OK; } void nsPACMan::StartLoading() { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); mLoadPending = false; // CancelExistingLoad was called... if (!mLoader) { - PostCancelPendingQ(NS_ERROR_ABORT); + ProcessPendingQ(NS_ERROR_ABORT); return; } if (NS_SUCCEEDED(mLoader->Init(this))) { // Always hit the origin server when loading PAC. nsCOMPtr<nsIIOService> ios = do_GetIOService(); if (ios) { nsCOMPtr<nsIChannel> channel; @@ -400,19 +288,28 @@ nsPACMan::StartLoading() channel->SetNotificationCallbacks(this); if (NS_SUCCEEDED(channel->AsyncOpen(mLoader, nullptr))) return; } } } CancelExistingLoad(); - PostCancelPendingQ(NS_ERROR_UNEXPECTED); + ProcessPendingQ(NS_ERROR_UNEXPECTED); } +void +nsPACMan::MaybeReloadPAC() +{ + if (!mPACURI) + return; + + if (PR_Now() > mScheduledReload) + LoadPACFromURI(nullptr); +} void nsPACMan::OnLoadFailure() { int32_t minInterval = 5; // 5 seconds int32_t maxInterval = 300; // 5 minutes nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); @@ -422,203 +319,123 @@ nsPACMan::OnLoadFailure() prefs->GetIntPref("network.proxy.autoconfig_retry_interval_max", &maxInterval); } int32_t interval = minInterval << mLoadFailureCount++; // seconds if (!interval || interval > maxInterval) interval = maxInterval; - mScheduledReload = TimeStamp::Now() + TimeDuration::FromSeconds(interval); +#ifdef DEBUG + printf("PAC load failure: will retry in %d seconds\n", interval); +#endif - // while we wait for the retry queued members should try direct - // even if that means fast failure. - PostCancelPendingQ(NS_ERROR_NOT_AVAILABLE); + mScheduledReload = PR_Now() + int64_t(interval) * PR_USEC_PER_SEC; } void nsPACMan::CancelExistingLoad() { if (mLoader) { nsCOMPtr<nsIRequest> request; mLoader->GetRequest(getter_AddRefs(request)); if (request) request->Cancel(NS_ERROR_ABORT); mLoader = nullptr; } } void -nsPACMan::PostProcessPendingQ() -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); - nsRefPtr<ExecutePACThreadAction> pending = - new ExecutePACThreadAction(this); - if (mPACThread) - mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL); -} - -void -nsPACMan::PostCancelPendingQ(nsresult status) -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); - nsRefPtr<ExecutePACThreadAction> pending = - new ExecutePACThreadAction(this); - pending->CancelQueue(status); - if (mPACThread) - mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL); -} - -void -nsPACMan::CancelPendingQ(nsresult status) +nsPACMan::ProcessPendingQ(nsresult status) { - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread"); - nsRefPtr<PendingPACQuery> query; - - while (!mPendingQ.isEmpty()) { - query = dont_AddRef(mPendingQ.popLast()); - query->Complete(status, EmptyCString()); + // Now, start any pending queries + PRCList *node = PR_LIST_HEAD(&mPendingQ); + while (node != &mPendingQ) { + PendingPACQuery *query = static_cast<PendingPACQuery *>(node); + node = PR_NEXT_LINK(node); + if (NS_SUCCEEDED(status)) { + // keep the query in the list (so we can complete it from Shutdown if + // necessary). + status = query->Start(nsIDNSService::RESOLVE_SPECULATE); + } + if (status == NS_ERROR_DNS_LOOKUP_QUEUE_FULL) { + query->OnLookupComplete(NULL, NULL, NS_OK); + status = NS_OK; + } else if (NS_FAILED(status)) { + // remove the query from the list + PR_REMOVE_LINK(query); + query->Complete(status, EmptyCString()); + NS_RELEASE(query); + } } - - if (mShutdown) - mPAC.Shutdown(); -} - -void -nsPACMan::ProcessPendingQ() -{ - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread"); - while (ProcessPending()); - - // do GC while the thread has nothing pending - mPAC.GC(); - - if (mShutdown) - mPAC.Shutdown(); } -// returns true if progress was made by shortening the queue -bool -nsPACMan::ProcessPending() -{ - if (mPendingQ.isEmpty()) - return false; - - // queue during normal load, but if we are retrying a failed load then - // fast fail the queries - if (mInProgress || (IsLoading() && !mLoadFailureCount)) - return false; - - nsRefPtr<PendingPACQuery> query(dont_AddRef(mPendingQ.popFirst())); - - if (mShutdown || IsLoading()) { - query->Complete(NS_ERROR_NOT_AVAILABLE, EmptyCString()); - return true; - } - - nsAutoCString pacString; - bool completed = false; - mInProgress = true; - nsAutoCString PACURI; - - // first we need to consider the system proxy changing the pac url - if (mSystemProxySettings && - NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) && - !PACURI.IsEmpty() && - !PACURI.Equals(mPACURISpec)) { - query->UseAlternatePACFile(PACURI); - completed = true; - } - - // now try the system proxy settings for this particular url if - // PAC was not specified - if (!completed && mSystemProxySettings && PACURI.IsEmpty() && - NS_SUCCEEDED(mSystemProxySettings-> - GetProxyForURI(query->mSpec, query->mScheme, - query->mHost, query->mPort, - pacString))) { - query->Complete(NS_OK, pacString); - completed = true; - } - - // the systemproxysettings didn't complete the resolution. try via PAC - if (!completed) { - nsresult status = mPAC.GetProxyForURI(query->mSpec, query->mHost, pacString); - query->Complete(status, pacString); - } - - mInProgress = false; - return true; -} - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsPACMan, nsIStreamLoaderObserver, - nsIInterfaceRequestor, nsIChannelEventSink) +NS_IMPL_ISUPPORTS3(nsPACMan, nsIStreamLoaderObserver, nsIInterfaceRequestor, + nsIChannelEventSink) NS_IMETHODIMP nsPACMan::OnStreamComplete(nsIStreamLoader *loader, nsISupports *context, nsresult status, uint32_t dataLen, const uint8_t *data) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread"); if (mLoader != loader) { // If this happens, then it means that LoadPACFromURI was called more // than once before the initial call completed. In this case, status // should be NS_ERROR_ABORT, and if so, then we know that we can and // should delay any processing. if (status == NS_ERROR_ABORT) return NS_OK; } + mLoader = nullptr; + if (NS_SUCCEEDED(status) && HttpRequestSucceeded(loader)) { // Get the URI spec used to load this PAC script. nsAutoCString pacURI; { nsCOMPtr<nsIRequest> request; loader->GetRequest(getter_AddRefs(request)); nsCOMPtr<nsIChannel> channel = do_QueryInterface(request); if (channel) { nsCOMPtr<nsIURI> uri; channel->GetURI(getter_AddRefs(uri)); if (uri) uri->GetAsciiSpec(pacURI); } } - // We assume that the PAC text is ASCII (or ISO-Latin-1). We've had this - // assumption forever, and some real-world PAC scripts actually have some - // non-ASCII text in comment blocks (see bug 296163). - const char *text = (const char *) data; - - // we have succeeded in loading the pac file using a bunch of interfaces that - // are main thread only, unfortunately we have to initialize the instance of - // the PAC evaluator (NS_PROXYAUTOCONFIG_CONTRACTID) on the pac thread, because - // that is where it will be used. - - nsRefPtr<ExecutePACThreadAction> pending = - new ExecutePACThreadAction(this); - pending->SetupPAC(text, dataLen, pacURI); - if (mPACThread) - mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL); + if (!mPAC) { + mPAC = do_CreateInstance(NS_PROXYAUTOCONFIG_CONTRACTID, &status); + if (!mPAC) + NS_WARNING("failed to instantiate PAC component"); + } + if (NS_SUCCEEDED(status)) { + // We assume that the PAC text is ASCII (or ISO-Latin-1). We've had this + // assumption forever, and some real-world PAC scripts actually have some + // non-ASCII text in comment blocks (see bug 296163). + const char *text = (const char *) data; + status = mPAC->Init(pacURI, NS_ConvertASCIItoUTF16(text, dataLen)); + } // Even if the PAC file could not be parsed, we did succeed in loading the // data for it. mLoadFailureCount = 0; } else { // We were unable to load the PAC file (presumably because of a network // failure). Try again a little later. OnLoadFailure(); } - if (NS_SUCCEEDED(status)) - PostProcessPendingQ(); - else - PostCancelPendingQ(status); + // Reset mPAC if necessary + if (mPAC && NS_FAILED(status)) + mPAC = nullptr; + ProcessPendingQ(status); return NS_OK; } NS_IMETHODIMP nsPACMan::GetInterface(const nsIID &iid, void **result) { // In case loading the PAC file requires authentication. if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) { @@ -644,31 +461,8 @@ nsPACMan::AsyncOnChannelRedirect(nsIChan { nsresult rv = NS_OK; if (NS_FAILED((rv = newChannel->GetURI(getter_AddRefs(mPACURI))))) return rv; callback->OnRedirectVerifyCallback(NS_OK); return NS_OK; } - -void -nsPACMan::NamePACThread() -{ - NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread"); - PR_SetCurrentThreadName("Proxy Resolution"); -} - -nsresult -nsPACMan::Init(nsISystemProxySettings *systemProxySettings) -{ - mSystemProxySettings = systemProxySettings; - - nsresult rv = NS_NewThread(getter_AddRefs(mPACThread), nullptr); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &nsPACMan::NamePACThread); - // don't check return value as it is not a big deal for this to fail. - mPACThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); - - return NS_OK; -}
--- a/netwerk/base/src/nsPACMan.h +++ b/netwerk/base/src/nsPACMan.h @@ -5,84 +5,45 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsPACMan_h__ #define nsPACMan_h__ #include "nsIStreamLoader.h" #include "nsIInterfaceRequestor.h" #include "nsIChannelEventSink.h" -#include "ProxyAutoConfig.h" -#include "nsICancelable.h" -#include "nsThreadUtils.h" +#include "nsIProxyAutoConfig.h" #include "nsIURI.h" #include "nsCOMPtr.h" #include "nsString.h" +#include "prclist.h" #include "mozilla/Attributes.h" -#include "mozilla/LinkedList.h" -#include "nsIThread.h" -#include "nsAutoPtr.h" -#include "nsISystemProxySettings.h" -#include "mozilla/TimeStamp.h" - -class nsPACMan; /** * This class defines a callback interface used by AsyncGetProxyForURI. */ class NS_NO_VTABLE nsPACManCallback : public nsISupports { public: /** * This method is invoked on the same thread that called AsyncGetProxyForURI. * * @param status * This parameter indicates whether or not the PAC query succeeded. * @param pacString * This parameter holds the value of the PAC string. It is empty when * status is a failure code. - * @param newPACURL - * This parameter holds the URL of a new PAC file that should be loaded - * before the query is evaluated again. At least one of pacString and - * newPACURL should be 0 length. */ - virtual void OnQueryComplete(nsresult status, - const nsCString &pacString, - const nsCString &newPACURL) = 0; -}; - -class PendingPACQuery MOZ_FINAL : public nsRunnable, - public mozilla::LinkedListElement<PendingPACQuery> -{ -public: - PendingPACQuery(nsPACMan *pacMan, nsIURI *uri, - nsPACManCallback *callback, bool mainThreadResponse); - - // can be called from either thread - void Complete(nsresult status, const nsCString &pacString); - void UseAlternatePACFile(const nsCString &pacURL); - - nsCString mSpec; - nsCString mScheme; - nsCString mHost; - int32_t mPort; - - NS_IMETHOD Run(void); /* nsRunnable */ - -private: - nsPACMan *mPACMan; // weak reference - nsRefPtr<nsPACManCallback> mCallback; - bool mOnMainThreadOnly; + virtual void OnQueryComplete(nsresult status, const nsCString &pacString) = 0; }; /** * This class provides an abstraction layer above the PAC thread. The methods * defined on this class are intended to be called on the main thread only. */ - class nsPACMan MOZ_FINAL : public nsIStreamLoaderObserver , public nsIInterfaceRequestor , public nsIChannelEventSink { public: NS_DECL_ISUPPORTS nsPACMan(); @@ -90,30 +51,40 @@ public: /** * This method may be called to shutdown the PAC manager. Any async queries * that have not yet completed will either finish normally or be canceled by * the time this method returns. */ void Shutdown(); /** + * This method queries a PAC result synchronously. + * + * @param uri + * The URI to query. + * @param result + * Holds the PAC result string upon return. + * + * @return NS_ERROR_IN_PROGRESS if the PAC file is not yet loaded. + * @return NS_ERROR_NOT_AVAILABLE if the PAC file could not be loaded. + */ + nsresult GetProxyForURI(nsIURI *uri, nsACString &result); + + /** * This method queries a PAC result asynchronously. The callback runs on the * calling thread. If the PAC file has not yet been loaded, then this method * will queue up the request, and complete it once the PAC file has been * loaded. * * @param uri * The URI to query. * @param callback * The callback to run once the PAC result is available. - * @param mustCallbackOnMainThread - * If set to false the callback can be made from the PAC thread */ - nsresult AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback, - bool mustCallbackOnMainThread); + nsresult AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback); /** * This method may be called to reload the PAC file. While we are loading * the PAC file, any asynchronous PAC queries will be queued up to be * processed once the PAC file finishes loading. * * @param pacURI * The nsIURI of the PAC file to load. If this parameter is null, @@ -129,84 +100,54 @@ public: /** * Returns true if the given URI matches the URI of our PAC file. */ bool IsPACURI(nsIURI *uri) { bool result; return mPACURI && NS_SUCCEEDED(mPACURI->Equals(uri, &result)) && result; } - bool IsPACURI(nsACString &spec) - { - nsAutoCString tmp; - return (mPACURI && NS_SUCCEEDED(mPACURI->GetSpec(tmp)) && tmp.Equals(spec)); - } - - NS_HIDDEN_(nsresult) Init(nsISystemProxySettings *); - static nsPACMan *sInstance; - - // PAC thread operations only - void ProcessPendingQ(); - void CancelPendingQ(nsresult); - private: NS_DECL_NSISTREAMLOADEROBSERVER NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSICHANNELEVENTSINK - friend class PendingPACQuery; - friend class PACLoadComplete; - friend class ExecutePACThreadAction; - ~nsPACMan(); /** * Cancel any existing load if any. */ void CancelExistingLoad(); /** + * Process mPendingQ. If status is a failure code, then the pending queue + * will be emptied. If status is a success code, then the pending requests + * will be processed (i.e., their Start method will be called). + */ + void ProcessPendingQ(nsresult status); + + /** * Start loading the PAC file. */ void StartLoading(); /** * Reload the PAC file if there is reason to. */ void MaybeReloadPAC(); /** * Called when we fail to load the PAC file. */ void OnLoadFailure(); - /** - * PostQuery() only runs on the PAC thread and it is used to - * place a pendingPACQuery into the queue and potentially - * execute the queue if it was otherwise empty - */ - nsresult PostQuery(PendingPACQuery *query); - - // PAC thread operations only - void PostProcessPendingQ(); - void PostCancelPendingQ(nsresult); - bool ProcessPending(); - void NamePACThread(); - private: - mozilla::net::ProxyAutoConfig mPAC; - nsCOMPtr<nsIThread> mPACThread; - nsCOMPtr<nsISystemProxySettings> mSystemProxySettings; - - mozilla::LinkedList<PendingPACQuery> mPendingQ; /* pac thread only */ - + nsCOMPtr<nsIProxyAutoConfig> mPAC; nsCOMPtr<nsIURI> mPACURI; - nsCString mPACURISpec; // for use off main thread + PRCList mPendingQ; nsCOMPtr<nsIStreamLoader> mLoader; bool mLoadPending; bool mShutdown; - mozilla::TimeStamp mScheduledReload; + PRTime mScheduledReload; uint32_t mLoadFailureCount; - - bool mInProgress; }; #endif // nsPACMan_h__
--- a/netwerk/base/src/nsProtocolProxyService.cpp +++ b/netwerk/base/src/nsProtocolProxyService.cpp @@ -7,36 +7,33 @@ #include "mozilla/Attributes.h" #include "mozilla/Util.h" #include "nsProtocolProxyService.h" #include "nsProxyInfo.h" #include "nsIClassInfoImpl.h" #include "nsIServiceManager.h" #include "nsXPIDLString.h" +#include "nsIProxyAutoConfig.h" #include "nsIIOService.h" #include "nsIObserverService.h" #include "nsIProtocolHandler.h" #include "nsIProtocolProxyCallback.h" #include "nsICancelable.h" #include "nsIDNSService.h" -#include "nsPIDNSService.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsReadableUtils.h" #include "nsThreadUtils.h" #include "nsString.h" #include "nsNetUtil.h" #include "nsNetCID.h" #include "nsCRT.h" #include "prnetdb.h" #include "nsPACMan.h" -#include "nsProxyRelease.h" -#include "mozilla/Mutex.h" -#include "mozilla/CondVar.h" //---------------------------------------------------------------------------- using namespace mozilla; #include "prlog.h" #if defined(PR_LOGGING) static PRLogModuleInfo *sLog = PR_NewLogModule("proxy"); @@ -70,59 +67,22 @@ public: nsAsyncResolveRequest(nsProtocolProxyService *pps, nsIURI *uri, uint32_t aResolveFlags, nsIProtocolProxyCallback *callback) : mStatus(NS_OK) , mDispatched(false) , mResolveFlags(aResolveFlags) , mPPS(pps) - , mXPComPPS(pps) , mURI(uri) , mCallback(callback) { NS_ASSERTION(mCallback, "null callback"); } - ~nsAsyncResolveRequest() - { - if (!NS_IsMainThread()) { - // these xpcom pointers might need to be proxied back to the - // main thread to delete safely, but if this request had its - // callbacks called normally they will all be null and this is a nop - - nsCOMPtr<nsIThread> mainThread; - NS_GetMainThread(getter_AddRefs(mainThread)); - - if (mURI) { - nsIURI *forgettable; - mURI.forget(&forgettable); - NS_ProxyRelease(mainThread, forgettable, false); - } - - if (mCallback) { - nsIProtocolProxyCallback *forgettable; - mCallback.forget(&forgettable); - NS_ProxyRelease(mainThread, forgettable, false); - } - - if (mProxyInfo) { - nsIProxyInfo *forgettable; - mProxyInfo.forget(&forgettable); - NS_ProxyRelease(mainThread, forgettable, false); - } - - if (mXPComPPS) { - nsIProtocolProxyService *forgettable; - mXPComPPS.forget(&forgettable); - NS_ProxyRelease(mainThread, forgettable, false); - } - } - } - void SetResult(nsresult status, nsIProxyInfo *pi) { mStatus = status; mProxyInfo = pi; } NS_IMETHOD Run() { @@ -159,29 +119,26 @@ public: mCallback = nullptr; // break possible reference cycle return rv; } private: // Called asynchronously, so we do not need to post another PLEvent // before calling DoCallback. - void OnQueryComplete(nsresult status, - const nsCString &pacString, - const nsCString &newPACURL) + void OnQueryComplete(nsresult status, const nsCString &pacString) { // If we've already called DoCallback then, nothing more to do. if (!mCallback) return; // Provided we haven't been canceled... if (mStatus == NS_OK) { mStatus = status; mPACString = pacString; - mPACURL = newPACURL; } // In the cancelation case, we may still have another PLEvent in // the queue that wants to call DoCallback. No need to wait for // it, just run the callback now. DoCallback(); } @@ -194,73 +151,36 @@ private: // Now apply proxy filters nsProtocolInfo info; mStatus = mPPS->GetProtocolInfo(mURI, &info); if (NS_SUCCEEDED(mStatus)) mPPS->ApplyFilters(mURI, info, mProxyInfo); else mProxyInfo = nullptr; - - LOG(("pac thread callback %s\n", mPACString.get())); - if (NS_SUCCEEDED(mStatus)) - mPPS->MaybeDisableDNSPrefetch(mProxyInfo); - mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus); - } - else if (NS_SUCCEEDED(mStatus) && !mPACURL.IsEmpty()) { - LOG(("pac thread callback indicates new pac file load\n")); - - // trigger load of new pac url - nsresult rv = mPPS->ConfigureFromPAC(mPACURL, false); - if (NS_SUCCEEDED(rv)) { - // now that the load is triggered, we can resubmit the query - nsRefPtr<nsAsyncResolveRequest> newRequest = - new nsAsyncResolveRequest(mPPS, mURI, mResolveFlags, mCallback); - rv = mPPS->mPACMan->AsyncGetProxyForURI(mURI, newRequest, false); - } - - if (NS_FAILED(rv)) - mCallback->OnProxyAvailable(this, mURI, nullptr, rv); - - // do not call onproxyavailable() in SUCCESS case - the newRequest will - // take care of that - } - else { - LOG(("pac thread callback did not provide information %X\n", mStatus)); - if (NS_SUCCEEDED(mStatus)) - mPPS->MaybeDisableDNSPrefetch(mProxyInfo); - mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus); } - // We are on the main thread now and don't need these any more so - // release them to avoid having to proxy them back to the main thread - // in the dtor + mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus); mCallback = nullptr; // in case the callback holds an owning ref to us - mPPS = nullptr; - mXPComPPS = nullptr; - mURI = nullptr; - mProxyInfo = nullptr; } private: nsresult mStatus; nsCString mPACString; - nsCString mPACURL; bool mDispatched; uint32_t mResolveFlags; - nsProtocolProxyService *mPPS; - nsCOMPtr<nsIProtocolProxyService> mXPComPPS; + nsRefPtr<nsProtocolProxyService> mPPS; nsCOMPtr<nsIURI> mURI; nsCOMPtr<nsIProtocolProxyCallback> mCallback; nsCOMPtr<nsIProxyInfo> mProxyInfo; }; -NS_IMPL_THREADSAFE_ISUPPORTS2(nsAsyncResolveRequest, nsICancelable, nsIRunnable) +NS_IMPL_ISUPPORTS2(nsAsyncResolveRequest, nsICancelable, nsIRunnable) //---------------------------------------------------------------------------- #define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t') // // apply mask to address (zeros out excluded bits). // @@ -461,22 +381,18 @@ nsProtocolProxyService::PrefsChanged(nsI mProxyConfig = type; reloadPAC = true; } if (mProxyConfig == PROXYCONFIG_SYSTEM) { mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); if (!mSystemProxySettings) mProxyConfig = PROXYCONFIG_DIRECT; - ResetPACThread(); } else { - if (mSystemProxySettings) { - mSystemProxySettings = nullptr; - ResetPACThread(); - } + mSystemProxySettings = nullptr; } } if (!pref || !strcmp(pref, PROXY_PREF("http"))) proxy_GetStringPref(prefBranch, PROXY_PREF("http"), mHTTPProxyHost); if (!pref || !strcmp(pref, PROXY_PREF("http_port"))) proxy_GetIntPref(prefBranch, PROXY_PREF("http_port"), mHTTPProxyPort); @@ -651,17 +567,17 @@ static const char kProxyType_UNKNOWN[] = const char * nsProtocolProxyService::ExtractProxyInfo(const char *start, uint32_t aResolveFlags, nsProxyInfo **result) { *result = nullptr; uint32_t flags = 0; - // see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl + // see BNF in nsIProxyAutoConfig.idl // find end of proxy info delimiter const char *end = start; while (*end && *end != ';') ++end; // find end of proxy type delimiter const char *sp = start; while (sp < end && *sp != ' ' && *sp != '\t') ++sp; @@ -695,67 +611,43 @@ nsProtocolProxyService::ExtractProxyInfo // support it. if (type == kProxyType_SOCKS || mSOCKSProxyRemoteDNS) flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; // extract host:port start = sp; while ((*start == ' ' || *start == '\t') && start < end) start++; - - // port defaults - if (type == kProxyType_HTTP) - port = 80; - else - port = 1080; - - nsProxyInfo *pi = new nsProxyInfo(); - pi->mType = type; - pi->mFlags = flags; - pi->mResolveFlags = aResolveFlags; - pi->mTimeout = mFailedProxyTimeout; - - // www.foo.com:8080 and http://www.foo.com:8080 - nsDependentCSubstring maybeURL(start, end - start); - nsCOMPtr<nsIURI> pacURI; - - nsAutoCString urlHost; - if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) && - NS_SUCCEEDED(pacURI->GetAsciiHost(urlHost)) && - !urlHost.IsEmpty()) { - // http://www.example.com:8080 - - pi->mHost = urlHost; - - int32_t tPort; - if (NS_SUCCEEDED(pacURI->GetPort(&tPort)) && tPort != -1) { - port = tPort; + if (start < end) { + host = start; + hostEnd = strchr(host, ':'); + if (!hostEnd || hostEnd > end) { + hostEnd = end; + // no port, so assume default + if (type == kProxyType_HTTP) + port = 80; + else + port = 1080; } - pi->mPort = port; + else + port = atoi(hostEnd + 1); } - else { - // www.example.com:8080 - if (start < end) { - host = start; - hostEnd = strchr(host, ':'); - if (!hostEnd || hostEnd > end) { - hostEnd = end; - // no port, so assume default - } - else { - port = atoi(hostEnd + 1); - } - } + nsProxyInfo *pi = new nsProxyInfo; + if (pi) { + pi->mType = type; + pi->mFlags = flags; + pi->mResolveFlags = aResolveFlags; + pi->mTimeout = mFailedProxyTimeout; // YES, it is ok to specify a null proxy host. if (host) { pi->mHost.Assign(host, hostEnd - host); pi->mPort = port; } + NS_ADDREF(*result = pi); } - NS_ADDREF(*result = pi); } while (*end == ';' || *end == ' ' || *end == '\t') ++end; return end; } void @@ -843,55 +735,24 @@ nsProtocolProxyService::IsProxyDisabled( mFailedProxies.Remove(key); return false; } return true; } nsresult -nsProtocolProxyService::SetupPACThread() -{ - if (mPACMan) - return NS_OK; - - mPACMan = new nsPACMan(); - - bool mainThreadOnly; - nsresult rv; - if (mSystemProxySettings && - NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) && - !mainThreadOnly) { - rv = mPACMan->Init(mSystemProxySettings); - } - else { - rv = mPACMan->Init(nullptr); - } - - if (NS_FAILED(rv)) - mPACMan = nullptr; - return rv; -} - -nsresult -nsProtocolProxyService::ResetPACThread() -{ - if (!mPACMan) - return NS_OK; - - mPACMan->Shutdown(); - mPACMan = nullptr; - return SetupPACThread(); -} - -nsresult nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec, bool forceReload) { - SetupPACThread(); + if (!mPACMan) { + mPACMan = new nsPACMan(); + if (!mPACMan) + return NS_ERROR_OUT_OF_MEMORY; + } nsCOMPtr<nsIURI> pacURI; nsresult rv = NS_NewURI(getter_AddRefs(pacURI), spec); if (NS_FAILED(rv)) return rv; if (mPACMan->IsPACURI(pacURI) && !forceReload) return NS_OK; @@ -948,172 +809,96 @@ nsProtocolProxyService::ReloadPAC() else if (type == PROXYCONFIG_WPAD) pacSpec.AssignLiteral(WPAD_URL); if (!pacSpec.IsEmpty()) ConfigureFromPAC(pacSpec, true); return NS_OK; } -// When sync interface is removed this can go away too -class nsAsyncBridgeRequest MOZ_FINAL : public nsPACManCallback +// nsIProtocolProxyService +NS_IMETHODIMP +nsProtocolProxyService::Resolve(nsIURI *uri, uint32_t flags, + nsIProxyInfo **result) { - NS_DECL_ISUPPORTS - - nsAsyncBridgeRequest() - : mMutex("nsDeprecatedCallback") - , mCondVar(mMutex, "nsDeprecatedCallback") - , mCompleted(false) - { - } - - void OnQueryComplete(nsresult status, - const nsCString &pacString, - const nsCString &newPACURL) - { - MutexAutoLock lock(mMutex); - mCompleted = true; - mStatus = status; - mPACString = pacString; - mPACURL = newPACURL; - mCondVar.Notify(); - } - - void Lock() { mMutex.Lock(); } - void Unlock() { mMutex.Unlock(); } - void Wait() { mCondVar.Wait(PR_SecondsToInterval(3)); } - -private: - ~nsAsyncBridgeRequest() - { - } - - friend class nsProtocolProxyService; - - Mutex mMutex; - CondVar mCondVar; - - nsresult mStatus; - nsCString mPACString; - nsCString mPACURL; - bool mCompleted; -}; -NS_IMPL_THREADSAFE_ISUPPORTS1(nsAsyncBridgeRequest, nsPACManCallback) - -// nsIProtocolProxyService2 -NS_IMETHODIMP -nsProtocolProxyService::DeprecatedBlockingResolve(nsIURI *aURI, - uint32_t aFlags, - nsIProxyInfo **retval) -{ - NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_ARG_POINTER(uri); nsProtocolInfo info; - nsresult rv = GetProtocolInfo(aURI, &info); + nsresult rv = GetProtocolInfo(uri, &info); if (NS_FAILED(rv)) return rv; - nsCOMPtr<nsIProxyInfo> pi; - bool usePACThread; - - // SystemProxySettings and PAC files can block the main thread - // but if neither of them are in use, we can just do the work - // right here and directly invoke the callback - - rv = Resolve_Internal(aURI, info, aFlags, &usePACThread, getter_AddRefs(pi)); - if (NS_FAILED(rv)) + bool usePAC; + rv = Resolve_Internal(uri, info, flags, &usePAC, result); + if (NS_FAILED(rv)) { + LOG(("Resolve_Internal returned rv(0x%08x)\n", rv)); return rv; - - if (!usePACThread || !mPACMan) { - ApplyFilters(aURI, info, pi); - pi.forget(retval); - return NS_OK; } - // Use the PAC thread to do the work, so we don't have to reimplement that - // code, but block this thread on that completion. - nsRefPtr<nsAsyncBridgeRequest> ctx = new nsAsyncBridgeRequest(); - ctx->Lock(); - if (NS_SUCCEEDED(mPACMan->AsyncGetProxyForURI(aURI, ctx, false))) { - // this can really block the main thread, so cap it at 3 seconds - ctx->Wait(); - } - ctx->Unlock(); - if (!ctx->mCompleted) - return NS_ERROR_FAILURE; - if (NS_FAILED(ctx->mStatus)) - return ctx->mStatus; + if (usePAC && mPACMan) { + NS_ASSERTION(*result == nullptr, "we should not have a result yet"); + + // If the caller didn't want us to invoke PAC, then error out. + if (flags & RESOLVE_NON_BLOCKING) + return NS_BASE_STREAM_WOULD_BLOCK; - // pretty much duplicate real DoCallback logic - - // Generate proxy info from the PAC string if appropriate - if (!ctx->mPACString.IsEmpty()) { - LOG(("sync pac thread callback %s\n", ctx->mPACString.get())); - ProcessPACString(ctx->mPACString, 0, getter_AddRefs(pi)); - ApplyFilters(aURI, info, pi); - pi.forget(retval); - return NS_OK; + // Query the PAC file synchronously. + nsCString pacString; + rv = mPACMan->GetProxyForURI(uri, pacString); + if (NS_SUCCEEDED(rv)) + ProcessPACString(pacString, flags, result); + else if (rv == NS_ERROR_IN_PROGRESS) { + // Construct a special UNKNOWN proxy entry that informs the caller + // that the proxy info is yet to be determined. + rv = NewProxyInfo_Internal(kProxyType_UNKNOWN, EmptyCString(), -1, + 0, 0, nullptr, flags, result); + if (NS_FAILED(rv)) + return rv; + } + else + NS_WARNING("failed querying PAC file; trying DIRECT"); } - if (!ctx->mPACURL.IsEmpty()) { - NS_WARNING("sync pac thread callback indicates new pac file load\n"); - // This is a problem and is one of the reasons this blocking interface - // is deprecated. The main loop needs to spin to make this reload happen. So - // we are going to kick off the reload and return an error - it will work - // next time. Because this sync interface is only used in the java plugin it - // is extremely likely that the pac file has already been loaded anyhow. - - rv = ConfigureFromPAC(ctx->mPACURL, false); - if (NS_FAILED(rv)) - return rv; - return NS_ERROR_NOT_AVAILABLE; - } - - *retval = nullptr; + ApplyFilters(uri, info, result); return NS_OK; } -// nsIProtocolProxyService NS_IMETHODIMP nsProtocolProxyService::AsyncResolve(nsIURI *uri, uint32_t flags, nsIProtocolProxyCallback *callback, nsICancelable **result) { NS_ENSURE_ARG_POINTER(uri); NS_ENSURE_ARG_POINTER(callback); nsRefPtr<nsAsyncResolveRequest> ctx = new nsAsyncResolveRequest(this, uri, flags, callback); + if (!ctx) + return NS_ERROR_OUT_OF_MEMORY; nsProtocolInfo info; nsresult rv = GetProtocolInfo(uri, &info); if (NS_FAILED(rv)) return rv; + bool usePAC; nsCOMPtr<nsIProxyInfo> pi; - bool usePACThread; - - // SystemProxySettings and PAC files can block the main thread - // but if neither of them are in use, we can just do the work - // right here and directly invoke the callback - - rv = Resolve_Internal(uri, info, flags, &usePACThread, getter_AddRefs(pi)); + rv = Resolve_Internal(uri, info, flags, &usePAC, getter_AddRefs(pi)); if (NS_FAILED(rv)) return rv; - if (!usePACThread || !mPACMan) { - // we can do it locally + if (!usePAC || !mPACMan) { ApplyFilters(uri, info, pi); + ctx->SetResult(NS_OK, pi); return ctx->DispatchCallback(); } - // else kick off a PAC thread query - - rv = mPACMan->AsyncGetProxyForURI(uri, ctx, true); + // else kick off a PAC query + rv = mPACMan->AsyncGetProxyForURI(uri, ctx); if (NS_SUCCEEDED(rv)) { *result = ctx; NS_ADDREF(*result); } return rv; } NS_IMETHODIMP @@ -1451,113 +1236,80 @@ nsProtocolProxyService::NewProxyInfo_Int NS_ADDREF(*aResult = proxyInfo); return NS_OK; } nsresult nsProtocolProxyService::Resolve_Internal(nsIURI *uri, const nsProtocolInfo &info, uint32_t flags, - bool *usePACThread, + bool *usePAC, nsIProxyInfo **result) { NS_ENSURE_ARG_POINTER(uri); - nsresult rv = SetupPACThread(); - if (NS_FAILED(rv)) - return rv; - *usePACThread = false; + *usePAC = false; *result = nullptr; if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) return NS_OK; // Can't proxy this (filters may not override) - // See bug #586908. - // Avoid endless loop if |uri| is the current PAC-URI. Returning OK - // here means that we will not use a proxy for this connection. - if (mPACMan && mPACMan->IsPACURI(uri)) - return NS_OK; - - bool mainThreadOnly; - if (mSystemProxySettings && - mProxyConfig == PROXYCONFIG_SYSTEM && - NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) && - !mainThreadOnly) { - *usePACThread = true; - return NS_OK; - } - - if (mSystemProxySettings && mProxyConfig == PROXYCONFIG_SYSTEM) { - // If the system proxy setting implementation is not threadsafe (e.g - // linux gconf), we'll do it inline here. Such implementations promise - // not to block - + if (mSystemProxySettings) { nsAutoCString PACURI; - nsAutoCString pacString; - - if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) && - !PACURI.IsEmpty()) { - // There is a PAC URI configured. If it is unchanged, then - // just execute the PAC thread. If it is changed then load - // the new value - - if (mPACMan && mPACMan->IsPACURI(PACURI)) { - // unchanged - *usePACThread = true; + if (NS_FAILED(mSystemProxySettings->GetPACURI(PACURI)) || + PACURI.IsEmpty()) { + nsAutoCString proxy; + nsresult rv = mSystemProxySettings->GetProxyForURI(uri, proxy); + if (NS_SUCCEEDED(rv)) { + ProcessPACString(proxy, flags, result); return NS_OK; } - - ConfigureFromPAC(PACURI, false); + // no proxy, stop search return NS_OK; } - nsAutoCString spec; - nsAutoCString host; - nsAutoCString scheme; - int32_t port = -1; + // See bug #586908. + // Avoid endless loop if |uri| is the current PAC-URI. Returning OK + // here means that we will not use a proxy for this connection. + if (mPACMan && mPACMan->IsPACURI(uri)) + return NS_OK; - uri->GetAsciiSpec(spec); - uri->GetAsciiHost(host); - uri->GetScheme(scheme); - uri->GetPort(&port); - - // now try the system proxy settings for this particular url - if (NS_SUCCEEDED(mSystemProxySettings-> - GetProxyForURI(spec, scheme, host, port, - pacString))) { - ProcessPACString(pacString, 0, result); - return NS_OK; - } + // Switch to new PAC file if that setting has changed. If the setting + // hasn't changed, ConfigureFromPAC will exit early. + nsresult rv = ConfigureFromPAC(PACURI, false); + if (NS_FAILED(rv)) + return rv; } // if proxies are enabled and this host:port combo is supposed to use a // proxy, check for a proxy. if (mProxyConfig == PROXYCONFIG_DIRECT || (mProxyConfig == PROXYCONFIG_MANUAL && !CanUseProxy(uri, info.defaultPort))) return NS_OK; // Proxy auto config magic... - if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD) { + if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD || + mProxyConfig == PROXYCONFIG_SYSTEM) { // Do not query PAC now. - *usePACThread = true; + *usePAC = true; return NS_OK; } // proxy info values const char *type = nullptr; const nsACString *host = nullptr; int32_t port = -1; uint32_t proxyFlags = 0; if ((flags & RESOLVE_PREFER_SOCKS_PROXY) && !mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { host = &mSOCKSProxyHost; - if (mSOCKSProxyVersion == 4) + if (mSOCKSProxyVersion == 4) type = kProxyType_SOCKS4; else type = kProxyType_SOCKS; port = mSOCKSProxyPort; if (mSOCKSProxyRemoteDNS) proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; } else if ((flags & RESOLVE_PREFER_HTTPS_PROXY) && @@ -1584,61 +1336,37 @@ nsProtocolProxyService::Resolve_Internal !(flags & RESOLVE_IGNORE_URI_SCHEME) && info.scheme.EqualsLiteral("ftp")) { host = &mFTPProxyHost; type = kProxyType_HTTP; port = mFTPProxyPort; } else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { host = &mSOCKSProxyHost; - if (mSOCKSProxyVersion == 4) + if (mSOCKSProxyVersion == 4) type = kProxyType_SOCKS4; else type = kProxyType_SOCKS; port = mSOCKSProxyPort; if (mSOCKSProxyRemoteDNS) proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; } if (type) { - rv = NewProxyInfo_Internal(type, *host, port, proxyFlags, - PR_UINT32_MAX, nullptr, flags, - result); + nsresult rv = NewProxyInfo_Internal(type, *host, port, proxyFlags, + PR_UINT32_MAX, nullptr, flags, + result); if (NS_FAILED(rv)) return rv; } return NS_OK; } void -nsProtocolProxyService::MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy) -{ - // Disable Prefetch in the DNS service if a proxy is in use. - if (!aProxy) - return; - - nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy); - if (!pi || - !pi->mType || - pi->mType == kProxyType_DIRECT) - return; - - nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); - if (!dns) - return; - nsCOMPtr<nsPIDNSService> pdns = do_QueryInterface(dns); - if (!pdns) - return; - - // We lose the prefetch optimization for the life of the dns service. - pdns->SetPrefetchEnabled(false); -} - -void nsProtocolProxyService::ApplyFilters(nsIURI *uri, const nsProtocolInfo &info, nsIProxyInfo **list) { if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) return; // We prune the proxy list prior to invoking each filter. This may be // somewhat inefficient, but it seems like a good idea since we want each @@ -1678,17 +1406,17 @@ nsProtocolProxyService::PruneProxyInfo(c // - If all proxies are disabled, return the full list // - Otherwise, remove the disabled proxies. // // Pruning of disallowed proxies works like this: // - If the protocol handler disallows the proxy, then we disallow it. // Start by removing all disallowed proxies if required: if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) { - nsProxyInfo *last = nullptr, *iter = head; + nsProxyInfo *last = nullptr, *iter = head; while (iter) { if (iter->Type() == kProxyType_HTTP) { // reject! if (last) last->mNext = iter->mNext; else head = iter->mNext; nsProxyInfo *next = iter->mNext; @@ -1702,32 +1430,32 @@ nsProtocolProxyService::PruneProxyInfo(c } if (!head) return; } // Now, scan to see if all remaining proxies are disabled. If so, then // we'll just bail and return them all. Otherwise, we'll go and prune the // disabled ones. - + bool allDisabled = true; nsProxyInfo *iter; for (iter = head; iter; iter = iter->mNext) { if (!IsProxyDisabled(iter)) { allDisabled = false; break; } } if (allDisabled) LOG(("All proxies are disabled, so trying all again")); else { // remove any disabled proxies. - nsProxyInfo *last = nullptr; + nsProxyInfo *last = nullptr; for (iter = head; iter; ) { if (IsProxyDisabled(iter)) { // reject! nsProxyInfo *reject = iter; iter = iter->mNext; if (last) last->mNext = iter;
--- a/netwerk/base/src/nsProtocolProxyService.h +++ b/netwerk/base/src/nsProtocolProxyService.h @@ -8,16 +8,17 @@ #include "nsString.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsTArray.h" #include "nsIPrefBranch.h" #include "nsIProtocolProxyService2.h" #include "nsIProtocolProxyFilter.h" +#include "nsIProxyAutoConfig.h" #include "nsISystemProxySettings.h" #include "nsIProxyInfo.h" #include "nsIObserver.h" #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsPACMan.h" #include "prtime.h" #include "prmem.h" @@ -266,28 +267,16 @@ protected: * The URI to test. * @param defaultPort * The default port for the given URI. * * @return True if the URI can use the specified proxy. */ NS_HIDDEN_(bool) CanUseProxy(nsIURI *uri, int32_t defaultPort); - /** - * Disable Prefetch in the DNS service if a proxy is in use. - * - * @param aProxy - * The proxy information - */ - NS_HIDDEN_(void) MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy); - -private: - nsresult SetupPACThread(); - nsresult ResetPACThread(); - public: // The Sun Forte compiler and others implement older versions of the // C++ standard's rules on access and nested classes. These structs // need to be public in order to deal with those compilers. struct HostInfoIP { uint16_t family; uint16_t mask_len;
new file mode 100644 --- /dev/null +++ b/netwerk/base/src/nsProxyAutoConfig.js @@ -0,0 +1,314 @@ +/* -*- Mode: Java; tab-width: 4; c-basic-offset: 4; -*- */ +/* vim:set ts=4 sw=4 sts=4 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + Script for Proxy Auto Config in the new world order. + - Gagan Saksena 04/24/00 +*/ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +const kDNS_CONTRACTID = "@mozilla.org/network/dns-service;1"; + +const nsISupports = Components.interfaces.nsISupports; +const nsIProxyAutoConfig = Components.interfaces.nsIProxyAutoConfig; +const nsIDNSService = Components.interfaces.nsIDNSService; + +var dns; + +// implementor of nsIProxyAutoConfig +function nsProxyAutoConfig() { + dns = Components.classes[kDNS_CONTRACTID].getService(nsIDNSService); +}; + +nsProxyAutoConfig.prototype = { + classID: Components.ID("63ac8c66-1dd2-11b2-b070-84d00d3eaece"), + + // sandbox in which we eval loaded autoconfig js file + _sandBox: null, + + QueryInterface: XPCOMUtils.generateQI([nsIProxyAutoConfig]), + + init: function(pacURI, pacText) { + // remove PAC configuration if requested + if (pacURI == "" || pacText == "") { + this._sandBox = null; + return; + } + + // allocate a fresh Sandbox to clear global scope for new PAC script + this._sandBox = new Components.utils.Sandbox(pacURI, + {sandboxName: 'nsProxyAutoConfig'}); + Components.utils.evalInSandbox(pacUtils, this._sandBox); + + // add predefined functions to pac + this._sandBox.importFunction(myIpAddress); + this._sandBox.importFunction(dnsResolve); + this._sandBox.importFunction(proxyAlert, "alert"); + + // evaluate loaded js file + Components.utils.evalInSandbox(pacText, this._sandBox); + }, + + getProxyForURI: function(testURI, testHost) { + if (!("FindProxyForURL" in this._sandBox)) + return null; + + // Call the original function + try { + var rval = this._sandBox.FindProxyForURL(testURI, testHost); + } catch (e) { + throw XPCSafeJSObjectWrapper(e); + } + return rval; + } +} + +function proxyAlert(msg) { + try { + // It would appear that the console service is threadsafe. + var cns = Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService); + cns.logStringMessage("PAC-alert: "+msg); + } catch (e) { + dump("PAC: proxyAlert ERROR: "+e+"\n"); + } +} + +// wrapper for getting local IP address called by PAC file +function myIpAddress() { + try { + return dns.resolve(dns.myHostName, 0).getNextAddrAsString(); + } catch (e) { + return '127.0.0.1'; + } +} + +// wrapper for resolving hostnames called by PAC file +function dnsResolve(host) { + try { + return dns.resolve(host, 0).getNextAddrAsString(); + } catch (e) { + return null; + } +} + +NSGetFactory = XPCOMUtils.generateNSGetFactory([nsProxyAutoConfig]); + +var pacUtils = +"function dnsDomainIs(host, domain) {\n" + +" return (host.length >= domain.length &&\n" + +" host.substring(host.length - domain.length) == domain);\n" + +"}\n" + + +"function dnsDomainLevels(host) {\n" + +" return host.split('.').length-1;\n" + +"}\n" + + +"function convert_addr(ipchars) {\n"+ +" var bytes = ipchars.split('.');\n"+ +" var result = ((bytes[0] & 0xff) << 24) |\n"+ +" ((bytes[1] & 0xff) << 16) |\n"+ +" ((bytes[2] & 0xff) << 8) |\n"+ +" (bytes[3] & 0xff);\n"+ +" return result;\n"+ +"}\n"+ + +"function isInNet(ipaddr, pattern, maskstr) {\n"+ +" var test = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ipaddr);\n"+ +" if (test == null) {\n"+ +" ipaddr = dnsResolve(ipaddr);\n"+ +" if (ipaddr == null)\n"+ +" return false;\n"+ +" } else if (test[1] > 255 || test[2] > 255 || \n"+ +" test[3] > 255 || test[4] > 255) {\n"+ +" return false; // not an IP address\n"+ +" }\n"+ +" var host = convert_addr(ipaddr);\n"+ +" var pat = convert_addr(pattern);\n"+ +" var mask = convert_addr(maskstr);\n"+ +" return ((host & mask) == (pat & mask));\n"+ +" \n"+ +"}\n"+ + +"function isPlainHostName(host) {\n" + +" return (host.search('\\\\.') == -1);\n" + +"}\n" + + +"function isResolvable(host) {\n" + +" var ip = dnsResolve(host);\n" + +" return (ip != null);\n" + +"}\n" + + +"function localHostOrDomainIs(host, hostdom) {\n" + +" return (host == hostdom) ||\n" + +" (hostdom.lastIndexOf(host + '.', 0) == 0);\n" + +"}\n" + + +"function shExpMatch(url, pattern) {\n" + +" pattern = pattern.replace(/\\./g, '\\\\.');\n" + +" pattern = pattern.replace(/\\*/g, '.*');\n" + +" pattern = pattern.replace(/\\?/g, '.');\n" + +" var newRe = new RegExp('^'+pattern+'$');\n" + +" return newRe.test(url);\n" + +"}\n" + + +"var wdays = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};\n" + + +"var months = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};\n"+ + +"function weekdayRange() {\n" + +" function getDay(weekday) {\n" + +" if (weekday in wdays) {\n" + +" return wdays[weekday];\n" + +" }\n" + +" return -1;\n" + +" }\n" + +" var date = new Date();\n" + +" var argc = arguments.length;\n" + +" var wday;\n" + +" if (argc < 1)\n" + +" return false;\n" + +" if (arguments[argc - 1] == 'GMT') {\n" + +" argc--;\n" + +" wday = date.getUTCDay();\n" + +" } else {\n" + +" wday = date.getDay();\n" + +" }\n" + +" var wd1 = getDay(arguments[0]);\n" + +" var wd2 = (argc == 2) ? getDay(arguments[1]) : wd1;\n" + +" return (wd1 == -1 || wd2 == -1) ? false\n" + +" : (wd1 <= wday && wday <= wd2);\n" + +"}\n" + + +"function dateRange() {\n" + +" function getMonth(name) {\n" + +" if (name in months) {\n" + +" return months[name];\n" + +" }\n" + +" return -1;\n" + +" }\n" + +" var date = new Date();\n" + +" var argc = arguments.length;\n" + +" if (argc < 1) {\n" + +" return false;\n" + +" }\n" + +" var isGMT = (arguments[argc - 1] == 'GMT');\n" + +"\n" + +" if (isGMT) {\n" + +" argc--;\n" + +" }\n" + +" // function will work even without explict handling of this case\n" + +" if (argc == 1) {\n" + +" var tmp = parseInt(arguments[0]);\n" + +" if (isNaN(tmp)) {\n" + +" return ((isGMT ? date.getUTCMonth() : date.getMonth()) ==\n" + +"getMonth(arguments[0]));\n" + +" } else if (tmp < 32) {\n" + +" return ((isGMT ? date.getUTCDate() : date.getDate()) == tmp);\n" + +" } else { \n" + +" return ((isGMT ? date.getUTCFullYear() : date.getFullYear()) ==\n" + +"tmp);\n" + +" }\n" + +" }\n" + +" var year = date.getFullYear();\n" + +" var date1, date2;\n" + +" date1 = new Date(year, 0, 1, 0, 0, 0);\n" + +" date2 = new Date(year, 11, 31, 23, 59, 59);\n" + +" var adjustMonth = false;\n" + +" for (var i = 0; i < (argc >> 1); i++) {\n" + +" var tmp = parseInt(arguments[i]);\n" + +" if (isNaN(tmp)) {\n" + +" var mon = getMonth(arguments[i]);\n" + +" date1.setMonth(mon);\n" + +" } else if (tmp < 32) {\n" + +" adjustMonth = (argc <= 2);\n" + +" date1.setDate(tmp);\n" + +" } else {\n" + +" date1.setFullYear(tmp);\n" + +" }\n" + +" }\n" + +" for (var i = (argc >> 1); i < argc; i++) {\n" + +" var tmp = parseInt(arguments[i]);\n" + +" if (isNaN(tmp)) {\n" + +" var mon = getMonth(arguments[i]);\n" + +" date2.setMonth(mon);\n" + +" } else if (tmp < 32) {\n" + +" date2.setDate(tmp);\n" + +" } else {\n" + +" date2.setFullYear(tmp);\n" + +" }\n" + +" }\n" + +" if (adjustMonth) {\n" + +" date1.setMonth(date.getMonth());\n" + +" date2.setMonth(date.getMonth());\n" + +" }\n" + +" if (isGMT) {\n" + +" var tmp = date;\n" + +" tmp.setFullYear(date.getUTCFullYear());\n" + +" tmp.setMonth(date.getUTCMonth());\n" + +" tmp.setDate(date.getUTCDate());\n" + +" tmp.setHours(date.getUTCHours());\n" + +" tmp.setMinutes(date.getUTCMinutes());\n" + +" tmp.setSeconds(date.getUTCSeconds());\n" + +" date = tmp;\n" + +" }\n" + +" return ((date1 <= date) && (date <= date2));\n" + +"}\n" + + +"function timeRange() {\n" + +" var argc = arguments.length;\n" + +" var date = new Date();\n" + +" var isGMT= false;\n"+ +"\n" + +" if (argc < 1) {\n" + +" return false;\n" + +" }\n" + +" if (arguments[argc - 1] == 'GMT') {\n" + +" isGMT = true;\n" + +" argc--;\n" + +" }\n" + +"\n" + +" var hour = isGMT ? date.getUTCHours() : date.getHours();\n" + +" var date1, date2;\n" + +" date1 = new Date();\n" + +" date2 = new Date();\n" + +"\n" + +" if (argc == 1) {\n" + +" return (hour == arguments[0]);\n" + +" } else if (argc == 2) {\n" + +" return ((arguments[0] <= hour) && (hour <= arguments[1]));\n" + +" } else {\n" + +" switch (argc) {\n" + +" case 6:\n" + +" date1.setSeconds(arguments[2]);\n" + +" date2.setSeconds(arguments[5]);\n" + +" case 4:\n" + +" var middle = argc >> 1;\n" + +" date1.setHours(arguments[0]);\n" + +" date1.setMinutes(arguments[1]);\n" + +" date2.setHours(arguments[middle]);\n" + +" date2.setMinutes(arguments[middle + 1]);\n" + +" if (middle == 2) {\n" + +" date2.setSeconds(59);\n" + +" }\n" + +" break;\n" + +" default:\n" + +" throw 'timeRange: bad number of arguments'\n" + +" }\n" + +" }\n" + +"\n" + +" if (isGMT) {\n" + +" date.setFullYear(date.getUTCFullYear());\n" + +" date.setMonth(date.getUTCMonth());\n" + +" date.setDate(date.getUTCDate());\n" + +" date.setHours(date.getUTCHours());\n" + +" date.setMinutes(date.getUTCMinutes());\n" + +" date.setSeconds(date.getUTCSeconds());\n" + +" }\n" + +" return ((date1 <= date) && (date <= date2));\n" + +"}\n" +
new file mode 100644 --- /dev/null +++ b/netwerk/base/src/nsProxyAutoConfig.manifest @@ -0,0 +1,2 @@ +component {63ac8c66-1dd2-11b2-b070-84d00d3eaece} nsProxyAutoConfig.js +contract @mozilla.org/network/proxy-auto-config;1 {63ac8c66-1dd2-11b2-b070-84d00d3eaece}
--- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -477,30 +477,16 @@ nsDNSService::Shutdown() res = mResolver; mResolver = nullptr; } if (res) res->Shutdown(); return NS_OK; } -NS_IMETHODIMP -nsDNSService::GetPrefetchEnabled(bool *outVal) -{ - *outVal = !mDisablePrefetch; - return NS_OK; -} - -NS_IMETHODIMP -nsDNSService::SetPrefetchEnabled(bool inVal) -{ - mDisablePrefetch = !inVal; - return NS_OK; -} - namespace { class DNSListenerProxy MOZ_FINAL : public nsIDNSListener { public: DNSListenerProxy(nsIDNSListener* aListener, nsIEventTarget* aTargetThread) : mListener(aListener) , mTargetThread(aTargetThread)
--- a/netwerk/dns/nsPIDNSService.idl +++ b/netwerk/dns/nsPIDNSService.idl @@ -5,30 +5,25 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDNSService.idl" /** * This is a private interface used by the internals of the networking library. * It will never be frozen. Do not use it in external code. */ -[scriptable, uuid(6b16fb1f-5709-4c94-a89f-a22be873c54d)] +[scriptable, uuid(a26c5b45-7707-4412-bbc1-2462b890848d)] interface nsPIDNSService : nsIDNSService { /** * called to initialize the DNS service. */ void init(); /** * called to shutdown the DNS service. any pending asynchronous * requests will be canceled, and the local cache of DNS records * will be cleared. NOTE: the operating system may still have * its own cache of DNS records, which would be unaffected by * this method. */ void shutdown(); - - /** - * Whether or not DNS prefetching (aka RESOLVE_SPECULATE) is enabled - */ - attribute boolean prefetchEnabled; };
--- a/netwerk/protocol/ftp/nsFTPChannel.h +++ b/netwerk/protocol/ftp/nsFTPChannel.h @@ -50,21 +50,16 @@ public: { SetURI(uri); } nsIProxyInfo *ProxyInfo() { return mProxyInfo; } - void SetProxyInfo(nsIProxyInfo *pi) - { - mProxyInfo = pi; - } - // Were we asked to resume a download? bool ResumeRequested() { return mResumeRequested; } // Download from this byte offset uint64_t StartPos() { return mStartPos; } // ID of the entity to resume downloading const nsCString &EntityID() {
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -28,18 +28,16 @@ #include "nsIURL.h" #include "nsISocketTransport.h" #include "nsIStreamListenerTee.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsIStringBundle.h" #include "nsAuthInformationHolder.h" #include "nsICharsetConverterManager.h" -#include "nsIProtocolProxyService.h" -#include "nsICancelable.h" #if defined(PR_LOGGING) extern PRLogModuleInfo* gFTPLog; #endif #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args) #define LOG_ALWAYS(args) PR_LOG(gFTPLog, PR_LOG_ALWAYS, args) // remove FTP parameters (starting with ";") from the path @@ -47,23 +45,22 @@ static void removeParamsFromPath(nsCString& path) { int32_t index = path.FindChar(';'); if (index >= 0) { path.SetLength(index); } } -NS_IMPL_ISUPPORTS_INHERITED5(nsFtpState, +NS_IMPL_ISUPPORTS_INHERITED4(nsFtpState, nsBaseContentStream, nsIInputStreamCallback, nsITransportEventSink, nsICacheListener, - nsIRequestObserver, - nsIProtocolProxyCallback) + nsIRequestObserver) nsFtpState::nsFtpState() : nsBaseContentStream(true) , mState(FTP_INIT) , mNextState(FTP_S_USER) , mKeepRunning(true) , mReceivedControlData(false) , mTryingCachedControl(false) @@ -76,31 +73,27 @@ nsFtpState::nsFtpState() , mStorReplyReceived(false) , mInternalError(NS_OK) , mReconnectAndLoginAgain(false) , mCacheConnection(true) , mPort(21) , mAddressChecked(false) , mServerIsIPv6(false) , mControlStatus(NS_OK) - , mDeferredCallbackPending(false) { LOG_ALWAYS(("FTP:(%x) nsFtpState created", this)); // make sure handler stays around NS_ADDREF(gFtpHandler); } nsFtpState::~nsFtpState() { LOG_ALWAYS(("FTP:(%x) nsFtpState destroyed", this)); - if (mProxyRequest) - mProxyRequest->Cancel(NS_ERROR_FAILURE); - // release reference to handler nsFtpProtocolHandler *handler = gFtpHandler; NS_RELEASE(handler); } // nsIInputStreamCallback implementation NS_IMETHODIMP nsFtpState::OnInputStreamReady(nsIAsyncInputStream *aInStream) @@ -1761,29 +1754,16 @@ nsFtpState::Init(nsFtpChannel *channel) int32_t port; rv = mChannel->URI()->GetPort(&port); if (NS_FAILED(rv)) return rv; if (port > 0) mPort = port; - // Lookup Proxy information asynchronously if it isn't already set - // on the channel and if we aren't configured explicitly to go directly - uint32_t proxyConfigType; - nsCOMPtr<nsIProtocolProxyService> pps = - do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID); - - if (pps && !mChannel->ProxyInfo() && - NS_SUCCEEDED(pps->GetProxyConfigType(&proxyConfigType)) && - proxyConfigType != nsIProtocolProxyService::PROXYCONFIG_DIRECT) { - pps->AsyncResolve(mChannel->URI(), 0, this, - getter_AddRefs(mProxyRequest)); - } - return NS_OK; } void nsFtpState::Connect() { mState = FTP_COMMAND_CONNECT; mNextState = FTP_S_USER; @@ -2170,90 +2150,24 @@ nsFtpState::CloseWithStatus(nsresult sta mDataStream = nullptr; if (mDoomCache && mCacheEntry) mCacheEntry->Doom(); mCacheEntry = nullptr; return nsBaseContentStream::CloseWithStatus(status); } -static nsresult -CreateHTTPProxiedChannel(nsIURI *uri, nsIProxyInfo *pi, nsIChannel **newChannel) -{ - nsresult rv; - nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsIProtocolHandler> handler; - rv = ioService->GetProtocolHandler("http", getter_AddRefs(handler)); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler, &rv); - if (NS_FAILED(rv)) - return rv; - - return pph->NewProxiedChannel(uri, pi, 0, nullptr, newChannel); -} - -NS_IMETHODIMP -nsFtpState::OnProxyAvailable(nsICancelable *request, nsIURI *uri, - nsIProxyInfo *pi, nsresult status) -{ - mProxyRequest = nullptr; - - // failed status code just implies DIRECT processing - - if (NS_SUCCEEDED(status)) { - nsAutoCString type; - if (pi && NS_SUCCEEDED(pi->GetType(type)) && type.EqualsLiteral("http")) { - // Proxy the FTP url via HTTP - // This would have been easier to just return a HTTP channel directly - // from nsIIOService::NewChannelFromURI(), but the proxy type cannot - // be reliabliy determined synchronously without jank due to pac, etc.. - LOG(("FTP:(%p) Configured to use a HTTP proxy channel\n", this)); - - nsCOMPtr<nsIChannel> newChannel; - if (NS_SUCCEEDED(CreateHTTPProxiedChannel(uri, pi, - getter_AddRefs(newChannel))) && - NS_SUCCEEDED(mChannel->Redirect(newChannel, - nsIChannelEventSink::REDIRECT_INTERNAL, - true))) { - LOG(("FTP:(%p) Redirected to use a HTTP proxy channel\n", this)); - return NS_OK; - } - } - else if (pi) { - // Proxy using the FTP protocol routed through a socks proxy - LOG(("FTP:(%p) Configured to use a SOCKS proxy channel\n", this)); - mChannel->SetProxyInfo(pi); - } - } - - if (mDeferredCallbackPending) { - mDeferredCallbackPending = false; - OnCallbackPending(); - } - return NS_OK; -} - void nsFtpState::OnCallbackPending() { // If this is the first call, then see if we could use the cache. If we // aren't going to read from (or write to) the cache, then just proceed to // connect to the server. if (mState == FTP_INIT) { - if (mProxyRequest) { - mDeferredCallbackPending = true; - return; - } - if (CheckCache()) { mState = FTP_WAIT_CACHE; return; } if (mCacheEntry && CanReadCacheEntry() && ReadCacheEntry()) { mState = FTP_READ_CACHE; return; }
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.h +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.h @@ -30,17 +30,16 @@ #include "nsIPrompt.h" #include "nsITransport.h" #include "nsIProxyInfo.h" #include "nsFtpControlConnection.h" #include "nsICacheEntryDescriptor.h" #include "nsICacheListener.h" -#include "nsIProtocolProxyCallback.h" // ftp server types #define FTP_GENERIC_TYPE 0 #define FTP_UNIX_TYPE 1 #define FTP_VMS_TYPE 8 #define FTP_NT_TYPE 9 #define FTP_OS2_TYPE 11 @@ -73,38 +72,34 @@ typedef enum _FTP_STATE { FTP_S_PASV, FTP_R_PASV, FTP_S_PWD, FTP_R_PWD } FTP_STATE; // higher level ftp actions typedef enum _FTP_ACTION {GET, PUT} FTP_ACTION; class nsFtpChannel; -class nsICancelable; // The nsFtpState object is the content stream for the channel. It implements // nsIInputStreamCallback, so it can read data from the control connection. It // implements nsITransportEventSink so it can mix status events from both the // control connection and the data connection. class nsFtpState : public nsBaseContentStream, public nsIInputStreamCallback, public nsITransportEventSink, public nsICacheListener, public nsIRequestObserver, - public nsFtpControlConnectionListener, - public nsIProtocolProxyCallback -{ + public nsFtpControlConnectionListener { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIINPUTSTREAMCALLBACK NS_DECL_NSITRANSPORTEVENTSINK NS_DECL_NSICACHELISTENER NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSIPROTOCOLPROXYCALLBACK // Override input stream methods: NS_IMETHOD CloseWithStatus(nsresult status); NS_IMETHOD Available(uint64_t *result); NS_IMETHOD ReadSegments(nsWriteSegmentFun fun, void *closure, uint32_t count, uint32_t *result); // nsFtpControlConnectionListener methods: @@ -263,14 +258,11 @@ private: // ***** control read gvars nsresult mControlStatus; nsCString mControlReadCarryOverBuf; nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry; bool mDoomCache; nsCString mSuppliedEntityID; - - nsCOMPtr<nsICancelable> mProxyRequest; - bool mDeferredCallbackPending; }; #endif //__nsFtpState__h_
--- a/netwerk/protocol/ftp/nsFtpProtocolHandler.cpp +++ b/netwerk/protocol/ftp/nsFtpProtocolHandler.cpp @@ -206,23 +206,21 @@ nsFtpProtocolHandler::NewURI(const nsACS if (NS_FAILED(rv)) return rv; return CallQueryInterface(url, result); } NS_IMETHODIMP nsFtpProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result) { - return NewProxiedChannel(url, nullptr, 0, nullptr, result); + return NewProxiedChannel(url, nullptr, result); } NS_IMETHODIMP nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo, - uint32_t proxyResolveFlags, - nsIURI *proxyURI, nsIChannel* *result) { NS_ENSURE_ARG_POINTER(uri); nsRefPtr<nsBaseChannel> channel; if (IsNeckoChild()) channel = new FTPChannelChild(uri); else channel = new nsFtpChannel(uri, proxyInfo);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -45,17 +45,16 @@ HttpBaseChannel::HttpBaseChannel() , mChooseApplicationCache(false) , mLoadedFromApplicationCache(false) , mChannelIsForDownload(false) , mTracingEnabled(true) , mTimingEnabled(false) , mAllowSpdy(true) , mPrivateBrowsing(false) , mSuspendCount(0) - , mProxyResolveFlags(0) { LOG(("Creating HttpBaseChannel @%x\n", this)); // grab a reference to the handler to ensure that it doesn't go away. NS_ADDREF(gHttpHandler); // Subfields of unions cannot be targeted in an initializer list mSelfAddr.raw.family = PR_AF_UNSPEC; @@ -70,33 +69,29 @@ HttpBaseChannel::~HttpBaseChannel() CleanRedirectCacheChainIfNecessary(); gHttpHandler->Release(); } nsresult HttpBaseChannel::Init(nsIURI *aURI, uint8_t aCaps, - nsProxyInfo *aProxyInfo, - uint32_t aProxyResolveFlags, - nsIURI *aProxyURI) + nsProxyInfo *aProxyInfo) { LOG(("HttpBaseChannel::Init [this=%p]\n", this)); NS_PRECONDITION(aURI, "null uri"); nsresult rv = nsHashPropertyBag::Init(); if (NS_FAILED(rv)) return rv; mURI = aURI; mOriginalURI = aURI; mDocumentURI = nullptr; mCaps = aCaps; - mProxyResolveFlags = aProxyResolveFlags; - mProxyURI = aProxyURI; // Construct connection info object nsAutoCString host; int32_t port = -1; bool usingSSL = false; rv = mURI->SchemeIs("https", &usingSSL); if (NS_FAILED(rv)) return rv; @@ -112,34 +107,34 @@ HttpBaseChannel::Init(nsIURI *aURI, if (NS_FAILED(rv)) return rv; LOG(("host=%s port=%d\n", host.get(), port)); rv = mURI->GetAsciiSpec(mSpec); if (NS_FAILED(rv)) return rv; LOG(("uri=%s\n", mSpec.get())); + mConnectionInfo = new nsHttpConnectionInfo(host, port, + aProxyInfo, usingSSL); + if (!mConnectionInfo) + return NS_ERROR_OUT_OF_MEMORY; + // Set default request method mRequestHead.SetMethod(nsHttp::Get); // Set request headers nsAutoCString hostLine; rv = nsHttpHandler::GenerateHostPort(host, port, hostLine); if (NS_FAILED(rv)) return rv; rv = mRequestHead.SetHeader(nsHttp::Host, hostLine); if (NS_FAILED(rv)) return rv; - rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead.Headers()); - if (NS_FAILED(rv)) return rv; - - nsAutoCString type; - if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) && - !type.EqualsLiteral("unknown")) - mProxyInfo = aProxyInfo; + rv = gHttpHandler-> + AddStandardRequestHeaders(&mRequestHead.Headers(), aCaps); return rv; } //----------------------------------------------------------------------------- // HttpBaseChannel::nsISupports //----------------------------------------------------------------------------- @@ -1522,19 +1517,17 @@ HttpBaseChannel::SetupReplacementChannel this, newChannel, preserveMethod)); uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE; // if the original channel was using SSL and this channel is not using // SSL, then no need to inhibit persistent caching. however, if the // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING // set, then allow the flag to apply to the redirected channel as well. // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels, // we only need to check if the original channel was using SSL. - bool usingSSL = false; - nsresult rv = mURI->SchemeIs("https", &usingSSL); - if (NS_SUCCEEDED(rv) && usingSSL) + if (mConnectionInfo->UsingSSL()) newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING; // Do not pass along LOAD_CHECK_OFFLINE_CACHE newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE; newChannel->SetLoadGroup(mLoadGroup); newChannel->SetNotificationCallbacks(mCallbacks); newChannel->SetLoadFlags(newLoadFlags);
--- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -55,19 +55,17 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIUPLOADCHANNEL NS_DECL_NSIUPLOADCHANNEL2 NS_DECL_NSITRACEABLECHANNEL HttpBaseChannel(); virtual ~HttpBaseChannel(); - virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo, - uint32_t aProxyResolveFlags, - nsIURI *aProxyURI); + virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo); // nsIRequest NS_IMETHOD GetName(nsACString& aName); NS_IMETHOD IsPending(bool *aIsPending); NS_IMETHOD GetStatus(nsresult *aStatus); NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup); NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup); NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags); @@ -221,17 +219,16 @@ protected: nsCOMPtr<nsIProgressEventSink> mProgressSink; nsCOMPtr<nsIURI> mReferrer; nsCOMPtr<nsIApplicationCache> mApplicationCache; nsHttpRequestHead mRequestHead; nsCOMPtr<nsIInputStream> mUploadStream; nsAutoPtr<nsHttpResponseHead> mResponseHead; nsRefPtr<nsHttpConnectionInfo> mConnectionInfo; - nsCOMPtr<nsIProxyInfo> mProxyInfo; nsCString mSpec; // ASCII encoded URL spec nsCString mContentTypeHint; nsCString mContentCharsetHint; nsCString mUserSetCookieHeader; PRNetAddr mSelfAddr; PRNetAddr mPeerAddr; @@ -267,19 +264,16 @@ protected: uint32_t mTimingEnabled : 1; uint32_t mAllowSpdy : 1; uint32_t mPrivateBrowsing : 1; // Current suspension depth for this channel object uint32_t mSuspendCount; nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys; - - uint32_t mProxyResolveFlags; - nsCOMPtr<nsIURI> mProxyURI; }; // Share some code while working around C++'s absurd inability to handle casting // of member functions between base/derived types. // - We want to store member function pointer to call at resume time, but one // such function--HandleAsyncAbort--we want to share between the // nsHttpChannel/HttpChannelChild. Can't define it in base class, because // then we'd have to cast member function ptr between base/derived class
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -328,27 +328,31 @@ nsHttpChannel::~nsHttpChannel() if (mAuthProvider) mAuthProvider->Disconnect(NS_ERROR_ABORT); } nsresult nsHttpChannel::Init(nsIURI *uri, uint8_t caps, - nsProxyInfo *proxyInfo, - uint32_t proxyResolveFlags, - nsIURI *proxyURI) + nsProxyInfo *proxyInfo) { - nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo, - proxyResolveFlags, proxyURI); + nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo); if (NS_FAILED(rv)) return rv; LOG(("nsHttpChannel::Init [this=%p]\n", this)); + mAuthProvider = + do_CreateInstance("@mozilla.org/network/http-channel-auth-provider;1", + &rv); + if (NS_FAILED(rv)) + return rv; + rv = mAuthProvider->Init(this); + return rv; } //----------------------------------------------------------------------------- // nsHttpChannel <private> //----------------------------------------------------------------------------- nsresult nsHttpChannel::Connect() @@ -398,16 +402,23 @@ nsHttpChannel::Connect() // ensure that we are using a valid hostname if (!net_IsValidHostName(nsDependentCString(mConnectionInfo->Host()))) return NS_ERROR_UNKNOWN_HOST; // Consider opening a TCP connection right away SpeculativeConnect(); + // are we offline? + bool offline = gIOService->IsOffline(); + if (offline) + mLoadFlags |= LOAD_ONLY_FROM_CACHE; + else if (PL_strcmp(mConnectionInfo->ProxyType(), "unknown") == 0) + return ResolveProxy(); // Lazily resolve proxy info + // Don't allow resuming when cache must be used if (mResuming && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) { LOG(("Resuming from cache is not supported yet")); return NS_ERROR_DOCUMENT_NOT_CACHED; } if (!gHttpHandler->UseCache()) return ContinueConnect(); @@ -1517,16 +1528,64 @@ nsHttpChannel::ProxyFailover() return rv; // XXXbz so where does this codepath remove us from the loadgroup, // exactly? return AsyncDoReplaceWithProxy(pi); } void +nsHttpChannel::HandleAsyncReplaceWithProxy() +{ + NS_PRECONDITION(!mCallOnResume, "How did that happen?"); + + if (mSuspendCount) { + LOG(("Waiting until resume to do async proxy replacement [this=%p]\n", + this)); + mCallOnResume = &nsHttpChannel::HandleAsyncReplaceWithProxy; + return; + } + + nsresult status = mStatus; + + nsCOMPtr<nsIProxyInfo> pi; + pi.swap(mTargetProxyInfo); + if (!mCanceled) { + PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncReplaceWithProxy); + status = AsyncDoReplaceWithProxy(pi); + if (NS_SUCCEEDED(status)) + return; + PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncReplaceWithProxy); + } + + if (NS_FAILED(status)) { + ContinueHandleAsyncReplaceWithProxy(status); + } +} + +nsresult +nsHttpChannel::ContinueHandleAsyncReplaceWithProxy(nsresult status) +{ + if (mLoadGroup && NS_SUCCEEDED(status)) { + mLoadGroup->RemoveRequest(this, nullptr, mStatus); + } + else if (NS_FAILED(status)) { + AsyncAbort(status); + } + + // Return NS_OK here, even it seems to be breaking the async function stack + // contract (i.e. passing the result code to a function bellow). + // ContinueHandleAsyncReplaceWithProxy will always be at the bottom of the + // stack. If we would return the failure code, the async function stack + // logic would cancel the channel synchronously, which is undesired after + // invoking AsyncAbort above. + return NS_OK; +} + +void nsHttpChannel::HandleAsyncRedirectChannelToHttps() { NS_PRECONDITION(!mCallOnResume, "How did that happen?"); if (mSuspendCount) { LOG(("Waiting until resume to do async redirect to https [this=%p]\n", this)); mCallOnResume = &nsHttpChannel::HandleAsyncRedirectChannelToHttps; return; @@ -1660,18 +1719,17 @@ nsHttpChannel::ContinueAsyncRedirectChan nsresult nsHttpChannel::AsyncDoReplaceWithProxy(nsIProxyInfo* pi) { LOG(("nsHttpChannel::AsyncDoReplaceWithProxy [this=%p pi=%p]", this, pi)); nsresult rv; nsCOMPtr<nsIChannel> newChannel; - rv = gHttpHandler->NewProxiedChannel(mURI, pi, mProxyResolveFlags, - mProxyURI, getter_AddRefs(newChannel)); + rv = gHttpHandler->NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel)); if (NS_FAILED(rv)) return rv; rv = SetupReplacementChannel(mURI, newChannel, true); if (NS_FAILED(rv)) return rv; // Inform consumers about this fake redirect @@ -1732,26 +1790,21 @@ nsHttpChannel::ResolveProxy() nsresult rv; nsCOMPtr<nsIProtocolProxyService> pps = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; - // Check if we are configured to directly connect. This will save us - // a round trip through the event dispatch system - uint32_t proxyConfigType; - if (NS_SUCCEEDED(pps->GetProxyConfigType(&proxyConfigType)) && - proxyConfigType == nsIProtocolProxyService::PROXYCONFIG_DIRECT) { - return NS_ERROR_FAILURE; - } - - return pps->AsyncResolve(mProxyURI ? mProxyURI : mURI, mProxyResolveFlags, - this, getter_AddRefs(mProxyRequest)); + uint32_t resolveFlags = 0; + if (mConnectionInfo->ProxyInfo()) + mConnectionInfo->ProxyInfo()->GetResolveFlags(&resolveFlags); + + return pps->AsyncResolve(mURI, resolveFlags, this, getter_AddRefs(mProxyRequest)); } bool HttpCacheQuery::ResponseWouldVary() const { AssertOnCacheThread(); nsresult rv; @@ -4299,158 +4352,98 @@ nsHttpChannel::AsyncOpen(nsIStreamListen NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); nsresult rv; rv = NS_CheckPortSafety(mURI); if (NS_FAILED(rv)) return rv; - // Remember the cookie header that was set, if any - const char *cookieHeader = mRequestHead.PeekHeader(nsHttp::Cookie); - if (cookieHeader) { - mUserSetCookieHeader = cookieHeader; - } - - AddCookiesToRequest(); - - // notify "http-on-modify-request" observers - gHttpHandler->OnModifyRequest(this); - - mIsPending = true; - mWasOpened = true; - - mListener = listener; - mListenerContext = context; - - // add ourselves to the load group. from this point forward, we'll report - // all failures asynchronously. - if (mLoadGroup) - mLoadGroup->AddRequest(this, nullptr); - - // Collect mAsyncOpenTime after we have called all observers like - // "http-on-modify-request" and load group observers that may set - // mTimingEnabled flag. - if (mTimingEnabled) - mAsyncOpenTime = mozilla::TimeStamp::Now(); - - // are we offline? - bool offline = gIOService->IsOffline(); - if (offline) - mLoadFlags |= LOAD_ONLY_FROM_CACHE; - - // the only time we would already know the proxy information at this - // point would be if we were proxying a non-http protocol like ftp - if (!mProxyInfo && NS_SUCCEEDED(ResolveProxy())) - return NS_OK; - - return BeginConnect(); -} - -nsresult -nsHttpChannel::BeginConnect() -{ - LOG(("nsHttpChannel::BeginConnect [this=%p]\n", this)); - nsresult rv; - - // Construct connection info object - nsAutoCString host; - int32_t port = -1; - bool usingSSL = false; - - rv = mURI->SchemeIs("https", &usingSSL); - if (NS_SUCCEEDED(rv)) - rv = mURI->GetAsciiHost(host); - if (NS_SUCCEEDED(rv)) - rv = mURI->GetPort(&port); - if (NS_SUCCEEDED(rv)) - rv = mURI->GetAsciiSpec(mSpec); - if (NS_FAILED(rv)) - return rv; - - // Reject the URL if it doesn't specify a host - if (host.IsEmpty()) - return NS_ERROR_MALFORMED_URI; - LOG(("host=%s port=%d\n", host.get(), port)); - LOG(("uri=%s\n", mSpec.get())); - - nsCOMPtr<nsProxyInfo> proxyInfo; - if (mProxyInfo) - proxyInfo = do_QueryInterface(mProxyInfo); - - mConnectionInfo = new nsHttpConnectionInfo(host, port, proxyInfo, usingSSL); - - mAuthProvider = - do_CreateInstance("@mozilla.org/network/http-channel-auth-provider;1", - &rv); - if (NS_SUCCEEDED(rv)) - rv = mAuthProvider->Init(this); - if (NS_FAILED(rv)) - return rv; - - // check to see if authorization headers should be included - mAuthProvider->AddAuthorizationHeaders(); - - // when proxying only use the pipeline bit if ProxyPipelining() allows it. - if (!mConnectionInfo->UsingConnect() && mConnectionInfo->UsingHttpProxy()) { - mCaps &= ~NS_HTTP_ALLOW_PIPELINING; - if (gHttpHandler->ProxyPipelining()) - mCaps |= NS_HTTP_ALLOW_PIPELINING; - } - - // if this somehow fails we can go on without it - gHttpHandler->AddConnectionHeader(&mRequestHead.Headers(), mCaps); - - if (!mConnectionInfo->UsingHttpProxy()) { + if (!(mConnectionInfo && mConnectionInfo->UsingHttpProxy())) { // Start a DNS lookup very early in case the real open is queued the DNS can // happen in parallel. Do not do so in the presence of an HTTP proxy as // all lookups other than for the proxy itself are done by the proxy. // // We keep the DNS prefetch object around so that we can retrieve // timing information from it. There is no guarantee that we actually // use the DNS prefetch data for the real connection, but as we keep // this data around for 3 minutes by default, this should almost always // be correct, and even when it isn't, the timing still represents _a_ // valid DNS lookup timing for the site, even if it is not _the_ // timing we used. mDNSPrefetch = new nsDNSPrefetch(mURI, mTimingEnabled); mDNSPrefetch->PrefetchHigh(); } + // Remember the cookie header that was set, if any + const char *cookieHeader = mRequestHead.PeekHeader(nsHttp::Cookie); + if (cookieHeader) { + mUserSetCookieHeader = cookieHeader; + } + + AddCookiesToRequest(); + + // check to see if authorization headers should be included + mAuthProvider->AddAuthorizationHeaders(); + + // notify "http-on-modify-request" observers + gHttpHandler->OnModifyRequest(this); + // Adjust mCaps according to our request headers: // - If "Connection: close" is set as a request header, then do not bother // trying to establish a keep-alive connection. if (mRequestHead.HasHeaderValue(nsHttp::Connection, "close")) mCaps &= ~(NS_HTTP_ALLOW_KEEPALIVE | NS_HTTP_ALLOW_PIPELINING); if ((mLoadFlags & VALIDATE_ALWAYS) || (BYPASS_LOCAL_CACHE(mLoadFlags))) mCaps |= NS_HTTP_REFRESH_DNS; // Force-Reload should reset the persistent connection pool for this host if (mLoadFlags & LOAD_FRESH_CONNECTION) mCaps |= NS_HTTP_CLEAR_KEEPALIVES; + + mIsPending = true; + mWasOpened = true; + + mListener = listener; + mListenerContext = context; + + // add ourselves to the load group. from this point forward, we'll report + // all failures asynchronously. + if (mLoadGroup) + mLoadGroup->AddRequest(this, nullptr); + + // Collect mAsyncOpenTime after we have called all obsrevers like + // "http-on-modify-request" and load group observers that may set + // mTimingEnabled flag. + if (mTimingEnabled) + mAsyncOpenTime = mozilla::TimeStamp::Now(); // We may have been cancelled already, either by on-modify-request // listeners or by load group observers; in that case, we should // not send the request to the server if (mCanceled) rv = mStatus; else rv = Connect(); if (NS_FAILED(rv)) { LOG(("Calling AsyncAbort [rv=%x mCanceled=%i]\n", rv, mCanceled)); CloseCacheEntry(true); AsyncAbort(rv); } else if (mLoadFlags & LOAD_CLASSIFY_URI) { nsRefPtr<nsChannelClassifier> classifier = new nsChannelClassifier(); + if (!classifier) { + Cancel(NS_ERROR_OUT_OF_MEMORY); + return NS_OK; + } + rv = classifier->Start(this); if (NS_FAILED(rv)) { Cancel(rv); - return rv; } } return NS_OK; } //----------------------------------------------------------------------------- // nsHttpChannel::nsIHttpChannelInternal @@ -4488,43 +4481,28 @@ nsHttpChannel::SetPriority(int32_t value //----------------------------------------------------------------------------- // nsHttpChannel::nsIProtocolProxyCallback //----------------------------------------------------------------------------- NS_IMETHODIMP nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIURI *uri, nsIProxyInfo *pi, nsresult status) { - LOG(("nsHttpChannel::OnProxyAvailable [this=%p pi=%p status=%x mStatus=%x]\n", - this, pi, status, mStatus)); mProxyRequest = nullptr; - nsresult rv; - // If status is a failure code, then it means that we failed to resolve // proxy info. That is a non-fatal error assuming it wasn't because the // request was canceled. We just failover to DIRECT when proxy resolution // fails (failure can mean that the PAC URL could not be loaded). - if (NS_SUCCEEDED(status)) - mProxyInfo = pi; - - if (!gHttpHandler->Active()) { - LOG(("nsHttpChannel::OnProxyAvailable [this=%p] " - "Handler no longer active.\n", this)); - rv = NS_ERROR_NOT_AVAILABLE; - } - else { - rv = BeginConnect(); - } - - if (NS_FAILED(rv)) { - Cancel(rv); - DoNotifyListener(); - } + // Need to replace this channel with a new one. It would be complex to try + // to change the value of mConnectionInfo since so much of our state may + // depend on its state. + mTargetProxyInfo = pi; + HandleAsyncReplaceWithProxy(); return NS_OK; } //----------------------------------------------------------------------------- // nsHttpChannel::nsIProxiedChannel //----------------------------------------------------------------------------- NS_IMETHODIMP
--- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -90,19 +90,17 @@ public: NS_IMETHOD GetURI(nsIURI **aURI); NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks); NS_IMETHOD GetLoadGroup(nsILoadGroup **aLoadGroup); NS_IMETHOD GetRequestMethod(nsACString& aMethod); nsHttpChannel(); virtual ~nsHttpChannel(); - virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo, - uint32_t aProxyResolveFlags, - nsIURI *aProxyURI); + virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo); // Methods HttpBaseChannel didn't implement for us or that we override. // // nsIRequest NS_IMETHOD Cancel(nsresult status); NS_IMETHOD Suspend(); NS_IMETHOD Resume(); // nsIChannel @@ -147,17 +145,16 @@ public: /* internal necko use only */ }; OfflineCacheEntryAsForeignMarker* GetOfflineCacheEntryAsForeignMarker(); private: typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result); bool RequestIsConditional(); - nsresult BeginConnect(); nsresult Connect(); nsresult ContinueConnect(); void SpeculativeConnect(); nsresult SetupTransaction(); nsresult CallOnStartRequest(); nsresult ProcessResponse(); nsresult ContinueProcessResponse(nsresult); nsresult ProcessNormal(); @@ -184,16 +181,18 @@ private: nsresult ContinueHandleAsyncFallback(nsresult); nsresult PromptTempRedirect(); virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, bool preserveMethod); // proxy specific methods nsresult ProxyFailover(); nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *); nsresult ContinueDoReplaceWithProxy(nsresult); + void HandleAsyncReplaceWithProxy(); + nsresult ContinueHandleAsyncReplaceWithProxy(nsresult); nsresult ResolveProxy(); // cache specific methods nsresult OpenCacheEntry(bool usingSSL); nsresult OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry, nsCacheAccessMode aAccess, nsresult aResult); nsresult OpenNormalCacheEntry(bool usingSSL); @@ -299,16 +298,19 @@ private: nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry; nsCacheAccessMode mOfflineCacheAccess; uint32_t mOfflineCacheLastModifiedTime; nsCOMPtr<nsIApplicationCache> mApplicationCacheForWrite; // auth specific data nsCOMPtr<nsIHttpChannelAuthProvider> mAuthProvider; + // Proxy info to replace with + nsCOMPtr<nsIProxyInfo> mTargetProxyInfo; + // If the channel is associated with a cache, and the URI matched // a fallback namespace, this will hold the key for the fallback // cache entry. nsCString mFallbackKey; friend class AutoRedirectVetoNotifier; friend class HttpAsyncAborter<nsHttpChannel>; friend class HttpCacheQuery;
--- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -126,19 +126,19 @@ NewURI(const nsACString &aSpec, nsHttpHandler *gHttpHandler = nullptr; nsHttpHandler::nsHttpHandler() : mConnMgr(nullptr) , mHttpVersion(NS_HTTP_VERSION_1_1) , mProxyHttpVersion(NS_HTTP_VERSION_1_1) , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE) + , mProxyCapabilities(NS_HTTP_ALLOW_KEEPALIVE) , mReferrerLevel(0xff) // by default we always send a referrer , mFastFallbackToIPv4(false) - , mProxyPipelining(true) , mIdleTimeout(PR_SecondsToInterval(10)) , mSpdyTimeout(PR_SecondsToInterval(180)) , mMaxRequestAttempts(10) , mMaxRequestDelay(10) , mIdleSynTimeout(250) , mMaxConnections(24) , mMaxPersistentConnectionsPerServer(2) , mMaxPersistentConnectionsPerProxy(4) @@ -162,17 +162,16 @@ nsHttpHandler::nsHttpHandler() , mUserAgentIsDirty(true) , mUseCache(true) , mPromptTempRedirect(true) , mSendSecureXSiteReferrer(true) , mEnablePersistentHttpsCaching(false) , mDoNotTrackEnabled(false) , mTelemetryEnabled(false) , mAllowExperiments(true) - , mHandlerActive(false) , mEnableSpdy(false) , mSpdyV2(true) , mSpdyV3(true) , mCoalesceSpdy(true) , mUseAlternateProtocol(false) , mSpdySendingChunkSize(ASpdySession::kSendingChunkSize) , mSpdyPingThreshold(PR_SecondsToInterval(44)) , mSpdyPingTimeout(PR_SecondsToInterval(8)) @@ -260,17 +259,16 @@ nsHttpHandler::Init() } appInfo->GetVersion(mAppVersion); mAppName.StripChars(" ()<>@,;:\\\"/[]?={}"); } else { mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION); } mSessionStartTime = NowInSeconds(); - mHandlerActive = true; rv = mAuthCache.Init(); if (NS_FAILED(rv)) return rv; rv = InitConnectionMgr(); if (NS_FAILED(rv)) return rv; mProductSub.AssignLiteral(MOZILLA_UAVERSION); @@ -328,17 +326,18 @@ nsHttpHandler::InitConnectionMgr() mMaxPersistentConnectionsPerProxy, mMaxRequestDelay, mMaxPipelinedRequests, mMaxOptimisticPipelinedRequests); return rv; } nsresult -nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request) +nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request, + uint8_t caps) { nsresult rv; // Add the "User-Agent" header rv = request->SetHeader(nsHttp::User_Agent, UserAgent()); if (NS_FAILED(rv)) return rv; // MIME based content negotiation lives! @@ -352,43 +351,36 @@ nsHttpHandler::AddStandardRequestHeaders rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages); if (NS_FAILED(rv)) return rv; } // Add the "Accept-Encoding" header rv = request->SetHeader(nsHttp::Accept_Encoding, mAcceptEncodings); if (NS_FAILED(rv)) return rv; - // Add the "Do-Not-Track" header - if (mDoNotTrackEnabled) { - rv = request->SetHeader(nsHttp::DoNotTrack, - NS_LITERAL_CSTRING("1")); - if (NS_FAILED(rv)) return rv; - } - - return NS_OK; -} - -nsresult -nsHttpHandler::AddConnectionHeader(nsHttpHeaderArray *request, - uint8_t caps) -{ // RFC2616 section 19.6.2 states that the "Connection: keep-alive" // and "Keep-alive" request headers should not be sent by HTTP/1.1 // user-agents. But this is not a problem in practice, and the // alternative proxy-connection is worse. see 570283 NS_NAMED_LITERAL_CSTRING(close, "close"); NS_NAMED_LITERAL_CSTRING(keepAlive, "keep-alive"); const nsACString *connectionType = &close; if (caps & NS_HTTP_ALLOW_KEEPALIVE) { connectionType = &keepAlive; } + // Add the "Do-Not-Track" header + if (mDoNotTrackEnabled) { + rv = request->SetHeader(nsHttp::DoNotTrack, + NS_LITERAL_CSTRING("1")); + if (NS_FAILED(rv)) return rv; + } + return request->SetHeader(nsHttp::Connection, *connectionType); } bool nsHttpHandler::IsAcceptableEncoding(const char *enc) { if (!enc) return false; @@ -946,18 +938,22 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc if (PREF_CHANGED(HTTP_PREF("pipelining.ssl"))) { rv = prefs->GetBoolPref(HTTP_PREF("pipelining.ssl"), &cVar); if (NS_SUCCEEDED(rv)) mPipeliningOverSSL = cVar; } if (PREF_CHANGED(HTTP_PREF("proxy.pipelining"))) { rv = prefs->GetBoolPref(HTTP_PREF("proxy.pipelining"), &cVar); - if (NS_SUCCEEDED(rv)) - mProxyPipelining = cVar; + if (NS_SUCCEEDED(rv)) { + if (cVar) + mProxyCapabilities |= NS_HTTP_ALLOW_PIPELINING; + else + mProxyCapabilities &= ~NS_HTTP_ALLOW_PIPELINING; + } } if (PREF_CHANGED(HTTP_PREF("qos"))) { rv = prefs->GetIntPref(HTTP_PREF("qos"), &val); if (NS_SUCCEEDED(rv)) mQoSBits = (uint8_t) clamped(val, 0, 0xff); } @@ -1374,17 +1370,17 @@ nsHttpHandler::NewChannel(nsIURI *uri, n rv = uri->SchemeIs("https", &isHttps); if (NS_FAILED(rv)) return rv; if (!isHttps) { NS_WARNING("Invalid URI scheme"); return NS_ERROR_UNEXPECTED; } } - return NewProxiedChannel(uri, nullptr, 0, nullptr, result); + return NewProxiedChannel(uri, nullptr, result); } NS_IMETHODIMP nsHttpHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) { // don't override anything. *_retval = false; return NS_OK; @@ -1392,18 +1388,16 @@ nsHttpHandler::AllowPort(int32_t port, c //----------------------------------------------------------------------------- // nsHttpHandler::nsIProxiedProtocolHandler //----------------------------------------------------------------------------- NS_IMETHODIMP nsHttpHandler::NewProxiedChannel(nsIURI *uri, nsIProxyInfo* givenProxyInfo, - uint32_t proxyResolveFlags, - nsIURI *proxyURI, nsIChannel **result) { nsRefPtr<HttpBaseChannel> httpChannel; LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n", givenProxyInfo)); nsCOMPtr<nsProxyInfo> proxyInfo; @@ -1418,30 +1412,36 @@ nsHttpHandler::NewProxiedChannel(nsIURI return rv; if (IsNeckoChild()) { httpChannel = new HttpChannelChild(); } else { httpChannel = new nsHttpChannel(); } - uint8_t caps = mCapabilities; + // select proxy caps if using a non-transparent proxy. SSL tunneling + // should not use proxy settings. + int8_t caps; + if (proxyInfo && !nsCRT::strcmp(proxyInfo->Type(), "http") && !https) + caps = mProxyCapabilities; + else + caps = mCapabilities; if (https) { // enable pipelining over SSL if requested if (mPipeliningOverSSL) caps |= NS_HTTP_ALLOW_PIPELINING; if (!IsNeckoChild()) { // HACK: make sure PSM gets initialized on the main thread. net_EnsurePSMInit(); } } - rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI); + rv = httpChannel->Init(uri, caps, proxyInfo); if (NS_FAILED(rv)) return rv; httpChannel.forget(result); return NS_OK; } //----------------------------------------------------------------------------- @@ -1504,18 +1504,16 @@ nsHttpHandler::Observe(nsISupports *subj if (strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) { nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(subject); if (prefBranch) PrefsChanged(prefBranch, NS_ConvertUTF16toUTF8(data).get()); } else if (strcmp(topic, "profile-change-net-teardown") == 0 || strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - mHandlerActive = false; - // clear cache of all authentication credentials. mAuthCache.ClearAll(); // ensure connection manager is shutdown if (mConnMgr) mConnMgr->Shutdown(); // need to reset the session start time since cache validation may
--- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -53,19 +53,18 @@ public: NS_DECL_NSIHTTPPROTOCOLHANDLER NS_DECL_NSIOBSERVER NS_DECL_NSISPECULATIVECONNECT nsHttpHandler(); virtual ~nsHttpHandler(); nsresult Init(); - nsresult AddStandardRequestHeaders(nsHttpHeaderArray *); - nsresult AddConnectionHeader(nsHttpHeaderArray *, - uint8_t capabilities); + nsresult AddStandardRequestHeaders(nsHttpHeaderArray *, + uint8_t capabilities); bool IsAcceptableEncoding(const char *encoding); const nsAFlatCString &UserAgent(); nsHttpVersion HttpVersion() { return mHttpVersion; } nsHttpVersion ProxyHttpVersion() { return mProxyHttpVersion; } uint8_t ReferrerLevel() { return mReferrerLevel; } bool SendSecureXSiteReferrer() { return mSendSecureXSiteReferrer; } @@ -74,17 +73,16 @@ public: PRIntervalTime SpdyTimeout() { return mSpdyTimeout; } uint16_t MaxRequestAttempts() { return mMaxRequestAttempts; } const char *DefaultSocketType() { return mDefaultSocketType.get(); /* ok to return null */ } nsIIDNService *IDNConverter() { return mIDNConverter; } uint32_t PhishyUserPassLength() { return mPhishyUserPassLength; } uint8_t GetQoSBits() { return mQoSBits; } uint16_t GetIdleSynTimeout() { return mIdleSynTimeout; } bool FastFallbackToIPv4() { return mFastFallbackToIPv4; } - bool ProxyPipelining() { return mProxyPipelining; } uint32_t MaxSocketCount(); bool EnforceAssocReq() { return mEnforceAssocReq; } bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; } bool IsTelemetryEnabled() { return mTelemetryEnabled; } bool AllowExperiments() { return mTelemetryEnabled && mAllowExperiments; } bool IsSpdyEnabled() { return mEnableSpdy; } @@ -230,19 +228,16 @@ public: { return mPipelineRescheduleTimeout; } PRIntervalTime GetPipelineTimeout() { return mPipelineReadTimeout; } mozilla::net::SpdyInformation *SpdyInfo() { return &mSpdyInfo; } - // returns true in between Init and Shutdown states - bool Active() { return mHandlerActive; } - private: // // Useragent/prefs helper methods // void BuildUserAgent(); void InitUserAgentComponents(); void PrefsChanged(nsIPrefBranch *prefs, const char *pref); @@ -273,20 +268,21 @@ private: // // prefs // uint8_t mHttpVersion; uint8_t mProxyHttpVersion; uint8_t mCapabilities; + uint8_t mProxyCapabilities; uint8_t mReferrerLevel; bool mFastFallbackToIPv4; - bool mProxyPipelining; + PRIntervalTime mIdleTimeout; PRIntervalTime mSpdyTimeout; uint16_t mMaxRequestAttempts; uint16_t mMaxRequestDelay; uint16_t mIdleSynTimeout; uint16_t mMaxConnections; @@ -355,19 +351,16 @@ private: bool mDoNotTrackEnabled; // Whether telemetry is reported or not bool mTelemetryEnabled; // The value of network.allow-experiments bool mAllowExperiments; - // true in between init and shutdown states - bool mHandlerActive; - // Try to use SPDY features instead of HTTP/1.1 over SSL mozilla::net::SpdyInformation mSpdyInfo; bool mEnableSpdy; bool mSpdyV2; bool mSpdyV3; bool mCoalesceSpdy; bool mUseAlternateProtocol; uint32_t mSpdySendingChunkSize;
--- a/netwerk/test/unit/test_protocolproxyservice.js +++ b/netwerk/test/unit/test_protocolproxyservice.js @@ -1,32 +1,20 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // This testcase exercises the Protocol Proxy Service -// These are the major sub tests: -// run_filter_test(); -// run_filter_test2() -// run_filter_test3() -// run_pref_test(); -// run_pac_test(); -// run_pac_cancel_test(); -// run_proxy_host_filters_test(); -// run_myipaddress_test(); - var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var pps = Components.classes["@mozilla.org/network/protocol-proxy-service;1"] .getService(); -var prefs = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch); /** * Test nsIProtocolHandler that allows proxying, but doesn't allow HTTP * proxying. */ function TestProtocolHandler() { } TestProtocolHandler.prototype = { @@ -150,220 +138,140 @@ resolveCallback.prototype = { this.nextFunction(pi); } }; function run_filter_test() { var uri = ios.newURI("http://www.mozilla.org/", null, null); // Verify initial state - var cb = new resolveCallback(); - cb.nextFunction = filter_test0_1; - var req = pps.asyncResolve(uri, 0, cb); -} -var filter01; -var filter02; - -function filter_test0_1(pi) { + var pi = pps.resolve(uri, 0); do_check_eq(pi, null); // Push a filter and verify the results - filter01 = new BasicFilter(); - filter02 = new BasicFilter(); - pps.registerFilter(filter01, 10); - pps.registerFilter(filter02, 20); + var filter1 = new BasicFilter(); + var filter2 = new BasicFilter(); + pps.registerFilter(filter1, 10); + pps.registerFilter(filter2, 20); - var cb = new resolveCallback(); - cb.nextFunction = filter_test0_2; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function filter_test0_2(pi) -{ + pi = pps.resolve(uri, 0); check_proxy(pi, "http", "localhost", 8080, 0, 10, true); check_proxy(pi.failoverProxy, "direct", "", -1, 0, 0, false); - pps.unregisterFilter(filter02); - - var cb = new resolveCallback(); - cb.nextFunction = filter_test0_3; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function filter_test0_3(pi) -{ + pps.unregisterFilter(filter2); + pi = pps.resolve(uri, 0); check_proxy(pi, "http", "localhost", 8080, 0, 10, true); check_proxy(pi.failoverProxy, "direct", "", -1, 0, 0, false); // Remove filter and verify that we return to the initial state - pps.unregisterFilter(filter01); - - var cb = new resolveCallback(); - cb.nextFunction = filter_test0_4; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function filter_test0_4(pi) -{ + pps.unregisterFilter(filter1); + pi = pps.resolve(uri, 0); do_check_eq(pi, null); - run_filter_test2(); } -var filter11; -var filter12; +function run_filter_test2() { + var uri = ios.newURI("http://www.mozilla.org/", null, null); -function run_filter_test2() { + // Verify initial state + + var pi = pps.resolve(uri, 0); + do_check_eq(pi, null); + // Push a filter and verify the results - filter11 = new TestFilter("http", "foo", 8080, 0, 10); - filter12 = new TestFilter("http", "bar", 8090, 0, 10); - pps.registerFilter(filter11, 20); - pps.registerFilter(filter12, 10); + var filter1 = new TestFilter("http", "foo", 8080, 0, 10); + var filter2 = new TestFilter("http", "bar", 8090, 0, 10); + pps.registerFilter(filter1, 20); + pps.registerFilter(filter2, 10); - var cb = new resolveCallback(); - cb.nextFunction = filter_test1_1; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function filter_test1_1(pi) { + pi = pps.resolve(uri, 0); check_proxy(pi, "http", "bar", 8090, 0, 10, true); check_proxy(pi.failoverProxy, "http", "foo", 8080, 0, 10, false); - pps.unregisterFilter(filter12); - - var cb = new resolveCallback(); - cb.nextFunction = filter_test1_2; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function filter_test1_2(pi) { + pps.unregisterFilter(filter2); + pi = pps.resolve(uri, 0); check_proxy(pi, "http", "foo", 8080, 0, 10, false); // Remove filter and verify that we return to the initial state - pps.unregisterFilter(filter11); - - var cb = new resolveCallback(); - cb.nextFunction = filter_test1_3; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function filter_test1_3(pi) { + pps.unregisterFilter(filter1); + pi = pps.resolve(uri, 0); do_check_eq(pi, null); - run_filter_test3(); } var filter_3_1; function run_filter_test3() { var uri = ios.newURI("http://www.mozilla.org/", null, null); // Push a filter and verify the results asynchronously filter_3_1 = new TestFilter("http", "foo", 8080, 0, 10); pps.registerFilter(filter_3_1, 20); var cb = new resolveCallback(); cb.nextFunction = filter_test3_1; var req = pps.asyncResolve(uri, 0, cb); + do_test_pending(); } function filter_test3_1(pi) { check_proxy(pi, "http", "foo", 8080, 0, 10, false); pps.unregisterFilter(filter_3_1); - run_pref_test(); + run_test_continued_3(); + do_test_finished(); } function run_pref_test() { var uri = ios.newURI("http://www.mozilla.org/", null, null); + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + // Verify 'direct' setting prefs.setIntPref("network.proxy.type", 0); - var cb = new resolveCallback(); - cb.nextFunction = pref_test1_1; - var req = pps.asyncResolve(uri, 0, cb); -} - -function pref_test1_1(pi) -{ + var pi = pps.resolve(uri, 0); do_check_eq(pi, null); // Verify 'manual' setting + prefs.setIntPref("network.proxy.type", 1); - var cb = new resolveCallback(); - cb.nextFunction = pref_test1_2; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function pref_test1_2(pi) -{ // nothing yet configured + pi = pps.resolve(uri, 0); do_check_eq(pi, null); // try HTTP configuration prefs.setCharPref("network.proxy.http", "foopy"); prefs.setIntPref("network.proxy.http_port", 8080); - var cb = new resolveCallback(); - cb.nextFunction = pref_test1_3; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function pref_test1_3(pi) -{ + pi = pps.resolve(uri, 0); check_proxy(pi, "http", "foopy", 8080, 0, -1, false); prefs.setCharPref("network.proxy.http", ""); prefs.setIntPref("network.proxy.http_port", 0); // try SOCKS configuration prefs.setCharPref("network.proxy.socks", "barbar"); prefs.setIntPref("network.proxy.socks_port", 1203); - var cb = new resolveCallback(); - cb.nextFunction = pref_test1_4; - var uri = ios.newURI("http://www.mozilla.org/", null, null); - var req = pps.asyncResolve(uri, 0, cb); -} - -function pref_test1_4(pi) -{ + pi = pps.resolve(uri, 0); check_proxy(pi, "socks", "barbar", 1203, 0, -1, false); - run_pac_test(); } function run_protocol_handler_test() { var uri = ios.newURI("moz-test:foopy", null, null); - var cb = new resolveCallback(); - cb.nextFunction = protocol_handler_test_1; - var req = pps.asyncResolve(uri, 0, cb); -} - -function protocol_handler_test_1(pi) -{ + var pi = pps.resolve(uri, 0); do_check_eq(pi, null); - prefs.setCharPref("network.proxy.autoconfig_url", ""); - prefs.setIntPref("network.proxy.type", 0); - - run_pac_cancel_test(); } function TestResolveCallback() { } TestResolveCallback.prototype = { QueryInterface: function TestResolveCallback_QueryInterface(iid) { if (iid.equals(Components.interfaces.nsIProtocolProxyCallback) || @@ -379,33 +287,66 @@ TestResolveCallback.prototype = { do_check_neq(req, null); do_check_neq(uri, null); do_check_eq(status, 0); do_check_neq(pi, null); check_proxy(pi, "http", "foopy", 8080, 0, -1, true); check_proxy(pi.failoverProxy, "direct", "", -1, -1, -1, false); + // verify direct query now that we know the PAC file is loaded + pi = pps.resolve(ios.newURI("http://bazbat.com/", null, null), 0); + do_check_neq(pi, null); + check_proxy(pi, "http", "foopy", 8080, 0, -1, true); + check_proxy(pi.failoverProxy, "direct", "", -1, -1, -1, false); + run_protocol_handler_test(); + + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + prefs.setCharPref("network.proxy.autoconfig_url", ""); + prefs.setIntPref("network.proxy.type", 0); + + run_test_continued(); + do_test_finished(); } }; function run_pac_test() { var pac = 'data:text/plain,' + 'function FindProxyForURL(url, host) {' + ' return "PROXY foopy:8080; DIRECT";' + '}'; var uri = ios.newURI("http://www.mozilla.org/", null, null); + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + // Configure PAC prefs.setIntPref("network.proxy.type", 2); prefs.setCharPref("network.proxy.autoconfig_url", pac); + // Test it out (we expect an "unknown" result since the PAC load is async) + var pi = pps.resolve(uri, 0); + do_check_neq(pi, null); + do_check_eq(pi.type, "unknown"); + + // We expect the NON_BLOCKING flag to trigger an exception here since + // we have configured the PPS to use PAC. + var hit_exception = false; + try { + pps.resolve(uri, pps.RESOLVE_NON_BLOCKING); + } catch (e) { + hit_exception = true; + } + do_check_eq(hit_exception, true); + var req = pps.asyncResolve(uri, 0, new TestResolveCallback()); + do_test_pending(); } function TestResolveCancelationCallback() { } TestResolveCancelationCallback.prototype = { QueryInterface: function TestResolveCallback_QueryInterface(iid) { if (iid.equals(Components.interfaces.nsIProtocolProxyCallback) || @@ -418,226 +359,130 @@ TestResolveCancelationCallback.prototype function TestResolveCancelationCallback_onProxyAvailable(req, uri, pi, status) { dump("*** uri=" + uri.spec + ", status=" + status + "\n"); do_check_neq(req, null); do_check_neq(uri, null); do_check_eq(status, Components.results.NS_ERROR_ABORT); do_check_eq(pi, null); + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); prefs.setCharPref("network.proxy.autoconfig_url", ""); prefs.setIntPref("network.proxy.type", 0); - run_proxy_host_filters_test(); + run_test_continued_2(); + do_test_finished(); } }; function run_pac_cancel_test() { var uri = ios.newURI("http://www.mozilla.org/", null, null); // Configure PAC var pac = 'data:text/plain,' + 'function FindProxyForURL(url, host) {' + ' return "PROXY foopy:8080; DIRECT";' + '}'; + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); prefs.setIntPref("network.proxy.type", 2); prefs.setCharPref("network.proxy.autoconfig_url", pac); var req = pps.asyncResolve(uri, 0, new TestResolveCancelationCallback()); req.cancel(Components.results.NS_ERROR_ABORT); -} - -var hostList; -var hostIDX; -var bShouldBeFiltered; -var hostNextFX; - -function check_host_filters(hl, shouldBe, nextFX) { - hostList = hl; - hostIDX = 0; - bShouldBeFiltered = shouldBe; - hostNextFX = nextFX; - - if (hostList.length > hostIDX) - check_host_filter(hostIDX); + do_test_pending(); } -function check_host_filters_cb() -{ - hostIDX++; - if (hostList.length > hostIDX) - check_host_filter(hostIDX); - else - hostNextFX(); -} - -function check_host_filter(i) { +function check_host_filters(hostList, bShouldBeFiltered) { var uri; - dump("*** uri=" + hostList[i] + " bShouldBeFiltered=" + bShouldBeFiltered + "\n"); - uri = ios.newURI(hostList[i], null, null); - - var cb = new resolveCallback(); - cb.nextFunction = host_filter_cb; - var req = pps.asyncResolve(uri, 0, cb); -} - -function host_filter_cb(proxy) -{ - if (bShouldBeFiltered) { - do_check_eq(proxy, null); - } else { - do_check_neq(proxy, null); - // Just to be sure, let's check that the proxy is correct - // - this should match the proxy setup in the calling function - check_proxy(proxy, "http", "foopy", 8080, 0, -1, false); + var proxy; + for (var i=0; i<hostList.length; i++) { + dump("*** uri=" + hostList[i] + " bShouldBeFiltered=" + bShouldBeFiltered + "\n"); + uri = ios.newURI(hostList, null, null); + proxy = pps.resolve(uri, 0); + if (bShouldBeFiltered) { + do_check_eq(proxy, null); + } else { + do_check_neq(proxy, null); + // Just to be sure, let's check that the proxy is correct + // - this should match the proxy setup in the calling function + check_proxy(proxy, "http", "foopy", 8080, 0, -1, false); + } } - check_host_filters_cb(); } // Verify that hists in the host filter list are not proxied // refers to "network.proxy.no_proxies_on" -var uriStrUseProxyList; -var uriStrUseProxyList; -var hostFilterList; - function run_proxy_host_filters_test() { // Get prefs object from DOM + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); // Setup a basic HTTP proxy configuration // - pps.resolve() needs this to return proxy info for non-filtered hosts prefs.setIntPref("network.proxy.type", 1); prefs.setCharPref("network.proxy.http", "foopy"); prefs.setIntPref("network.proxy.http_port", 8080); // Setup host filter list string for "no_proxies_on" - hostFilterList = "www.mozilla.org, www.google.com, www.apple.com, " + var hostFilterList = "www.mozilla.org, www.google.com, www.apple.com, " + ".domain, .domain2.org" prefs.setCharPref("network.proxy.no_proxies_on", hostFilterList); do_check_eq(prefs.getCharPref("network.proxy.no_proxies_on"), hostFilterList); - + var rv; // Check the hosts that should be filtered out - uriStrFilterList = [ "http://www.mozilla.org/", + var uriStrFilterList = [ "http://www.mozilla.org/", "http://www.google.com/", "http://www.apple.com/", "http://somehost.domain/", "http://someotherhost.domain/", "http://somehost.domain2.org/", "http://somehost.subdomain.domain2.org/" ]; - check_host_filters(uriStrFilterList, true, host_filters_1); -} + check_host_filters(uriStrFilterList, true); -function host_filters_1() -{ // Check the hosts that should be proxied - uriStrUseProxyList = [ "http://www.mozilla.com/", + var uriStrUseProxyList = [ "http://www.mozilla.com/", "http://mail.google.com/", "http://somehost.domain.co.uk/", "http://somelocalhost/" ]; - check_host_filters(uriStrUseProxyList, false, host_filters_2); -} - -function host_filters_2() -{ + check_host_filters(uriStrUseProxyList, false); + // Set no_proxies_on to include local hosts prefs.setCharPref("network.proxy.no_proxies_on", hostFilterList + ", <local>"); do_check_eq(prefs.getCharPref("network.proxy.no_proxies_on"), hostFilterList + ", <local>"); + // Amend lists - move local domain to filtered list uriStrFilterList.push(uriStrUseProxyList.pop()); - check_host_filters(uriStrFilterList, true, host_filters_3); -} + check_host_filters(uriStrFilterList, true); + check_host_filters(uriStrUseProxyList, false); -function host_filters_3() -{ - check_host_filters(uriStrUseProxyList, false, host_filters_4); -} - -function host_filters_4() -{ // Cleanup prefs.setCharPref("network.proxy.no_proxies_on", ""); do_check_eq(prefs.getCharPref("network.proxy.no_proxies_on"), ""); - run_myipaddress_test(); -} - -function run_myipaddress_test() -{ - // This test makes sure myIpAddress() comes up with some valid - // IP address other than localhost. The DUT must be configured with - // an Internet route for this to work - though no Internet traffic - // should be created. - - var pac = 'data:text/plain,' + - 'function FindProxyForURL(url, host) {' + - ' return "PROXY " + myIpAddress() + ":1234";' + - '}'; - - // no traffic to this IP is ever sent, it is just a public IP that - // does not require DNS to determine a route. - var uri = ios.newURI("http://192.0.43.10/", null, null); - - prefs.setIntPref("network.proxy.type", 2); - prefs.setCharPref("network.proxy.autoconfig_url", pac); - - var cb = new resolveCallback(); - cb.nextFunction = myipaddress_callback; - var req = pps.asyncResolve(uri, 0, cb); -} - -function myipaddress_callback(pi) -{ - do_check_neq(pi, null); - do_check_eq(pi.type, "http"); - do_check_eq(pi.port, 1234); - - // make sure we didn't return localhost - do_check_neq(pi.host, null); - do_check_neq(pi.host, "127.0.0.1"); - do_check_neq(pi.host, "::1"); - - prefs.setIntPref("network.proxy.type", 0); do_test_finished(); } -function run_deprecated_sync_test() -{ - var uri = ios.newURI("http://www.mozilla.org/", null, null); - - pps.QueryInterface(Components.interfaces.nsIProtocolProxyService2); - - // Verify initial state - var pi = pps.deprecatedBlockingResolve(uri, 0); - do_check_eq(pi, null); - - // Push a filter and verify the results - var filter1 = new BasicFilter(); - var filter2 = new BasicFilter(); - pps.registerFilter(filter1, 10); - pps.registerFilter(filter2, 20); - - pi = pps.deprecatedBlockingResolve(uri, 0); - check_proxy(pi, "http", "localhost", 8080, 0, 10, true); - check_proxy(pi.failoverProxy, "direct", "", -1, 0, 0, false); - - pps.unregisterFilter(filter2); - pi = pps.deprecatedBlockingResolve(uri, 0); - check_proxy(pi, "http", "localhost", 8080, 0, 10, true); - check_proxy(pi.failoverProxy, "direct", "", -1, 0, 0, false); - - // Remove filter and verify that we return to the initial state - pps.unregisterFilter(filter1); - pi = pps.deprecatedBlockingResolve(uri, 0); - do_check_eq(pi, null); -} - function run_test() { register_test_protocol_handler(); - - // any synchronous tests - run_deprecated_sync_test(); + run_filter_test(); + run_filter_test2(); + run_pref_test(); + run_pac_test(); + // additional tests may be added to run_test_continued +} - // start of asynchronous test chain - run_filter_test(); - do_test_pending(); +function run_test_continued() { + run_pac_cancel_test(); + // additional tests may be added to run_test_continued_3 } + +function run_test_continued_2() { + run_filter_test3(); +} + +function run_test_continued_3() { + run_proxy_host_filters_test(); +}
--- a/netwerk/test/unit/test_proxy-failover_canceled.js +++ b/netwerk/test/unit/test_proxy-failover_canceled.js @@ -28,21 +28,34 @@ function finish_test(request, buffer) } function run_test() { httpServer = new HttpServer(); httpServer.registerPathHandler("/content", contentHandler); httpServer.start(4444); - // we want to cancel the failover proxy engage, so, do not allow - // redirects from now. + var nc = new ChannelEventSink(); + var on_modify_request_count = 0; - var nc = new ChannelEventSink(); - nc._flags = ES_ABORT_REDIRECT; + modifyrequestobserver = {observe: function() { + // We get 2 on-modify-request notifications: + // 1. when proxy service resolves the proxy settings from PAC function + // 2. when we try to fail over the first proxy (moving to the second one) + // + // In the second case we want to cancel the proxy engage, so, do not allow + // redirects from now. + + if (++on_modify_request_count == 2) + nc._flags = ES_ABORT_REDIRECT; + }} + + var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + os.addObserver(modifyrequestobserver, "http-on-modify-request", false); var prefserv = Cc["@mozilla.org/preferences-service;1"]. getService(Ci.nsIPrefService); var prefs = prefserv.getBranch("network.proxy."); prefs.setIntPref("type", 2); prefs.setCharPref("autoconfig_url", "data:text/plain," + "function FindProxyForURL(url, host) {return 'PROXY a_non_existent_domain_x7x6c572v:80; PROXY localhost:4444';}" );
--- a/netwerk/test/unit/test_proxy-replace_canceled.js +++ b/netwerk/test/unit/test_proxy-replace_canceled.js @@ -36,21 +36,13 @@ function run_test() var prefserv = Cc["@mozilla.org/preferences-service;1"]. getService(Ci.nsIPrefService); var prefs = prefserv.getBranch("network.proxy."); prefs.setIntPref("type", 2); prefs.setCharPref("autoconfig_url", "data:text/plain," + "function FindProxyForURL(url, host) {return 'PROXY localhost:4444';}" ); - // this test assumed that a AsyncOnChannelRedirect query is made for - // each proxy failover or on the inital proxy only when PAC mode is used. - // Neither of those are documented anywhere that I can find and the latter - // hasn't been a useful property because it is PAC dependent and the type - // is generally unknown and OS driven. 769764 changed that to remove the - // internal redirect used to setup the initial proxy/channel as that isn't - // a redirect in any sense. - var chan = make_channel("http://localhost:4444/content"); + chan.notificationCallbacks = new ChannelEventSink(ES_ABORT_REDIRECT); chan.asyncOpen(new ChannelListener(finish_test, null, CL_EXPECT_FAILURE), null); - chan.cancel(Cr.NS_BINDING_ABORTED); do_test_pending(); }
--- a/toolkit/components/passwordmgr/test/test_bug_627616.html +++ b/toolkit/components/passwordmgr/test/test_bug_627616.html @@ -10,43 +10,23 @@ <script class="testbody" type="text/javascript"> SimpleTest.waitForExplicitFinish(); var Cc = SpecialPowers.wrap(Components).classes; testNum = 1; var login, login2; - - var resolveCallback = { - - QueryInterface : function (iid) { - const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports]; - - if (!interfaces.some( function(v) { return iid.equals(v) } )) - throw Components.results.NS_ERROR_NO_INTERFACE; - return this; - }, - - onProxyAvailable : function (req, uri, pi, status) { - init2(SpecialPowers.wrap(pi).host, SpecialPowers.wrap(pi).port); - } - }; - - function init1() { + function init() { var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(); var uri = ios.newURI("http://example.com", null, null); - pps.asyncResolve(uri, 0, resolveCallback); - } - - function init2(proxyHost, proxyPort) { - - var mozproxy = "moz-proxy://" + proxyHost + ":" + proxyPort; + var pi = pps.resolve(uri, 0); + var mozproxy = "moz-proxy://" + pi.host + ":" + pi.port; var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo); login.init(mozproxy, null, "proxy_realm", "proxy_user", "proxy_pass", "", ""); pwmgr.addLogin(login); login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo); login2.init("http://mochi.test:8888", null, "mochirealm", "user1name", "user1pass", "", ""); @@ -111,17 +91,17 @@ cleanup(); SimpleTest.finish(); } } var pendingTests = [{expectedDialogs: 2, test: testNonAnonymousCredentials}, {expectedDialogs: 1, test: testAnonymousCredentials}, {expectedDialogs: 0, test: testAnonymousNoAuth}]; - init1(); + init(); runNextTest(); function handleDialog(doc, testNum) { var dialog = doc.getElementById("commonDialog"); dialog.acceptDialog(); gExpectedDialogs--; startCallbackTimer();
--- a/toolkit/components/passwordmgr/test/test_prompt.html +++ b/toolkit/components/passwordmgr/test/test_prompt.html @@ -18,26 +18,29 @@ Login Manager test: username/password pr <pre id="test"> <script class="testbody" type="text/javascript"> /** Test for Login Manager: username / password prompts. **/ var pwmgr, ioService var tmplogin, login1, login2A, login2B, login2C, login2D, login2E, login3A, login3B, login4, proxyLogin; var mozproxy, proxiedHost = "http://mochi.test:8888"; -var testNum = 1; -function initLogins(pi) { +function initLogins() { pwmgr = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); ioService = Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService); - mozproxy = "moz-proxy://" + SpecialPowers.wrap(pi).host + ":" + - SpecialPowers.wrap(pi).port; + // Figure out what our proxy is set to -- can't just hardcode this, because + // mobile platforms don't use localhost. + var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(); + var uri = ioService.newURI(proxiedHost, null, null); + var pi = pps.resolve(uri, 0); + mozproxy = "moz-proxy://" + pi.host + ":" + pi.port; tmpLogin = Cc["@mozilla.org/login-manager/loginInfo;1"]. createInstance(Ci.nsILoginInfo); login1 = Cc["@mozilla.org/login-manager/loginInfo;1"]. createInstance(Ci.nsILoginInfo); login2A = Cc["@mozilla.org/login-manager/loginInfo;1"]. createInstance(Ci.nsILoginInfo); @@ -116,45 +119,16 @@ ok(true, "removing login 4..."); ok(true, "removing proxyLogin..."); pwmgr.removeLogin(proxyLogin); } catch (e) { ok(false, "finishTest FAILED: " + e); } ok(true, "whee, done!"); SimpleTest.finish(); } -var resolveCallback = { -QueryInterface : function (iid) { -const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports]; - - if (!interfaces.some( function(v) { return iid.equals(v) } )) - throw Components.results.NS_ERROR_NO_INTERFACE; - return this; -}, - - onProxyAvailable : function (req, uri, pi, status) { - initLogins(pi); - doTests(); - } -}; - -function startup() { - //need to allow for arbitrary network servers defined in PAC instead of a hardcoded moz-proxy. - var ios = SpecialPowers.wrap(Components) - .classes["@mozilla.org/network/io-service;1"] - .getService(Components.interfaces.nsIIOService); - - var pps = SpecialPowers.wrap(Components) - .classes["@mozilla.org/network/protocol-proxy-service;1"] - .getService(); - - var uri = ios.newURI("http://example.com", null, null); - pps.asyncResolve(uri, 0, resolveCallback); -} - function addNotificationCallback(cb) { storageObserver.notificationCallbacks.push(cb); } var storageObserver = { notificationCallbacks: [], @@ -590,19 +564,18 @@ dumpNotifications(); default: ok(false, "Uhh, unhandled switch for testNum #" + testNum); break; } } -startup(); +initLogins(); -function doTests() { var authinfo = { username : "", password : "", domain : "", flags : Ci.nsIAuthInformation.AUTH_HOST, authenticationScheme : "basic", realm : "" @@ -646,17 +619,17 @@ var result = { value : null }; var isOk; // popupNotifications (not *popup*) is a constant, per-tab container. So, we // only need to fetch it once. var popupNotifications = getPopupNotifications(window.top); ok(popupNotifications, "Got popupNotifications"); // ===== test 1 ===== -testNum = 1; +var testNum = 1; startCallbackTimer(); isOk = prompter1.prompt(dialogTitle(), dialogText, "http://example.com", Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result); ok(isOk, "Checking dialog return value (accept)"); ok(didDialog, "handleDialog was invoked"); is(result.value, "xyz", "Checking prompt() returned value"); @@ -1158,13 +1131,12 @@ authMgr.clearAll(); // ===== test 1000 ===== testNum = 1000; startCallbackTimer(); iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1"; // ...remaining tests are driven by handleLoad()... SimpleTest.waitForExplicitFinish(); -} </script> </pre> </body> </html>
--- a/toolkit/components/passwordmgr/test/test_prompt_async.html +++ b/toolkit/components/passwordmgr/test/test_prompt_async.html @@ -64,33 +64,42 @@ this.windowsRegistered = 0; } } var monitor = new dialogMonitor(); var pwmgr, logins = []; - function initLogins(pi) { + function initLogins() { pwmgr = SpecialPowers.wrap(Components) .classes["@mozilla.org/login-manager;1"] .getService(Ci.nsILoginManager); function addLogin(host, realm, user, pass) { var login = SpecialPowers.wrap(Components) .classes["@mozilla.org/login-manager/loginInfo;1"] .createInstance(Ci.nsILoginInfo); login.init(host, null, realm, user, pass, "", ""); pwmgr.addLogin(login); logins.push(login); } - var mozproxy = "moz-proxy://" + - SpecialPowers.wrap(pi).host + ":" + - SpecialPowers.wrap(pi).port; + //need to allow for arbitrary network servers defined in PAC instead of a hardcoded moz-proxy. + var ios = SpecialPowers.wrap(Components) + .classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + + var pps = SpecialPowers.wrap(Components) + .classes["@mozilla.org/network/protocol-proxy-service;1"] + .getService(); + + var uri = ios.newURI("http://example.com", null, null); + var pi = pps.resolve(uri, 0); + var mozproxy = "moz-proxy://" + pi.host + ":" + pi.port; addLogin(mozproxy, "proxy_realm", "proxy_user", "proxy_pass"); addLogin(mozproxy, "proxy_realm2", "proxy_user2", "proxy_pass2"); addLogin(mozproxy, "proxy_realm3", "proxy_user3", "proxy_pass3"); addLogin(mozproxy, "proxy_realm4", @@ -120,59 +129,32 @@ .classes['@mozilla.org/network/http-auth-manager;1'] .getService(Ci.nsIHttpAuthManager); authMgr.clearAll(); monitor.shutdown(); SimpleTest.finish(); } - var resolveCallback = { - QueryInterface : function (iid) { - const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports]; - - if (!interfaces.some( function(v) { return iid.equals(v) } )) - throw Components.results.NS_ERROR_NO_INTERFACE; - return this; - }, - - onProxyAvailable : function (req, uri, pi, status) { - initLogins(pi); - doTest(testNum); - } - }; - - function startup() { - //need to allow for arbitrary network servers defined in PAC instead of a hardcoded moz-proxy. - var ios = SpecialPowers.wrap(Components) - .classes["@mozilla.org/network/io-service;1"] - .getService(Components.interfaces.nsIIOService); - - var pps = SpecialPowers.wrap(Components) - .classes["@mozilla.org/network/protocol-proxy-service;1"] - .getService(); - - var uri = ios.newURI("http://example.com", null, null); - pps.asyncResolve(uri, 0, resolveCallback); - } // --------------- Test loop spin ---------------- var testNum = 1; var iframe1; var iframe2a; var iframe2b; window.onload = function () { iframe1 = document.getElementById("iframe1"); iframe2a = document.getElementById("iframe2a"); iframe2b = document.getElementById("iframe2b"); iframe1.onload = onFrameLoad; iframe2a.onload = onFrameLoad; iframe2b.onload = onFrameLoad; - startup(); + initLogins(); + doTest(testNum); } var expectedLoads; var expectedDialogs; function onFrameLoad() { if (--expectedLoads == 0) { // All pages expected to load has loaded, continue with the next test
--- a/toolkit/system/osxproxy/nsOSXSystemProxySettings.mm +++ b/toolkit/system/osxproxy/nsOSXSystemProxySettings.mm @@ -29,17 +29,17 @@ public: void ProxyHasChanged(); // is there a PAC url specified in the system configuration bool IsAutoconfigEnabled() const; // retrieve the pac url nsresult GetAutoconfigURL(nsAutoCString& aResult) const; // Find the SystemConfiguration proxy & port for a given URI - nsresult FindSCProxyPort(const nsACString &aScheme, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy); + nsresult FindSCProxyPort(nsIURI* aURI, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy); // is host:port on the proxy exception list? bool IsInExceptionList(const nsACString& aHost) const; private: ~nsOSXSystemProxySettings(); SCDynamicStoreContext mContext; @@ -53,24 +53,17 @@ private: CFStringRef mEnabled; CFStringRef mHost; CFStringRef mPort; bool mIsSocksProxy; }; static const SchemeMapping gSchemeMappingList[]; }; -NS_IMPL_THREADSAFE_ISUPPORTS1(nsOSXSystemProxySettings, nsISystemProxySettings) - -NS_IMETHODIMP -nsOSXSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) -{ - *aMainThreadOnly = false; - return NS_OK; -} +NS_IMPL_ISUPPORTS1(nsOSXSystemProxySettings, nsISystemProxySettings) // Mapping of URI schemes to SystemConfiguration keys const nsOSXSystemProxySettings::SchemeMapping nsOSXSystemProxySettings::gSchemeMappingList[] = { {"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort, false}, {"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort, false}, {"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort, false}, {"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort, true}, {NULL, NULL, NULL, NULL, false}, @@ -158,26 +151,26 @@ nsOSXSystemProxySettings::ProxyHasChange [mProxyDict release]; mProxyDict = (NSDictionary*)SCDynamicStoreCopyProxies(mSystemDynamicStore); NS_OBJC_END_TRY_ABORT_BLOCK; } nsresult -nsOSXSystemProxySettings::FindSCProxyPort(const nsACString &aScheme, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy) +nsOSXSystemProxySettings::FindSCProxyPort(nsIURI* aURI, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE); for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) { // Check for matching scheme (when appropriate) - if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) && - !keys->mIsSocksProxy) + bool res; + if ((NS_FAILED(aURI->SchemeIs(keys->mScheme, &res)) || !res) && !keys->mIsSocksProxy) continue; // Check the proxy is enabled NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled]; NS_ENSURE_TRUE(enabled == NULL || [enabled isKindOfClass:[NSNumber class]], NS_ERROR_FAILURE); if ([enabled intValue] == 0) continue; @@ -305,30 +298,30 @@ nsOSXSystemProxySettings::GetPACURI(nsAC } return NS_ERROR_FAILURE; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } nsresult -nsOSXSystemProxySettings::GetProxyForURI(const nsACString & aSpec, - const nsACString & aScheme, - const nsACString & aHost, - const int32_t aPort, - nsACString & aResult) +nsOSXSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + nsAutoCString host; + nsresult rv = aURI->GetHost(host); + NS_ENSURE_SUCCESS(rv, rv); + int32_t proxyPort; nsAutoCString proxyHost; bool proxySocks; - nsresult rv = FindSCProxyPort(aScheme, proxyHost, proxyPort, proxySocks); + rv = FindSCProxyPort(aURI, proxyHost, proxyPort, proxySocks); - if (NS_FAILED(rv) || IsInExceptionList(aHost)) { + if (NS_FAILED(rv) || IsInExceptionList(host)) { aResult.AssignLiteral("DIRECT"); } else if (proxySocks) { aResult.Assign(NS_LITERAL_CSTRING("SOCKS ") + proxyHost + nsPrintfCString(":%d", proxyPort)); } else { aResult.Assign(NS_LITERAL_CSTRING("PROXY ") + proxyHost + nsPrintfCString(":%d", proxyPort)); } return NS_OK;
--- a/toolkit/system/unixproxy/nsLibProxySettings.cpp +++ b/toolkit/system/unixproxy/nsLibProxySettings.cpp @@ -1,16 +1,17 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISystemProxySettings.h" #include "mozilla/ModuleUtils.h" #include "nsIServiceManager.h" +#include "nsIIOService.h" #include "nsIURI.h" #include "nsString.h" #include "nsNetUtil.h" #include "nsCOMPtr.h" #include "nspr.h" extern "C" { #include <proxy.h> @@ -28,93 +29,99 @@ private: ~nsUnixSystemProxySettings() { if (mProxyFactory) px_proxy_factory_free(mProxyFactory); } pxProxyFactory *mProxyFactory; }; -NS_IMPL_THREADSAFE_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings) - -NS_IMETHODIMP -nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) -{ - *aMainThreadOnly = false; - return NS_OK; -} +NS_IMPL_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings) nsresult nsUnixSystemProxySettings::Init() { return NS_OK; } nsresult nsUnixSystemProxySettings::GetPACURI(nsACString& aResult) { // Make sure we return an empty result. aResult.Truncate(); return NS_OK; } nsresult -nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec, - const nsACString & aScheme, - const nsACString & aHost, - const int32_t aPort, - nsACString & aResult) +nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult) { nsresult rv; if (!mProxyFactory) { mProxyFactory = px_proxy_factory_new(); } NS_ENSURE_TRUE(mProxyFactory, NS_ERROR_NOT_AVAILABLE); + nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString spec; + rv = aURI->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); + char **proxyArray = nullptr; - proxyArray = px_proxy_factory_get_proxies(mProxyFactory, - PromiseFlatCString(aSpec).get()); + proxyArray = px_proxy_factory_get_proxies(mProxyFactory, (char*)(spec.get())); NS_ENSURE_TRUE(proxyArray, NS_ERROR_NOT_AVAILABLE); // Translate libproxy's output to PAC string as expected // libproxy returns an array of proxies in the format: // <procotol>://[username:password@]proxy:port // or // direct:// // // PAC format: "PROXY proxy1.foo.com:8080; PROXY proxy2.foo.com:8080; DIRECT" - // but nsISystemProxySettings allows "PROXY http://proxy.foo.com:8080" as well. - int c = 0; while (proxyArray[c] != NULL) { if (!aResult.IsEmpty()) { aResult.AppendLiteral("; "); } - // figure out the scheme, and we can't use nsIIOService::NewURI because - // this is not the main thread. - char *colon = strchr (proxyArray[c], ':'); - uint32_t schemelen = colon ? colon - proxyArray[c] : 0; - if (schemelen < 1) { + bool isScheme = false; + nsXPIDLCString schemeString; + nsXPIDLCString hostPortString; + nsCOMPtr<nsIURI> proxyURI; + + rv = ios->NewURI(nsDependentCString(proxyArray[c]), + nullptr, + nullptr, + getter_AddRefs(proxyURI)); + if (NS_FAILED(rv)) { c++; continue; } - if (schemelen == 6 && !strncasecmp(proxyArray[c], "direct", 6)) { - aResult.AppendLiteral("DIRECT"); + proxyURI->GetScheme(schemeString); + if (NS_SUCCEEDED(proxyURI->SchemeIs("http", &isScheme)) && isScheme) { + schemeString.AssignLiteral("proxy"); } - else { - aResult.AppendLiteral("PROXY "); - aResult.Append(proxyArray[c]); + aResult.Append(schemeString); + if (NS_SUCCEEDED(proxyURI->SchemeIs("direct", &isScheme)) && !isScheme) { + // Add the proxy URI only if it's not DIRECT + proxyURI->GetHostPort(hostPortString); + aResult.AppendLiteral(" "); + aResult.Append(hostPortString); } c++; } +#ifdef DEBUG + printf("returned PAC proxy string: %s\n", PromiseFlatCString(aResult).get()); +#endif + PR_Free(proxyArray); return NS_OK; } #define NS_UNIXSYSTEMPROXYSERVICE_CID /* 0fa3158c-d5a7-43de-9181-a285e74cf1d4 */\ { 0x0fa3158c, 0xd5a7, 0x43de, \ {0x91, 0x81, 0xa2, 0x85, 0xe7, 0x4c, 0xf1, 0xd4 } }
--- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp +++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp @@ -13,17 +13,16 @@ #include "prnetdb.h" #include "prenv.h" #include "nsPrintfCString.h" #include "nsNetUtil.h" #include "nsISupportsPrimitives.h" #include "nsIGSettingsService.h" #include "nsInterfaceHashtable.h" #include "mozilla/Attributes.h" -#include "nsIURI.h" class nsUnixSystemProxySettings MOZ_FINAL : public nsISystemProxySettings { public: NS_DECL_ISUPPORTS NS_DECL_NSISYSTEMPROXYSETTINGS nsUnixSystemProxySettings() {} nsresult Init(); @@ -39,24 +38,16 @@ private: nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult); nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult); nsresult GetProxyFromGSettings(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult); nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, nsACString& aResult); }; NS_IMPL_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings) -NS_IMETHODIMP -nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) -{ - // dbus prevents us from being threadsafe, but this routine should not block anyhow - *aMainThreadOnly = true; - return NS_OK; -} - nsresult nsUnixSystemProxySettings::Init() { mSchemeProxySettings.Init(5); mGConf = do_GetService(NS_GCONFSERVICE_CONTRACTID); mGSettings = do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); if (mGSettings) { mGSettings->GetCollectionForSchema(NS_LITERAL_CSTRING("org.gnome.system.proxy"), @@ -155,20 +146,18 @@ IsInNoProxyList(const nsACString& aHost, } static void SetProxyResult(const char* aType, const nsACString& aHost, int32_t aPort, nsACString& aResult) { aResult.AppendASCII(aType); aResult.Append(' '); aResult.Append(aHost); - if (aPort > 0) { - aResult.Append(':'); - aResult.Append(nsPrintfCString("%d", aPort)); - } + aResult.Append(':'); + aResult.Append(nsPrintfCString("%d", aPort)); } static nsresult GetProxyFromEnvironment(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult) { @@ -487,31 +476,39 @@ nsUnixSystemProxySettings::GetProxyFromG if (NS_FAILED(rv)) { aResult.AppendLiteral("DIRECT"); } return NS_OK; } nsresult -nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec, - const nsACString & aScheme, - const nsACString & aHost, - const int32_t aPort, - nsACString & aResult) +nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult) { + nsAutoCString scheme; + nsresult rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString host; + rv = aURI->GetHost(host); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t port; + rv = aURI->GetPort(&port); + NS_ENSURE_SUCCESS(rv, rv); + if (mProxySettings) { - nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult); - if (NS_SUCCEEDED(rv)) + rv = GetProxyFromGSettings(scheme, host, port, aResult); + if (rv == NS_OK) return rv; } if (mGConf) - return GetProxyFromGConf(aScheme, aHost, aPort, aResult); + return GetProxyFromGConf(scheme, host, port, aResult); - return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult); + return GetProxyFromEnvironment(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) NS_DEFINE_NAMED_CID(NS_UNIXSYSTEMPROXYSERVICE_CID);
--- a/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp +++ b/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp @@ -27,38 +27,51 @@ public: private: ~nsWindowsSystemProxySettings() {}; bool MatchOverride(const nsACString& aHost); bool PatternMatch(const nsACString& aHost, const nsACString& aOverride); }; -NS_IMPL_THREADSAFE_ISUPPORTS1(nsWindowsSystemProxySettings, nsISystemProxySettings) - -NS_IMETHODIMP -nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) -{ - *aMainThreadOnly = false; - return NS_OK; -} - +NS_IMPL_ISUPPORTS1(nsWindowsSystemProxySettings, nsISystemProxySettings) nsresult nsWindowsSystemProxySettings::Init() { return NS_OK; } +static void SetProxyResult(const char* aType, const nsACString& aHost, + int32_t aPort, nsACString& aResult) +{ + aResult.AssignASCII(aType); + aResult.Append(' '); + aResult.Append(aHost); + aResult.Append(':'); + aResult.Append(nsPrintfCString("%d", aPort)); +} + static void SetProxyResult(const char* aType, const nsACString& aHostPort, nsACString& aResult) { - aResult.AssignASCII(aType); - aResult.Append(' '); - aResult.Append(aHostPort); + nsCOMPtr<nsIURI> uri; + nsAutoCString host; + int32_t port; + + // Try parsing it as a URI. + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aHostPort)) && + NS_SUCCEEDED(uri->GetHost(host)) && !host.IsEmpty() && + NS_SUCCEEDED(uri->GetPort(&port))) { + SetProxyResult(aType, host, port, aResult); + } else { + aResult.AssignASCII(aType); + aResult.Append(' '); + aResult.Append(aHostPort); + } } static void SetProxyResultDirect(nsACString& aResult) { // For whatever reason, a proxy is not to be used. aResult.AssignASCII("DIRECT"); } @@ -204,41 +217,45 @@ nsWindowsSystemProxySettings::GetPACURI( } if (NS_SUCCEEDED(rv)) aResult = NS_ConvertUTF16toUTF8(buf); return rv; } nsresult -nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec, - const nsACString & aScheme, - const nsACString & aHost, - const int32_t aPort, - nsACString & aResult) +nsWindowsSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult) { nsresult rv; uint32_t flags = 0; nsAutoString buf; rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf); if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) { SetProxyResultDirect(aResult); return NS_OK; } - if (MatchOverride(aHost)) { + nsAutoCString scheme; + rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString host; + rv = aURI->GetHost(host); + NS_ENSURE_SUCCESS(rv, rv); + + if (MatchOverride(host)) { SetProxyResultDirect(aResult); return NS_OK; } NS_ConvertUTF16toUTF8 cbuf(buf); nsAutoCString prefix; - ToLowerCase(aScheme, prefix); + ToLowerCase(scheme, prefix); prefix.Append('='); nsAutoCString specificProxy; nsAutoCString defaultProxy; nsAutoCString socksProxy; int32_t start = 0; int32_t end = cbuf.Length();