fixes bug 224237 "PAC: make failover behave according to specification"
original patch by jerry.tan@sun.com with revisions by darin, r=biesi git-svn-id: svn://10.0.0.236/trunk@158673 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
8c5919cfec
commit
7e1bdbfb80
@ -598,6 +598,7 @@ pref("network.proxy.socks", "");
|
||||
pref("network.proxy.socks_port", 0);
|
||||
pref("network.proxy.socks_version", 5);
|
||||
pref("network.proxy.no_proxies_on", "localhost, 127.0.0.1");
|
||||
pref("network.proxy.failover_timeout", 1800); // 30 minutes
|
||||
pref("network.online", true); //online/offline
|
||||
pref("network.cookie.cookieBehavior", 3); // 0-Accept, 1-dontAcceptForeign, 2-dontUse, 3-p3p
|
||||
pref("network.cookie.disableCookieForMailNews", true); // disable all cookies for mail
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/* -*- 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
|
||||
*
|
||||
@ -20,6 +21,7 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* 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
|
||||
@ -36,20 +38,96 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIURI.idl"
|
||||
|
||||
interface nsIProxyInfo;
|
||||
interface nsIChannel;
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, uuid(91c4fe40-76c2-433f-9324-ffdae12df4b4)]
|
||||
/**
|
||||
* nsIProtocolProxyService provides methods to access information about
|
||||
* various network proxies.
|
||||
*/
|
||||
[scriptable, uuid(6b40d918-c01a-42a2-ab4d-4ea0b707f91f)]
|
||||
interface nsIProtocolProxyService : nsISupports
|
||||
{
|
||||
/**
|
||||
* This attribute indicates whether or not support for proxies is enabled.
|
||||
*/
|
||||
readonly attribute PRBool proxyEnabled;
|
||||
|
||||
/** Given a uri, return a proxyInfo */
|
||||
/**
|
||||
* This method returns a nsIProxyInfo instance that identifies a proxy to
|
||||
* be used for loading the given URL. Otherwise, this method returns null
|
||||
* indicating that a direct connection should be used.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to test.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** Return a proxyInfo with the given data */
|
||||
nsIProxyInfo newProxyInfo(in string type, in string host, in long port);
|
||||
/**
|
||||
* This method may be called to construct a nsIProxyInfo instance from
|
||||
* the given parameters. This method may be useful in conjunction with
|
||||
* nsISocketTransportService::createTransport for creating, for example,
|
||||
* a SOCKS connection.
|
||||
*
|
||||
* @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
|
||||
* possible.
|
||||
* @param aHost
|
||||
* The proxy hostname or IP address.
|
||||
* @param aPort
|
||||
* The proxy port.
|
||||
*/
|
||||
nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost, in long aPort);
|
||||
|
||||
void configureFromPAC(in string url);
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param aProxyInfo
|
||||
* The proxy that was unavailable.
|
||||
* @param aURI
|
||||
* The URI that was originally passed to ExamineForProxy.
|
||||
* @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.
|
||||
*
|
||||
* @throw NS_ERROR_NOT_AVAILABLE if there is no alternate proxy available.
|
||||
*/
|
||||
nsIProxyInfo getFailoverForProxy(in nsIProxyInfo aProxyInfo,
|
||||
in nsIURI aURI,
|
||||
in nsresult aReason);
|
||||
};
|
||||
|
||||
@ -38,26 +38,24 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/* This interface is PRIVATE.
|
||||
/**
|
||||
* This interface is PRIVATE.
|
||||
*
|
||||
* It is used as an opaque cookie, and this class may change at
|
||||
* any time without notice.
|
||||
*
|
||||
* @see nsIProtocolProxyService::GetProxyInfo
|
||||
* 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
|
||||
*/
|
||||
|
||||
native constCharPtr(const char*);
|
||||
|
||||
[scriptable, uuid(b65d22b0-1dd1-11b2-8f95-920e5b7b56f0)]
|
||||
interface nsIProxyInfo : nsISupports
|
||||
{
|
||||
[noscript, notxpcom] constCharPtr Host();
|
||||
[noscript, notxpcom] PRInt32 Port();
|
||||
[noscript, notxpcom] PRInt32 Port();
|
||||
[noscript, notxpcom] constCharPtr Type();
|
||||
|
||||
/**
|
||||
* proxy info objects may be chained if several proxies could be treated
|
||||
* equivalently. this is used to support proxy failover.
|
||||
*/
|
||||
readonly attribute nsIProxyInfo next;
|
||||
};
|
||||
|
||||
|
||||
@ -561,10 +561,10 @@ NS_CheckPortSafety(PRInt32 port,
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
NS_NewProxyInfo(const char *type,
|
||||
const char *host,
|
||||
PRInt32 port,
|
||||
nsIProxyInfo **result)
|
||||
NS_NewProxyInfo(const nsACString &type,
|
||||
const nsACString &host,
|
||||
PRInt32 port,
|
||||
nsIProxyInfo **result)
|
||||
{
|
||||
nsresult rv;
|
||||
static NS_DEFINE_CID(kPPSServiceCID, NS_PROTOCOLPROXYSERVICE_CID);
|
||||
|
||||
@ -75,36 +75,29 @@ class nsIOService : public nsIIOService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIIOService methods:
|
||||
NS_DECL_NSIIOSERVICE
|
||||
|
||||
// nsIObserver methods:
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// nsIOService methods:
|
||||
nsIOService();
|
||||
virtual ~nsIOService();
|
||||
nsIOService() NS_HIDDEN;
|
||||
~nsIOService() NS_HIDDEN;
|
||||
|
||||
static NS_METHOD
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
nsresult Init();
|
||||
nsresult NewURI(const char* aSpec, nsIURI* aBaseURI,
|
||||
nsIURI* *result, nsIProtocolHandler* *hdlrResult);
|
||||
NS_HIDDEN_(nsresult) Init();
|
||||
NS_HIDDEN_(nsresult) NewURI(const char* aSpec, nsIURI* aBaseURI,
|
||||
nsIURI* *result,
|
||||
nsIProtocolHandler* *hdlrResult);
|
||||
|
||||
protected:
|
||||
nsresult GetCachedProtocolHandler(const char *scheme,
|
||||
nsIProtocolHandler* *hdlrResult,
|
||||
PRUint32 start=0,
|
||||
PRUint32 end=0);
|
||||
nsresult CacheProtocolHandler(const char *scheme,
|
||||
nsIProtocolHandler* hdlr);
|
||||
NS_HIDDEN_(nsresult) GetCachedProtocolHandler(const char *scheme,
|
||||
nsIProtocolHandler* *hdlrResult,
|
||||
PRUint32 start=0,
|
||||
PRUint32 end=0);
|
||||
NS_HIDDEN_(nsresult) CacheProtocolHandler(const char *scheme,
|
||||
nsIProtocolHandler* hdlr);
|
||||
|
||||
// Prefs wrangling
|
||||
void PrefsChanged(nsIPrefBranch *prefs, const char *pref = nsnull);
|
||||
void GetPrefBranch(nsIPrefBranchInternal **);
|
||||
void ParsePortList(nsIPrefBranch *prefBranch, const char *pref, PRBool remove);
|
||||
NS_HIDDEN_(void) PrefsChanged(nsIPrefBranch *prefs, const char *pref = nsnull);
|
||||
NS_HIDDEN_(void) GetPrefBranch(nsIPrefBranchInternal **);
|
||||
NS_HIDDEN_(void) ParsePortList(nsIPrefBranch *prefBranch, const char *pref, PRBool remove);
|
||||
|
||||
protected:
|
||||
PRPackedBool mOffline;
|
||||
@ -126,5 +119,3 @@ public:
|
||||
};
|
||||
|
||||
#endif // nsIOService_h__
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; 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
|
||||
*
|
||||
@ -40,8 +41,8 @@
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIProxyAutoConfig.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranchInternal.h"
|
||||
@ -51,6 +52,16 @@
|
||||
#include "nsCRT.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "prlog.h"
|
||||
#if defined(PR_LOGGING)
|
||||
static PRLogModuleInfo *sLog = PR_NewLogModule("proxy");
|
||||
#endif
|
||||
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t')
|
||||
|
||||
//
|
||||
@ -118,11 +129,72 @@ proxy_GetIntPref(nsIPrefBranch *aPrefBranch,
|
||||
aResult = temp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
~nsProxyInfo()
|
||||
{
|
||||
NS_IF_RELEASE(mNext);
|
||||
}
|
||||
|
||||
nsProxyInfo(const char *type = nsnull)
|
||||
: mType(type)
|
||||
, mPort(-1)
|
||||
, mNext(nsnull)
|
||||
{}
|
||||
|
||||
const char *mType; // pointer to static kProxyType_XYZ value
|
||||
nsCString mHost;
|
||||
PRInt32 mPort;
|
||||
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_ISUPPORTS2(nsProtocolProxyService,
|
||||
nsIProtocolProxyService,
|
||||
nsIObserver)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsProtocolProxyService::nsProxyInfo,
|
||||
nsIProxyInfo)
|
||||
|
||||
nsProtocolProxyService::nsProtocolProxyService()
|
||||
: mUseProxy(0)
|
||||
@ -132,6 +204,8 @@ nsProtocolProxyService::nsProtocolProxyService()
|
||||
, mHTTPSProxyPort(-1)
|
||||
, mSOCKSProxyPort(-1)
|
||||
, mSOCKSProxyVersion(4)
|
||||
, mSessionStart(PR_Now())
|
||||
, mFailedProxyTimeout(30 * 60) // 30 minute default
|
||||
{
|
||||
}
|
||||
|
||||
@ -147,8 +221,12 @@ nsProtocolProxyService::~nsProtocolProxyService()
|
||||
nsresult
|
||||
nsProtocolProxyService::Init()
|
||||
{
|
||||
if (!mFailedProxies.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// failure to access prefs is non-fatal
|
||||
nsCOMPtr<nsIPrefBranchInternal> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
nsCOMPtr<nsIPrefBranchInternal> prefBranch =
|
||||
do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefBranch) {
|
||||
// monitor proxy prefs
|
||||
prefBranch->AddObserver("network.proxy", this, PR_FALSE);
|
||||
@ -156,6 +234,7 @@ nsProtocolProxyService::Init()
|
||||
// read all prefs
|
||||
PrefsChanged(prefBranch, nsnull);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -238,6 +317,9 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
||||
mSOCKSProxyVersion = 4;
|
||||
}
|
||||
|
||||
if (!pref || !strcmp(pref, "network.proxy.failover_timeout"))
|
||||
proxy_GetIntPref(prefBranch, "network.proxy.failover_timeout", mFailedProxyTimeout);
|
||||
|
||||
if (!pref || !strcmp(pref, "network.proxy.no_proxies_on")) {
|
||||
rv = prefBranch->GetCharPref("network.proxy.no_proxies_on",
|
||||
getter_Copies(tempString));
|
||||
@ -248,7 +330,7 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
||||
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(), mPACURL.get())))
|
||||
if (NS_SUCCEEDED(rv) && (!reloadPAC || strcmp(tempString.get(), mPACURI.get())))
|
||||
ConfigureFromPAC(tempString);
|
||||
}
|
||||
}
|
||||
@ -257,47 +339,47 @@ nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
|
||||
void* PR_CALLBACK
|
||||
nsProtocolProxyService::HandlePACLoadEvent(PLEvent* aEvent)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsProtocolProxyService *pps =
|
||||
(nsProtocolProxyService *) PL_GetEventOwner(aEvent);
|
||||
if (!pps) {
|
||||
NS_ERROR("HandlePACLoadEvent owner is null");
|
||||
return 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 NULL;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (pps->mPACURL.IsEmpty()) {
|
||||
if (pps->mPACURI.IsEmpty()) {
|
||||
NS_ERROR("HandlePACLoadEvent: js PACURL component is empty");
|
||||
return NULL;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIIOService> pIOService(do_GetIOService(&rv));
|
||||
if (!pIOService || NS_FAILED(rv)) {
|
||||
NS_ERROR("Cannot get IO Service");
|
||||
return NULL;
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("No IO service");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> pURI;
|
||||
rv = pIOService->NewURI(pps->mPACURL, nsnull, nsnull, getter_AddRefs(pURI));
|
||||
rv = ios->NewURI(pps->mPACURI, nsnull, nsnull, getter_AddRefs(pURI));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("New URI failed");
|
||||
return NULL;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
rv = pps->mPAC->LoadPACFromURI(pURI, pIOService);
|
||||
rv = pps->mPAC->LoadPACFromURI(pURI, ios);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Load PAC failed");
|
||||
return NULL;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void PR_CALLBACK
|
||||
@ -396,8 +478,6 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n
|
||||
{
|
||||
// see BNF in nsIProxyAutoConfig.idl
|
||||
|
||||
*result = nsnull;
|
||||
|
||||
// find end of proxy info delimiter
|
||||
const char *end = start;
|
||||
while (*end && *end != ';') ++end;
|
||||
@ -452,7 +532,7 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n
|
||||
pi->mType = type;
|
||||
// YES, it is ok to specify a null proxy host.
|
||||
if (host) {
|
||||
pi->mHost = PL_strndup(host, hostEnd - host);
|
||||
pi->mHost.Assign(host, hostEnd - host);
|
||||
pi->mPort = port;
|
||||
}
|
||||
NS_ADDREF(*result = pi);
|
||||
@ -464,6 +544,179 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, n
|
||||
return end;
|
||||
}
|
||||
|
||||
void
|
||||
nsProtocolProxyService::GetProxyKey(nsProxyInfo *pi, nsCString &key)
|
||||
{
|
||||
key.AssignASCII(pi->mType);
|
||||
if (!pi->mHost.IsEmpty()) {
|
||||
key.Append(' ');
|
||||
key.Append(pi->mHost);
|
||||
key.Append(':');
|
||||
key.AppendInt(pi->mPort);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsProtocolProxyService::SecondsSinceSessionStart()
|
||||
{
|
||||
PRTime now = PR_Now();
|
||||
|
||||
// get time elapsed since session start
|
||||
PRInt64 diff;
|
||||
LL_SUB(diff, now, mSessionStart);
|
||||
|
||||
// convert microseconds to seconds
|
||||
PRTime ups;
|
||||
LL_I2L(ups, PR_USEC_PER_SEC);
|
||||
LL_DIV(diff, diff, ups);
|
||||
|
||||
// convert to 32 bit value
|
||||
PRUint32 dsec;
|
||||
LL_L2UI(dsec, diff);
|
||||
|
||||
return dsec;
|
||||
}
|
||||
|
||||
void
|
||||
nsProtocolProxyService::EnableProxy(nsProxyInfo *pi)
|
||||
{
|
||||
nsCAutoString key;
|
||||
GetProxyKey(pi, key);
|
||||
mFailedProxies.Remove(key);
|
||||
}
|
||||
|
||||
void
|
||||
nsProtocolProxyService::DisableProxy(nsProxyInfo *pi)
|
||||
{
|
||||
nsCAutoString key;
|
||||
GetProxyKey(pi, key);
|
||||
|
||||
PRUint32 dsec = SecondsSinceSessionStart();
|
||||
|
||||
// Add timeout to interval (this is the time when the proxy can
|
||||
// be tried again).
|
||||
dsec += mFailedProxyTimeout;
|
||||
|
||||
// NOTE: The classic codebase would increase the timeout value
|
||||
// incrementally each time a subsequent failure occured.
|
||||
// We could do the same, but it would require that we not
|
||||
// remove proxy entries in IsProxyDisabled or otherwise
|
||||
// change the way we are recording disabled proxies.
|
||||
// Simpler is probably better for now, and at least the
|
||||
// user can tune the timeout setting via preferences.
|
||||
|
||||
LOG(("DisableProxy %s %d\n", key.get(), dsec));
|
||||
|
||||
// If this fails, oh well... means we don't have enough memory
|
||||
// to remember the failed proxy.
|
||||
mFailedProxies.Put(key, dsec);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi)
|
||||
{
|
||||
nsCAutoString key;
|
||||
GetProxyKey(pi, key);
|
||||
|
||||
PRUint32 val;
|
||||
if (!mFailedProxies.Get(key, &val))
|
||||
return PR_FALSE;
|
||||
|
||||
PRUint32 dsec = SecondsSinceSessionStart();
|
||||
|
||||
// if time passed has exceeded interval, then try proxy again.
|
||||
if (dsec > val) {
|
||||
mFailedProxies.Remove(key);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsProxyInfo *
|
||||
nsProtocolProxyService::BuildProxyList(const char *proxies,
|
||||
PRBool permitHttp,
|
||||
PRBool pruneDisabledProxies)
|
||||
{
|
||||
nsProxyInfo *pi = nsnull, *first = nsnull, *last = nsnull;
|
||||
while (*proxies) {
|
||||
proxies = ExtractProxyInfo(proxies, permitHttp, &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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// nsIProtocolProxyService
|
||||
NS_IMETHODIMP
|
||||
nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult)
|
||||
@ -490,68 +743,42 @@ nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult)
|
||||
// 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)
|
||||
return ExaminePACForProxy(aURI, flags, aResult);
|
||||
|
||||
// proxy info values
|
||||
const char *type = nsnull;
|
||||
char *host = nsnull;
|
||||
const nsACString *host = nsnull;
|
||||
PRInt32 port = -1;
|
||||
|
||||
// Proxy auto config magic...
|
||||
if (2 == mUseProxy) {
|
||||
if (!mPAC) {
|
||||
NS_ERROR("ERROR: PAC js component is null, assuming DIRECT");
|
||||
return NS_OK; // assume DIRECT connection for now
|
||||
}
|
||||
|
||||
nsCAutoString proxyStr;
|
||||
rv = mPAC->GetProxyForURI(aURI, proxyStr);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool permitHttp = (flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP);
|
||||
nsProxyInfo *pi, *last = nsnull;
|
||||
const char *p = proxyStr.get();
|
||||
while (*p) {
|
||||
p = ExtractProxyInfo(p, permitHttp, &pi);
|
||||
if (pi) {
|
||||
if (last)
|
||||
last->mNext = pi;
|
||||
else
|
||||
NS_ADDREF(*aResult = pi);
|
||||
last = pi;
|
||||
}
|
||||
}
|
||||
// if only DIRECT was specified then return no proxy info.
|
||||
if (last && *aResult == last && last->mType == kProxyType_DIRECT)
|
||||
NS_RELEASE(*aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 &&
|
||||
scheme.EqualsLiteral("http")) {
|
||||
host = ToNewCString(mHTTPProxyHost);
|
||||
host = &mHTTPProxyHost;
|
||||
type = kProxyType_HTTP;
|
||||
port = mHTTPProxyPort;
|
||||
}
|
||||
else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 &&
|
||||
scheme.EqualsLiteral("https")) {
|
||||
host = ToNewCString(mHTTPSProxyHost);
|
||||
host = &mHTTPSProxyHost;
|
||||
type = kProxyType_HTTP;
|
||||
port = mHTTPSProxyPort;
|
||||
}
|
||||
else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 &&
|
||||
scheme.EqualsLiteral("ftp")) {
|
||||
host = ToNewCString(mFTPProxyHost);
|
||||
host = &mFTPProxyHost;
|
||||
type = kProxyType_HTTP;
|
||||
port = mFTPProxyPort;
|
||||
}
|
||||
else if (!mGopherProxyHost.IsEmpty() && mGopherProxyPort > 0 &&
|
||||
scheme.EqualsLiteral("gopher")) {
|
||||
host = ToNewCString(mGopherProxyHost);
|
||||
host = &mGopherProxyHost;
|
||||
type = kProxyType_HTTP;
|
||||
port = mGopherProxyPort;
|
||||
}
|
||||
else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) {
|
||||
host = ToNewCString(mSOCKSProxyHost);
|
||||
host = &mSOCKSProxyHost;
|
||||
if (mSOCKSProxyVersion == 4)
|
||||
type = kProxyType_SOCKS4;
|
||||
else
|
||||
@ -560,14 +787,14 @@ nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult)
|
||||
}
|
||||
|
||||
if (type)
|
||||
return NewProxyInfo_Internal(type, host, port, aResult);
|
||||
return NewProxyInfo_Internal(type, *host, port, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProtocolProxyService::NewProxyInfo(const char *aType,
|
||||
const char *aHost,
|
||||
nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
|
||||
const nsACString &aHost,
|
||||
PRInt32 aPort,
|
||||
nsIProxyInfo **aResult)
|
||||
{
|
||||
@ -581,7 +808,7 @@ nsProtocolProxyService::NewProxyInfo(const char *aType,
|
||||
// proxy info instance. we just reference the string literals directly :)
|
||||
const char *type = nsnull;
|
||||
for (PRUint32 i=0; i<NS_ARRAY_LENGTH(types); ++i) {
|
||||
if (PL_strcasecmp(aType, types[i]) == 0) {
|
||||
if (aType.LowerCaseEqualsASCII(types[i]) == 0) {
|
||||
type = types[i];
|
||||
break;
|
||||
}
|
||||
@ -591,33 +818,27 @@ nsProtocolProxyService::NewProxyInfo(const char *aType,
|
||||
if (aPort <= 0)
|
||||
aPort = -1;
|
||||
|
||||
return NewProxyInfo_Internal(type, nsCRT::strdup(aHost), aPort, aResult);
|
||||
return NewProxyInfo_Internal(type, aHost, aPort, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProtocolProxyService::ConfigureFromPAC(const char *url)
|
||||
nsProtocolProxyService::ConfigureFromPAC(const nsACString &aURI)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
mPACURL.Assign(url);
|
||||
mPACURI = aURI;
|
||||
mFailedProxies.Clear();
|
||||
|
||||
/* now we need to setup a callback from the main ui thread
|
||||
in which we will load the pac file from the specified
|
||||
url. loading it now, in the current thread results in a
|
||||
browser crash */
|
||||
nsresult rv;
|
||||
|
||||
// get event queue service
|
||||
nsCOMPtr<nsIEventQueueService> eqs =
|
||||
do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID);
|
||||
if (!eqs) {
|
||||
NS_ERROR("Failed to get EventQueue service");
|
||||
return 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 ui thread's event queue
|
||||
// get current thread's event queue
|
||||
nsCOMPtr<nsIEventQueue> eq = nsnull;
|
||||
rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq));
|
||||
if (NS_FAILED(rv) || !eqs) {
|
||||
NS_ERROR("Failed to get UI EventQueue");
|
||||
rv = NS_GetCurrentEventQ(getter_AddRefs(eq));
|
||||
if (NS_FAILED(rv) || !eq) {
|
||||
NS_ERROR("Failed to get current event queue");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -643,7 +864,46 @@ NS_IMETHODIMP
|
||||
nsProtocolProxyService::GetProxyEnabled(PRBool *enabled)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(enabled);
|
||||
*enabled = mUseProxy;
|
||||
*enabled = (mUseProxy != 0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy,
|
||||
nsIURI *aURI,
|
||||
nsresult aStatus,
|
||||
nsIProxyInfo **aResult)
|
||||
{
|
||||
// We only support failover when a PAC file is configured.
|
||||
if (mUseProxy != 2)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// Verify that |aProxy| is one of our nsProxyInfo objects.
|
||||
nsProxyInfo *pi = nsnull;
|
||||
aProxy->QueryInterface(kProxyInfoID, (void **) &pi);
|
||||
if (!pi)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
// OK, the QI checked out. We can proceed. Release the extra reference
|
||||
// acquired by the call to QI now so we don't have to worry about it later.
|
||||
// Moreover, call Release on |aProxy| instead of |pi| since we are going to
|
||||
// use |pi| directly from now on.
|
||||
aProxy->Release();
|
||||
|
||||
// Remember that this proxy is down.
|
||||
DisableProxy(pi);
|
||||
|
||||
// NOTE: At this point, we might want to prompt the user if we have
|
||||
// not already tried going DIRECT. This is something that the
|
||||
// classic codebase supported; however, IE6 does not prompt.
|
||||
|
||||
if (!pi->mNext)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
LOG(("PAC failover from %s %s:%d to %s %s:%d\n",
|
||||
pi->mType, pi->mHost.get(), pi->mPort,
|
||||
pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort));
|
||||
|
||||
NS_ADDREF(*aResult = pi->mNext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -779,7 +1039,7 @@ nsProtocolProxyService::LoadFilters(const char *filters)
|
||||
#endif
|
||||
|
||||
mFiltersArray.AppendElement(hinfo);
|
||||
hinfo = NULL;
|
||||
hinfo = nsnull;
|
||||
loser:
|
||||
if (hinfo)
|
||||
delete hinfo;
|
||||
@ -793,13 +1053,11 @@ nsProtocolProxyService::GetProtocolInfo(const char *aScheme,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mIOService) {
|
||||
mIOService = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
rv = mIOService->GetProtocolHandler(aScheme, getter_AddRefs(handler));
|
||||
rv = ios->GetProtocolHandler(aScheme, getter_AddRefs(handler));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = handler->GetProtocolFlags(&aFlags);
|
||||
@ -810,12 +1068,11 @@ nsProtocolProxyService::GetProtocolInfo(const char *aScheme,
|
||||
|
||||
nsresult
|
||||
nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
|
||||
char *aHost,
|
||||
const nsACString &aHost,
|
||||
PRInt32 aPort,
|
||||
nsIProxyInfo **aResult)
|
||||
{
|
||||
nsProxyInfo *proxyInfo = nsnull;
|
||||
NS_NEWXPCOM(proxyInfo, nsProxyInfo);
|
||||
nsProxyInfo *proxyInfo = new nsProxyInfo();
|
||||
if (!proxyInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
|
||||
@ -41,16 +41,23 @@
|
||||
#include "plevent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIProtocolProxyService.h"
|
||||
#include "nsIProxyAutoConfig.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "prtime.h"
|
||||
#include "prmem.h"
|
||||
#include "prio.h"
|
||||
|
||||
typedef nsDataHashtable<nsCStringHashKey, PRUint32> nsFailedProxyTable;
|
||||
|
||||
class nsProxyInfo;
|
||||
|
||||
class nsProtocolProxyService : public nsIProtocolProxyService
|
||||
, public nsIObserver
|
||||
{
|
||||
@ -59,56 +66,27 @@ public:
|
||||
NS_DECL_NSIPROTOCOLPROXYSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsProtocolProxyService();
|
||||
virtual ~nsProtocolProxyService();
|
||||
nsProtocolProxyService() NS_HIDDEN;
|
||||
~nsProtocolProxyService() NS_HIDDEN;
|
||||
|
||||
nsresult Init();
|
||||
NS_HIDDEN_(nsresult) Init();
|
||||
|
||||
void PrefsChanged(nsIPrefBranch *, const char* pref);
|
||||
|
||||
class nsProxyInfo : public nsIProxyInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD_(const char*) Host() {
|
||||
return mHost;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(PRInt32) Port() {
|
||||
return mPort;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(const char*) Type() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetNext(nsIProxyInfo **result) {
|
||||
NS_IF_ADDREF(*result = mNext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual ~nsProxyInfo() {
|
||||
if (mHost) nsMemory::Free(mHost);
|
||||
}
|
||||
|
||||
nsProxyInfo() : mType(nsnull), mHost(nsnull), mPort(-1) {
|
||||
}
|
||||
|
||||
const char *mType;
|
||||
char *mHost; // owning reference
|
||||
PRInt32 mPort;
|
||||
nsCOMPtr<nsIProxyInfo> mNext;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
const char *ExtractProxyInfo(const char *proxy, PRBool permitHttp, nsProxyInfo **);
|
||||
|
||||
nsresult GetProtocolInfo(const char *scheme, PRUint32 &flags, PRInt32 &defaultPort);
|
||||
nsresult NewProxyInfo_Internal(const char *type, char *host, PRInt32 port, nsIProxyInfo **);
|
||||
void LoadFilters(const char *filters);
|
||||
PRBool CanUseProxy(nsIURI *aURI, PRInt32 defaultPort);
|
||||
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, nsIProxyInfo **);
|
||||
NS_HIDDEN_(void) LoadFilters(const char *filters);
|
||||
NS_HIDDEN_(PRBool) CanUseProxy(nsIURI *aURI, PRInt32 defaultPort);
|
||||
|
||||
static PRBool PR_CALLBACK CleanupFilterArray(void *aElement, void *aData);
|
||||
static void* PR_CALLBACK HandlePACLoadEvent(PLEvent* aEvent);
|
||||
@ -150,31 +128,31 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
nsVoidArray mFiltersArray;
|
||||
nsVoidArray mFiltersArray;
|
||||
PRUint16 mUseProxy;
|
||||
|
||||
nsCOMPtr<nsIIOService> mIOService;
|
||||
nsCString mHTTPProxyHost;
|
||||
PRInt32 mHTTPProxyPort;
|
||||
|
||||
PRUint16 mUseProxy;
|
||||
nsCString mFTPProxyHost;
|
||||
PRInt32 mFTPProxyPort;
|
||||
|
||||
nsCString mHTTPProxyHost;
|
||||
PRInt32 mHTTPProxyPort;
|
||||
nsCString mGopherProxyHost;
|
||||
PRInt32 mGopherProxyPort;
|
||||
|
||||
nsCString mFTPProxyHost;
|
||||
PRInt32 mFTPProxyPort;
|
||||
|
||||
nsCString mGopherProxyHost;
|
||||
PRInt32 mGopherProxyPort;
|
||||
|
||||
nsCString mHTTPSProxyHost;
|
||||
PRInt32 mHTTPSProxyPort;
|
||||
nsCString mHTTPSProxyHost;
|
||||
PRInt32 mHTTPSProxyPort;
|
||||
|
||||
nsCString mSOCKSProxyHost;
|
||||
PRInt32 mSOCKSProxyPort;
|
||||
PRInt32 mSOCKSProxyVersion;
|
||||
nsCString mSOCKSProxyHost;
|
||||
PRInt32 mSOCKSProxyPort;
|
||||
PRInt32 mSOCKSProxyVersion;
|
||||
|
||||
nsCOMPtr<nsIProxyAutoConfig> mPAC;
|
||||
nsCString mPACURL;
|
||||
nsCString mPACURI;
|
||||
|
||||
PRTime mSessionStart;
|
||||
nsFailedProxyTable mFailedProxies;
|
||||
PRInt32 mFailedProxyTimeout;
|
||||
};
|
||||
|
||||
#endif // !nsProtocolProxyService_h__
|
||||
|
||||
|
||||
@ -895,28 +895,36 @@ nsHttpChannel::ProxyFailover()
|
||||
{
|
||||
LOG(("nsHttpChannel::ProxyFailover [this=%x]\n", this));
|
||||
|
||||
NS_ASSERTION(mConnectionInfo->ProxyInfo(), "no proxy info");
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIProtocolProxyService> pps =
|
||||
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIProxyInfo> pi;
|
||||
mConnectionInfo->ProxyInfo()->GetNext(getter_AddRefs(pi));
|
||||
// if null result, then bail...
|
||||
if (!pi)
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = pps->GetFailoverForProxy(mConnectionInfo->ProxyInfo(), mURI, mStatus,
|
||||
getter_AddRefs(pi));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = gHttpHandler->NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
SetupReplacementChannel(mURI, newChannel, PR_TRUE);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// open new channel
|
||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mStatus = NS_BINDING_REDIRECTED;
|
||||
mListener = nsnull;
|
||||
mListenerContext = nsnull;
|
||||
}
|
||||
}
|
||||
rv = SetupReplacementChannel(mURI, newChannel, PR_TRUE);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// open new channel
|
||||
rv = newChannel->AsyncOpen(mListener, mListenerContext);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mStatus = NS_BINDING_REDIRECTED;
|
||||
mListener = nsnull;
|
||||
mListenerContext = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -3557,8 +3565,10 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
}
|
||||
|
||||
// on proxy errors, try to failover
|
||||
if (mStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
|
||||
mStatus == NS_ERROR_UNKNOWN_PROXY_HOST) {
|
||||
if (mConnectionInfo->ProxyInfo() &&
|
||||
(mStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
|
||||
mStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
|
||||
mStatus == NS_ERROR_NET_TIMEOUT)) {
|
||||
if (NS_SUCCEEDED(ProxyFailover()))
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user