diff --git a/mozilla/browser/components/preferences/connection.js b/mozilla/browser/components/preferences/connection.js index 9cdc2d93b25..10195ed6b49 100644 --- a/mozilla/browser/components/preferences/connection.js +++ b/mozilla/browser/components/preferences/connection.js @@ -141,8 +141,8 @@ var gConnectionsDialog = { reloadPAC: function () { var autoURL = document.getElementById("networkProxyAutoconfigURL"); - var pps = Components.classesByID["{e9b301c0-e0e4-11D3-a1a8-0050041caf44}"] - .getService(Components.interfaces.nsIProtocolProxyService); + var pps = Components.classes["@mozilla.org/network/protocol-proxy-service;1"] + .getService(Components.interfaces.nsPIProtocolProxyService); pps.configureFromPAC(autoURL.value); }, diff --git a/mozilla/embedding/components/build/nsModule.cpp b/mozilla/embedding/components/build/nsModule.cpp index 64821d6e1d7..4df3454cb1e 100644 --- a/mozilla/embedding/components/build/nsModule.cpp +++ b/mozilla/embedding/components/build/nsModule.cpp @@ -50,6 +50,8 @@ #include "nsCommandGroup.h" #include "nsPrintingPromptService.h" #include "nsBaseCommandController.h" +#include "nsPrompt.h" +#include "nsNetCID.h" #include "nsEmbedCID.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowWatcher, Init) @@ -63,6 +65,54 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCommandParams, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsControllerCommandGroup) NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseCommandController) +#define NS_DEFAULTPROMPT_CLASSNAME \ + "nsDefaultPrompt" +#define NS_DEFAULTPROMPT_CID \ +{ /* 2e41ada0-62b7-4902-b9a6-e4542aa458ba */ \ + 0x2e41ada0, \ + 0x62b7, \ + 0x4902, \ + {0xb9, 0xa6, 0xe4, 0x54, 0x2a, 0xa4, 0x58, 0xba} \ +} + +#define NS_DEFAULTAUTHPROMPT_CLASSNAME \ + "nsDefaultAuthPrompt" +#define NS_DEFAULTAUTHPROMPT_CID \ +{ /* ca200860-4696-40d7-88fa-4490d423a8ef */ \ + 0xca200860, \ + 0x4696, \ + 0x40d7, \ + {0x88, 0xfa, 0x44, 0x90, 0xd4, 0x23, 0xa8, 0xef} \ +} + +static NS_METHOD +nsDefaultPromptConstructor(nsISupports *outer, const nsIID &iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsCOMPtr prompt; + nsresult rv = NS_NewPrompter(getter_AddRefs(prompt), nsnull); + if (NS_FAILED(rv)) + return rv; + + return prompt->QueryInterface(iid, result); +} + +static NS_METHOD +nsDefaultAuthPromptConstructor(nsISupports *outer, const nsIID &iid, void **result) +{ + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsCOMPtr prompt; + nsresult rv = NS_NewAuthPrompter(getter_AddRefs(prompt), nsnull); + if (NS_FAILED(rv)) + return rv; + + return prompt->QueryInterface(iid, result); +} + #ifdef MOZ_XUL NS_GENERIC_FACTORY_CONSTRUCTOR(nsDialogParamBlock) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPromptService, Init) @@ -92,7 +142,9 @@ static const nsModuleComponentInfo gComponents[] = { { "Command Manager", NS_COMMAND_MANAGER_CID, NS_COMMAND_MANAGER_CONTRACTID, nsCommandManagerConstructor }, { "Command Params", NS_COMMAND_PARAMS_CID, NS_COMMAND_PARAMS_CONTRACTID, nsCommandParamsConstructor }, { "Command Group", NS_CONTROLLER_COMMAND_GROUP_CID, NS_CONTROLLER_COMMAND_GROUP_CONTRACTID, nsControllerCommandGroupConstructor }, - { "Base Command Controller", NS_BASECOMMANDCONTROLLER_CID, NS_BASECOMMANDCONTROLLER_CONTRACTID, nsBaseCommandControllerConstructor } + { "Base Command Controller", NS_BASECOMMANDCONTROLLER_CID, NS_BASECOMMANDCONTROLLER_CONTRACTID, nsBaseCommandControllerConstructor }, + { NS_DEFAULTPROMPT_CLASSNAME, NS_DEFAULTPROMPT_CID, NS_DEFAULTPROMPT_CONTRACTID, nsDefaultPromptConstructor }, + { NS_DEFAULTAUTHPROMPT_CLASSNAME, NS_DEFAULTAUTHPROMPT_CID, NS_DEFAULTAUTHPROMPT_CONTRACTID, nsDefaultAuthPromptConstructor } #ifdef MOZ_PROFILESHARING ,{ "Profile Sharing Setup", NS_PROFILESHARINGSETUP_CID, NS_PROFILESHARINGSETUP_CONTRACTID, nsProfileSharingSetupConstructor } #endif diff --git a/mozilla/mail/components/preferences/connection.js b/mozilla/mail/components/preferences/connection.js index 792639e49b7..b072e2eed38 100644 --- a/mozilla/mail/components/preferences/connection.js +++ b/mozilla/mail/components/preferences/connection.js @@ -142,8 +142,8 @@ var gConnectionsDialog = { reloadPAC: function () { var autoURL = document.getElementById("networkProxyAutoconfigURL"); - var pps = Components.classesByID["{e9b301c0-e0e4-11D3-a1a8-0050041caf44}"] - .getService(Components.interfaces.nsIProtocolProxyService); + var pps = Components.classes["@mozilla.org/network/protocol-proxy-service;1"] + .getService(Components.interfaces.nsPIProtocolProxyService); pps.configureFromPAC(autoURL.value); }, diff --git a/mozilla/mailnews/base/util/nsMsgProtocol.cpp b/mozilla/mailnews/base/util/nsMsgProtocol.cpp index a7b45ceb4bd..3cbf24dafc3 100644 --- a/mozilla/mailnews/base/util/nsMsgProtocol.cpp +++ b/mozilla/mailnews/base/util/nsMsgProtocol.cpp @@ -213,9 +213,14 @@ nsMsgProtocol::OpenNetworkSocket(nsIURI * aURL, const char *connectionType, if (NS_SUCCEEDED(rv)) rv = proxyUri->SetScheme(NS_LITERAL_CSTRING("mailto")); } + // + // XXX(darin): Consider using AsyncResolve instead to avoid blocking + // the calling thread in cases where PAC may call into + // our DNS resolver. + // if (NS_SUCCEEDED(rv)) - rv = pps->ExamineForProxy(proxyUri, getter_AddRefs(proxyInfo)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully call ExamineForProxy"); + rv = pps->Resolve(proxyUri, 0, getter_AddRefs(proxyInfo)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully resolve a proxy"); if (NS_FAILED(rv)) proxyInfo = nsnull; } diff --git a/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp b/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp index 87be9b6a643..73a42222ebc 100644 --- a/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp +++ b/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp @@ -3067,25 +3067,12 @@ NS_IMETHODIMP nsPluginHostImpl::FindProxyForURL(const char* url, char* *result) nsCOMPtr uriIn; nsCOMPtr proxyService; nsCOMPtr ioService; - PRBool isProxyEnabled; proxyService = do_GetService(kProtocolProxyServiceCID, &res); if (NS_FAILED(res) || !proxyService) { return res; } - if (NS_FAILED(proxyService->GetProxyEnabled(&isProxyEnabled))) { - return res; - } - - if (!isProxyEnabled) { - *result = PL_strdup("DIRECT"); - if (nsnull == *result) { - res = NS_ERROR_OUT_OF_MEMORY; - } - return res; - } - ioService = do_GetService(kIOServiceCID, &res); if (NS_FAILED(res) || !ioService) { return res; @@ -3099,25 +3086,32 @@ NS_IMETHODIMP nsPluginHostImpl::FindProxyForURL(const char* url, char* *result) nsCOMPtr pi; - res = proxyService->ExamineForProxy(uriIn, - getter_AddRefs(pi)); + res = proxyService->Resolve(uriIn, 0, getter_AddRefs(pi)); if (NS_FAILED(res)) { return res; } - if (!pi || !pi->Host() || pi->Port() <= 0) { + nsCAutoString host, type; + PRInt32 port = -1; + + // These won't fail, and even if they do... we'll be ok. + pi->GetType(type); + pi->GetHost(host); + pi->GetPort(&port); + + if (!pi || host.IsEmpty() || port <= 0 || host.EqualsLiteral("direct")) { *result = PL_strdup("DIRECT"); - } else if (!nsCRT::strcasecmp(pi->Type(), "http")) { - *result = PR_smprintf("PROXY %s:%d", pi->Host(), pi->Port()); - } else if (!nsCRT::strcasecmp(pi->Type(), "socks4")) { - *result = PR_smprintf("SOCKS %s:%d", pi->Host(), pi->Port()); - } else if (!nsCRT::strcasecmp(pi->Type(), "socks")) { + } else if (type.EqualsLiteral("http")) { + *result = PR_smprintf("PROXY %s:%d", host.get(), port); + } else if (type.EqualsLiteral("socks4")) { + *result = PR_smprintf("SOCKS %s:%d", host.get(), port); + } else if (type.EqualsLiteral("socks")) { // XXX - this is socks5, but there is no API for us to tell the // plugin that fact. SOCKS for now, in case the proxy server // speaks SOCKS4 as well. See bug 78176 // For a long time this was returning an http proxy type, so // very little is probably broken by this - *result = PR_smprintf("SOCKS %s:%d", pi->Host(), pi->Port()); + *result = PR_smprintf("SOCKS %s:%d", host.get(), port); } else { NS_ASSERTION(PR_FALSE, "Unknown proxy type!"); *result = PL_strdup("DIRECT"); diff --git a/mozilla/netwerk/base/public/Makefile.in b/mozilla/netwerk/base/public/Makefile.in index a5bf8625d31..53549a40fc6 100644 --- a/mozilla/netwerk/base/public/Makefile.in +++ b/mozilla/netwerk/base/public/Makefile.in @@ -77,6 +77,8 @@ XPIDLSRCS = \ nsIProgressEventSink.idl \ nsIPrompt.idl \ nsIProtocolProxyService.idl \ + nsIProtocolProxyFilter.idl \ + nsIProtocolProxyCallback.idl \ nsIProxiedProtocolHandler.idl \ nsIProxyAutoConfig.idl \ nsIProxyInfo.idl \ @@ -107,6 +109,7 @@ XPIDLSRCS = \ nsIAuthModule.idl \ nsIContentSniffer.idl \ nsIAuthPromptProvider.idl \ + nsPIProtocolProxyService.idl \ nsIChannelEventSink.idl \ $(NULL) diff --git a/mozilla/netwerk/base/public/nsIProtocolProxyCallback.idl b/mozilla/netwerk/base/public/nsIProtocolProxyCallback.idl new file mode 100644 index 00000000000..460311c06a9 --- /dev/null +++ b/mozilla/netwerk/base/public/nsIProtocolProxyCallback.idl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIURI; +interface nsIProxyInfo; + +/** + * This interface servers as a closure for nsIProtocolProxyService's + * asyncResolve method. + */ +[scriptable, uuid(71eba501-2982-4abf-95ab-cf87afc853ad)] +interface nsIProtocolProxyCallback : nsISupports +{ + /** + * This method is called when proxy info is available or when an error + * in the proxy resolution occurs. + * + * @param aContext + * The value returned from asyncResolve. + * @param aURI + * The URI passed to asyncResolve. + * @param aProxyInfo + * The resulting proxy info or null if there is no associated proxy + * info for aURI. As with the result of nsIProtocolProxyService's + * resolve method, a null result implies that a direct connection + * should be used. + * @param aStatus + * The status of the callback. This is a failure code if the request + * could not be satisfied, in which case the value of aStatus + * indicates the reason for the failure. + */ + void onProxyAvailable(in nsISupports aContext, + in nsIURI aURI, + in nsIProxyInfo aProxyInfo, + in nsresult aStatus); +}; diff --git a/mozilla/netwerk/base/public/nsIProtocolProxyFilter.idl b/mozilla/netwerk/base/public/nsIProtocolProxyFilter.idl new file mode 100644 index 00000000000..a00dbfbd16d --- /dev/null +++ b/mozilla/netwerk/base/public/nsIProtocolProxyFilter.idl @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIProtocolProxyService; +interface nsIProxyInfo; +interface nsIURI; + +/** + * This interface is used to apply filters to the proxies selected for a given + * URI. Use nsIProtocolProxyService::registerFilter to hook up instances of + * this interface. + * + * @status UNDER_REVIEW + */ +[scriptable, uuid(f424abd3-32b4-456c-9f45-b7e3376cb0d1)] +interface nsIProtocolProxyFilter : nsISupports +{ + /** + * This method is called to apply proxy filter rules for the given URI + * and proxy object (or list of proxy objects). + * + * @param aProxyService + * A reference to the Protocol Proxy Service. This is passed so that + * implementations may easily access methods such as newProxyInfo. + * @param aURI + * The URI for which these proxy settings apply. + * @param aProxy + * The proxy (or list of proxies) that would be used by default for + * the given URI. This may be null. + * + * @return The proxy (or list of proxies) that should be used in place of + * aProxy. This can be just be aProxy if the filter chooses not to + * modify the proxy. It can also be null to indicate that a direct + * connection should be used. Use aProxyService.newProxyInfo to + * construct nsIProxyInfo objects. + */ + nsIProxyInfo applyFilter(in nsIProtocolProxyService aProxyService, + in nsIURI aURI, in nsIProxyInfo aProxy); +}; diff --git a/mozilla/netwerk/base/public/nsIProtocolProxyService.idl b/mozilla/netwerk/base/public/nsIProtocolProxyService.idl index 1b03de9aa0e..2fee40fbca5 100644 --- a/mozilla/netwerk/base/public/nsIProtocolProxyService.idl +++ b/mozilla/netwerk/base/public/nsIProtocolProxyService.idl @@ -39,6 +39,8 @@ #include "nsISupports.idl" +interface nsIProtocolProxyCallback; +interface nsIProtocolProxyFilter; interface nsIProxyInfo; interface nsIChannel; interface nsIURI; @@ -46,38 +48,85 @@ interface nsIURI; /** * nsIProtocolProxyService provides methods to access information about * various network proxies. + * + * @status UNDER_REVIEW */ -[scriptable, uuid(ec2da5ae-eb2e-11d8-9782-0004e22243f8)] +[scriptable, uuid(faea2185-8e5b-44a8-ae8f-5fd3f20972af)] interface nsIProtocolProxyService : nsISupports { /** - * This attribute indicates whether or not support for proxies is enabled. + * 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. */ - readonly attribute PRBool proxyEnabled; - + const unsigned long RESOLVE_NON_BLOCKING = 1; + /** * This method returns a nsIProxyInfo instance that identifies a proxy to - * be used for loading the given URL. Otherwise, this method returns null + * 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 OR of the RESOLVE_ flags defined above. Pass 0 to + * specify the default behavior. * * 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 examineForProxy may be passed to the newProxiedChannel method - * to create a nsIChannel to the given URI that uses the specified proxy. + * 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 + * 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 */ - nsIProxyInfo examineForProxy(in nsIURI aURI); + nsIProxyInfo resolve(in nsIURI aURI, in unsigned long aFlags); + + /** + * This method is an asychronous version of the resolve method. Unlike + * resolve, this method is guaranteed not to block the calling thread + * waiting for DNS queries to complete. This method is intended as a + * substitute for resolve when the result is not needed immediately. + * + * @param aURI + * The URI to test. + * @param aFlags + * A bit-wise OR of the RESOLVE_ flags defined above. Pass 0 to + * specify the default behavior. + * @param aCallback + * The object to be notified when the result is available. + * + * @return a context for the operation that can be used to cancel the + * asychronous operation. See for example cancelAsyncResolve. + */ + nsISupports asyncResolve(in nsIURI aURI, + in unsigned long aFlags, + in nsIProtocolProxyCallback aCallback); + + /** + * This method may be used to cancel a pending asyncResolve callback. When + * this is called, the callback object passed to asyncResolve will be + * notified with an error condition of NS_ERROR_ABORT. + * + * @param aContext + * The return value from asyncResolve. + */ + void cancelAsyncResolve(in nsISupports aContext); /** * This method may be called to construct a nsIProxyInfo instance from @@ -88,10 +137,11 @@ interface nsIProtocolProxyService : nsISupports * @param aType * The proxy type. This is a string value that identifies the proxy * type. Standard values include: - * "HTTP" - specifies a HTTP proxy - * "SOCKS" - specifies a SOCKS version 5 proxy - * "SOCKS4" - specifies a SOCKS version 4 proxy - * The type name is case insensitive. Other string values may be + * "http" - specifies a HTTP proxy + * "socks" - specifies a SOCKS version 5 proxy + * "socks4" - specifies a SOCKS version 4 proxy + * "direct" - specifies a direct connection (useful for failover) + * The type name is case-insensitive. Other string values may be * possible. * @param aHost * The proxy hostname or IP address. @@ -100,31 +150,30 @@ interface nsIProtocolProxyService : nsISupports * @param aFlags * Flags associated with this connection. See nsIProxyInfo.idl * for currently defined flags. + * @param aFailoverTimeout + * Specifies the length of time (in seconds) to ignore this proxy if + * this proxy fails. Pass PR_UINT32_MAX to specify the default + * timeout value, causing nsIProxyInfo::failoverTimeout to be + * assigned the default value. + * @param aFailoverProxy + * Specifies the next proxy to try if this proxy fails. This + * parameter may be null. */ nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost, - in long aPort, in unsigned long aFlags); - - /** - * This method may be called to re-configure proxy settings given a URI - * to a new proxy auto config file. This method may return before the - * configuration actually takes affect (i.e., the URI may be loaded - * asynchronously). - * - * @param aURI - * The location of the PAC file to load. - */ - void configureFromPAC(in AUTF8String aURI); + in long aPort, in unsigned long aFlags, + in unsigned long aFailoverTimeout, + in nsIProxyInfo aFailoverProxy); /** * If the proxy identified by aProxyInfo is unavailable for some reason, * this method may be called to access an alternate proxy that may be used - * instead. As a side-effect, this method may affect future return values - * from examineForProxy as well as from getFailoverProxy. + * instead. As a side-effect, this method may affect future result values + * from resolve/asyncResolve as well as from getFailoverForProxy. * * @param aProxyInfo * The proxy that was unavailable. * @param aURI - * The URI that was originally passed to ExamineForProxy. + * The URI that was originally passed to resolve/asyncResolve. * @param aReason * The error code corresponding to the proxy failure. This value * may be used to tune the delay before this proxy is used again. @@ -134,4 +183,49 @@ interface nsIProtocolProxyService : nsISupports nsIProxyInfo getFailoverForProxy(in nsIProxyInfo aProxyInfo, in nsIURI aURI, in nsresult aReason); + + /** + * This method may be used to register a proxy filter instance. Each proxy + * filter is registered with an associated position that determines the + * order in which the filters are applied (starting from position 0). When + * resolve/asyncResolve is called, it generates a list of proxies for the + * given URI, and then it applies the proxy filters. The filters have the + * opportunity to modify the list of proxies. + * + * If two filters register for the same position, then the filters will be + * visited in the order in which they were registered. + * + * If the filter is already registered, then its position will be updated. + * + * After filters have been run, any disabled or disallowed proxies will be + * removed from the list. A proxy is disabled if it had previously failed- + * over to another proxy (see getFailoverForProxy). A proxy is disallowed, + * for example, if it is a HTTP proxy and the nsIProtocolHandler for the + * queried URI does not permit proxying via HTTP. + * + * If a nsIProtocolHandler disallows all proxying, then filters will never + * have a chance to intercept proxy requests for such URLs. + * + * @param aFilter + * The nsIProtocolProxyFilter instance to be registered. + * @param aPosition + * The position of the filter. + * + * NOTE: It is possible to construct filters that compete with one another + * in undesirable ways. This API does not attempt to protect against such + * problems. It is recommended that any extensions that choose to call + * this method make their position value configurable at runtime (perhaps + * via the preferences service). + */ + void registerFilter(in nsIProtocolProxyFilter aFilter, + in unsigned long aPosition); + + /** + * This method may be used to unregister a proxy filter instance. All + * filters will be automatically unregistered at XPCOM shutdown. + * + * @param aFilter + * The nsIProtocolProxyFilter instance to be unregistered. + */ + void unregisterFilter(in nsIProtocolProxyFilter aFilter); }; diff --git a/mozilla/netwerk/base/public/nsIProxyAutoConfig.idl b/mozilla/netwerk/base/public/nsIProxyAutoConfig.idl index c5a905a2db6..025c9559d21 100644 --- a/mozilla/netwerk/base/public/nsIProxyAutoConfig.idl +++ b/mozilla/netwerk/base/public/nsIProxyAutoConfig.idl @@ -44,32 +44,42 @@ * The nsIProxyAutoConfig interface is used for setting arbitrary proxy * configurations based on the specified URL. * - * Note this interface wraps (at least in a the implementation) the older + * Note this interface wraps (at least in the implementation) the older * hacks of proxy auto config. * * - Gagan Saksena 04/23/00 */ -interface nsIURI; -interface nsIIOService; - -[scriptable, uuid(26fae72a-1dd2-11b2-9dd9-cb3e0c2c79ba)] +[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 BNF: + * 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 = - * LWS = *( SP | HT ) - * SP = - * HT = + * 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 = + * LWS = *( SP | HT ) + * SP = + * HT = * * NOTE: direct-type and proxy-type are case insensitive * NOTE: SOCKS implies SOCKS4 @@ -81,11 +91,13 @@ interface nsIProxyAutoConfig : nsISupports * * 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 nsIURI aURI); - - /** - * Load the PAC file from the specified URI - */ - void loadPACFromURI(in nsIURI aURI, in nsIIOService ioService); + ACString getProxyForURI(in ACString aTestURI, in ACString aTestHost); }; diff --git a/mozilla/netwerk/base/public/nsIProxyInfo.idl b/mozilla/netwerk/base/public/nsIProxyInfo.idl index 672dc2ce4e2..bbe07b8d4b7 100644 --- a/mozilla/netwerk/base/public/nsIProxyInfo.idl +++ b/mozilla/netwerk/base/public/nsIProxyInfo.idl @@ -40,30 +40,65 @@ #include "nsISupports.idl" /** - * This interface is PRIVATE. + * This interface identifies a proxy server. * - * It is used as an opaque cookie, and this class may change at - * any time without notice. - * - * XXX The HTTP protocol handler does not treat this type as opaque, - * so perhaps it is wrong to restrict it to be opaque. - * - * @see nsIProtocolProxyService::examineForProxy - * @see nsISocketTransportService::createTransport + * @status UNDER_REVIEW */ -native constCharPtr(const char*); - -[scriptable, uuid(cefb3b30-e82f-11d8-329c-0004e22243f8)] +[scriptable, uuid(3fe9308b-1608-4fa0-933c-c5ec2c6175fd)] interface nsIProxyInfo : nsISupports { - [noscript, notxpcom] constCharPtr Host(); - [noscript, notxpcom] PRInt32 Port(); - [noscript, notxpcom] constCharPtr Type(); - [noscript, notxpcom] PRUint32 Flags(); + /** + * This attribute specifies the hostname of the proxy server. + */ + readonly attribute AUTF8String host; - /* This flag is set if the proxy is to perform name resolution - * itself. If this is the case, the hostname is used in some - * fashion, and we shouldn't do any form of DNS lookup ourselves. - */ - const unsigned short TRANSPARENT_PROXY_RESOLVES_HOST = 1 << 0; + /** + * This attribute specifies the port number of the proxy server. + */ + readonly attribute long port; + + /** + * This attribute specifies the type of the proxy server as an ASCII string. + * + * Some special values for this attribute include (but are not limited to) + * the following: + * "http" HTTP proxy (or SSL CONNECT for HTTPS) + * "socks" SOCKS v5 proxy + * "socks4" SOCKS v4 proxy + * "direct" no proxy + */ + readonly attribute ACString type; + + /** + * This attribute specifies flags that modify the proxy type. The value of + * this attribute is the bit-wise combination of the Proxy Flags defined + * below. Any undefined bits are reserved for future use. + */ + readonly attribute unsigned long flags; + + /** + * This attribute specifies the failover timeout in seconds for this proxy. + * If a nsIProxyInfo is reported as failed via nsIProtocolProxyService:: + * getFailoverForProxy, then the failed proxy will not be used again for this + * many seconds. + */ + readonly attribute unsigned long failoverTimeout; + + /** + * This attribute specifies the proxy to failover to when this proxy fails. + */ + attribute nsIProxyInfo failoverProxy; + + + /**************************************************************************** + * The following "Proxy Flags" may be bit-wise combined to construct the flags + * attribute defined on this interface. + */ + + /** + * This flag is set if the proxy is to perform name resolution itself. If + * this is the case, the hostname is used in some fashion, and we shouldn't + * do any form of DNS lookup ourselves. + */ + const unsigned short TRANSPARENT_PROXY_RESOLVES_HOST = 1 << 0; }; diff --git a/mozilla/netwerk/base/public/nsNetUtil.h b/mozilla/netwerk/base/public/nsNetUtil.h index 74e37e7843d..da5e69367a4 100644 --- a/mozilla/netwerk/base/public/nsNetUtil.h +++ b/mozilla/netwerk/base/public/nsNetUtil.h @@ -597,7 +597,8 @@ NS_NewProxyInfo(const nsACString &type, static NS_DEFINE_CID(kPPSServiceCID, NS_PROTOCOLPROXYSERVICE_CID); nsCOMPtr pps = do_GetService(kPPSServiceCID, &rv); if (NS_SUCCEEDED(rv)) - rv = pps->NewProxyInfo(type, host, port, flags, result); + rv = pps->NewProxyInfo(type, host, port, flags, PR_UINT32_MAX, nsnull, + result); return rv; } @@ -669,7 +670,7 @@ NS_ExamineForProxy(const char *scheme, if (NS_SUCCEEDED(rv)) { rv = uri->SetSpec(spec); if (NS_SUCCEEDED(rv)) - rv = pps->ExamineForProxy(uri, proxyInfo); + rv = pps->Resolve(uri, 0, proxyInfo); } } return rv; diff --git a/mozilla/netwerk/base/public/nsPIProtocolProxyService.idl b/mozilla/netwerk/base/public/nsPIProtocolProxyService.idl new file mode 100644 index 00000000000..15d37385dcf --- /dev/null +++ b/mozilla/netwerk/base/public/nsPIProtocolProxyService.idl @@ -0,0 +1,68 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 sts=4 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIProtocolProxyService.idl" + +/** + * THIS IS A PRIVATE INTERFACE + * + * It exists purely as a hack to support the configureFromPAC method used by + * the preference panels in the various apps. Those apps need to be taught to + * just use the preferences API to "reload" the PAC file. Then, at that point, + * we can eliminate this interface completely. + */ +[scriptable, uuid(d2c7b3eb-7778-468b-ae9b-c106c2afb5d1)] +interface nsPIProtocolProxyService : nsIProtocolProxyService +{ + /** + * This method may be called to re-configure proxy settings given a URI + * to a new proxy auto config file. This method may return before the + * configuration actually takes affect (i.e., the URI may be loaded + * asynchronously). + * + * WARNING: This method is considered harmful since it may cause the PAC + * preferences to be out of sync with the state of the Protocol Proxy + * Service. This method is going to be eliminated in the near future. + * + * @param aURI + * The location of the PAC file to load. If this value is empty, + * then the PAC configuration will be removed. + */ + void configureFromPAC(in AUTF8String aURI); +}; diff --git a/mozilla/netwerk/base/src/Makefile.in b/mozilla/netwerk/base/src/Makefile.in index 3b41b6f2cc8..ced8789357f 100644 --- a/mozilla/netwerk/base/src/Makefile.in +++ b/mozilla/netwerk/base/src/Makefile.in @@ -1,3 +1,4 @@ +# vim:set ts=8 sw=8 sts=8 noet: # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -70,6 +71,8 @@ CPPSRCS = \ nsLoadGroup.cpp \ nsMIMEInputStream.cpp \ nsProtocolProxyService.cpp \ + nsProxyInfo.cpp \ + nsPACMan.cpp \ nsRequestObserverProxy.cpp \ nsSimpleStreamListener.cpp \ nsSimpleURI.cpp \ diff --git a/mozilla/netwerk/base/src/nsIOService.cpp b/mozilla/netwerk/base/src/nsIOService.cpp index fcf3334825b..125086bc10e 100644 --- a/mozilla/netwerk/base/src/nsIOService.cpp +++ b/mozilla/netwerk/base/src/nsIOService.cpp @@ -187,6 +187,8 @@ nsIOService::Init() // down later. If we wait until the nsIOService is being shut down, // GetService will fail at that point. + // TODO(darin): Load the Socket and DNS services lazily. + mSocketTransportService = do_GetService(kSocketTransportServiceCID, &rv); if (NS_FAILED(rv)) NS_WARNING("failed to get socket transport service"); @@ -195,10 +197,6 @@ nsIOService::Init() if (NS_FAILED(rv)) NS_WARNING("failed to get DNS service"); - mProxyService = do_GetService(kProtocolProxyServiceCID, &rv); - if (NS_FAILED(rv)) - NS_WARNING("failed to get protocol proxy service"); - // XXX hack until xpidl supports error info directly (bug 13423) nsCOMPtr errorService = do_GetService(kErrorServiceCID); if (errorService) { @@ -451,34 +449,48 @@ nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result) nsCAutoString scheme; rv = aURI->GetScheme(scheme); - if (NS_FAILED(rv)) return rv; - - nsCOMPtr pi; - if (mProxyService) { - rv = mProxyService->ExamineForProxy(aURI, getter_AddRefs(pi)); - if (NS_FAILED(rv)) - pi = 0; - } + if (NS_FAILED(rv)) + return rv; nsCOMPtr handler; + rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); + if (NS_FAILED(rv)) + return rv; - if (pi && !strcmp(pi->Type(),"http")) { - // we are going to proxy this channel using an http proxy - rv = GetProtocolHandler("http", getter_AddRefs(handler)); - if (NS_FAILED(rv)) return rv; - } else { - rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); - if (NS_FAILED(rv)) return rv; + PRUint32 protoFlags; + rv = handler->GetProtocolFlags(&protoFlags); + 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 pi; + if (!mProxyService) { + mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID); + if (!mProxyService) + NS_WARNING("failed to get protocol proxy service"); + } + if (mProxyService) { + rv = mProxyService->Resolve(aURI, 0, getter_AddRefs(pi)); + if (NS_FAILED(rv)) + pi = nsnull; + } + if (pi) { + nsCAutoString 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 pph = do_QueryInterface(handler); + if (pph) + return pph->NewProxiedChannel(aURI, pi, result); + } } - nsCOMPtr pph = do_QueryInterface(handler); - - if (pph) - rv = pph->NewProxiedChannel(aURI, pi, result); - else - rv = handler->NewChannel(aURI, result); - - return rv; + return handler->NewChannel(aURI, result); } NS_IMETHODIMP @@ -691,7 +703,7 @@ nsIOService::Observe(nsISupports *subject, SetOffline(PR_TRUE); // Break circular reference. - mProxyService = 0; + mProxyService = nsnull; } return NS_OK; } diff --git a/mozilla/netwerk/base/src/nsPACMan.cpp b/mozilla/netwerk/base/src/nsPACMan.cpp new file mode 100644 index 00000000000..9e971bc056e --- /dev/null +++ b/mozilla/netwerk/base/src/nsPACMan.cpp @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsPACMan.h" +#include "nsIDNSService.h" +#include "nsIDNSListener.h" +#include "nsEventQueueUtils.h" +#include "nsNetUtil.h" +#include "nsAutoLock.h" +#include "nsAutoPtr.h" +#include "nsIAuthPrompt.h" +#include "nsCRT.h" +#include "prmon.h" + +//----------------------------------------------------------------------------- + +// These objects are stored in nsPACMan::mPendingQ + +class PendingPACQuery : public PRCList, public nsIDNSListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSLISTENER + + PendingPACQuery(nsPACMan *pacMan, nsIURI *uri, nsPACManCallback *callback) + : mPACMan(pacMan) + , mURI(uri) + , mCallback(callback) + { + PR_INIT_CLIST(this); + } + + nsresult Start(); + void Complete(nsresult status, const nsCString &pacString); + +private: + nsPACMan *mPACMan; // weak reference + nsCOMPtr mURI; + nsRefPtr mCallback; + nsCOMPtr mDNSRequest; +}; + +// This is threadsafe because we implement nsIDNSListener +NS_IMPL_THREADSAFE_ISUPPORTS1(PendingPACQuery, nsIDNSListener) + +nsresult +PendingPACQuery::Start() +{ + if (mDNSRequest) + return NS_OK; // already started + + nsresult rv; + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + NS_WARNING("unable to get the DNS service"); + return rv; + } + + nsCAutoString host; + rv = mURI->GetAsciiHost(host); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr eventQ; + rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) + return rv; + + rv = dns->AsyncResolve(host, 0, this, eventQ, getter_AddRefs(mDNSRequest)); + if (NS_FAILED(rv)) + NS_WARNING("DNS AsyncResolve failed"); + + return rv; +} + +// This may be called before or after OnLookupComplete +void +PendingPACQuery::Complete(nsresult status, const nsCString &pacString) +{ + if (!mCallback) + return; + + mCallback->OnQueryComplete(status, pacString); + mCallback = nsnull; + + if (mDNSRequest) { + mDNSRequest->Cancel(); + mDNSRequest = nsnull; + } +} + +NS_IMETHODIMP +PendingPACQuery::OnLookupComplete(nsIDNSRequest *request, + nsIDNSRecord *record, + nsresult status) +{ + // 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 = nsnull; // 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); + NS_RELEASE_THIS(); + + nsCAutoString pacString; + status = mPACMan->GetProxyForURI(mURI, pacString); + Complete(status, pacString); + return NS_OK; +} + +//----------------------------------------------------------------------------- + +nsPACMan::nsPACMan() + : mLoadEvent(nsnull) + , mShutdown(PR_FALSE) +{ + PR_INIT_CLIST(&mPendingQ); +} + +nsPACMan::~nsPACMan() +{ + NS_ASSERTION(mLoader == nsnull, "pac man not shutdown properly"); + NS_ASSERTION(mPAC == nsnull, "pac man not shutdown properly"); + NS_ASSERTION(PR_CLIST_IS_EMPTY(&mPendingQ), "pac man not shutdown properly"); +} + +void +nsPACMan::Shutdown() +{ + CancelExistingLoad(); + ProcessPendingQ(NS_ERROR_ABORT); + + mPAC = nsnull; + mShutdown = PR_TRUE; +} + +nsresult +nsPACMan::GetProxyForURI(nsIURI *uri, nsACString &result) +{ + NS_ENSURE_STATE(!mShutdown); + + if (!mPAC || IsLoading()) + return NS_ERROR_NOT_AVAILABLE; + + nsCAutoString spec, host; + uri->GetAsciiSpec(spec); + uri->GetAsciiHost(host); + + return mPAC->GetProxyForURI(spec, host, result); +} + +nsresult +nsPACMan::AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback) +{ + NS_ENSURE_STATE(!mShutdown); + + 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. + if (IsLoading()) + return NS_OK; + + nsresult rv = query->Start(); + if (NS_FAILED(rv)) { + NS_WARNING("failed to start PAC query"); + PR_REMOVE_LINK(query); + NS_RELEASE(query); + } + + return rv; +} + +void *PR_CALLBACK +nsPACMan::LoadEvent_Handle(PLEvent *ev) +{ + NS_REINTERPRET_CAST(nsPACMan *, PL_GetEventOwner(ev))->StartLoading(); + return nsnull; +} + +void PR_CALLBACK +nsPACMan::LoadEvent_Destroy(PLEvent *ev) +{ + nsPACMan *self = NS_REINTERPRET_CAST(nsPACMan *, PL_GetEventOwner(ev)); + self->mLoadEvent = nsnull; + self->Release(); + delete ev; +} + +nsresult +nsPACMan::LoadPACFromURI(const nsACString &uriSpec) +{ + NS_ENSURE_STATE(!mShutdown); + + nsCOMPtr loader = + do_CreateInstance(NS_STREAMLOADER_CONTRACTID); + NS_ENSURE_STATE(loader); + + // Since we might get called from nsProtocolProxyService::Init, we need to + // post an event back to the main thread before we try to use the IO service. + // + // But, we need to flag ourselves as loading, so that we queue up any PAC + // queries the enter between now and when we actually load the PAC file. + + if (!mLoadEvent) { + mLoadEvent = new PLEvent; + if (!mLoadEvent) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF_THIS(); + PL_InitEvent(mLoadEvent, this, LoadEvent_Handle, LoadEvent_Destroy); + + nsCOMPtr eventQ; + nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv) || NS_FAILED(rv = eventQ->PostEvent(mLoadEvent))) { + PL_DestroyEvent(mLoadEvent); + return rv; + } + } + + CancelExistingLoad(); + + mLoader = loader; + mPACSpec = uriSpec; + mPAC = nsnull; + return NS_OK; +} + +nsresult +nsPACMan::StartLoading() +{ + // CancelExistingLoad was called... + if (!mLoader) { + ProcessPendingQ(NS_ERROR_ABORT); + return NS_OK; + } + + // Always hit the origin server when loading PAC. + nsCOMPtr ios = do_GetIOService(); + if (ios) { + nsCOMPtr channel; + ios->NewChannel(mPACSpec, nsnull, nsnull, getter_AddRefs(channel)); + if (channel) { + channel->SetLoadFlags(nsIRequest::LOAD_BYPASS_CACHE); + channel->SetNotificationCallbacks(this); + if (NS_SUCCEEDED(mLoader->Init(channel, this, nsnull))) + return NS_OK; + } + } + + CancelExistingLoad(); + ProcessPendingQ(NS_ERROR_UNEXPECTED); + return NS_OK; +} + +void +nsPACMan::CancelExistingLoad() +{ + if (mLoader) { + nsCOMPtr request; + mLoader->GetRequest(getter_AddRefs(request)); + if (request) + request->Cancel(NS_ERROR_ABORT); + mLoader = nsnull; + } +} + +void +nsPACMan::ProcessPendingQ(nsresult status) +{ + // Now, start any pending queries + PRCList *node = PR_LIST_HEAD(&mPendingQ); + while (node != &mPendingQ) { + PendingPACQuery *query = NS_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(); + } + if (NS_FAILED(status)) { + // remove the query from the list + PR_REMOVE_LINK(query); + query->Complete(status, EmptyCString()); + NS_RELEASE(query); + } + } +} + +NS_IMPL_ISUPPORTS2(nsPACMan, nsIStreamLoaderObserver, nsIInterfaceRequestor) + +NS_IMETHODIMP +nsPACMan::OnStreamComplete(nsIStreamLoader *loader, + nsISupports *context, + nsresult status, + PRUint32 dataLen, + const PRUint8 *data) +{ + if (mLoader != loader) { + // If this happens, then it means that LoadPACFromURI was called more + // than once before the initial call completed. In this case, status + // should be NS_ERROR_ABORT, and if so, then we know that we can and + // should delay any processing. + if (status == NS_ERROR_ABORT) + return NS_OK; + } + + mLoader = nsnull; + + if (NS_SUCCEEDED(status)) { + // Get the URI spec used to load this PAC script. + nsCAutoString pacURI; + { + nsCOMPtr request; + loader->GetRequest(getter_AddRefs(request)); + nsCOMPtr channel = do_QueryInterface(request); + if (channel) { + nsCOMPtr uri; + channel->GetURI(getter_AddRefs(uri)); + if (uri) + uri->GetAsciiSpec(pacURI); + } + } + + 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. We've had this assumption + // forever, so no reason to change this now. + const char *text = (const char *) data; + if (!nsCRT::IsAscii(text, dataLen)) { + NS_WARNING("PAC text is not ASCII"); + status = NS_ERROR_UNEXPECTED; + } + else { + status = mPAC->Init(pacURI, NS_ConvertASCIItoUTF16(text, dataLen)); + } + } + } + + // Reset mPAC if necessary + if (mPAC && NS_FAILED(status)) + mPAC = nsnull; + + ProcessPendingQ(status); + return NS_OK; +} + +NS_IMETHODIMP +nsPACMan::GetInterface(const nsIID &iid, void **result) +{ + // In case loading the PAC file requires authentication. + if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) + return CallCreateInstance(NS_DEFAULTAUTHPROMPT_CONTRACTID, + nsnull, iid, result); + + return NS_ERROR_NO_INTERFACE; +} diff --git a/mozilla/netwerk/base/src/nsPACMan.h b/mozilla/netwerk/base/src/nsPACMan.h new file mode 100644 index 00000000000..41687327b93 --- /dev/null +++ b/mozilla/netwerk/base/src/nsPACMan.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsPACMan_h__ +#define nsPACMan_h__ + +#include "nsIStreamLoader.h" +#include "nsIInterfaceRequestor.h" +#include "nsIProxyAutoConfig.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "prclist.h" +#include "plevent.h" + +/** + * This class defines a callback interface used by AsyncGetProxyForURI. + */ +class NS_NO_VTABLE nsPACManCallback : public nsISupports +{ +public: + /** + * This method is invoked on the same thread that called AsyncGetProxyForURI. + * + * @param status + * This parameter indicates whether or not the PAC query succeeded. + * @param pacString + * This parameter holds the value of the PAC string. It is empty when + * status is a failure code. + */ + virtual void OnQueryComplete(nsresult status, const nsCString &pacString) = 0; +}; + +/** + * This class provides an abstraction layer above the PAC thread. The methods + * defined on this class are intended to be called on the main thread only. + */ +class nsPACMan : public nsIStreamLoaderObserver, public nsIInterfaceRequestor +{ +public: + NS_DECL_ISUPPORTS + + nsPACMan(); + + /** + * This method may be called to shutdown the PAC manager. Any async queries + * that have not yet completed will either finish normally or be canceled by + * the time this method returns. + */ + void Shutdown(); + + /** + * This method queries a PAC result synchronously. + * + * @param uri + * The URI to query. + * @param result + * Holds the PAC result string upon return. + * + * @return NS_ERROR_NOT_AVAILABLE if the PAC file is not yet loaded. + */ + nsresult GetProxyForURI(nsIURI *uri, nsACString &result); + + /** + * This method queries a PAC result asynchronously. The callback runs on the + * calling thread. If the PAC file has not yet been loaded, then this method + * will queue up the request, and complete it once the PAC file has been + * loaded. + * + * @param uri + * The URI to query. + * @param callback + * The callback to run once the PAC result is available. + */ + nsresult AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback); + + /** + * This method may be called to reload the PAC file. While we are loading + * the PAC file, any asynchronous PAC queries will be queued up to be + * processed once the PAC file finishes loading. + * + * @param uriSpec + * The URI spec of the PAC file to load. + */ + nsresult LoadPACFromURI(const nsACString &uriSpec); + + /** + * Returns true if we are currently loading the PAC file. + */ + PRBool IsLoading() { return mLoader != nsnull; } + +private: + NS_DECL_NSISTREAMLOADEROBSERVER + NS_DECL_NSIINTERFACEREQUESTOR + + ~nsPACMan(); + + /** + * Cancel any existing load if any. + */ + void CancelExistingLoad(); + + /** + * Process mPendingQ. If status is a failure code, then the pending queue + * will be emptied. If status is a success code, then the pending requests + * will be processed (i.e., their Start method will be called). + */ + void ProcessPendingQ(nsresult status); + + /** + * Start loading the PAC file. + */ + nsresult StartLoading(); + + /** + * Event fu for calling StartLoading asynchronously. + */ + PR_STATIC_CALLBACK(void *) LoadEvent_Handle(PLEvent *); + PR_STATIC_CALLBACK(void) LoadEvent_Destroy(PLEvent *); + +private: + nsCOMPtr mPAC; + nsCString mPACSpec; + PRCList mPendingQ; + nsCOMPtr mLoader; + PLEvent *mLoadEvent; + PRPackedBool mShutdown; +}; + +#endif // nsPACMan_h__ diff --git a/mozilla/netwerk/base/src/nsProtocolProxyService.cpp b/mozilla/netwerk/base/src/nsProtocolProxyService.cpp index 6e5cb92bf6f..5047a38fa83 100644 --- a/mozilla/netwerk/base/src/nsProtocolProxyService.cpp +++ b/mozilla/netwerk/base/src/nsProtocolProxyService.cpp @@ -38,13 +38,16 @@ * ***** END LICENSE BLOCK ***** */ #include "nsProtocolProxyService.h" +#include "nsProxyInfo.h" #include "nsIServiceManager.h" #include "nsXPIDLString.h" #include "nsIProxyAutoConfig.h" #include "nsAutoLock.h" #include "nsEventQueueUtils.h" #include "nsIIOService.h" +#include "nsIObserverService.h" #include "nsIProtocolHandler.h" +#include "nsIProtocolProxyCallback.h" #include "nsIDNSService.h" #include "nsIPrefService.h" #include "nsIPrefBranch2.h" @@ -54,6 +57,7 @@ #include "nsCRT.h" #include "prnetdb.h" #include "nsEventQueueUtils.h" +#include "nsPACMan.h" //---------------------------------------------------------------------------- @@ -65,6 +69,144 @@ static PRLogModuleInfo *sLog = PR_NewLogModule("proxy"); //---------------------------------------------------------------------------- +// This structure is intended to be allocated on the stack +struct nsProtocolInfo { + nsCAutoString scheme; + PRUint32 flags; + PRInt32 defaultPort; +}; + +//---------------------------------------------------------------------------- + +#define NS_ASYNCRESOLVECONTEXT_IID \ +{ /* c5fb0580-0cea-4d6a-8f76-ae61dc644d3a */ \ + 0xc5fb0580, \ + 0x0cea, \ + 0x4d6a, \ + {0x8f, 0x76, 0xae, 0x61, 0xdc, 0x64, 0x4d, 0x3a} \ +} + +class nsAsyncResolveContext : public PLEvent, public nsPACManCallback +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ASYNCRESOLVECONTEXT_IID) + NS_DECL_ISUPPORTS + + nsAsyncResolveContext(nsProtocolProxyService *pps, nsIURI *uri, + nsIProtocolProxyCallback *callback) + : mStatus(NS_OK) + , mDispatched(PR_FALSE) + , mPPS(pps) + , mURI(uri) + , mCallback(callback) + { + PL_InitEvent(this, nsnull, HandleEvent, CleanupEvent); + } + + // Called on the main thread + void SetResult(nsresult status, nsIProxyInfo *pi) + { + mStatus = status; + mProxyInfo = pi; + } + + // Called on the main thread + void Cancel() + { + if (mDispatched) + return; + SetResult(NS_ERROR_ABORT, nsnull); + DispatchCallback(); + } + + // Called on any thread + nsresult DispatchCallback() + { + nsCOMPtr eventQ; + nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) { + NS_WARNING("could not get current event queue"); + return rv; + } + NS_ADDREF_THIS(); + rv = eventQ->PostEvent(this); + if (NS_FAILED(rv)) { + NS_WARNING("unable to dispatch callback event"); + PL_DestroyEvent(this); + return rv; + } + mDispatched = PR_TRUE; + return NS_OK; + } + +private: + + // Called asynchronously, so we do not need to post another PLEvent + // before calling DoCallback. + void OnQueryComplete(nsresult status, const nsCString &pacString) + { + if (mDispatched) + return; + + mDispatched = PR_TRUE; + mStatus = status; + mPACString = pacString; + DoCallback(); + } + + // Called on the main thread + void DoCallback() + { + // Generate proxy info from the PAC string if appropriate + if (NS_SUCCEEDED(mStatus) && !mProxyInfo && !mPACString.IsEmpty()) + mPPS->ProcessPACString(mPACString, getter_AddRefs(mProxyInfo)); + + // Now apply proxy filters + if (NS_SUCCEEDED(mStatus)) { + nsProtocolInfo info; + mStatus = mPPS->GetProtocolInfo(mURI, &info); + if (NS_SUCCEEDED(mStatus)) + mPPS->ApplyFilters(mURI, info, mProxyInfo); + else + mProxyInfo = nsnull; + } + + mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus); + mCallback = nsnull; // in case the callback holds an owning ref to us + } + + PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev) + { + nsAsyncResolveContext *self = + NS_STATIC_CAST(nsAsyncResolveContext *, ev); + if (self->mCallback) + self->DoCallback(); + return nsnull; + } + + PR_STATIC_CALLBACK(void) CleanupEvent(PLEvent *ev) + { + nsAsyncResolveContext *self = + NS_STATIC_CAST(nsAsyncResolveContext *, ev); + NS_RELEASE(self); // balance AddRef in DispatchCallback + } + +private: + + nsresult mStatus; + nsCString mPACString; + PRBool mDispatched; + + nsRefPtr mPPS; + nsCOMPtr mURI; + nsCOMPtr mCallback; + nsCOMPtr mProxyInfo; +}; + +NS_IMPL_ISUPPORTS1(nsAsyncResolveContext, nsAsyncResolveContext) + +//---------------------------------------------------------------------------- + #define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t') // @@ -147,80 +289,14 @@ proxy_GetBoolPref(nsIPrefBranch *aPrefBranch, //---------------------------------------------------------------------------- -class nsProxyInfo : public nsIProxyInfo -{ -public: - NS_DECL_ISUPPORTS - - NS_IMETHOD_(const char*) Host() - { - return mHost.get(); - } - - NS_IMETHOD_(PRInt32) Port() - { - return mPort; - } - - NS_IMETHOD_(const char*) Type() - { - return mType; - } - - NS_IMETHOD_(PRUint32) Flags() { - return mFlags; - } - - ~nsProxyInfo() - { - NS_IF_RELEASE(mNext); - } - - nsProxyInfo(const char *type = nsnull) - : mType(type) - , mPort(-1) - , mFlags(0) - , mNext(nsnull) - {} - - const char *mType; // pointer to static kProxyType_XYZ value - nsCString mHost; - PRInt32 mPort; - PRUint32 mFlags; - nsProxyInfo *mNext; -}; - -#define NS_PROXYINFO_ID \ -{ /* ed42f751-825e-4cc2-abeb-3670711a8b85 */ \ - 0xed42f751, \ - 0x825e, \ - 0x4cc2, \ - {0xab, 0xeb, 0x36, 0x70, 0x71, 0x1a, 0x8b, 0x85} \ -} -static NS_DEFINE_IID(kProxyInfoID, NS_PROXYINFO_ID); - -// These objects will be accessed on the socket transport thread. -NS_IMPL_THREADSAFE_ADDREF(nsProxyInfo) -NS_IMPL_THREADSAFE_RELEASE(nsProxyInfo) - -NS_INTERFACE_MAP_BEGIN(nsProxyInfo) - NS_INTERFACE_MAP_ENTRY(nsIProxyInfo) - NS_INTERFACE_MAP_ENTRY(nsISupports) - // see nsProtocolProxyInfo::GetFailoverForProxy - if (aIID.Equals(kProxyInfoID)) - foundInterface = this; - else -NS_INTERFACE_MAP_END - -//---------------------------------------------------------------------------- - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsProtocolProxyService, - nsIProtocolProxyService, - nsIDNSListener, - nsIObserver) +NS_IMPL_ISUPPORTS3(nsProtocolProxyService, + nsIProtocolProxyService, + nsPIProtocolProxyService, + nsIObserver) nsProtocolProxyService::nsProtocolProxyService() - : mUseProxy(0) + : mFilters(nsnull) + , mProxyConfig(eProxyConfig_Direct) , mHTTPProxyPort(-1) , mFTPProxyPort(-1) , mGopherProxyPort(-1) @@ -228,6 +304,7 @@ nsProtocolProxyService::nsProtocolProxyService() , mSOCKSProxyPort(-1) , mSOCKSProxyVersion(4) , mSOCKSProxyRemoteDNS(PR_FALSE) + , mPACMan(nsnull) , mSessionStart(PR_Now()) , mFailedProxyTimeout(30 * 60) // 30 minute default { @@ -235,10 +312,9 @@ nsProtocolProxyService::nsProtocolProxyService() nsProtocolProxyService::~nsProtocolProxyService() { - if (mFiltersArray.Count() > 0) { - mFiltersArray.EnumerateForwards(CleanupFilterArray, nsnull); - mFiltersArray.Clear(); - } + // These should have been cleaned up in our Observe method. + NS_ASSERTION(mHostFiltersArray.Count() == 0 && mFilters == nsnull && + mPACMan == nsnull, "what happened to xpcom-shutdown?"); } // nsProtocolProxyService methods @@ -259,6 +335,12 @@ nsProtocolProxyService::Init() PrefsChanged(prefBranch, nsnull); } + // register for shutdown notification so we can clean ourselves up properly. + nsCOMPtr obs = + do_GetService("@mozilla.org/observer-service;1"); + if (obs) + obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); + return NS_OK; } @@ -267,9 +349,28 @@ nsProtocolProxyService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { - nsCOMPtr prefs = do_QueryInterface(aSubject); - if (prefs) - PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get()); + if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { + // cleanup + if (mHostFiltersArray.Count() > 0) { + mHostFiltersArray.EnumerateForwards(CleanupFilterArray, nsnull); + mHostFiltersArray.Clear(); + } + if (mFilters) { + delete mFilters; + mFilters = nsnull; + } + if (mPACMan) { + mPACMan->Shutdown(); + mPACMan = nsnull; + } + } + else { + NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, + "what is this random observer event?"); + nsCOMPtr prefs = do_QueryInterface(aSubject); + if (prefs) + PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get()); + } return NS_OK; } @@ -285,18 +386,20 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, PRInt32 type = -1; rv = prefBranch->GetIntPref("network.proxy.type",&type); if (NS_SUCCEEDED(rv)) { - // bug 115720 - type 3 is the same as 0 (no proxy), - // for ns4.x backwards compatability - if (type == 3) { - type = 0; + // bug 115720 - for ns4.x backwards compatability + if (type == eProxyConfig_Direct4x) { + type = eProxyConfig_Direct; // Reset the type so that the dialog looks correct, and we // don't have to handle this case everywhere else // I'm paranoid about a loop of some sort - only do this // if we're enumerating all prefs, and ignore any error if (!pref) - prefBranch->SetIntPref("network.proxy.type", 0); + prefBranch->SetIntPref("network.proxy.type", type); + } else if (type >= eProxyConfig_Last) { + LOG(("unknown proxy type: %lu; assuming direct\n", type)); + type = eProxyConfig_Direct; } - mUseProxy = type; // type == 2 is fixed PAC URL, 4 is WPAD + mProxyConfig = NS_STATIC_CAST(ProxyConfig, type); reloadPAC = PR_TRUE; } } @@ -351,81 +454,43 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, rv = prefBranch->GetCharPref("network.proxy.no_proxies_on", getter_Copies(tempString)); if (NS_SUCCEEDED(rv)) - LoadFilters(tempString.get()); + LoadHostFilters(tempString.get()); } - if ((!pref || !strcmp(pref, "network.proxy.autoconfig_url") || reloadPAC) && - (mUseProxy == 2)) { - rv = prefBranch->GetCharPref("network.proxy.autoconfig_url", - getter_Copies(tempString)); - if (NS_SUCCEEDED(rv) && (!reloadPAC || strcmp(tempString.get(), mPACURI.get()))) - ConfigureFromPAC(tempString); + // We're done if not using PAC or WPAD + if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD) + return; + + // OK, we need to reload the PAC file if: + // 1) network.proxy.type changed, or + // 2) network.proxy.autoconfig_url changed and PAC is configured + + if (!pref || !strcmp(pref, "network.proxy.autoconfig_url")) + reloadPAC = PR_TRUE; + + if (reloadPAC) { + tempString.Truncate(); + if (mProxyConfig == eProxyConfig_PAC) { + prefBranch->GetCharPref("network.proxy.autoconfig_url", + getter_Copies(tempString)); + } + else if (mProxyConfig == eProxyConfig_WPAD) { + // We diverge from the WPAD spec here in that we don't walk the + // hosts's FQDN, stripping components until we hit a TLD. Doing so + // is dangerous in the face of an incomplete list of TLDs, and TLDs + // get added over time. We could consider doing only a single + // substitution of the first component, if that proves to help + // compatibility. + tempString.AssignLiteral("http://wpad/wpad.dat"); + } + ConfigureFromPAC(tempString); } - - if ((!pref || reloadPAC) && (mUseProxy == 4)) - ConfigureFromWPAD(); -} - -// this is the main ui thread calling us back, load the pac now -void* PR_CALLBACK -nsProtocolProxyService::HandlePACLoadEvent(PLEvent* aEvent) -{ - nsProtocolProxyService *pps = - (nsProtocolProxyService *) PL_GetEventOwner(aEvent); - if (!pps) { - NS_ERROR("HandlePACLoadEvent owner is null"); - return nsnull; - } - - nsresult rv; - - // create pac js component - pps->mPAC = do_CreateInstance(NS_PROXYAUTOCONFIG_CONTRACTID, &rv); - if (!pps->mPAC || NS_FAILED(rv)) { - NS_ERROR("Cannot load PAC js component"); - return nsnull; - } - - if (pps->mPACURI.IsEmpty()) { - NS_ERROR("HandlePACLoadEvent: js PACURL component is empty"); - return nsnull; - } - - nsCOMPtr ios = do_GetIOService(&rv); - if (NS_FAILED(rv)) { - NS_ERROR("No IO service"); - return nsnull; - } - - nsCOMPtr pURI; - rv = ios->NewURI(pps->mPACURI, nsnull, nsnull, getter_AddRefs(pURI)); - if (NS_FAILED(rv)) { - NS_ERROR("New URI failed"); - return nsnull; - } - - rv = pps->mPAC->LoadPACFromURI(pURI, ios); - if (NS_FAILED(rv)) { - NS_ERROR("Load PAC failed"); - return nsnull; - } - - return nsnull; -} - -void PR_CALLBACK -nsProtocolProxyService::DestroyPACLoadEvent(PLEvent* aEvent) -{ - nsProtocolProxyService *pps = - (nsProtocolProxyService*) PL_GetEventOwner(aEvent); - NS_IF_RELEASE(pps); - delete aEvent; } PRBool nsProtocolProxyService::CanUseProxy(nsIURI *aURI, PRInt32 defaultPort) { - if (mFiltersArray.Count() == 0) + if (mHostFiltersArray.Count() == 0) return PR_TRUE; PRInt32 port; @@ -462,8 +527,8 @@ nsProtocolProxyService::CanUseProxy(nsIURI *aURI, PRInt32 defaultPort) } PRInt32 index = -1; - while (++index < mFiltersArray.Count()) { - HostInfo *hinfo = (HostInfo *) mFiltersArray[index]; + while (++index < mHostFiltersArray.Count()) { + HostInfo *hinfo = (HostInfo *) mHostFiltersArray[index]; if (is_ipaddr != hinfo->is_ipaddr) continue; @@ -505,7 +570,7 @@ static const char kProxyType_SOCKS5[] = "socks5"; static const char kProxyType_DIRECT[] = "direct"; const char * -nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, nsProxyInfo **result) +nsProtocolProxyService::ExtractProxyInfo(const char *start, nsProxyInfo **result) { *result = nsnull; PRUint32 flags = 0; @@ -524,7 +589,7 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n const char *type = nsnull; switch (len) { case 5: - if (permitHttp && PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) + if (PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) type = kProxyType_HTTP; else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0) type = kProxyType_SOCKS4; // assume v4 for 4x compat @@ -572,6 +637,7 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n if (pi) { pi->mType = type; pi->mFlags = flags; + pi->mTimeout = mFailedProxyTimeout; // YES, it is ok to specify a null proxy host. if (host) { pi->mHost.Assign(host, hostEnd - host); @@ -637,7 +703,7 @@ nsProtocolProxyService::DisableProxy(nsProxyInfo *pi) // Add timeout to interval (this is the time when the proxy can // be tried again). - dsec += mFailedProxyTimeout; + dsec += pi->mTimeout; // NOTE: The classic codebase would increase the timeout value // incrementally each time a subsequent failure occured. @@ -675,166 +741,112 @@ nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi) return PR_TRUE; } -nsProxyInfo * -nsProtocolProxyService::BuildProxyList(const char *proxies, - PRBool permitHttp, - PRBool pruneDisabledProxies) +void +nsProtocolProxyService::ProcessPACString(const nsCString &pacString, + nsIProxyInfo **result) { + if (pacString.IsEmpty()) { + *result = nsnull; + return; + } + + const char *proxies = pacString.get(); + nsProxyInfo *pi = nsnull, *first = nsnull, *last = nsnull; while (*proxies) { - proxies = ExtractProxyInfo(proxies, permitHttp, &pi); + proxies = ExtractProxyInfo(proxies, &pi); if (pi) { - if (pruneDisabledProxies && IsProxyDisabled(pi)) - NS_RELEASE(pi); - else { - if (last) { - NS_ASSERTION(last->mNext == nsnull, "leaking nsProxyInfo"); - last->mNext = pi; - } - else - first = pi; - - // since we are about to use this proxy, make sure it is not - // on the disabled proxy list. we'll add it back to that list - // if we have to (in GetFailoverForProxy). - EnableProxy(pi); - - last = pi; + if (last) { + NS_ASSERTION(last->mNext == nsnull, "leaking nsProxyInfo"); + last->mNext = pi; } + else + first = pi; + last = pi; } } - return first; -} - -nsresult -nsProtocolProxyService::ExaminePACForProxy(nsIURI *aURI, - PRUint32 aProtoFlags, - nsIProxyInfo **aResult) -{ - // the following two failure cases can happen if we are queried before the - // PAC file is loaded. in these cases, we have no choice but to try a - // direct connection and hope for the best. the user will just have to - // press reload if the page doesn't load :-( - - if (!mPAC) { - NS_WARNING("PAC JS component is null; assuming DIRECT..."); - return NS_OK; - } - - nsCAutoString proxyStr; - nsresult rv = mPAC->GetProxyForURI(aURI, proxyStr); - if (NS_FAILED(rv)) { - NS_WARNING("PAC GetProxyForURI failed; assuming DIRECT..."); - return NS_OK; - } - if (proxyStr.IsEmpty()) { - NS_WARNING("PAC GetProxyForURI returned an empty string; assuming DIRECT..."); - return NS_OK; - } - - PRBool permitHttp = (aProtoFlags & nsIProtocolHandler::ALLOWS_PROXY_HTTP); - - // result is AddRef'd - nsProxyInfo *pi = BuildProxyList(proxyStr.get(), permitHttp, PR_TRUE); - if (pi) { - // - // if only DIRECT was specified then return no proxy info, and we're done. - // - if (!pi->mNext && pi->mType == kProxyType_DIRECT) - NS_RELEASE(pi); - } - else { - // - // if all of the proxy servers were marked invalid, then we'll go ahead - // and return the full list. this code works by rebuilding the list - // without pruning disabled proxies. - // - // we could have built the whole list and then removed those that were - // disabled, but it is less code to build the list twice. - // - pi = BuildProxyList(proxyStr.get(), permitHttp, PR_FALSE); - } - - *aResult = pi; - return NS_OK; + *result = first; } // nsIProtocolProxyService NS_IMETHODIMP -nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult) +nsProtocolProxyService::Resolve(nsIURI *uri, PRUint32 flags, + nsIProxyInfo **result) { - nsresult rv = NS_OK; - - NS_ASSERTION(aURI, "need a uri folks."); + nsProtocolInfo info; + nsresult rv = GetProtocolInfo(uri, &info); + if (NS_FAILED(rv)) + return rv; - *aResult = nsnull; + PRBool usePAC; + rv = Resolve_Internal(uri, info, &usePAC, result); + if (NS_FAILED(rv)) + return rv; - nsCAutoString scheme; - rv = aURI->GetScheme(scheme); - if (NS_FAILED(rv)) return rv; + if (usePAC && mPACMan) { + NS_ASSERTION(*result == nsnull, "we should not have a result yet"); - PRUint32 flags; - PRInt32 defaultPort; - rv = GetProtocolInfo(scheme.get(), flags, defaultPort); - if (NS_FAILED(rv)) return rv; + // If the caller didn't want us to invoke PAC, then error out. + if (flags & RESOLVE_NON_BLOCKING) + return NS_BASE_STREAM_WOULD_BLOCK; - if (!(flags & nsIProtocolHandler::ALLOWS_PROXY)) - return NS_OK; // Can't proxy this - - // if proxies are enabled and this host:port combo is - // supposed to use a proxy, check for a proxy. - if (0 == mUseProxy || (1 == mUseProxy && !CanUseProxy(aURI, defaultPort))) - return NS_OK; - - // Proxy auto config magic... - if (2 == mUseProxy || 4 == mUseProxy) - return ExaminePACForProxy(aURI, flags, aResult); - - // proxy info values - const char *type = nsnull; - const nsACString *host = nsnull; - PRInt32 port = -1; - - PRUint32 proxyFlags = 0; - - if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 && - scheme.EqualsLiteral("http")) { - host = &mHTTPProxyHost; - type = kProxyType_HTTP; - port = mHTTPProxyPort; - } - else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 && - scheme.EqualsLiteral("https")) { - host = &mHTTPSProxyHost; - type = kProxyType_HTTP; - port = mHTTPSProxyPort; - } - else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 && - scheme.EqualsLiteral("ftp")) { - host = &mFTPProxyHost; - type = kProxyType_HTTP; - port = mFTPProxyPort; - } - else if (!mGopherProxyHost.IsEmpty() && mGopherProxyPort > 0 && - scheme.EqualsLiteral("gopher")) { - host = &mGopherProxyHost; - type = kProxyType_HTTP; - port = mGopherProxyPort; - } - else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { - host = &mSOCKSProxyHost; - if (mSOCKSProxyVersion == 4) - type = kProxyType_SOCKS4; + // Query the PAC file synchronously. + nsCString pacString; + rv = mPACMan->GetProxyForURI(uri, pacString); + if (NS_FAILED(rv)) + NS_WARNING("failed querying PAC file; trying DIRECT"); else - type = kProxyType_SOCKS; - port = mSOCKSProxyPort; - if (mSOCKSProxyRemoteDNS) - proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; + ProcessPACString(pacString, result); } - if (type) - return NewProxyInfo_Internal(type, *host, port, proxyFlags, aResult); + ApplyFilters(uri, info, result); + return NS_OK; +} +NS_IMETHODIMP +nsProtocolProxyService::AsyncResolve(nsIURI *uri, PRUint32 flags, + nsIProtocolProxyCallback *callback, + nsISupports **result) +{ + nsCOMPtr ctx = + new nsAsyncResolveContext(this, uri, callback); + if (!ctx) + return NS_ERROR_OUT_OF_MEMORY; + + nsProtocolInfo info; + nsresult rv = GetProtocolInfo(uri, &info); + if (NS_FAILED(rv)) + return rv; + + PRBool usePAC; + nsCOMPtr pi; + rv = Resolve_Internal(uri, info, &usePAC, getter_AddRefs(pi)); + if (NS_FAILED(rv)) + return rv; + + if (!usePAC || !mPACMan) { + ApplyFilters(uri, info, pi); + + ctx->SetResult(NS_OK, pi); + ctx->DispatchCallback(); + return NS_OK; + } + + // else kick off a PAC query + rv = mPACMan->AsyncGetProxyForURI(uri, ctx); + if (NS_SUCCEEDED(rv)) { + *result = ctx; + NS_ADDREF(*result); + } + return rv; +} + +NS_IMETHODIMP +nsProtocolProxyService::CancelAsyncResolve(nsISupports *context) +{ + nsCOMPtr ctx = do_QueryInterface(context); + NS_ENSURE_ARG(ctx); + ctx->Cancel(); return NS_OK; } @@ -843,12 +855,15 @@ nsProtocolProxyService::NewProxyInfo(const nsACString &aType, const nsACString &aHost, PRInt32 aPort, PRUint32 aFlags, + PRUint32 aFailoverTimeout, + nsIProxyInfo *aFailoverProxy, nsIProxyInfo **aResult) { static const char *types[] = { kProxyType_HTTP, kProxyType_SOCKS, - kProxyType_SOCKS4 + kProxyType_SOCKS4, + kProxyType_DIRECT }; // resolve type; this allows us to avoid copying the type string into each @@ -865,54 +880,24 @@ nsProtocolProxyService::NewProxyInfo(const nsACString &aType, if (aPort <= 0) aPort = -1; - return NewProxyInfo_Internal(type, aHost, aPort, aFlags, aResult); + return NewProxyInfo_Internal(type, aHost, aPort, aFlags, aFailoverTimeout, + aFailoverProxy, aResult); } NS_IMETHODIMP -nsProtocolProxyService::ConfigureFromPAC(const nsACString &aURI) +nsProtocolProxyService::ConfigureFromPAC(const nsACString &spec) { - mPACURI = aURI; + if (!mPACMan) { + mPACMan = new nsPACMan(); + if (!mPACMan) + return NS_ERROR_OUT_OF_MEMORY; + } + + mPACURI = spec; mFailedProxies.Clear(); - nsresult rv; - - // Now we need to setup a callback from the current thread, in which we - // will load the PAC file from the specified URI. Loading it now, causes - // re-entrancy problems for the XPCOM Service Manager (since we require the - // IO Service in order to load the PAC URI). - - // get current thread's event queue - nsCOMPtr eq = nsnull; - rv = NS_GetCurrentEventQ(getter_AddRefs(eq)); - if (NS_FAILED(rv) || !eq) { - NS_ERROR("Failed to get current event queue"); - return rv; - } - - // create an event - PLEvent* event = new PLEvent; - // AddRef this because it is being placed in the PLEvent struct - // It will be Released when DestroyPACLoadEvent is called - NS_ADDREF_THIS(); - PL_InitEvent(event, this, - nsProtocolProxyService::HandlePACLoadEvent, - nsProtocolProxyService::DestroyPACLoadEvent); - - // post the event into the ui event queue - rv = eq->PostEvent(event); - if (NS_FAILED(rv)) { - NS_ERROR("Failed to post PAC load event to UI EventQueue"); - PL_DestroyEvent(event); - } - return rv; -} - -NS_IMETHODIMP -nsProtocolProxyService::GetProxyEnabled(PRBool *enabled) -{ - NS_ENSURE_ARG_POINTER(enabled); - *enabled = (mUseProxy != 0); - return NS_OK; + LOG(("LoadPACFromURI(\"%s\")\n", mPACURI.get())); + return mPACMan->LoadPACFromURI(mPACURI); } NS_IMETHODIMP @@ -922,14 +907,12 @@ nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy, nsIProxyInfo **aResult) { // We only support failover when a PAC file is configured. - if (mUseProxy != 2) + if (mProxyConfig != eProxyConfig_PAC && mProxyConfig != eProxyConfig_WPAD) return NS_ERROR_NOT_AVAILABLE; // Verify that |aProxy| is one of our nsProxyInfo objects. - nsRefPtr pi; - aProxy->QueryInterface(kProxyInfoID, getter_AddRefs(pi)); - if (!pi) - return NS_ERROR_INVALID_ARG; + nsCOMPtr pi = do_QueryInterface(aProxy); + NS_ENSURE_ARG(pi); // OK, the QI checked out. We can proceed. // Remember that this proxy is down. @@ -950,6 +933,66 @@ nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy, return NS_OK; } +NS_IMETHODIMP +nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter *filter, + PRUint32 position) +{ + UnregisterFilter(filter); // remove this filter if we already have it + + FilterLink *link = new FilterLink(position, filter); + if (!link) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mFilters) { + mFilters = link; + return NS_OK; + } + + // insert into mFilters in sorted order + FilterLink *last = nsnull; + for (FilterLink *iter = mFilters; iter; iter = iter->next) { + if (position < iter->position) { + if (last) { + link->next = last->next; + last->next = link; + } else { + link->next = mFilters; + mFilters = link; + } + return NS_OK; + } + last = iter; + } + // our position is equal to or greater than the last link in the list + last->next = link; + return NS_OK; +} + +NS_IMETHODIMP +nsProtocolProxyService::UnregisterFilter(nsIProtocolProxyFilter *filter) +{ + // QI to nsISupports so we can safely test object identity. + nsCOMPtr givenObject = do_QueryInterface(filter); + + FilterLink *last = nsnull; + for (FilterLink *iter = mFilters; iter; iter = iter->next) { + nsCOMPtr object = do_QueryInterface(iter->filter); + if (object == givenObject) { + if (last) + last->next = iter->next; + else + mFilters = iter->next; + iter->next = nsnull; + delete iter; + return NS_OK; + } + last = iter; + } + + // No need to throw an exception in this case. + return NS_OK; +} + PRBool PR_CALLBACK nsProtocolProxyService::CleanupFilterArray(void *aElement, void *aData) { @@ -960,12 +1003,12 @@ nsProtocolProxyService::CleanupFilterArray(void *aElement, void *aData) } void -nsProtocolProxyService::LoadFilters(const char *filters) +nsProtocolProxyService::LoadHostFilters(const char *filters) { // check to see the owners flag? /!?/ TODO - if (mFiltersArray.Count() > 0) { - mFiltersArray.EnumerateForwards(CleanupFilterArray, nsnull); - mFiltersArray.Clear(); + if (mHostFiltersArray.Count() > 0) { + mHostFiltersArray.EnumerateForwards(CleanupFilterArray, nsnull); + mHostFiltersArray.Clear(); } if (!filters) @@ -1060,7 +1103,7 @@ nsProtocolProxyService::LoadFilters(const char *filters) //#define DEBUG_DUMP_FILTERS #ifdef DEBUG_DUMP_FILTERS - printf("loaded filter[%u]:\n", mFiltersArray.Count()); + printf("loaded filter[%u]:\n", mHostFiltersArray.Count()); printf(" is_ipaddr = %u\n", hinfo->is_ipaddr); printf(" port = %u\n", hinfo->port); if (hinfo->is_ipaddr) { @@ -1081,7 +1124,7 @@ nsProtocolProxyService::LoadFilters(const char *filters) } #endif - mFiltersArray.AppendElement(hinfo); + mHostFiltersArray.AppendElement(hinfo); hinfo = nsnull; loser: if (hinfo) @@ -1090,23 +1133,29 @@ loser: } nsresult -nsProtocolProxyService::GetProtocolInfo(const char *aScheme, - PRUint32 &aFlags, - PRInt32 &defaultPort) +nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info) { nsresult rv; + rv = uri->GetScheme(info->scheme); + if (NS_FAILED(rv)) + return rv; + nsCOMPtr ios = do_GetIOService(&rv); - if (NS_FAILED(rv)) return rv; + if (NS_FAILED(rv)) + return rv; nsCOMPtr handler; - rv = ios->GetProtocolHandler(aScheme, getter_AddRefs(handler)); - if (NS_FAILED(rv)) return rv; + rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler)); + if (NS_FAILED(rv)) + return rv; - rv = handler->GetProtocolFlags(&aFlags); - if (NS_FAILED(rv)) return rv; + rv = handler->GetProtocolFlags(&info->flags); + if (NS_FAILED(rv)) + return rv; - return handler->GetDefaultPort(&defaultPort); + rv = handler->GetDefaultPort(&info->defaultPort); + return rv; } nsresult @@ -1114,8 +1163,16 @@ nsProtocolProxyService::NewProxyInfo_Internal(const char *aType, const nsACString &aHost, PRInt32 aPort, PRUint32 aFlags, + PRUint32 aFailoverTimeout, + nsIProxyInfo *aFailoverProxy, nsIProxyInfo **aResult) { + nsCOMPtr failover; + if (aFailoverProxy) { + failover = do_QueryInterface(aFailoverProxy); + NS_ENSURE_ARG(failover); + } + nsProxyInfo *proxyInfo = new nsProxyInfo(); if (!proxyInfo) return NS_ERROR_OUT_OF_MEMORY; @@ -1124,51 +1181,211 @@ nsProtocolProxyService::NewProxyInfo_Internal(const char *aType, proxyInfo->mHost = aHost; proxyInfo->mPort = aPort; proxyInfo->mFlags = aFlags; + proxyInfo->mTimeout = aFailoverTimeout == PR_UINT32_MAX + ? mFailedProxyTimeout : aFailoverTimeout; + failover.swap(proxyInfo->mNext); NS_ADDREF(*aResult = proxyInfo); return NS_OK; } -void -nsProtocolProxyService::ConfigureFromWPAD() +nsresult +nsProtocolProxyService::Resolve_Internal(nsIURI *uri, + const nsProtocolInfo &info, + PRBool *usePAC, + nsIProxyInfo **result) { - nsCOMPtr dnsService = do_GetService(NS_DNSSERVICE_CONTRACTID); - if (!dnsService) { - NS_ERROR("Can't run WPAD: no DNS service?"); - return; - } - - // Asynchronously resolve "wpad", configuring from PAC if we find one (in our - // OnLookupComplete method). - // - // We diverge from the WPAD spec here in that we don't walk the hosts's - // FQDN, stripping components until we hit a TLD. Doing so is dangerous in - // the face of an incomplete list of TLDs, and TLDs get added over time. We - // could consider doing only a single substitution of the first component, - // if that proves to help compatibility. + NS_ENSURE_ARG_POINTER(uri); - nsCOMPtr curQ; - nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(curQ)); - if (NS_FAILED(rv)) { - NS_ERROR("Can't run WPAD: can't get event queue for async resolve!"); - return; - } - - nsCOMPtr request; - rv = dnsService->AsyncResolve(NS_LITERAL_CSTRING("wpad"), - nsIDNSService::RESOLVE_BYPASS_CACHE, - this, curQ, getter_AddRefs(request)); - if (NS_FAILED(rv)) { - NS_ERROR("Can't run WPAD: AsyncResolve failed"); - } -} + *usePAC = PR_FALSE; + *result = nsnull; + + if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) + return NS_OK; // Can't proxy this (filters may not override) + + // if proxies are enabled and this host:port combo is supposed to use a + // proxy, check for a proxy. + if (mProxyConfig == eProxyConfig_Direct || + (mProxyConfig == eProxyConfig_Manual && + !CanUseProxy(uri, info.defaultPort))) + return NS_OK; + + // Proxy auto config magic... + if (mProxyConfig == eProxyConfig_PAC || mProxyConfig == eProxyConfig_WPAD) { + // Do not query PAC now. + *usePAC = PR_TRUE; + return NS_OK; + } + + // proxy info values + const char *type = nsnull; + const nsACString *host = nsnull; + PRInt32 port = -1; + + PRUint32 proxyFlags = 0; + + if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 && + info.scheme.EqualsLiteral("http")) { + host = &mHTTPProxyHost; + type = kProxyType_HTTP; + port = mHTTPProxyPort; + } + else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 && + info.scheme.EqualsLiteral("https")) { + host = &mHTTPSProxyHost; + type = kProxyType_HTTP; + port = mHTTPSProxyPort; + } + else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 && + info.scheme.EqualsLiteral("ftp")) { + host = &mFTPProxyHost; + type = kProxyType_HTTP; + port = mFTPProxyPort; + } + else if (!mGopherProxyHost.IsEmpty() && mGopherProxyPort > 0 && + info.scheme.EqualsLiteral("gopher")) { + host = &mGopherProxyHost; + type = kProxyType_HTTP; + port = mGopherProxyPort; + } + else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { + host = &mSOCKSProxyHost; + if (mSOCKSProxyVersion == 4) + type = kProxyType_SOCKS4; + else + type = kProxyType_SOCKS; + port = mSOCKSProxyPort; + if (mSOCKSProxyRemoteDNS) + proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; + } + + if (type) { + nsresult rv = NewProxyInfo_Internal(type, *host, port, proxyFlags, + PR_UINT32_MAX, nsnull, result); + if (NS_FAILED(rv)) + return rv; + } -NS_IMETHODIMP -nsProtocolProxyService::OnLookupComplete(nsIDNSRequest *aRequest, - nsIDNSRecord *aRecord, - nsresult aStatus) -{ - if (aRecord) - ConfigureFromPAC(NS_LITERAL_CSTRING("http://wpad/wpad.dat")); return NS_OK; } + +void +nsProtocolProxyService::ApplyFilters(nsIURI *uri, const nsProtocolInfo &info, + nsIProxyInfo **list) +{ + if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) + return; + + // We prune the proxy list prior to invoking each filter. This may be + // somewhat inefficient, but it seems like a good idea since we want each + // filter to "see" a valid proxy list. + + nsresult rv; + nsCOMPtr result; + + for (FilterLink *iter = mFilters; iter; iter = iter->next) { + PruneProxyInfo(info, list); + + rv = iter->filter->ApplyFilter(this, uri, *list, + getter_AddRefs(result)); + if (NS_FAILED(rv)) + continue; + result.swap(*list); + } + + PruneProxyInfo(info, list); +} + +void +nsProtocolProxyService::PruneProxyInfo(const nsProtocolInfo &info, + nsIProxyInfo **list) +{ + if (!*list) + return; + nsProxyInfo *head = nsnull; + CallQueryInterface(*list, &head); + if (!head) { + NS_NOTREACHED("nsIProxyInfo must QI to nsProxyInfo"); + return; + } + NS_RELEASE(*list); + + // Pruning of disabled proxies works like this: + // - If all proxies are disabled, return the full list + // - Otherwise, remove the disabled proxies. + // + // Pruning of disallowed proxies works like this: + // - If the protocol handler disallows the proxy, then we disallow it. + + // Start by removing all disallowed proxies if required: + if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) { + nsProxyInfo *last = nsnull; + for (nsProxyInfo *iter = head; iter; iter = iter->mNext, last = iter) { + if (iter->Type() == kProxyType_HTTP) { + // reject! + if (last) + last->mNext = iter->mNext; + else + head = iter->mNext; + iter->mNext = nsnull; + NS_RELEASE(iter); + } + } + if (!head) + return; + } + + // Now, scan to see if all remaining proxies are disabled. If so, then + // we'll just bail and return them all. Otherwise, we'll go and prune the + // disabled ones. + + PRBool allDisabled = PR_TRUE; + + nsProxyInfo *iter; + for (iter = head; iter; iter = iter->mNext) { + if (!IsProxyDisabled(iter)) { + allDisabled = PR_FALSE; + break; + } + } + + if (allDisabled) + LOG(("All proxies are disabled, so trying all again")); + else { + // remove any disabled proxies. + nsProxyInfo *last = nsnull; + for (iter = head; iter; ) { + if (IsProxyDisabled(iter)) { + // reject! + nsProxyInfo *reject = iter; + + iter = iter->mNext; + if (last) + last->mNext = iter; + else + head = iter; + + reject->mNext = nsnull; + NS_RELEASE(reject); + continue; + } + + // since we are about to use this proxy, make sure it is not on + // the disabled proxy list. we'll add it back to that list if + // we have to (in GetFailoverForProxy). + // + // XXX(darin): It might be better to do this as a final pass. + // + EnableProxy(iter); + + last = iter; + iter = iter->mNext; + } + } + + // if only DIRECT was specified then return no proxy info, and we're done. + if (head && !head->mNext && head->mType == kProxyType_DIRECT) + NS_RELEASE(head); + + *list = head; // Transfer ownership +} diff --git a/mozilla/netwerk/base/src/nsProtocolProxyService.h b/mozilla/netwerk/base/src/nsProtocolProxyService.h index efd75871812..02dc3ef9b12 100644 --- a/mozilla/netwerk/base/src/nsProtocolProxyService.h +++ b/mozilla/netwerk/base/src/nsProtocolProxyService.h @@ -44,14 +44,15 @@ #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsVoidArray.h" -#include "nsIDNSListener.h" #include "nsIPrefBranch.h" -#include "nsIProtocolProxyService.h" +#include "nsPIProtocolProxyService.h" +#include "nsIProtocolProxyFilter.h" #include "nsIProxyAutoConfig.h" #include "nsIProxyInfo.h" #include "nsIObserver.h" #include "nsDataHashtable.h" #include "nsHashKeys.h" +#include "nsPACMan.h" #include "prtime.h" #include "prmem.h" #include "prio.h" @@ -59,39 +60,227 @@ typedef nsDataHashtable nsFailedProxyTable; class nsProxyInfo; +class nsProtocolInfo; -class nsProtocolProxyService : public nsIProtocolProxyService +class nsProtocolProxyService : public nsPIProtocolProxyService , public nsIObserver - , public nsIDNSListener { public: NS_DECL_ISUPPORTS + NS_DECL_NSPIPROTOCOLPROXYSERVICE NS_DECL_NSIPROTOCOLPROXYSERVICE NS_DECL_NSIOBSERVER - NS_DECL_NSIDNSLISTENER nsProtocolProxyService() NS_HIDDEN; - ~nsProtocolProxyService() NS_HIDDEN; NS_HIDDEN_(nsresult) Init(); - void PrefsChanged(nsIPrefBranch *, const char* pref); - protected: + friend class nsAsyncResolveContext; - NS_HIDDEN_(const char *) ExtractProxyInfo(const char *proxy, PRBool permitHttp, nsProxyInfo **); - NS_HIDDEN_(nsProxyInfo *)BuildProxyList(const char *proxyStr, PRBool permitHttp, PRBool pruneDisabledProxies); - NS_HIDDEN_(void) GetProxyKey(nsProxyInfo *, nsCString &); - NS_HIDDEN_(PRUint32) SecondsSinceSessionStart(); - NS_HIDDEN_(void) EnableProxy(nsProxyInfo *); - NS_HIDDEN_(void) DisableProxy(nsProxyInfo *); - NS_HIDDEN_(PRBool) IsProxyDisabled(nsProxyInfo *); - NS_HIDDEN_(nsresult) ExaminePACForProxy(nsIURI *aURI, PRUint32 protoFlags, nsIProxyInfo **aResult); - NS_HIDDEN_(nsresult) GetProtocolInfo(const char *scheme, PRUint32 &flags, PRInt32 &defaultPort); - NS_HIDDEN_(nsresult) NewProxyInfo_Internal(const char *type, const nsACString &host, PRInt32 port, PRUint32 flags, nsIProxyInfo **); - NS_HIDDEN_(void) LoadFilters(const char *filters); - NS_HIDDEN_(PRBool) CanUseProxy(nsIURI *aURI, PRInt32 defaultPort); - NS_HIDDEN_(void) ConfigureFromWPAD(); + ~nsProtocolProxyService() NS_HIDDEN; + + /** + * This method is called whenever a preference may have changed or + * to initialize all preferences. + * + * @param prefs + * This must be a pointer to the root pref branch. + * @param name + * This can be the name of a fully-qualified preference, or it can + * be null, in which case all preferences will be initialized. + */ + NS_HIDDEN_(void) PrefsChanged(nsIPrefBranch *prefs, const char *name); + + /** + * This method is called to create a nsProxyInfo instance from the given + * PAC-style proxy string. It parses up to the end of the string, or to + * the next ';' character. + * + * @param proxy + * The PAC-style proxy string to parse. This must not be null. + * @param result + * Upon return this points to a newly allocated nsProxyInfo or null + * if the proxy string was invalid. + * + * @return A pointer beyond the parsed proxy string (never null). + */ + NS_HIDDEN_(const char *) ExtractProxyInfo(const char *proxy, + nsProxyInfo **result); + + /** + * This method builds a list of nsProxyInfo objects from the given PAC- + * style string. + * + * @param pacString + * The PAC-style proxy string to parse. This may be empty. + * @param result + * The resulting list of proxy info objects. + */ + NS_HIDDEN_(void) ProcessPACString(const nsCString &pacString, + nsIProxyInfo **result); + + /** + * This method generates a string valued identifier for the given + * nsProxyInfo object. + * + * @param pi + * The nsProxyInfo object from which to generate the key. + * @param result + * Upon return, this parameter holds the generated key. + */ + NS_HIDDEN_(void) GetProxyKey(nsProxyInfo *pi, nsCString &result); + + /** + * @return Seconds since start of session. + */ + NS_HIDDEN_(PRUint32) SecondsSinceSessionStart(); + + /** + * This method removes the specified proxy from the disabled list. + * + * @param pi + * The nsProxyInfo object identifying the proxy to enable. + */ + NS_HIDDEN_(void) EnableProxy(nsProxyInfo *pi); + + /** + * This method adds the specified proxy to the disabled list. + * + * @param pi + * The nsProxyInfo object identifying the proxy to disable. + */ + NS_HIDDEN_(void) DisableProxy(nsProxyInfo *pi); + + /** + * This method tests to see if the given proxy is disabled. + * + * @param pi + * The nsProxyInfo object identifying the proxy to test. + * + * @return True if the specified proxy is disabled. + */ + NS_HIDDEN_(PRBool) IsProxyDisabled(nsProxyInfo *pi); + + /** + * This method queries the protocol handler for the given scheme to check + * for the protocol flags and default port. + * + * @param uri + * The URI to query. + * @param info + * Holds information about the protocol upon return. Pass address + * of structure when you call this method. This parameter must not + * be null. + */ + NS_HIDDEN_(nsresult) GetProtocolInfo(nsIURI *uri, nsProtocolInfo *result); + + /** + * This method is an internal version nsIProtocolProxyService::newProxyInfo + * that expects a string literal for the type. + * + * @param type + * The proxy type. + * @param host + * The proxy host name (UTF-8 ok). + * @param port + * The proxy port number. + * @param flags + * The proxy flags (nsIProxyInfo::flags). + * @param timeout + * The failover timeout for this proxy. + * @param next + * The next proxy to try if this one fails. + * @param result + * The resulting nsIProxyInfo object. + */ + NS_HIDDEN_(nsresult) NewProxyInfo_Internal(const char *type, + const nsACString &host, + PRInt32 port, + PRUint32 flags, + PRUint32 timeout, + nsIProxyInfo *next, + nsIProxyInfo **result); + + /** + * This method is an internal version of Resolve that does not query PAC. + * It performs all of the built-in processing, and reports back to the + * caller with either the proxy info result or a flag to instruct the + * caller to use PAC instead. + * + * @param uri + * The URI to test. + * @param info + * Information about the URI's protocol. + * @param usePAC + * If this flag is set upon return, then PAC should be queried to + * resolve the proxy info. + * @param result + * The resulting proxy info or null. + */ + NS_HIDDEN_(nsresult) Resolve_Internal(nsIURI *uri, + const nsProtocolInfo &info, + PRBool *usePAC, + nsIProxyInfo **result); + + /** + * This method applies the registered filters to the given proxy info + * list, and returns a possibly modified list. + * + * @param uri + * The URI corresponding to this proxy info list. + * @param info + * Information about the URI's protocol. + * @param proxyInfo + * The proxy info list to be modified. This is an inout param. + */ + NS_HIDDEN_(void) ApplyFilters(nsIURI *uri, const nsProtocolInfo &info, + nsIProxyInfo **proxyInfo); + + /** + * This method is a simple wrapper around ApplyFilters that takes the + * proxy info list inout param as a nsCOMPtr. + */ + inline void ApplyFilters(nsIURI *uri, const nsProtocolInfo &info, + nsCOMPtr &proxyInfo) + { + nsIProxyInfo *pi = nsnull; + proxyInfo.swap(pi); + ApplyFilters(uri, info, &pi); + proxyInfo.swap(pi); + } + + /** + * This method prunes out disabled and disallowed proxies from a given + * proxy info list. + * + * @param info + * Information about the URI's protocol. + * @param proxyInfo + * The proxy info list to be modified. This is an inout param. + */ + NS_HIDDEN_(void) PruneProxyInfo(const nsProtocolInfo &info, + nsIProxyInfo **proxyInfo); + + /** + * This method populates mHostFiltersArray from the given string. + * + * @param hostFilters + * A "no-proxy-for" exclusion list. + */ + NS_HIDDEN_(void) LoadHostFilters(const char *hostFilters); + + /** + * This method checks the given URI against mHostFiltersArray. + * + * @param uri + * The URI to test. + * @param defaultPort + * The default port for the given URI. + * + * @return True if the URI can use the specified proxy. + */ + NS_HIDDEN_(PRBool) CanUseProxy(nsIURI *uri, PRInt32 defaultPort); static PRBool PR_CALLBACK CleanupFilterArray(void *aElement, void *aData); static void* PR_CALLBACK HandlePACLoadEvent(PLEvent* aEvent); @@ -115,6 +304,15 @@ public: protected: + enum ProxyConfig { + eProxyConfig_Direct, + eProxyConfig_Manual, + eProxyConfig_PAC, + eProxyConfig_Direct4x, + eProxyConfig_WPAD, + eProxyConfig_Last + }; + // simplified array of filters defined by this struct struct HostInfo { PRBool is_ipaddr; @@ -133,8 +331,27 @@ protected: } }; - nsVoidArray mFiltersArray; - PRUint16 mUseProxy; + // This structure is allocated for each registered nsIProtocolProxyFilter. + struct FilterLink { + struct FilterLink *next; + PRUint32 position; + nsCOMPtr filter; + + FilterLink(PRUint32 p, nsIProtocolProxyFilter *f) + : next(nsnull), position(p), filter(f) {} + + // Chain deletion to simplify cleaning up the filter links + ~FilterLink() { if (next) delete next; } + }; + + // Holds an array of HostInfo objects + nsVoidArray mHostFiltersArray; + + // Points to the start of a sorted by position, singly linked list + // of FilterLink objects. + FilterLink *mFilters; + + ProxyConfig mProxyConfig; nsCString mHTTPProxyHost; PRInt32 mHTTPProxyPort; @@ -153,8 +370,8 @@ protected: PRInt32 mSOCKSProxyVersion; PRBool mSOCKSProxyRemoteDNS; - nsCOMPtr mPAC; nsCString mPACURI; + nsRefPtr mPACMan; // non-null if we are using PAC PRTime mSessionStart; nsFailedProxyTable mFailedProxies; diff --git a/mozilla/netwerk/base/src/nsProxyAutoConfig.js b/mozilla/netwerk/base/src/nsProxyAutoConfig.js index 9f3ba5f8567..162298e6a0a 100644 --- a/mozilla/netwerk/base/src/nsProxyAutoConfig.js +++ b/mozilla/netwerk/base/src/nsProxyAutoConfig.js @@ -1,4 +1,5 @@ /* -*- Mode: Java; tab-width: 4; c-basic-offset: 4; -*- */ +/* vim:set ts=4 sw=4 sts=4 et: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -22,6 +23,7 @@ * Contributor(s): * Akhil Arora * Tomi Leppikangas + * Darin Fisher * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -42,102 +44,64 @@ - Gagan Saksena 04/24/00 */ -const kPAC_CONTRACTID = "@mozilla.org/network/proxy-auto-config;1"; -const kIOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1"; const kDNS_CONTRACTID = "@mozilla.org/network/dns-service;1"; +const kPAC_CONTRACTID = "@mozilla.org/network/proxy-auto-config;1"; const kPAC_CID = Components.ID("{63ac8c66-1dd2-11b2-b070-84d00d3eaece}"); + +const nsISupports = Components.interfaces.nsISupports; const nsIProxyAutoConfig = Components.interfaces.nsIProxyAutoConfig; -const nsIIOService = Components.interfaces['nsIIOService']; -const nsIDNSService = Components.interfaces.nsIDNSService; -const nsIRequest = Components.interfaces.nsIRequest; +const nsIDNSService = Components.interfaces.nsIDNSService; // implementor of nsIProxyAutoConfig function nsProxyAutoConfig() {}; -// global variable that will hold the downloaded js -var pac = null; -//hold PAC's URL, used in evalAsCodebase() -var pacURL; -// ptr to eval'ed FindProxyForURL function -var LocalFindProxyForURL = null; -// sendbox in which we eval loaded autoconfig js file -var ProxySandBox = null; - nsProxyAutoConfig.prototype = { - sis: null, - done: false, + // sandbox in which we eval loaded autoconfig js file + _sandBox: null, - getProxyForURI: function(uri) { - // If we're not done loading the pac yet, wait (ideally). For - // now, just return DIRECT to avoid loops. A simple mutex - // between getProxyForURI and loadPACFromURI locks-up the - // browser. - if (!this.done) - return null; + // ptr to eval'ed FindProxyForURL function + _findProxyForURL: null, - if (!LocalFindProxyForURL) - return null; - - // Call the original function- - return LocalFindProxyForURL(uri.spec, uri.host); + QueryInterface: function(iid) { + if (iid.Equals(nsIProxyAutoConfig) || + iid.Equals(nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; }, - loadPACFromURI: function(uri, ioService) { - this.done = false; - var channel = ioService.newChannelFromURI(uri); - // don't cache the PAC content - channel.loadFlags |= nsIRequest.LOAD_BYPASS_CACHE; - pacURL = uri.spec; - channel.notificationCallbacks = this; - channel.asyncOpen(this, null); - Components.returnCode = Components.results.NS_OK; - }, - - // nsIInterfaceRequestor interface - getInterface: function(iid, instance) { - if (iid.equals(Components.interfaces.nsIAuthPrompt)) { - // use the window watcher service to get a nsIAuthPrompt impl - var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] - .getService(Components.interfaces.nsIWindowWatcher); - return ww.getNewAuthPrompter(null); + init: function(pacURI, pacText) { + // remove PAC configuration if requested + if (pacURI == "" || pacText == "") { + this._findProxyForURL = null; + this._sandBox = null; } - Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; - return null; - }, - // nsIStreamListener interface - onStartRequest: function(request, ctxt) { - pac = ''; - LocalFindProxyForURL=null; - this.sis = - Components.Constructor('@mozilla.org/scriptableinputstream;1', - 'nsIScriptableInputStream', - 'init'); - }, + // allocate a fresh Sandbox to clear global scope for new PAC script + this._sandBox = new Sandbox(); - onStopRequest: function(request, ctxt, status) { - if(!ProxySandBox) { - ProxySandBox = new Sandbox(); - } // add predefined functions to pac - var mypac = pacUtils + pac; - ProxySandBox.myIpAddress = myIpAddress; - ProxySandBox.dnsResolve = dnsResolve; - ProxySandBox.alert = proxyAlert; + var mypac = pacUtils + pacText; + this._sandBox.myIpAddress = myIpAddress; + this._sandBox.dnsResolve = dnsResolve; + this._sandBox.alert = proxyAlert; + // evaluate loaded js file - evalInSandbox(mypac, ProxySandBox, pacURL); - LocalFindProxyForURL=ProxySandBox.FindProxyForURL; - this.done = true; + evalInSandbox(mypac, this._sandBox, pacURI); + this._findProxyForURL = this._sandBox.FindProxyForURL; }, - onDataAvailable: function(request, ctxt, inStream, sourceOffset, count) { - var ins = new this.sis(inStream); - pac += ins.read(count); + getProxyForURI: function(testURI, testHost) { + if (!this._findProxyForURL) + return null; + + // Call the original function + return this._findProxyForURL(testURI, testHost); } } 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); @@ -200,22 +164,17 @@ pacFactory.createInstance = throw Components.results.NS_ERROR_NO_AGGREGATION; if (!iid.equals(nsIProxyAutoConfig) && - !iid.equals(Components.interfaces.nsIStreamListener) && - !iid.equals(Components.interfaces.nsIRequestObserver) && !iid.equals(Components.interfaces.nsISupports)) { - // shouldn't this be NO_INTERFACE? - throw Components.results.NS_ERROR_INVALID_ARG; + throw Components.results.NS_ERROR_NO_INTERFACE; } - return PacMan; + return pac; } function NSGetModule(compMgr, fileSpec) { return pacModule; } -var PacMan = new nsProxyAutoConfig() ; - -var ios = Components.classes[kIOSERVICE_CONTRACTID].getService(nsIIOService); +var pac = new nsProxyAutoConfig() ; var dns = Components.classes[kDNS_CONTRACTID].getService(nsIDNSService); var pacUtils = diff --git a/mozilla/netwerk/base/src/nsProxyInfo.cpp b/mozilla/netwerk/base/src/nsProxyInfo.cpp new file mode 100644 index 00000000000..55a8da76fec --- /dev/null +++ b/mozilla/netwerk/base/src/nsProxyInfo.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsProxyInfo.h" +#include "nsCOMPtr.h" + +// Yes, we support QI to nsProxyInfo +NS_IMPL_THREADSAFE_ISUPPORTS2(nsProxyInfo, nsProxyInfo, nsIProxyInfo) + +NS_IMETHODIMP +nsProxyInfo::GetHost(nsACString &result) +{ + result = mHost; + return NS_OK; +} + +NS_IMETHODIMP +nsProxyInfo::GetPort(PRInt32 *result) +{ + *result = mPort; + return NS_OK; +} + +NS_IMETHODIMP +nsProxyInfo::GetType(nsACString &result) +{ + result = mType; + return NS_OK; +} + +NS_IMETHODIMP +nsProxyInfo::GetFlags(PRUint32 *result) +{ + *result = mFlags; + return NS_OK; +} + +NS_IMETHODIMP +nsProxyInfo::GetFailoverTimeout(PRUint32 *result) +{ + *result = mTimeout; + return NS_OK; +} + +NS_IMETHODIMP +nsProxyInfo::GetFailoverProxy(nsIProxyInfo **result) +{ + NS_IF_ADDREF(*result = mNext); + return NS_OK; +} + +NS_IMETHODIMP +nsProxyInfo::SetFailoverProxy(nsIProxyInfo *proxy) +{ + nsCOMPtr pi = do_QueryInterface(proxy); + NS_ENSURE_ARG(pi); + + pi.swap(mNext); + return NS_OK; +} diff --git a/mozilla/netwerk/base/src/nsProxyInfo.h b/mozilla/netwerk/base/src/nsProxyInfo.h new file mode 100644 index 00000000000..2827b08a879 --- /dev/null +++ b/mozilla/netwerk/base/src/nsProxyInfo.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsProxyInfo_h__ +#define nsProxyInfo_h__ + +#include "nsIProxyInfo.h" +#include "nsString.h" + +// Use to support QI nsIProxyInfo to nsProxyInfo +#define NS_PROXYINFO_IID \ +{ /* ed42f751-825e-4cc2-abeb-3670711a8b85 */ \ + 0xed42f751, \ + 0x825e, \ + 0x4cc2, \ + {0xab, 0xeb, 0x36, 0x70, 0x71, 0x1a, 0x8b, 0x85} \ +} + +// This class is exposed to other classes inside Necko for fast access +// to the nsIProxyInfo attributes. +class nsProxyInfo : public nsIProxyInfo +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYINFO_IID) + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROXYINFO + + // Cheap accessors for use within Necko + const nsCString &Host() { return mHost; } + PRInt32 Port() { return mPort; } + const char *Type() { return mType; } + PRUint32 Flags() { return mFlags; } + +private: + friend class nsProtocolProxyService; + + nsProxyInfo(const char *type = nsnull) + : mType(type) + , mPort(-1) + , mFlags(0) + , mTimeout(PR_UINT32_MAX) + , mNext(nsnull) + {} + + ~nsProxyInfo() + { + NS_IF_RELEASE(mNext); + } + + const char *mType; // pointer to statically allocated value + nsCString mHost; + PRInt32 mPort; + PRUint32 mFlags; + PRUint32 mTimeout; + nsProxyInfo *mNext; +}; + +#endif // nsProxyInfo_h__ diff --git a/mozilla/netwerk/base/src/nsSocketTransport2.cpp b/mozilla/netwerk/base/src/nsSocketTransport2.cpp index aa2673ff40e..a5711b44da7 100644 --- a/mozilla/netwerk/base/src/nsSocketTransport2.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransport2.cpp @@ -46,6 +46,7 @@ #include "nsStreamUtils.h" #include "nsNetSegmentUtils.h" #include "nsTransportUtils.h" +#include "nsProxyInfo.h" #include "nsNetCID.h" #include "nsAutoLock.h" #include "nsCOMPtr.h" @@ -63,7 +64,6 @@ #include "nsISocketProviderService.h" #include "nsISocketProvider.h" #include "nsISSLSocketControl.h" -#include "nsIProxyInfo.h" #include "nsIPipe.h" #if defined(XP_WIN) && !defined (WINCE) @@ -722,8 +722,14 @@ nsSocketTransport::~nsSocketTransport() nsresult nsSocketTransport::Init(const char **types, PRUint32 typeCount, const nsACString &host, PRUint16 port, - nsIProxyInfo *proxyInfo) + nsIProxyInfo *givenProxyInfo) { + nsCOMPtr proxyInfo; + if (givenProxyInfo) { + proxyInfo = do_QueryInterface(givenProxyInfo); + NS_ENSURE_ARG(proxyInfo); + } + // init socket type info mPort = port; diff --git a/mozilla/netwerk/build/nsNetCID.h b/mozilla/netwerk/build/nsNetCID.h index 02a19c36f9e..dfb5dba0001 100644 --- a/mozilla/netwerk/build/nsNetCID.h +++ b/mozilla/netwerk/build/nsNetCID.h @@ -71,7 +71,7 @@ {0x91, 0x55, 0xc3, 0x50, 0x94, 0x28, 0x46, 0x1e} \ } -// service implementing nsIProtocolProxyService. +// service implementing nsIProtocolProxyService and nsPIProtocolProxyService. #define NS_PROTOCOLPROXYSERVICE_CLASSNAME \ "nsProtocolProxyService" #define NS_PROTOCOLPROXYSERVICE_CONTRACTID \ @@ -435,6 +435,24 @@ {0x94, 0xdb, 0xd4, 0xf8, 0x59, 0x05, 0x82, 0x15} \ } +// component implementing nsIPrompt +// +// NOTE: this implementation does not have any way to correctly parent itself, +// it is almost always wrong to get a prompt via this interface. +// use nsIWindowWatcher instead whenever possible. +// +#define NS_DEFAULTPROMPT_CONTRACTID \ + "@mozilla.org/network/default-prompt;1" + +// component implementing nsIAuthPrompt +// +// NOTE: this implementation does not have any way to correctly parent itself, +// it is almost always wrong to get an auth prompt via this interface. +// use nsIWindowWatcher instead whenever possible. +// +#define NS_DEFAULTAUTHPROMPT_CONTRACTID \ + "@mozilla.org/network/default-auth-prompt;1" + /****************************************************************************** * netwerk/cache/ classes */ diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp index 85fd7ccfca4..c2ea101f655 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -150,7 +150,7 @@ nsHttpChannel::~nsHttpChannel() nsresult nsHttpChannel::Init(nsIURI *uri, PRUint8 caps, - nsIProxyInfo *proxyInfo) + nsProxyInfo *proxyInfo) { nsresult rv; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h index 28ded61d1d2..bae842191c1 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h @@ -77,7 +77,7 @@ class nsHttpResponseHead; class nsAHttpConnection; class nsIHttpAuthenticator; -class nsIProxyInfo; +class nsProxyInfo; //----------------------------------------------------------------------------- // nsHttpChannel @@ -115,7 +115,7 @@ public: nsresult Init(nsIURI *uri, PRUint8 capabilities, - nsIProxyInfo* proxyInfo); + nsProxyInfo* proxyInfo); public: /* internal; workaround lame compilers */ typedef void (nsHttpChannel:: *nsAsyncCallback)(void); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h b/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h index 4323901b203..adf6f01f146 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpConnectionInfo.h @@ -40,7 +40,7 @@ #define nsHttpConnectionInfo_h__ #include "nsHttp.h" -#include "nsIProxyInfo.h" +#include "nsProxyInfo.h" #include "nsCOMPtr.h" #include "nsDependentString.h" #include "nsString.h" @@ -55,7 +55,7 @@ class nsHttpConnectionInfo { public: nsHttpConnectionInfo(const nsACString &host, PRInt32 port, - nsIProxyInfo* proxyInfo, + nsProxyInfo* proxyInfo, PRBool usingSSL=PR_FALSE) : mRef(0) , mProxyInfo(proxyInfo) @@ -95,7 +95,7 @@ public: SetOriginServer(nsDependentCString(host), port); } - const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host() : nsnull; } + const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nsnull; } PRInt32 ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; } const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nsnull; } @@ -113,7 +113,7 @@ public: const char *Host() const { return mHost.get(); } PRInt32 Port() const { return mPort; } - nsIProxyInfo *ProxyInfo() { return mProxyInfo; } + nsProxyInfo *ProxyInfo() { return mProxyInfo; } PRBool UsingHttpProxy() const { return mUsingHttpProxy; } PRBool UsingSSL() const { return mUsingSSL; } PRInt32 DefaultPort() const { return mUsingSSL ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT; } @@ -123,7 +123,7 @@ private: nsCString mHashKey; nsCString mHost; PRInt32 mPort; - nsCOMPtr mProxyInfo; + nsCOMPtr mProxyInfo; PRPackedBool mUsingHttpProxy; PRPackedBool mUsingSSL; }; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp b/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp index 5abc72af7ac..057672ee107 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp @@ -1385,13 +1385,19 @@ nsHttpHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval) NS_IMETHODIMP nsHttpHandler::NewProxiedChannel(nsIURI *uri, - nsIProxyInfo* proxyInfo, + nsIProxyInfo* givenProxyInfo, nsIChannel **result) { nsHttpChannel *httpChannel = nsnull; LOG(("nsHttpHandler::NewProxiedChannel [proxyInfo=%p]\n", - proxyInfo)); + givenProxyInfo)); + + nsCOMPtr proxyInfo; + if (givenProxyInfo) { + proxyInfo = do_QueryInterface(givenProxyInfo); + NS_ENSURE_ARG(proxyInfo); + } PRBool https; nsresult rv = uri->SchemeIs("https", &https); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp index 9e1a00060a4..50eb99ed06e 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp @@ -124,8 +124,8 @@ nsHttpTransaction::nsHttpTransaction() , mContentLength(-1) , mContentRead(0) , mChunkedDecoder(nsnull) - , mPriority(0) , mStatus(NS_OK) + , mPriority(0) , mRestartCount(0) , mCaps(0) , mClosed(PR_FALSE) diff --git a/mozilla/netwerk/test/Makefile.in b/mozilla/netwerk/test/Makefile.in index 2ac21cd4234..3aa8534dd92 100644 --- a/mozilla/netwerk/test/Makefile.in +++ b/mozilla/netwerk/test/Makefile.in @@ -91,13 +91,18 @@ DEFINES += $(TK_CFLAGS) include $(topsrcdir)/config/rules.mk +_UNIT_FILES = unit/test_all.sh \ + unit/head.js \ + unit/tail.js \ + unit/test_protocolproxyservice.js +libs:: $(_UNIT_FILES) + $(INSTALL) $^ $(DIST)/bin/necko_unit_tests + _RES_FILES = urlparse.dat \ urlparse_unx.dat \ jarlist.dat \ $(NULL) - libs:: $(_RES_FILES) - $(INSTALL) $^ $(DIST)/bin/res - + $(INSTALL) $^ $(DIST)/bin/res install:: $(_RES_FILES) $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/res diff --git a/mozilla/netwerk/test/unit/head.js b/mozilla/netwerk/test/unit/head.js new file mode 100644 index 00000000000..c68f9801f84 --- /dev/null +++ b/mozilla/netwerk/test/unit/head.js @@ -0,0 +1,133 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This file contains common code that is loaded with each test file. + +const nsIEventQueueService = Components.interfaces.nsIEventQueueService; +const nsIEventQueue = Components.interfaces.nsIEventQueue; + +var _eqs; +var _quit = false; +var _fail = false; +var _tests_pending = 0; + +function _TimerCallback(expr) { + this._expr = expr; +} +_TimerCallback.prototype = { + _expr: "", + QueryInterface: function(iid) { + if (iid.Equals(Components.interfaces.nsITimerCallback) || + iid.Equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + notify: function(timer) { + eval(this._expr); + } +}; + +function do_timeout(delay, expr) { + var timer = Components.classes["@mozilla.org/timer;1"] + .createInstance(Components.interfaces.nsITimer); + timer.initWithCallback(new _TimerCallback(expr), delay, timer.TYPE_ONE_SHOT); +} + +function do_main() { + if (_quit) + return; + + dump("*** running event loop\n"); + var eq = _eqs.getSpecialEventQueue(_eqs.CURRENT_THREAD_EVENT_QUEUE); + + eq.eventLoop(); // unblocked via interrupt from do_quit() + + // process any remaining events before exiting + eq.processPendingEvents(); + eq.stopAcceptingEvents(); + eq.processPendingEvents(); +} + +function do_quit() { + dump("*** exiting\n"); + + _quit = true; + + // interrupt the current thread to make eventLoop return. + var thr = Components.classes["@mozilla.org/thread;1"] + .createInstance(Components.interfaces.nsIThread); + thr.currentThread.interrupt(); +} + +function do_throw(text) { + _fail = true; + do_quit(); + dump("*** CHECK FAILED: " + text + "\n"); + var frame = Components.stack; + while (frame != null) { + dump(frame + "\n"); + frame = frame.caller; + } + throw Components.results.NS_ERROR_ABORT; +} + +function do_check_neq(_left, _right) { + if (_left == _right) + do_throw(_left + " != " + _right); +} + +function do_check_eq(_left, _right) { + if (_left != _right) + do_throw(_left + " == " + _right); +} + +function do_test_pending() { + dump("*** test pending\n"); + _tests_pending++; +} + +function do_test_finished() { + dump("*** test finished\n"); + if (--_tests_pending == 0) + do_quit(); +} + +// setup the main thread event queue +_eqs = Components.classes["@mozilla.org/event-queue-service;1"] + .getService(nsIEventQueueService); +_eqs.createMonitoredThreadEventQueue(); diff --git a/mozilla/netwerk/test/unit/tail.js b/mozilla/netwerk/test/unit/tail.js new file mode 100644 index 00000000000..8a2410f7387 --- /dev/null +++ b/mozilla/netwerk/test/unit/tail.js @@ -0,0 +1,52 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +try { + do_test_pending(); + run_test(); + do_test_finished(); + do_main(); +} catch (e) { + _fail = true; + dump(e + "\n"); +} + +if (_fail) + dump("*** FAIL ***\n"); +else + dump("*** PASS ***\n"); diff --git a/mozilla/netwerk/test/unit/test_all.sh b/mozilla/netwerk/test/unit/test_all.sh new file mode 100755 index 00000000000..2e50ed74961 --- /dev/null +++ b/mozilla/netwerk/test/unit/test_all.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# +# vim:set ts=2 sw=2 sts=2 et: +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is Google Inc. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** */ + +# allow core dumps +ulimit -c 999999 + +dir=`dirname $0` +bin="$dir/.." + +for t in $dir/test_*.js +do + LD_LIBRARY_PATH=$bin $bin/xpcshell -f $dir/head.js -f $t -f $dir/tail.js 2> $t.log 1>&2 + if [ `grep -c '\*\*\* PASS' $t.log` = 0 ] + then + echo "$t: FAIL (see $t.log)" + else + echo "$t: PASS" + fi +done diff --git a/mozilla/netwerk/test/unit/test_protocolproxyservice.js b/mozilla/netwerk/test/unit/test_protocolproxyservice.js new file mode 100644 index 00000000000..2ad3ee7bd96 --- /dev/null +++ b/mozilla/netwerk/test/unit/test_protocolproxyservice.js @@ -0,0 +1,281 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This testcase exercises the Protocol Proxy Service + +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(Components.interfaces.nsIProtocolProxyService); + +function check_proxy(pi, type, host, port, flags, timeout, hasNext) { + do_check_neq(pi, null); + do_check_eq(pi.type, type); + do_check_eq(pi.host, host); + do_check_eq(pi.port, port); + if (flags != -1) + do_check_eq(pi.flags, flags); + if (timeout != -1) + do_check_eq(pi.failoverTimeout, timeout); + if (hasNext) + do_check_neq(pi.failoverProxy, null); + else + do_check_eq(pi.failoverProxy, null); +} + +function TestFilter(type, host, port, flags, timeout) { + this._type = type; + this._host = host; + this._port = port; + this._flags = flags; + this._timeout = timeout; +} +TestFilter.prototype = { + _type: "", + _host: "", + _port: -1, + _flags: 0, + _timeout: 0, + QueryInterface: function(iid) { + if (iid.Equals(Components.interfaces.nsIProtocolProxyFilter) || + iid.Equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + applyFilter: function(pps, uri, pi) { + var pi_tail = pps.newProxyInfo(this._type, this._host, this._port, + this._flags, this._timeout, null); + if (pi) + pi.failoverProxy = pi_tail; + else + pi = pi_tail; + return pi; + } +}; + +function BasicFilter() {} +BasicFilter.prototype = { + QueryInterface: function(iid) { + if (iid.Equals(Components.interfaces.nsIProtocolProxyFilter) || + iid.Equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + applyFilter: function(pps, uri, pi) { + return pps.newProxyInfo("http", "localhost", 8080, 0, 10, + pps.newProxyInfo("direct", "", -1, 0, 0, null)); + } +}; + +function run_filter_test() { + var uri = ios.newURI("http://www.mozilla.org/", null, null); + + // Verify initial state + + var pi = pps.resolve(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.resolve(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.resolve(uri, 0); + check_proxy(pi, "http", "localhost", 8080, 0, 10, true); + check_proxy(pi.failoverProxy, "direct", "", -1, 0, 0, false); + + // Remove filter and verify that we return to the initial state + + pps.unregisterFilter(filter1); + pi = pps.resolve(uri, 0); + do_check_eq(pi, null); +} + +function run_filter_test2() { + var uri = ios.newURI("http://www.mozilla.org/", null, null); + + // Verify initial state + + var pi = pps.resolve(uri, 0); + do_check_eq(pi, null); + + // 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); + + pi = pps.resolve(uri, 0); + check_proxy(pi, "http", "bar", 8090, 0, 10, true); + check_proxy(pi.failoverProxy, "http", "foo", 8080, 0, 10, false); + + pps.unregisterFilter(filter2); + pi = pps.resolve(uri, 0); + check_proxy(pi, "http", "foo", 8080, 0, 10, false); + + // Remove filter and verify that we return to the initial state + + pps.unregisterFilter(filter1); + pi = pps.resolve(uri, 0); + do_check_eq(pi, null); +} + +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); + do_check_eq(pi, null); + + // Verify 'manual' setting + + prefs.setIntPref("network.proxy.type", 1); + + // 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); + check_proxy(pi, "http", "foopy", 8080, 0, -1, false); + + prefs.setCharPref("network.proxy.http", ""); + prefs.setIntPref("network.proxy.http_port", 0); + + // try SOCKS configuration + prefs.setCharPref("network.proxy.socks", "barbar"); + prefs.setIntPref("network.proxy.socks_port", 1203); + + pi = pps.resolve(uri, 0); + check_proxy(pi, "socks", "barbar", 1203, 0, -1, false); +} + +function TestResolveCallback() {} + +TestResolveCallback.prototype = { + QueryInterface: + function TestResolveCallback_QueryInterface(iid) { + if (iid.Equals(Components.interfaces.nsIProtocolProxyCallback) || + iid.Equals(Components.interfaces.nsISupports)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + onProxyAvailable: + function TestResolveCallback_onProxyAvailable(ctx, uri, pi, status) { + dump("*** uri=" + uri.spec + ", status=" + status + "\n"); + + do_check_neq(ctx, null); + do_check_neq(uri, null); + do_check_eq(status, 0); + do_check_neq(pi, null); + + check_proxy(pi, "http", "foopy", 8080, 0, -1, true); + check_proxy(pi.failoverProxy, "direct", "", -1, -1, -1, false); + + // verify direct query now that we know the PAC file is loaded + pi = pps.resolve(ios.newURI("http://bazbat.com/", null, null), 0); + do_check_neq(pi, null); + check_proxy(pi, "http", "foopy", 8080, 0, -1, true); + check_proxy(pi.failoverProxy, "direct", "", -1, -1, -1, false); + + 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); + + do_test_finished(); + } +}; + +function run_pac_test() { + var pac = 'data:text/plain,' + + 'function FindProxyForURL(url, host) {' + + ' return "PROXY foopy:8080; DIRECT";' + + '}'; + var uri = ios.newURI("http://www.mozilla.org/", null, null); + + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + + // Configure PAC + + prefs.setIntPref("network.proxy.type", 2); + prefs.setCharPref("network.proxy.autoconfig_url", pac); + + // Test it out (we expect no result yet since the PAC load is async) + var pi = pps.resolve(uri, 0); + do_check_eq(pi, null); + + // 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 ctx = pps.asyncResolve(uri, 0, new TestResolveCallback()); + do_test_pending(); +} + +function run_test() { + run_filter_test(); + run_filter_test2(); + run_pref_test(); + run_pac_test(); +} diff --git a/mozilla/netwerk/test/unit/test_sample.js b/mozilla/netwerk/test/unit/test_sample.js new file mode 100644 index 00000000000..6136433c5c3 --- /dev/null +++ b/mozilla/netwerk/test/unit/test_sample.js @@ -0,0 +1,45 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This is the most basic testcase. It just sets a timeout, and then exits the +// test harness when that timeout fires. This is meant to demonstrate that +// there is a complete event system available to test scripts. +function run_test() { + do_test_pending(); + do_timeout(1000, "do_test_finished();"); +} diff --git a/mozilla/xpfe/components/prefwindow/resources/content/pref-proxies.js b/mozilla/xpfe/components/prefwindow/resources/content/pref-proxies.js index fec1d75178a..f6513d9304f 100644 --- a/mozilla/xpfe/components/prefwindow/resources/content/pref-proxies.js +++ b/mozilla/xpfe/components/prefwindow/resources/content/pref-proxies.js @@ -116,12 +116,11 @@ function enableUnlockedElements(elements) } } -const nsIProtocolProxyService = Components.interfaces.nsIProtocolProxyService; -const kPROTPROX_CID = '{e9b301c0-e0e4-11D3-a1a8-0050041caf44}'; +const nsPIProtocolProxyService = Components.interfaces.nsPIProtocolProxyService; function ReloadPAC() { - var pps = Components.classesByID[kPROTPROX_CID] - .getService(nsIProtocolProxyService); + var pps = Components.classes["@mozilla.org/network/protocol-proxy-service;1"] + .getService(nsPIProtocolProxyService); pps.configureFromPAC(autoURL.value); }