bug 769764 move proxy resolution to separate thread and remove sync api r=biesi sr=josh

This commit is contained in:
Patrick McManus 2012-09-13 15:22:56 -04:00
Родитель 6d71cf000f
Коммит 2fbed15e29
44 изменённых файлов: 2414 добавлений и 1294 удалений

Просмотреть файл

@ -366,8 +366,6 @@
@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

Просмотреть файл

@ -361,8 +361,6 @@
@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

Просмотреть файл

@ -87,6 +87,8 @@ 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
@ -921,6 +923,7 @@ xpicleanup@BIN_SUFFIX@
components/nsPlacesExpiration.js
components/nsPrivateBrowsingService.js
components/nsPrompter.js
components/nsProxyAutoConfig.manifest
components/nsProxyAutoConfig.js
components/nsSafebrowsingApplication.js
components/nsSearchService.js

Просмотреть файл

@ -31,7 +31,7 @@
#include "nsIURL.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsIProtocolProxyService.h"
#include "nsIProtocolProxyService2.h"
#include "nsIStreamConverterService.h"
#include "nsIFile.h"
#if defined(XP_MACOSX)
@ -743,12 +743,17 @@ nsresult nsPluginHost::FindProxyForURL(const char* url, char* *result)
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;
@ -760,7 +765,8 @@ nsresult nsPluginHost::FindProxyForURL(const char* url, char* *result)
nsCOMPtr<nsIProxyInfo> pi;
res = proxyService->Resolve(uriIn, 0, getter_AddRefs(pi));
// Remove this with bug 778201
res = proxyService2->DeprecatedBlockingResolve(uriIn, 0, getter_AddRefs(pi));
if (NS_FAILED(res))
return res;

Просмотреть файл

@ -275,8 +275,6 @@
@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

Просмотреть файл

@ -342,8 +342,6 @@
@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

Просмотреть файл

@ -66,7 +66,6 @@ XPIDLSRCS = \
nsIProtocolProxyFilter.idl \
nsIProtocolProxyCallback.idl \
nsIProxiedProtocolHandler.idl \
nsIProxyAutoConfig.idl \
nsIProxyInfo.idl \
nsITransport.idl \
nsISocketTransport.idl \

Просмотреть файл

@ -17,24 +17,10 @@ interface nsIURI;
* nsIProtocolProxyService provides methods to access information about
* various network proxies.
*/
[scriptable, uuid(d7ec6237-162e-40f5-a2b4-46ccd5fa83c9)]
[scriptable, uuid(e77c642b-026f-41ce-9b23-f829a6e3f300)]
interface nsIProtocolProxyService : nsISupports
{
/**
* 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;
/** Flag 1 << 0 is unused **/
/**
* When the proxy configuration is manual this flag may be passed to the
@ -77,44 +63,9 @@ interface nsIProtocolProxyService : nsISupports
const unsigned long RESOLVE_ALWAYS_TUNNEL = (1 << 4);
/**
* 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.
* 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.
*
* @param aURI
* The URI to test.
@ -128,6 +79,20 @@ interface nsIProtocolProxyService : nsISupports
* @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);

Просмотреть файл

@ -9,7 +9,7 @@
/**
* An extension of nsIProtocolProxyService
*/
[scriptable, uuid(dbd9565d-29b1-437a-bff5-2fc339e2c5df)]
[scriptable, uuid(bed3702d-9374-4804-a20f-32baed8e2954)]
interface nsIProtocolProxyService2 : nsIProtocolProxyService
{
/**
@ -17,4 +17,13 @@ interface nsIProtocolProxyService2 : nsIProtocolProxyService
* 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);
};

Просмотреть файл

@ -9,12 +9,26 @@ interface nsIChannel;
interface nsIURI;
interface nsIProxyInfo;
[scriptable, uuid(0a24fed4-1dd2-11b2-a75c-9f8b9a8f9ba7)]
[scriptable, uuid(2b63fe69-b0fc-48f2-a2df-adb795a4ce5c)]
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);
nsIChannel newProxiedChannel(in nsIURI uri, in nsIProxyInfo proxyInfo,
in unsigned long proxyResolveFlags,
in nsIURI proxyURI);
};

Просмотреть файл

@ -1,68 +0,0 @@
/* -*- 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);
};

Просмотреть файл

@ -13,17 +13,31 @@
* either return the proper proxy data from the autoconfig URL specified in the system proxy,
* or generate proxy data based on the system's manual proxy settings.
*/
[scriptable, uuid(a9f3ae38-b769-4e0b-9317-578388e326c9)]
[scriptable, uuid(971591cd-277e-409a-bbf6-0a79879cd307)]
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 nsIProxyAutoConfig::getProxyForURI; this function behaves exactly
* the same way.
* 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"
*/
AUTF8String getProxyForURI(in nsIURI aURI);
AUTF8String getProxyForURI(in AUTF8String testSpec,
in AUTF8String testScheme,
in AUTF8String testHost,
in int32_t testPort);
};

Просмотреть файл

@ -851,40 +851,6 @@ NS_GetReferrerFromChannel(nsIChannel *channel,
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,

Просмотреть файл

@ -66,8 +66,11 @@ CPPSRCS = \
RedirectChannelRegistrar.cpp \
nsPreloadedStream.cpp \
nsStreamListenerWrapper.cpp \
ProxyAutoConfig.cpp \
$(NULL)
LOCAL_INCLUDES += -I$(topsrcdir)/dom/base
ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
CPPSRCS += nsURLHelperOS2.cpp
else
@ -97,11 +100,6 @@ ifdef MOZ_ENABLE_QTNETWORK
endif
endif
EXTRA_COMPONENTS = \
$(srcdir)/nsProxyAutoConfig.js \
$(srcdir)/nsProxyAutoConfig.manifest \
$(NULL)
EXTRA_JS_MODULES = \
NetUtil.jsm \
$(NULL)

Просмотреть файл

@ -0,0 +1,623 @@
/* -*- 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 "jsapi.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"
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"
"";
// The PACResolver is used for dnsResolve()
class PACResolver MOZ_FINAL : public nsIDNSListener
{
public:
NS_DECL_ISUPPORTS
PACResolver()
: mStatus(NS_ERROR_FAILURE)
{
}
NS_IMETHODIMP OnLookupComplete(nsICancelable *request,
nsIDNSRecord *record,
nsresult status)
{
mRequest = nullptr;
mStatus = status;
mResponse = record;
return NS_OK;
}
nsresult mStatus;
nsCOMPtr<nsICancelable> mRequest;
nsCOMPtr<nsIDNSRecord> mResponse;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(PACResolver, nsIDNSListener)
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);
}
static
JSBool PACResolve(const nsCString &aHostName, nsCString &aDottedDecimal)
{
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
nsCOMPtr<PACResolver> helper = new PACResolver();
if (!dns || NS_FAILED(dns->AsyncResolve(aHostName, 0, helper,
NS_GetCurrentThread(),
getter_AddRefs(helper->mRequest))))
return false;
// 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->GetNextAddrAsString(aDottedDecimal)))
return false;
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;
nsCString dottedDecimal;
if (!hostName.init(cx, arg1))
return false;
if (!PACResolve(NS_ConvertUTF16toUTF8(hostName), dottedDecimal))
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;
}
nsCString hostName;
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
if (!dns || NS_FAILED(dns->GetMyHostName(hostName))) {
hostName.AssignLiteral("127.0.0.1");
}
nsCString dottedDecimal;
if (!PACResolve(hostName, dottedDecimal)) {
dottedDecimal.AssignLiteral("127.0.0.1");
}
JSString *dottedDecimalString = JS_NewStringCopyZ(cx, dottedDecimal.get());
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(dottedDecimalString));
return true;
}
// 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 (!mRunning)
return SetupJS();
mJSNeedsSetup = true;
return NS_OK;
}
nsresult
ProxyAutoConfig::SetupJS()
{
mJSNeedsSetup = false;
NS_ABORT_IF_FALSE(!mRunning, "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 mRunning flag keeps a new PAC file from being installed
// while the event loop is spinning on a DNS function. Don't early return.
mRunning = true;
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;
}
}
}
mRunning = false;
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 (mRunning || mShutdown)
return;
mShutdown = true;
delete mJSRuntime;
mJSRuntime = nullptr;
}
} // namespace mozilla
} // namespace mozilla::net

Просмотреть файл

@ -0,0 +1,89 @@
/* -*- 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"
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)
, mRunning(false)
, mJSNeedsSetup(false)
, mShutdown(false)
{
MOZ_COUNT_CTOR(ProxyAutoConfig);
}
~ProxyAutoConfig();
nsresult Init(const nsCString &aPACURI,
const nsCString &aPACScript);
void Shutdown();
void GC();
/**
* 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:
// used to compile the PAC file and setup the execution context
nsresult SetupJS();
JSRuntimeWrapper *mJSRuntime;
bool mRunning;
bool mJSNeedsSetup;
bool mShutdown;
nsCString mPACScript;
nsCString mPACURI;
};
}} // namespace mozilla::net
#endif // ProxyAutoConfig_h__

Просмотреть файл

@ -701,7 +701,9 @@ nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
SUSPEND_PUMP_FOR_SCOPE();
if (mListener) // null in case of redirect
return mListener->OnStartRequest(this, mListenerContext);
return NS_OK;
}
NS_IMETHODIMP
@ -716,6 +718,7 @@ nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
// Cause IsPending to return false.
mPump = nullptr;
if (mListener) // null in case of redirect
mListener->OnStopRequest(this, mListenerContext, mStatus);
mListener = nullptr;
mListenerContext = nullptr;

Просмотреть файл

@ -39,6 +39,9 @@
#include "nsIConsoleService.h"
#include "nsIUploadChannel2.h"
#include "nsXULAppAPI.h"
#include "nsIProxiedChannel.h"
#include "nsIProtocolProxyCallback.h"
#include "nsICancelable.h"
#include "mozilla/FunctionTimer.h"
@ -576,31 +579,6 @@ 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,
@ -625,25 +603,10 @@ nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
if (NS_FAILED(rv))
return rv;
// 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 = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, result);
else
rv = handler->NewChannel(aURI, result);
NS_ENSURE_SUCCESS(rv, rv);
@ -1212,35 +1175,79 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
}
// nsISpeculativeConnect
NS_IMETHODIMP
nsIOService::SpeculativeConnect(nsIURI *aURI,
nsIInterfaceRequestor *aCallbacks,
nsIEventTarget *aTarget)
class IOServiceProxyCallback MOZ_FINAL : public nsIProtocolProxyCallback
{
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 = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
rv = mIOService->GetProtocolHandler(scheme.get(),
getter_AddRefs(handler));
if (NS_FAILED(rv))
return rv;
return NS_OK;
nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
do_QueryInterface(handler);
if (!speculativeHandler)
return NS_OK;
return speculativeHandler->SpeculativeConnect(aURI,
aCallbacks,
aTarget);
speculativeHandler->SpeculativeConnect(aURI,
mCallbacks,
mTarget);
return NS_OK;
}
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));
}

Просмотреть файл

@ -6,21 +6,24 @@
#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.
@ -41,100 +44,206 @@ HttpRequestSucceeded(nsIStreamLoader *loader)
//-----------------------------------------------------------------------------
// These objects are stored in nsPACMan::mPendingQ
// The ExecuteCallback runnable is triggered by
// nsPACManCallback::OnQueryComplete on the Main thread when its completion is
// discovered on the pac thread
class PendingPACQuery MOZ_FINAL : public PRCList,
public nsIDNSListener
class ExecuteCallback MOZ_FINAL : public nsRunnable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDNSLISTENER
PendingPACQuery(nsPACMan *pacMan, nsIURI *uri, nsPACManCallback *callback)
: mPACMan(pacMan)
, mURI(uri)
, mCallback(callback)
ExecuteCallback(nsPACManCallback *aCallback,
nsresult status)
: mCallback(aCallback)
, mStatus(status)
{
PR_INIT_CLIST(this);
}
nsresult Start(uint32_t flags);
void Complete(nsresult status, const nsCString &pacString);
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:
nsPACMan *mPACMan; // weak reference
nsCOMPtr<nsIURI> mURI;
nsRefPtr<nsPACManCallback> mCallback;
nsCOMPtr<nsICancelable> mDNSRequest;
nsresult mStatus;
nsCString mPACString;
nsCString mPACURL;
};
// This is threadsafe because we implement nsIDNSListener
NS_IMPL_THREADSAFE_ISUPPORTS1(PendingPACQuery, nsIDNSListener)
//-----------------------------------------------------------------------------
nsresult
PendingPACQuery::Start(uint32_t flags)
// 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)
{
if (mDNSRequest)
return NS_OK; // already started
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;
}
nsAutoCString host;
rv = mURI->GetAsciiHost(host);
if (NS_FAILED(rv))
return rv;
rv = dns->AsyncResolve(host, flags, this, NS_GetCurrentThread(),
getter_AddRefs(mDNSRequest));
if (NS_FAILED(rv))
NS_WARNING("DNS AsyncResolve failed");
return rv;
NS_IMETHODIMP Run()
{
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)
{
}
NS_IMETHODIMP Run()
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread");
mPACMan->mLoader = nullptr;
mPACMan->PostProcessPendingQ();
return NS_OK;
}
private:
nsRefPtr<nsPACMan> mPACMan;
};
//-----------------------------------------------------------------------------
// 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
{
public:
// by default we just process the queue
ExecutePACThreadAction(nsPACMan *aPACMan)
: mPACMan(aPACMan)
, mCancel(false)
, mSetupPAC(false)
{ }
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;
}
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;
}
private:
nsRefPtr<nsPACMan> mPACMan;
bool mCancel;
nsresult mCancelStatus;
bool mSetupPAC;
nsCString mSetupPACData;
nsCString mSetupPACURI;
};
//-----------------------------------------------------------------------------
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);
}
// This may be called before or after OnLookupComplete
void
PendingPACQuery::Complete(nsresult status, const nsCString &pacString)
{
if (!mCallback)
return;
mCallback->OnQueryComplete(status, pacString);
mCallback = nullptr;
if (mDNSRequest) {
mDNSRequest->Cancel(NS_ERROR_ABORT);
mDNSRequest = nullptr;
nsRefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, status);
runnable->SetPACString(pacString);
if (mOnMainThreadOnly)
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
else
runnable->Run();
}
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();
}
NS_IMETHODIMP
PendingPACQuery::OnLookupComplete(nsICancelable *request,
nsIDNSRecord *record,
nsresult status)
PendingPACQuery::Run()
{
// 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();
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread");
mPACMan->PostQuery(this);
return NS_OK;
}
@ -143,87 +252,87 @@ PendingPACQuery::OnLookupComplete(nsICancelable *request,
nsPACMan::nsPACMan()
: mLoadPending(false)
, mShutdown(false)
, mScheduledReload(LL_MAXINT)
, mLoadFailureCount(0)
, mInProgress(false)
{
PR_INIT_CLIST(&mPendingQ);
NS_ABORT_IF_FALSE(NS_IsMainThread(), "pacman must be created on main thread");
}
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(mPAC == nullptr, "pac man not shutdown properly");
NS_ASSERTION(PR_CLIST_IS_EMPTY(&mPendingQ), "pac man not shutdown properly");
NS_ASSERTION(mPendingQ.isEmpty(), "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)
nsPACMan::AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback,
bool mainThreadResponse)
{
NS_ENSURE_STATE(!mShutdown);
if (IsPACURI(uri)) {
result.Truncate();
return NS_OK;
}
MaybeReloadPAC();
if (IsLoading())
return NS_ERROR_IN_PROGRESS;
if (!mPAC)
NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread");
if (mShutdown)
return NS_ERROR_NOT_AVAILABLE;
nsAutoCString spec, host;
uri->GetAsciiSpec(spec);
uri->GetAsciiHost(host);
// Maybe Reload PAC
if (mPACURI && !mScheduledReload.IsNull() &&
TimeStamp::Now() > mScheduledReload)
LoadPACFromURI(nullptr);
return mPAC->GetProxyForURI(spec, host, result);
nsRefPtr<PendingPACQuery> query =
new PendingPACQuery(this, uri, callback, mainThreadResponse);
if (IsPACURI(uri)) {
// deal with this directly instead of queueing it
query->Complete(NS_OK, EmptyCString());
return NS_OK;
}
return mPACThread->Dispatch(query, nsIEventTarget::DISPATCH_NORMAL);
}
nsresult
nsPACMan::AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback)
nsPACMan::PostQuery(PendingPACQuery *query)
{
NS_ENSURE_STATE(!mShutdown);
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread");
MaybeReloadPAC();
PendingPACQuery *query = new PendingPACQuery(this, uri, callback);
if (!query)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(query);
PR_APPEND_LINK(query, &mPendingQ);
// 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);
if (IsLoading() && !isPACURI)
if (mShutdown) {
query->Complete(NS_ERROR_NOT_AVAILABLE, 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 rv;
// 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;
}
nsresult
@ -256,21 +365,24 @@ nsPACMan::LoadPACFromURI(nsIURI *pacURI)
mLoader = loader;
if (pacURI) {
mPACURI = pacURI;
mPACURI->GetSpec(mPACURISpec);
mLoadFailureCount = 0; // reset
}
mScheduledReload = LL_MAXINT;
mPAC = nullptr;
// reset to Null
mScheduledReload = TimeStamp();
return NS_OK;
}
void
nsPACMan::StartLoading()
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread");
mLoadPending = false;
// CancelExistingLoad was called...
if (!mLoader) {
ProcessPendingQ(NS_ERROR_ABORT);
PostCancelPendingQ(NS_ERROR_ABORT);
return;
}
@ -293,18 +405,9 @@ nsPACMan::StartLoading()
}
CancelExistingLoad();
ProcessPendingQ(NS_ERROR_UNEXPECTED);
PostCancelPendingQ(NS_ERROR_UNEXPECTED);
}
void
nsPACMan::MaybeReloadPAC()
{
if (!mPACURI)
return;
if (PR_Now() > mScheduledReload)
LoadPACFromURI(nullptr);
}
void
nsPACMan::OnLoadFailure()
@ -324,11 +427,11 @@ nsPACMan::OnLoadFailure()
if (!interval || interval > maxInterval)
interval = maxInterval;
#ifdef DEBUG
printf("PAC load failure: will retry in %d seconds\n", interval);
#endif
mScheduledReload = TimeStamp::Now() + TimeDuration::FromSeconds(interval);
mScheduledReload = PR_Now() + int64_t(interval) * PR_USEC_PER_SEC;
// while we wait for the retry queued members should try direct
// even if that means fast failure.
PostCancelPendingQ(NS_ERROR_NOT_AVAILABLE);
}
void
@ -344,32 +447,110 @@ nsPACMan::CancelExistingLoad()
}
void
nsPACMan::ProcessPendingQ(nsresult status)
nsPACMan::PostProcessPendingQ()
{
// 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);
}
}
NS_ABORT_IF_FALSE(NS_IsMainThread(), "wrong thread");
nsRefPtr<ExecutePACThreadAction> pending =
new ExecutePACThreadAction(this);
if (mPACThread)
mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL);
}
NS_IMPL_ISUPPORTS3(nsPACMan, nsIStreamLoaderObserver, nsIInterfaceRequestor,
nsIChannelEventSink)
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)
{
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread");
nsRefPtr<PendingPACQuery> query;
while (!mPendingQ.isEmpty()) {
query = dont_AddRef(mPendingQ.popLast());
query->Complete(status, EmptyCString());
}
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_IMETHODIMP
nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
@ -378,6 +559,7 @@ nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
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
@ -387,8 +569,6 @@ nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
return NS_OK;
}
mLoader = nullptr;
if (NS_SUCCEEDED(status) && HttpRequestSucceeded(loader)) {
// Get the URI spec used to load this PAC script.
nsAutoCString pacURI;
@ -404,18 +584,21 @@ nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
}
}
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));
}
// 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);
// Even if the PAC file could not be parsed, we did succeed in loading the
// data for it.
@ -426,11 +609,11 @@ nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
OnLoadFailure();
}
// Reset mPAC if necessary
if (mPAC && NS_FAILED(status))
mPAC = nullptr;
if (NS_SUCCEEDED(status))
PostProcessPendingQ();
else
PostCancelPendingQ(status);
ProcessPendingQ(status);
return NS_OK;
}
@ -466,3 +649,26 @@ nsPACMan::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel,
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;
}

Просмотреть файл

@ -10,12 +10,20 @@
#include "nsIStreamLoader.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"
#include "nsIProxyAutoConfig.h"
#include "ProxyAutoConfig.h"
#include "nsICancelable.h"
#include "nsThreadUtils.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.
@ -31,14 +39,45 @@ public:
* @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) = 0;
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;
};
/**
* 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
@ -55,19 +94,6 @@ public:
*/
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
@ -78,8 +104,11 @@ public:
* 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);
nsresult AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback,
bool mustCallbackOnMainThread);
/**
* This method may be called to reload the PAC file. While we are loading
@ -105,11 +134,28 @@ public:
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();
/**
@ -117,13 +163,6 @@ private:
*/
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.
*/
@ -139,15 +178,35 @@ private:
*/
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:
nsCOMPtr<nsIProxyAutoConfig> mPAC;
mozilla::net::ProxyAutoConfig mPAC;
nsCOMPtr<nsIThread> mPACThread;
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
mozilla::LinkedList<PendingPACQuery> mPendingQ; /* pac thread only */
nsCOMPtr<nsIURI> mPACURI;
PRCList mPendingQ;
nsCString mPACURISpec; // for use off main thread
nsCOMPtr<nsIStreamLoader> mLoader;
bool mLoadPending;
bool mShutdown;
PRTime mScheduledReload;
mozilla::TimeStamp mScheduledReload;
uint32_t mLoadFailureCount;
bool mInProgress;
};
#endif // nsPACMan_h__

Просмотреть файл

@ -12,7 +12,6 @@
#include "nsIClassInfoImpl.h"
#include "nsIServiceManager.h"
#include "nsXPIDLString.h"
#include "nsIProxyAutoConfig.h"
#include "nsIIOService.h"
#include "nsIObserverService.h"
#include "nsIProtocolHandler.h"
@ -29,6 +28,9 @@
#include "nsCRT.h"
#include "prnetdb.h"
#include "nsPACMan.h"
#include "nsProxyRelease.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h"
//----------------------------------------------------------------------------
@ -72,12 +74,49 @@ public:
, 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;
@ -124,7 +163,9 @@ private:
// Called asynchronously, so we do not need to post another PLEvent
// before calling DoCallback.
void OnQueryComplete(nsresult status, const nsCString &pacString)
void OnQueryComplete(nsresult status,
const nsCString &pacString,
const nsCString &newPACURL)
{
// If we've already called DoCallback then, nothing more to do.
if (!mCallback)
@ -134,6 +175,7 @@ private:
if (mStatus == NS_OK) {
mStatus = status;
mPACString = pacString;
mPACURL = newPACURL;
}
// In the cancelation case, we may still have another PLEvent in
@ -156,26 +198,59 @@ private:
mPPS->ApplyFilters(mURI, info, mProxyInfo);
else
mProxyInfo = nullptr;
LOG(("pac thread callback %s\n", mPACString.get()));
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));
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 = 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;
nsRefPtr<nsProtocolProxyService> mPPS;
nsProtocolProxyService *mPPS;
nsCOMPtr<nsIProtocolProxyService> mXPComPPS;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIProtocolProxyCallback> mCallback;
nsCOMPtr<nsIProxyInfo> mProxyInfo;
};
NS_IMPL_ISUPPORTS2(nsAsyncResolveRequest, nsICancelable, nsIRunnable)
NS_IMPL_THREADSAFE_ISUPPORTS2(nsAsyncResolveRequest, nsICancelable, nsIRunnable)
//----------------------------------------------------------------------------
@ -386,8 +461,12 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID);
if (!mSystemProxySettings)
mProxyConfig = PROXYCONFIG_DIRECT;
ResetPACThread();
} else {
if (mSystemProxySettings) {
mSystemProxySettings = nullptr;
ResetPACThread();
}
}
}
@ -572,7 +651,7 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start,
*result = nullptr;
uint32_t flags = 0;
// see BNF in nsIProxyAutoConfig.idl
// see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl
// find end of proxy info delimiter
const char *end = start;
@ -616,33 +695,57 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start,
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;
}
pi->mPort = port;
}
else {
// www.example.com:8080
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;
}
else
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')
@ -739,15 +842,46 @@ nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi)
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)
{
if (!mPACMan) {
mPACMan = new nsPACMan();
if (!mPACMan)
return NS_ERROR_OUT_OF_MEMORY;
}
SetupPACThread();
nsCOMPtr<nsIURI> pacURI;
nsresult rv = NS_NewURI(getter_AddRefs(pacURI), spec);
@ -814,53 +948,125 @@ nsProtocolProxyService::ReloadPAC()
return NS_OK;
}
// nsIProtocolProxyService
NS_IMETHODIMP
nsProtocolProxyService::Resolve(nsIURI *uri, uint32_t flags,
nsIProxyInfo **result)
// When sync interface is removed this can go away too
class nsAsyncBridgeRequest MOZ_FINAL : public nsPACManCallback
{
NS_ENSURE_ARG_POINTER(uri);
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);
nsProtocolInfo info;
nsresult rv = GetProtocolInfo(uri, &info);
nsresult rv = GetProtocolInfo(aURI, &info);
if (NS_FAILED(rv))
return 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;
}
nsCOMPtr<nsIProxyInfo> pi;
bool usePACThread;
if (usePAC && mPACMan) {
NS_ASSERTION(*result == nullptr, "we should not have a result yet");
// 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
// If the caller didn't want us to invoke PAC, then error out.
if (flags & RESOLVE_NON_BLOCKING)
return NS_BASE_STREAM_WOULD_BLOCK;
// 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);
rv = Resolve_Internal(aURI, info, aFlags, &usePACThread, getter_AddRefs(pi));
if (NS_FAILED(rv))
return rv;
}
else
NS_WARNING("failed querying PAC file; trying DIRECT");
}
ApplyFilters(uri, info, result);
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;
// 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;
}
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;
return NS_OK;
}
// nsIProtocolProxyService
NS_IMETHODIMP
nsProtocolProxyService::AsyncResolve(nsIURI *uri, uint32_t flags,
nsIProtocolProxyCallback *callback,
@ -871,29 +1077,33 @@ nsProtocolProxyService::AsyncResolve(nsIURI *uri, uint32_t flags,
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;
rv = Resolve_Internal(uri, info, flags, &usePAC, getter_AddRefs(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));
if (NS_FAILED(rv))
return rv;
if (!usePAC || !mPACMan) {
if (!usePACThread || !mPACMan) {
// we can do it locally
ApplyFilters(uri, info, pi);
ctx->SetResult(NS_OK, pi);
return ctx->DispatchCallback();
}
// else kick off a PAC query
rv = mPACMan->AsyncGetProxyForURI(uri, ctx);
// else kick off a PAC thread query
rv = mPACMan->AsyncGetProxyForURI(uri, ctx, true);
if (NS_SUCCEEDED(rv)) {
*result = ctx;
NS_ADDREF(*result);
@ -1241,42 +1451,76 @@ nsresult
nsProtocolProxyService::Resolve_Internal(nsIURI *uri,
const nsProtocolInfo &info,
uint32_t flags,
bool *usePAC,
bool *usePACThread,
nsIProxyInfo **result)
{
NS_ENSURE_ARG_POINTER(uri);
nsresult rv = SetupPACThread();
if (NS_FAILED(rv))
return rv;
*usePAC = false;
*usePACThread = false;
*result = nullptr;
if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
return NS_OK; // Can't proxy this (filters may not override)
if (mSystemProxySettings) {
nsAutoCString PACURI;
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;
}
// no proxy, stop search
return NS_OK;
}
// 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;
// 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;
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
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;
return NS_OK;
}
ConfigureFromPAC(PACURI, false);
return NS_OK;
}
nsAutoCString spec;
nsAutoCString host;
nsAutoCString scheme;
int32_t port = -1;
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;
}
}
// if proxies are enabled and this host:port combo is supposed to use a
@ -1287,10 +1531,9 @@ nsProtocolProxyService::Resolve_Internal(nsIURI *uri,
return NS_OK;
// Proxy auto config magic...
if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD ||
mProxyConfig == PROXYCONFIG_SYSTEM) {
if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD) {
// Do not query PAC now.
*usePAC = true;
*usePACThread = true;
return NS_OK;
}
@ -1351,7 +1594,7 @@ nsProtocolProxyService::Resolve_Internal(nsIURI *uri,
}
if (type) {
nsresult rv = NewProxyInfo_Internal(type, *host, port, proxyFlags,
rv = NewProxyInfo_Internal(type, *host, port, proxyFlags,
PR_UINT32_MAX, nullptr, flags,
result);
if (NS_FAILED(rv))

Просмотреть файл

@ -13,7 +13,6 @@
#include "nsIPrefBranch.h"
#include "nsIProtocolProxyService2.h"
#include "nsIProtocolProxyFilter.h"
#include "nsIProxyAutoConfig.h"
#include "nsISystemProxySettings.h"
#include "nsIProxyInfo.h"
#include "nsIObserver.h"
@ -272,6 +271,10 @@ protected:
*/
NS_HIDDEN_(bool) CanUseProxy(nsIURI *uri, int32_t defaultPort);
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

Просмотреть файл

@ -1,314 +0,0 @@
/* -*- 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"

Просмотреть файл

@ -1,2 +0,0 @@
component {63ac8c66-1dd2-11b2-b070-84d00d3eaece} nsProxyAutoConfig.js
contract @mozilla.org/network/proxy-auto-config;1 {63ac8c66-1dd2-11b2-b070-84d00d3eaece}

Просмотреть файл

@ -55,6 +55,11 @@ public:
return mProxyInfo;
}
void SetProxyInfo(nsIProxyInfo *pi)
{
mProxyInfo = pi;
}
// Were we asked to resume a download?
bool ResumeRequested() { return mResumeRequested; }

Просмотреть файл

@ -33,6 +33,8 @@
#include "nsIStringBundle.h"
#include "nsAuthInformationHolder.h"
#include "nsICharsetConverterManager.h"
#include "nsIProtocolProxyService.h"
#include "nsICancelable.h"
#if defined(PR_LOGGING)
extern PRLogModuleInfo* gFTPLog;
@ -50,12 +52,13 @@ removeParamsFromPath(nsCString& path)
}
}
NS_IMPL_ISUPPORTS_INHERITED4(nsFtpState,
NS_IMPL_ISUPPORTS_INHERITED5(nsFtpState,
nsBaseContentStream,
nsIInputStreamCallback,
nsITransportEventSink,
nsICacheListener,
nsIRequestObserver)
nsIRequestObserver,
nsIProtocolProxyCallback)
nsFtpState::nsFtpState()
: nsBaseContentStream(true)
@ -78,6 +81,7 @@ nsFtpState::nsFtpState()
, mAddressChecked(false)
, mServerIsIPv6(false)
, mControlStatus(NS_OK)
, mDeferredCallbackPending(false)
{
LOG_ALWAYS(("FTP:(%x) nsFtpState created", this));
@ -89,6 +93,9 @@ 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);
@ -1759,6 +1766,19 @@ nsFtpState::Init(nsFtpChannel *channel)
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;
}
@ -2155,6 +2175,67 @@ nsFtpState::CloseWithStatus(nsresult status)
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()
{
@ -2163,6 +2244,11 @@ nsFtpState::OnCallbackPending()
// connect to the server.
if (mState == FTP_INIT) {
if (mProxyRequest) {
mDeferredCallbackPending = true;
return;
}
if (CheckCache()) {
mState = FTP_WAIT_CACHE;
return;

Просмотреть файл

@ -35,6 +35,7 @@
#include "nsICacheEntryDescriptor.h"
#include "nsICacheListener.h"
#include "nsIProtocolProxyCallback.h"
// ftp server types
#define FTP_GENERIC_TYPE 0
@ -77,6 +78,7 @@ typedef enum _FTP_STATE {
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
@ -88,13 +90,16 @@ class nsFtpState : public nsBaseContentStream,
public nsITransportEventSink,
public nsICacheListener,
public nsIRequestObserver,
public nsFtpControlConnectionListener {
public nsFtpControlConnectionListener,
public nsIProtocolProxyCallback
{
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);
@ -263,6 +268,9 @@ private:
bool mDoomCache;
nsCString mSuppliedEntityID;
nsCOMPtr<nsICancelable> mProxyRequest;
bool mDeferredCallbackPending;
};
#endif //__nsFtpState__h_

Просмотреть файл

@ -211,11 +211,13 @@ nsFtpProtocolHandler::NewURI(const nsACString &aSpec,
NS_IMETHODIMP
nsFtpProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
{
return NewProxiedChannel(url, nullptr, result);
return NewProxiedChannel(url, nullptr, 0, nullptr, result);
}
NS_IMETHODIMP
nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo,
uint32_t proxyResolveFlags,
nsIURI *proxyURI,
nsIChannel* *result)
{
NS_ENSURE_ARG_POINTER(uri);

Просмотреть файл

@ -50,6 +50,7 @@ HttpBaseChannel::HttpBaseChannel()
, mAllowSpdy(true)
, mPrivateBrowsing(false)
, mSuspendCount(0)
, mProxyResolveFlags(0)
{
LOG(("Creating HttpBaseChannel @%x\n", this));
@ -74,7 +75,9 @@ HttpBaseChannel::~HttpBaseChannel()
nsresult
HttpBaseChannel::Init(nsIURI *aURI,
uint8_t aCaps,
nsProxyInfo *aProxyInfo)
nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI)
{
LOG(("HttpBaseChannel::Init [this=%p]\n", this));
@ -87,6 +90,8 @@ HttpBaseChannel::Init(nsIURI *aURI,
mOriginalURI = aURI;
mDocumentURI = nullptr;
mCaps = aCaps;
mProxyResolveFlags = aProxyResolveFlags;
mProxyURI = aProxyURI;
// Construct connection info object
nsAutoCString host;
@ -112,11 +117,6 @@ HttpBaseChannel::Init(nsIURI *aURI,
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);
@ -128,8 +128,13 @@ HttpBaseChannel::Init(nsIURI *aURI,
rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
if (NS_FAILED(rv)) return rv;
rv = gHttpHandler->
AddStandardRequestHeaders(&mRequestHead.Headers(), aCaps);
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;
return rv;
}
@ -1522,7 +1527,9 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
// 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.
if (mConnectionInfo->UsingSSL())
bool usingSSL = false;
nsresult rv = mURI->SchemeIs("https", &usingSSL);
if (NS_SUCCEEDED(rv) && usingSSL)
newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
// Do not pass along LOAD_CHECK_OFFLINE_CACHE

Просмотреть файл

@ -60,7 +60,9 @@ public:
HttpBaseChannel();
virtual ~HttpBaseChannel();
virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo);
virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI);
// nsIRequest
NS_IMETHOD GetName(nsACString& aName);
@ -224,6 +226,7 @@ protected:
nsCOMPtr<nsIInputStream> mUploadStream;
nsAutoPtr<nsHttpResponseHead> mResponseHead;
nsRefPtr<nsHttpConnectionInfo> mConnectionInfo;
nsCOMPtr<nsIProxyInfo> mProxyInfo;
nsCString mSpec; // ASCII encoded URL spec
nsCString mContentTypeHint;
@ -269,6 +272,9 @@ protected:
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

Просмотреть файл

@ -333,21 +333,17 @@ nsHttpChannel::~nsHttpChannel()
nsresult
nsHttpChannel::Init(nsIURI *uri,
uint8_t caps,
nsProxyInfo *proxyInfo)
nsProxyInfo *proxyInfo,
uint32_t proxyResolveFlags,
nsIURI *proxyURI)
{
nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo);
nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo,
proxyResolveFlags, proxyURI);
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;
}
//-----------------------------------------------------------------------------
@ -407,13 +403,6 @@ nsHttpChannel::Connect()
// 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"));
@ -1532,54 +1521,6 @@ nsHttpChannel::ProxyFailover()
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()
{
@ -1724,7 +1665,8 @@ nsHttpChannel::AsyncDoReplaceWithProxy(nsIProxyInfo* pi)
nsresult rv;
nsCOMPtr<nsIChannel> newChannel;
rv = gHttpHandler->NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel));
rv = gHttpHandler->NewProxiedChannel(mURI, pi, mProxyResolveFlags,
mProxyURI, getter_AddRefs(newChannel));
if (NS_FAILED(rv))
return rv;
@ -1795,11 +1737,16 @@ nsHttpChannel::ResolveProxy()
if (NS_FAILED(rv))
return rv;
uint32_t resolveFlags = 0;
if (mConnectionInfo->ProxyInfo())
mConnectionInfo->ProxyInfo()->GetResolveFlags(&resolveFlags);
// 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(mURI, resolveFlags, this, getter_AddRefs(mProxyRequest));
return pps->AsyncResolve(mProxyURI ? mProxyURI : mURI, mProxyResolveFlags,
this, getter_AddRefs(mProxyRequest));
}
bool
@ -4357,7 +4304,102 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
if (NS_FAILED(rv))
return rv;
if (!(mConnectionInfo && mConnectionInfo->UsingHttpProxy())) {
// 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()) {
// 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.
@ -4373,20 +4415,6 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
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.
@ -4401,23 +4429,6 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
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
@ -4431,14 +4442,10 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
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;
}
}
@ -4486,18 +4493,33 @@ 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).
// 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();
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();
}
return NS_OK;
}

Просмотреть файл

@ -95,7 +95,9 @@ public:
nsHttpChannel();
virtual ~nsHttpChannel();
virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo);
virtual nsresult Init(nsIURI *aURI, uint8_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI);
// Methods HttpBaseChannel didn't implement for us or that we override.
//
@ -150,6 +152,7 @@ private:
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
bool RequestIsConditional();
nsresult BeginConnect();
nsresult Connect();
nsresult ContinueConnect();
void SpeculativeConnect();
@ -186,8 +189,6 @@ private:
nsresult ProxyFailover();
nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *);
nsresult ContinueDoReplaceWithProxy(nsresult);
void HandleAsyncReplaceWithProxy();
nsresult ContinueHandleAsyncReplaceWithProxy(nsresult);
nsresult ResolveProxy();
// cache specific methods
@ -303,9 +304,6 @@ private:
// 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.

Просмотреть файл

@ -131,9 +131,9 @@ nsHttpHandler::nsHttpHandler()
, 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)
@ -167,6 +167,7 @@ nsHttpHandler::nsHttpHandler()
, mDoNotTrackEnabled(false)
, mTelemetryEnabled(false)
, mAllowExperiments(true)
, mHandlerActive(false)
, mEnableSpdy(false)
, mSpdyV2(true)
, mSpdyV3(true)
@ -264,6 +265,7 @@ nsHttpHandler::Init()
}
mSessionStartTime = NowInSeconds();
mHandlerActive = true;
rv = mAuthCache.Init();
if (NS_FAILED(rv)) return rv;
@ -331,8 +333,7 @@ nsHttpHandler::InitConnectionMgr()
}
nsresult
nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
uint8_t caps)
nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request)
{
nsresult rv;
@ -356,6 +357,20 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
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
@ -369,13 +384,6 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request,
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);
}
@ -943,12 +951,8 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("proxy.pipelining"))) {
rv = prefs->GetBoolPref(HTTP_PREF("proxy.pipelining"), &cVar);
if (NS_SUCCEEDED(rv)) {
if (cVar)
mProxyCapabilities |= NS_HTTP_ALLOW_PIPELINING;
else
mProxyCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
}
if (NS_SUCCEEDED(rv))
mProxyPipelining = cVar;
}
if (PREF_CHANGED(HTTP_PREF("qos"))) {
@ -1375,7 +1379,7 @@ nsHttpHandler::NewChannel(nsIURI *uri, nsIChannel **result)
}
}
return NewProxiedChannel(uri, nullptr, result);
return NewProxiedChannel(uri, nullptr, 0, nullptr, result);
}
NS_IMETHODIMP
@ -1393,6 +1397,8 @@ nsHttpHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
NS_IMETHODIMP
nsHttpHandler::NewProxiedChannel(nsIURI *uri,
nsIProxyInfo* givenProxyInfo,
uint32_t proxyResolveFlags,
nsIURI *proxyURI,
nsIChannel **result)
{
nsRefPtr<HttpBaseChannel> httpChannel;
@ -1417,13 +1423,7 @@ nsHttpHandler::NewProxiedChannel(nsIURI *uri,
httpChannel = new nsHttpChannel();
}
// 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;
uint8_t caps = mCapabilities;
if (https) {
// enable pipelining over SSL if requested
@ -1436,7 +1436,7 @@ nsHttpHandler::NewProxiedChannel(nsIURI *uri,
}
}
rv = httpChannel->Init(uri, caps, proxyInfo);
rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI);
if (NS_FAILED(rv))
return rv;
@ -1509,6 +1509,8 @@ nsHttpHandler::Observe(nsISupports *subject,
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();

Просмотреть файл

@ -58,7 +58,8 @@ public:
virtual ~nsHttpHandler();
nsresult Init();
nsresult AddStandardRequestHeaders(nsHttpHeaderArray *,
nsresult AddStandardRequestHeaders(nsHttpHeaderArray *);
nsresult AddConnectionHeader(nsHttpHeaderArray *,
uint8_t capabilities);
bool IsAcceptableEncoding(const char *encoding);
@ -78,6 +79,7 @@ public:
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; }
@ -233,6 +235,9 @@ public:
mozilla::net::SpdyInformation *SpdyInfo() { return &mSpdyInfo; }
// returns true in between Init and Shutdown states
bool Active() { return mHandlerActive; }
private:
//
@ -273,11 +278,10 @@ private:
uint8_t mHttpVersion;
uint8_t mProxyHttpVersion;
uint8_t mCapabilities;
uint8_t mProxyCapabilities;
uint8_t mReferrerLevel;
bool mFastFallbackToIPv4;
bool mProxyPipelining;
PRIntervalTime mIdleTimeout;
PRIntervalTime mSpdyTimeout;
@ -356,6 +360,9 @@ private:
// 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;

Просмотреть файл

@ -6,10 +6,21 @@
// 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();
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
@ -143,61 +154,109 @@ 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 pi = pps.resolve(uri, 0);
var filter01;
var filter02;
function filter_test0_1(pi) {
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);
filter01 = new BasicFilter();
filter02 = new BasicFilter();
pps.registerFilter(filter01, 10);
pps.registerFilter(filter02, 20);
pi = pps.resolve(uri, 0);
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)
{
check_proxy(pi, "http", "localhost", 8080, 0, 10, true);
check_proxy(pi.failoverProxy, "direct", "", -1, 0, 0, false);
pps.unregisterFilter(filter2);
pi = pps.resolve(uri, 0);
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)
{
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.resolve(uri, 0);
do_check_eq(pi, null);
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 run_filter_test2() {
var uri = ios.newURI("http://www.mozilla.org/", null, null);
// Verify initial state
var pi = pps.resolve(uri, 0);
function filter_test0_4(pi)
{
do_check_eq(pi, null);
run_filter_test2();
}
var filter11;
var filter12;
function run_filter_test2() {
// Push a filter and verify the results
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);
filter11 = new TestFilter("http", "foo", 8080, 0, 10);
filter12 = new TestFilter("http", "bar", 8090, 0, 10);
pps.registerFilter(filter11, 20);
pps.registerFilter(filter12, 10);
pi = pps.resolve(uri, 0);
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) {
check_proxy(pi, "http", "bar", 8090, 0, 10, true);
check_proxy(pi.failoverProxy, "http", "foo", 8080, 0, 10, false);
pps.unregisterFilter(filter2);
pi = pps.resolve(uri, 0);
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) {
check_proxy(pi, "http", "foo", 8080, 0, 10, false);
// Remove filter and verify that we return to the initial state
pps.unregisterFilter(filter1);
pi = pps.resolve(uri, 0);
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) {
do_check_eq(pi, null);
run_filter_test3();
}
var filter_3_1;
@ -213,42 +272,56 @@ function run_filter_test3() {
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_test_continued_3();
do_test_finished();
run_pref_test();
}
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 pi = pps.resolve(uri, 0);
var cb = new resolveCallback();
cb.nextFunction = pref_test1_1;
var req = pps.asyncResolve(uri, 0, cb);
}
function pref_test1_1(pi)
{
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);
pi = pps.resolve(uri, 0);
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)
{
check_proxy(pi, "http", "foopy", 8080, 0, -1, false);
prefs.setCharPref("network.proxy.http", "");
@ -258,15 +331,33 @@ function run_pref_test() {
prefs.setCharPref("network.proxy.socks", "barbar");
prefs.setIntPref("network.proxy.socks_port", 1203);
pi = pps.resolve(uri, 0);
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)
{
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 pi = pps.resolve(uri, 0);
var cb = new resolveCallback();
cb.nextFunction = protocol_handler_test_1;
var req = pps.asyncResolve(uri, 0, cb);
}
function protocol_handler_test_1(pi)
{
do_check_eq(pi, null);
prefs.setCharPref("network.proxy.autoconfig_url", "");
prefs.setIntPref("network.proxy.type", 0);
run_pac_cancel_test();
}
function TestResolveCallback() {
@ -292,21 +383,7 @@ TestResolveCallback.prototype = {
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();
}
};
@ -317,31 +394,12 @@ function run_pac_test() {
'}';
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() {
@ -364,13 +422,10 @@ TestResolveCancelationCallback.prototype = {
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_test_continued_2();
do_test_finished();
run_proxy_host_filters_test();
}
};
@ -382,23 +437,49 @@ function run_pac_cancel_test() {
'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);
do_test_pending();
}
function check_host_filters(hostList, bShouldBeFiltered) {
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);
}
function check_host_filters_cb()
{
hostIDX++;
if (hostList.length > hostIDX)
check_host_filter(hostIDX);
else
hostNextFX();
}
function check_host_filter(i) {
var uri;
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);
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 {
@ -407,17 +488,19 @@ function check_host_filters(hostList, bShouldBeFiltered) {
// - 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);
@ -425,39 +508,51 @@ function run_proxy_host_filters_test() {
prefs.setIntPref("network.proxy.http_port", 8080);
// Setup host filter list string for "no_proxies_on"
var hostFilterList = "www.mozilla.org, www.google.com, www.apple.com, "
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
var uriStrFilterList = [ "http://www.mozilla.org/",
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);
check_host_filters(uriStrFilterList, true, host_filters_1);
}
function host_filters_1()
{
// Check the hosts that should be proxied
var uriStrUseProxyList = [ "http://www.mozilla.com/",
uriStrUseProxyList = [ "http://www.mozilla.com/",
"http://mail.google.com/",
"http://somehost.domain.co.uk/",
"http://somelocalhost/" ];
check_host_filters(uriStrUseProxyList, false);
check_host_filters(uriStrUseProxyList, false, host_filters_2);
}
function host_filters_2()
{
// 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);
check_host_filters(uriStrUseProxyList, false);
check_host_filters(uriStrFilterList, true, host_filters_3);
}
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"), "");
@ -465,24 +560,44 @@ function run_proxy_host_filters_test() {
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();
// start of asynchronous test chain
run_filter_test();
run_filter_test2();
run_pref_test();
run_pac_test();
// additional tests may be added to run_test_continued
}
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();
do_test_pending();
}

Просмотреть файл

@ -33,24 +33,11 @@ function run_test()
httpServer.registerPathHandler("/content", contentHandler);
httpServer.start(4444);
var nc = new ChannelEventSink();
var on_modify_request_count = 0;
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
// we want to cancel the failover proxy engage, so, do not allow
// redirects from now.
if (++on_modify_request_count == 2)
var nc = new ChannelEventSink();
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);

Просмотреть файл

@ -41,8 +41,16 @@ function run_test()
"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();
}

Просмотреть файл

@ -15,13 +15,33 @@
testNum = 1;
var login, login2;
function init() {
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() {
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);
var pi = pps.resolve(uri, 0);
var mozproxy = "moz-proxy://" + pi.host + ":" + pi.port;
pps.asyncResolve(uri, 0, resolveCallback);
}
function init2(proxyHost, proxyPort) {
var mozproxy = "moz-proxy://" + proxyHost + ":" + proxyPort;
var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
@ -96,7 +116,7 @@
var pendingTests = [{expectedDialogs: 2, test: testNonAnonymousCredentials},
{expectedDialogs: 1, test: testAnonymousCredentials},
{expectedDialogs: 0, test: testAnonymousNoAuth}];
init();
init1();
runNextTest();
function handleDialog(doc, testNum)

Просмотреть файл

@ -23,19 +23,16 @@ Login Manager test: 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() {
function initLogins(pi) {
pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
ioService = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
// 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;
mozproxy = "moz-proxy://" + SpecialPowers.wrap(pi).host + ":" +
SpecialPowers.wrap(pi).port;
tmpLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
@ -124,6 +121,35 @@ 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);
@ -569,8 +595,9 @@ dumpNotifications();
}
initLogins();
startup();
function doTests() {
var authinfo = {
username : "",
password : "",
@ -624,7 +651,7 @@ var popupNotifications = getPopupNotifications(window.top);
ok(popupNotifications, "Got popupNotifications");
// ===== test 1 =====
var testNum = 1;
testNum = 1;
startCallbackTimer();
isOk = prompter1.prompt(dialogTitle(), dialogText, "http://example.com",
Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
@ -1136,6 +1163,7 @@ iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
// ...remaining tests are driven by handleLoad()...
SimpleTest.waitForExplicitFinish();
}
</script>
</pre>
</body>

Просмотреть файл

@ -69,7 +69,7 @@
var pwmgr, logins = [];
function initLogins() {
function initLogins(pi) {
pwmgr = SpecialPowers.wrap(Components)
.classes["@mozilla.org/login-manager;1"]
.getService(Ci.nsILoginManager);
@ -83,18 +83,9 @@
logins.push(login);
}
//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;
var mozproxy = "moz-proxy://" +
SpecialPowers.wrap(pi).host + ":" +
SpecialPowers.wrap(pi).port;
addLogin(mozproxy, "proxy_realm",
"proxy_user", "proxy_pass");
@ -134,6 +125,34 @@
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;
@ -148,8 +167,7 @@
iframe2a.onload = onFrameLoad;
iframe2b.onload = onFrameLoad;
initLogins();
doTest(testNum);
startup();
}
var expectedLoads;

Просмотреть файл

@ -34,7 +34,7 @@ public:
nsresult GetAutoconfigURL(nsAutoCString& aResult) const;
// Find the SystemConfiguration proxy & port for a given URI
nsresult FindSCProxyPort(nsIURI* aURI, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy);
nsresult FindSCProxyPort(const nsACString &aScheme, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy);
// is host:port on the proxy exception list?
bool IsInExceptionList(const nsACString& aHost) const;
@ -58,7 +58,14 @@ private:
static const SchemeMapping gSchemeMappingList[];
};
NS_IMPL_ISUPPORTS1(nsOSXSystemProxySettings, nsISystemProxySettings)
NS_IMPL_THREADSAFE_ISUPPORTS1(nsOSXSystemProxySettings, nsISystemProxySettings)
NS_IMETHODIMP
nsOSXSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
{
*aMainThreadOnly = false;
return NS_OK;
}
// Mapping of URI schemes to SystemConfiguration keys
const nsOSXSystemProxySettings::SchemeMapping nsOSXSystemProxySettings::gSchemeMappingList[] = {
@ -156,7 +163,7 @@ nsOSXSystemProxySettings::ProxyHasChanged()
}
nsresult
nsOSXSystemProxySettings::FindSCProxyPort(nsIURI* aURI, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy)
nsOSXSystemProxySettings::FindSCProxyPort(const nsACString &aScheme, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
@ -164,8 +171,8 @@ nsOSXSystemProxySettings::FindSCProxyPort(nsIURI* aURI, nsACString& aResultHost,
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) {
// Check for matching scheme (when appropriate)
bool res;
if ((NS_FAILED(aURI->SchemeIs(keys->mScheme, &res)) || !res) && !keys->mIsSocksProxy)
if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) &&
!keys->mIsSocksProxy)
continue;
// Check the proxy is enabled
@ -303,20 +310,20 @@ nsOSXSystemProxySettings::GetPACURI(nsACString& aResult)
}
nsresult
nsOSXSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
nsOSXSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
const nsACString & aScheme,
const nsACString & aHost,
const int32_t aPort,
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;
rv = FindSCProxyPort(aURI, proxyHost, proxyPort, proxySocks);
nsresult rv = FindSCProxyPort(aScheme, proxyHost, proxyPort, proxySocks);
if (NS_FAILED(rv) || IsInExceptionList(host)) {
if (NS_FAILED(rv) || IsInExceptionList(aHost)) {
aResult.AssignLiteral("DIRECT");
} else if (proxySocks) {
aResult.Assign(NS_LITERAL_CSTRING("SOCKS ") + proxyHost + nsPrintfCString(":%d", proxyPort));

Просмотреть файл

@ -6,7 +6,6 @@
#include "nsISystemProxySettings.h"
#include "mozilla/ModuleUtils.h"
#include "nsIServiceManager.h"
#include "nsIIOService.h"
#include "nsIURI.h"
#include "nsString.h"
#include "nsNetUtil.h"
@ -34,7 +33,14 @@ private:
pxProxyFactory *mProxyFactory;
};
NS_IMPL_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings)
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUnixSystemProxySettings, nsISystemProxySettings)
NS_IMETHODIMP
nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
{
*aMainThreadOnly = false;
return NS_OK;
}
nsresult
nsUnixSystemProxySettings::Init()
@ -51,7 +57,11 @@ nsUnixSystemProxySettings::GetPACURI(nsACString& aResult)
}
nsresult
nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
const nsACString & aScheme,
const nsACString & aHost,
const int32_t aPort,
nsACString & aResult)
{
nsresult rv;
@ -60,15 +70,9 @@ nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
}
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, (char*)(spec.get()));
proxyArray = px_proxy_factory_get_proxies(mProxyFactory,
PromiseFlatCString(aSpec).get());
NS_ENSURE_TRUE(proxyArray, NS_ERROR_NOT_AVAILABLE);
// Translate libproxy's output to PAC string as expected
@ -78,45 +82,34 @@ nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
// 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("; ");
}
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)) {
// 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) {
c++;
continue;
}
proxyURI->GetScheme(schemeString);
if (NS_SUCCEEDED(proxyURI->SchemeIs("http", &isScheme)) && isScheme) {
schemeString.AssignLiteral("proxy");
if (schemelen == 6 && !strncasecmp(proxyArray[c], "direct", 6)) {
aResult.AppendLiteral("DIRECT");
}
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);
else {
aResult.AppendLiteral("PROXY ");
aResult.Append(proxyArray[c]);
}
c++;
}
#ifdef DEBUG
printf("returned PAC proxy string: %s\n", PromiseFlatCString(aResult).get());
#endif
PR_Free(proxyArray);
return NS_OK;
}

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsIGSettingsService.h"
#include "nsInterfaceHashtable.h"
#include "mozilla/Attributes.h"
#include "nsIURI.h"
class nsUnixSystemProxySettings MOZ_FINAL : public nsISystemProxySettings {
public:
@ -43,6 +44,14 @@ private:
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()
{
@ -151,9 +160,11 @@ static void SetProxyResult(const char* aType, const nsACString& aHost,
aResult.AppendASCII(aType);
aResult.Append(' ');
aResult.Append(aHost);
if (aPort > 0) {
aResult.Append(':');
aResult.Append(nsPrintfCString("%d", aPort));
}
}
static nsresult
GetProxyFromEnvironment(const nsACString& aScheme,
@ -481,29 +492,21 @@ nsUnixSystemProxySettings::GetProxyFromGSettings(const nsACString& aScheme,
}
nsresult
nsUnixSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
const nsACString & aScheme,
const nsACString & aHost,
const int32_t aPort,
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) {
rv = GetProxyFromGSettings(scheme, host, port, aResult);
if (rv == NS_OK)
nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult);
if (NS_SUCCEEDED(rv))
return rv;
}
if (mGConf)
return GetProxyFromGConf(scheme, host, port, aResult);
return GetProxyFromGConf(aScheme, aHost, aPort, aResult);
return GetProxyFromEnvironment(scheme, host, port, aResult);
return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult);
}
#define NS_UNIXSYSTEMPROXYSERVICE_CID /* 0fa3158c-d5a7-43de-9181-a285e74cf1d4 */\

Просмотреть файл

@ -32,7 +32,15 @@ private:
bool PatternMatch(const nsACString& aHost, const nsACString& aOverride);
};
NS_IMPL_ISUPPORTS1(nsWindowsSystemProxySettings, nsISystemProxySettings)
NS_IMPL_THREADSAFE_ISUPPORTS1(nsWindowsSystemProxySettings, nsISystemProxySettings)
NS_IMETHODIMP
nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
{
*aMainThreadOnly = false;
return NS_OK;
}
nsresult
nsWindowsSystemProxySettings::Init()
@ -40,34 +48,13 @@ 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)
{
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)
{
@ -222,7 +209,11 @@ nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult)
}
nsresult
nsWindowsSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
const nsACString & aScheme,
const nsACString & aHost,
const int32_t aPort,
nsACString & aResult)
{
nsresult rv;
uint32_t flags = 0;
@ -234,15 +225,7 @@ nsWindowsSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
return NS_OK;
}
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)) {
if (MatchOverride(aHost)) {
SetProxyResultDirect(aResult);
return NS_OK;
}
@ -250,7 +233,7 @@ nsWindowsSystemProxySettings::GetProxyForURI(nsIURI* aURI, nsACString& aResult)
NS_ConvertUTF16toUTF8 cbuf(buf);
nsAutoCString prefix;
ToLowerCase(scheme, prefix);
ToLowerCase(aScheme, prefix);
prefix.Append('=');