fixes bug 84798 "PAC: Failover does not work" r=dougt sr=alecf

This commit is contained in:
darin%netscape.com 2003-04-15 23:07:12 +00:00
Родитель 5cd17198b5
Коммит a9f3b48e39
11 изменённых файлов: 338 добавлений и 195 удалений

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

@ -20,6 +20,9 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gagan Saksena <gagan@netscape.com> (original author)
* Denis Antrushin <adu@sparc.spb.su>
* Darin Fisher <darin@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,18 +38,18 @@
*
* ***** END LICENSE BLOCK ***** */
/**
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
hacks of proxy auto config.
- Gagan Saksena 04/23/00
*/
#include "nsISupports.idl"
/**
* The nsIProxyAutoConfig interface is used for setting arbitrary proxy
* configurations based on the specified URL.
*
* Note this interface wraps (at least in a the implementation) the older
* hacks of proxy auto config.
*
* - Gagan Saksena 04/23/00
*/
interface nsIURI;
interface nsIIOService;
@ -54,26 +57,35 @@ interface nsIIOService;
interface nsIProxyAutoConfig : nsISupports
{
/**
* Get the proxy for the specified host
*/
void ProxyForURL(in nsIURI uri, out string host, out long port, out string type);
* Get the proxy string for the specified URI. The proxy string is
* given by the following BNF:
*
* result = proxy-spec *( proxy-sep proxy-spec )
* proxy-spec = direct-type | proxy-type LWS proxy-host [":" proxy-port]
* direct-type = "DIRECT"
* proxy-type = "PROXY" | "SOCKS" | "SOCKS4" | "SOCKS5"
* proxy-sep = ";" LWS
* proxy-host = hostname | ipv4-address-literal
* proxy-port = <any 16-bit unsigned integer>
* LWS = *( SP | HT )
* SP = <US-ASCII SP, space (32)>
* HT = <US-ASCII HT, horizontal-tab (9)>
*
* NOTE: direct-type and proxy-type are case insensitive
* NOTE: SOCKS implies SOCKS4
*
* Examples:
* "PROXY proxy1.foo.com:8080; PROXY proxy2.foo.com:8080; DIRECT"
* "SOCKS socksproxy"
* "DIRECT"
*
* XXX add support for IPv6 address literals.
* XXX quote whatever the official standard is for PAC.
*/
ACString getProxyForURI(in nsIURI aURI);
/**
* Load the PAC file from the specified URI
*/
void LoadPACFromURL(in nsIURI uri, in nsIIOService ioService);
* Load the PAC file from the specified URI
*/
void loadPACFromURI(in nsIURI aURI, in nsIIOService ioService);
};
%{C++
#define NS_PROXY_AUTO_CONFIG_CID \
{ /* 63ac8c66-1dd2-11b2-b070-84d00d3eaece */ \
0x63ac8c66, \
0x1dd2, \
0x11b2, \
{0xb0, 0x70, 0x84, 0xd0, 0x0d, 0x3e, 0xae, 0xce} \
}
#define NS_PROXY_AUTO_CONFIG_CONTRACTID \
"@mozilla.org/network/proxy_autoconfig;1"
%}

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

@ -53,5 +53,11 @@ interface nsIProxyInfo : nsISupports
[noscript, notxpcom] constCharPtr Host();
[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;
};

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

@ -347,7 +347,19 @@ nsInputStreamPump::OnStateStart()
{
LOG((" OnStateStart [this=%x]\n", this));
nsresult rv = mListener->OnStartRequest(this, mListenerContext);
nsresult rv;
// need to check the reason why the stream is ready. this is required
// so our listener can check our status from OnStartRequest.
// XXX async streams should have a GetStatus method!
if (NS_SUCCEEDED(mStatus)) {
PRUint32 avail;
rv = mAsyncStream->Available(&avail);
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_CLOSED)
mStatus = rv;
}
rv = mListener->OnStartRequest(this, mListenerContext);
// an error returned from OnStartRequest should cause us to abort; however,
// we must not stomp on mStatus if already canceled.
@ -441,6 +453,7 @@ nsInputStreamPump::OnStateTransfer()
// if stream is now closed, advance to STATE_STOP right away.
// Available may return 0 bytes available at the moment; that
// would not mean that we are done.
// XXX async streams should have a GetStatus method!
rv = mAsyncStream->Available(&avail);
if (NS_SUCCEEDED(rv))
return STATE_TRANSFER;

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

@ -121,9 +121,9 @@ nsProtocolProxyService::~nsProtocolProxyService()
// nsProtocolProxyService methods
nsresult
nsProtocolProxyService::Init() {
nsresult rv = NS_OK;
nsProtocolProxyService::Init()
{
nsresult rv;
mPrefs = do_GetService(kPrefServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
@ -264,7 +264,7 @@ nsProtocolProxyService::HandlePACLoadEvent(PLEvent* aEvent)
}
// create pac js component
pps->mPAC = do_CreateInstance(NS_PROXY_AUTO_CONFIG_CONTRACTID, &rv);
pps->mPAC = do_CreateInstance(NS_PROXYAUTOCONFIG_CONTRACTID, &rv);
if (!pps->mPAC || NS_FAILED(rv)) {
NS_ERROR("Cannot load PAC js component");
return NULL;
@ -281,14 +281,14 @@ nsProtocolProxyService::HandlePACLoadEvent(PLEvent* aEvent)
return NULL;
}
nsCOMPtr<nsIURI> pURL;
rv = pIOService->NewURI(pps->mPACURL, nsnull, nsnull, getter_AddRefs(pURL));
nsCOMPtr<nsIURI> pURI;
rv = pIOService->NewURI(pps->mPACURL, nsnull, nsnull, getter_AddRefs(pURI));
if (NS_FAILED(rv)) {
NS_ERROR("New URI failed");
return NULL;
}
rv = pps->mPAC->LoadPACFromURL(pURL, pIOService);
rv = pps->mPAC->LoadPACFromURI(pURI, pIOService);
if (NS_FAILED(rv)) {
NS_ERROR("Load PAC failed");
return NULL;
@ -381,9 +381,88 @@ nsProtocolProxyService::CanUseProxy(nsIURI *aURI, PRInt32 defaultPort)
return PR_TRUE;
}
static const char kProxyType_HTTP[] = "http";
static const char kProxyType_PROXY[] = "proxy";
static const char kProxyType_SOCKS[] = "socks";
static const char kProxyType_SOCKS4[] = "socks4";
static const char kProxyType_SOCKS5[] = "socks5";
static const char kProxyType_DIRECT[] = "direct";
const char *
nsProtocolProxyService::ExtractProxyInfo(const char *start, PRBool permitHttp, nsProxyInfo **result)
{
// see BNF in nsIProxyAutoConfig.idl
*result = nsnull;
// find end of proxy info delimiter
const char *end = start;
while (*end && *end != ';') ++end;
// find end of proxy type delimiter
const char *sp = start;
while (sp < end && *sp != ' ' && *sp != '\t') ++sp;
PRUint32 len = sp - start;
const char *type = nsnull;
switch (len) {
case 5:
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
break;
case 6:
if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0)
type = kProxyType_DIRECT;
else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0)
type = kProxyType_SOCKS4;
else if (PL_strncasecmp(start, kProxyType_SOCKS5, 6) == 0)
type = kProxyType_SOCKS5;
break;
}
if (type) {
const char *host = nsnull, *hostEnd;
PRInt32 port = -1;
// extract host:port
start = sp;
while ((*start == ' ' || *start == '\t') && start < end)
start++;
if (start < end) {
host = start;
hostEnd = strchr(host, ':');
if (!hostEnd || hostEnd > end) {
hostEnd = end;
// no port, so assume default
if (type == kProxyType_HTTP)
port = 80;
else
port = 1080;
}
else
port = atoi(hostEnd + 1);
}
nsProxyInfo *pi = new nsProxyInfo;
if (pi) {
pi->mType = type;
// YES, it is ok to specify a null proxy host.
if (host) {
pi->mHost = PL_strndup(host, hostEnd - host);
pi->mPort = port;
}
NS_ADDREF(*result = pi);
}
}
while (*end == ';' || *end == ' ' || *end == '\t')
++end;
return end;
}
// nsIProtocolProxyService
NS_IMETHODIMP
nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo* *aResult) {
nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo **aResult)
{
nsresult rv = NS_OK;
NS_ASSERTION(aURI, "need a uri folks.");
@ -419,33 +498,26 @@ nsProtocolProxyService::ExamineForProxy(nsIURI *aURI, nsIProxyInfo* *aResult) {
return NS_OK; // assume DIRECT connection for now
}
nsXPIDLCString rawType; // XXX an enum might make better sense here
rv = mPAC->ProxyForURL(aURI, &host, &port, getter_Copies(rawType));
if (NS_SUCCEEDED(rv) && rawType && host) {
//
// Accept only known values for the proxy type
//
if (PL_strcasecmp(rawType, "http") == 0) {
if (flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)
type = "http";
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;
}
}
else if (PL_strcasecmp(rawType, "socks") == 0)
type = "socks";
else if (PL_strcasecmp(rawType, "socks4") == 0)
type = "socks4";
// if only DIRECT was specified then return no proxy info.
if (last && *aResult == last && last->mType == kProxyType_DIRECT)
NS_RELEASE(*aResult);
}
if (type) {
if (port <= 0)
port = -1;
return NewProxyInfo_Internal(type, host, port, aResult);
}
// assume errors mean direct - its better than just failing, and
// the js conosle will have the specific error
if (host)
nsMemory::Free(host);
return NS_OK;
}

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

@ -80,6 +80,11 @@ public:
return mType;
}
NS_IMETHOD GetNext(nsIProxyInfo **result) {
NS_IF_ADDREF(*result = mNext);
return NS_OK;
}
virtual ~nsProxyInfo() {
if (mHost) nsMemory::Free(mHost);
}
@ -87,13 +92,16 @@ public:
nsProxyInfo() : mType(nsnull), mHost(nsnull), mPort(-1) {
}
const char *mType;
char *mHost;
PRInt32 mPort;
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 GetStringPref(const char *pref, nsCString &result);

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

@ -42,7 +42,7 @@
- Gagan Saksena 04/24/00
*/
const kPAC_CONTRACTID = "@mozilla.org/network/proxy_autoconfig;1";
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_CID = Components.ID("{63ac8c66-1dd2-11b2-b070-84d00d3eaece}");
@ -67,59 +67,19 @@ nsProxyAutoConfig.prototype = {
sis: null,
done: false,
ProxyForURL: function(url, host, port, type) {
/* If we're not done loading the pac yet, wait (ideally). For
now, just return DIRECT to avoid loops. A simple mutex
between ProxyForURL and LoadPACFromURL locks-up the
browser. */
if (!this.done) {
host.value = null;
type.value = "direct";
return;
}
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;
var uri = url.QueryInterface(Components.interfaces.nsIURI);
// Call the original function-
var proxy = LocalFindProxyForURL(uri.spec, uri.host);
if(proxy == null) {
return;
}
/* we ignore everything else past the first proxy.
we could theoretically check isResolvable now and continue
parsing (see bug 84798). but for now... */
proxy = proxy.split(";")[0];
// direct connection (no proxy)
if ( proxy.search(/^\s*DIRECT\s*$/i) != -1 ) {
host.value = null;
type.value = "direct";
}
else {
// split proxy string to find proxy type, proxy host and port number
var typehostport = /^\s*(\w+)\s+([^:]+)(:\d+)?/(proxy);
if(typehostport != null) {
host.value = typehostport[2];
typehostport[1] = typehostport[1].toUpperCase();
switch(typehostport[1]) {
case "PROXY": // http PROXY
// assume port 80 if port number not specified (see bug 91630)
port.value = (typehostport[3] != null)? typehostport[3].substr(1): 80;
type.value = "http";
break;
case "SOCKS": // SOCKS v4
// assume port 1080 like NN4 if port number not specified
port.value = (typehostport[3] != null)? typehostport[3].substr(1): 1080;
type.value = "socks4";
break;
// Currently only SOCKS v4 is supported (see bug 78176)
}
}
}
return LocalFindProxyForURL(uri.spec, uri.host);
},
LoadPACFromURL: function(uri, ioService) {
loadPACFromURI: function(uri, ioService) {
this.done = false;
var channel = ioService.newChannelFromURI(uri);
// don't cache the PAC content
@ -152,7 +112,7 @@ nsProxyAutoConfig.prototype = {
'init');
},
onStopRequest: function(request, ctxt, status, errorMsg) {
onStopRequest: function(request, ctxt, status) {
if(!ProxySandBox) {
ProxySandBox = new Sandbox();
}
@ -205,7 +165,7 @@ pacModule.registerSelf =
function (compMgr, fileSpec, location, type) {
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
compMgr.registerFactoryLocation(kPAC_CID,
"Proxy Auto Config",
"nsProxyAutoConfig",
kPAC_CONTRACTID,
fileSpec,
location,

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

@ -666,7 +666,8 @@ nsSocketTransport::Init(const char **types, PRUint32 typeCount,
mProxyHost = proxyInfo->Host();
// grab proxy type (looking for "socks" for example)
proxyType = proxyInfo->Type();
if (proxyType && strcmp(proxyType, "http") == 0)
if (proxyType && (strcmp(proxyType, "http") == 0 ||
strcmp(proxyType, "direct") == 0))
proxyType = nsnull;
}

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

@ -70,6 +70,19 @@
{0xa1, 0xa8, 0x0, 0x50, 0x4, 0x1c, 0xaf, 0x44} \
}
// service implementing nsIProxyAutoConfig.
#define NS_PROXYAUTOCONFIG_CLASSNAME \
"nsProxyAutoConfig"
#define NS_PROXYAUTOCONFIG_CONTRACTID \
"@mozilla.org/network/proxy-auto-config;1"
#define NS_PROXYAUTOCONFIG_CID \
{ /* 63ac8c66-1dd2-11b2-b070-84d00d3eaece */ \
0x63ac8c66, \
0x1dd2, \
0x11b2, \
{0xb0, 0x70, 0x84, 0xd0, 0x0d, 0x3e, 0xae, 0xce} \
}
// component implementing nsILoadGroup.
#define NS_LOADGROUP_CLASSNAME \
"nsLoadGroup"

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

@ -799,6 +799,36 @@ nsHttpChannel::PromptTempRedirect()
return rv;
}
nsresult
nsHttpChannel::ProxyFailover()
{
LOG(("nsHttpChannel::ProxyFailover [this=%x]\n", this));
NS_ASSERTION(mConnectionInfo->ProxyInfo(), "no proxy info");
nsCOMPtr<nsIProxyInfo> pi;
mConnectionInfo->ProxyInfo()->GetNext(getter_AddRefs(pi));
// if null result, then bail...
if (!pi)
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsIChannel> newChannel;
rv = gHttpHandler->NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel));
if (NS_SUCCEEDED(rv)) {
SetupReplacementChannel(mURI, newChannel, PR_TRUE);
// open new channel
rv = newChannel->AsyncOpen(mListener, mListenerContext);
if (NS_SUCCEEDED(rv)) {
mStatus = NS_BINDING_REDIRECTED;
mListener = nsnull;
mListenerContext = nsnull;
}
}
return rv;
}
//-----------------------------------------------------------------------------
// nsHttpChannel <byte-range>
//-----------------------------------------------------------------------------
@ -1519,6 +1549,82 @@ nsHttpChannel::InstallCacheListener(PRUint32 offset)
// nsHttpChannel <redirect>
//-----------------------------------------------------------------------------
nsresult
nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
nsIChannel *newChannel,
PRBool preserveMethod)
{
PRUint32 newLoadFlags = mLoadFlags | LOAD_REPLACE;
// if the original channel was using SSL and this channel is not using
// SSL, then no need to inhibit persistent caching. however, if the
// original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
// set, then allow the flag to apply to the redirected channel as well.
// since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
// we only need to check if the original channel was using SSL.
if (mConnectionInfo->UsingSSL())
newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
newChannel->SetOriginalURI(mOriginalURI);
newChannel->SetLoadGroup(mLoadGroup);
newChannel->SetNotificationCallbacks(mCallbacks);
newChannel->SetLoadFlags(newLoadFlags);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
if (!httpChannel)
return NS_OK; // no other options to set
if (preserveMethod) {
nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(httpChannel);
if (mUploadStream && uploadChannel) {
// rewind upload stream
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
if (seekable)
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
// replicate original call to SetUploadStream...
if (mUploadStreamHasHeaders)
uploadChannel->SetUploadStream(mUploadStream, NS_LITERAL_CSTRING(""), -1);
else {
const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
const char *clen = mRequestHead.PeekHeader(nsHttp::Content_Length);
if (ctype && clen)
uploadChannel->SetUploadStream(mUploadStream,
nsDependentCString(ctype),
atoi(clen));
}
}
// must happen after setting upload stream since SetUploadStream
// may change the request method.
httpChannel->SetRequestMethod(nsDependentCString(mRequestHead.Method()));
}
// convey the referrer if one was used for this channel to the next one
if (mReferrer)
httpChannel->SetReferrer(mReferrer);
// convey the mAllowPipelining flag
httpChannel->SetAllowPipelining(mAllowPipelining);
// convey the new redirection limit
httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
if (httpInternal) {
// update the DocumentURI indicator since we are being redirected.
// if this was a top-level document channel, then the new channel
// should have its mDocumentURI point to newURI; otherwise, we
// just need to pass along our mDocumentURI to the new channel.
if (newURI && (mURI == mDocumentURI))
httpInternal->SetDocumentURI(newURI);
else
httpInternal->SetDocumentURI(mDocumentURI);
}
// convey the mApplyConversion flag (bug 91862)
nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(httpChannel);
if (encodedChannel)
encodedChannel->SetApplyConversion(mApplyConversion);
return NS_OK;
}
nsresult
nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
{
@ -1555,6 +1661,7 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
// as a base...
nsCOMPtr<nsIIOService> ioService;
rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
if (NS_FAILED(rv)) return rv;
// the new uri should inherit the origin charset of the current uri
nsCAutoString originCharset;
@ -1599,79 +1706,19 @@ nsHttpChannel::ProcessRedirection(PRUint32 redirectType)
}
}
PRUint32 newLoadFlags = mLoadFlags | LOAD_REPLACE;
// if the original channel was using SSL and this channel is not using
// SSL, then no need to inhibit persistent caching. however, if the
// original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
// set, then allow the flag to apply to the redirected channel as well.
// since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
// we only need to check if the original channel was using SSL.
if (mConnectionInfo->UsingSSL())
newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
// build the new channel
rv = NS_NewChannel(getter_AddRefs(newChannel), newURI, ioService, mLoadGroup,
mCallbacks, newLoadFlags);
if (NS_FAILED(rv)) return rv;
// convey the original uri
rv = newChannel->SetOriginalURI(mOriginalURI);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
if (httpChannel) {
if (redirectType == 307 && mUploadStream) {
//307 is Temporary Redirect response. Redirect the postdata to the new URI.
rv = PromptTempRedirect();
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream, &rv);
if (NS_FAILED(rv)) return rv;
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(httpChannel, &rv);
if (NS_FAILED(rv)) return rv;
if (mUploadStreamHasHeaders)
uploadChannel->SetUploadStream(mUploadStream, NS_LITERAL_CSTRING(""), -1);
else {
const char *ctype;
ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
const char *clength;
clength = mRequestHead.PeekHeader(nsHttp::Content_Length);
uploadChannel->SetUploadStream(mUploadStream, nsDependentCString(ctype), atoi(clength));
}
httpChannel->SetRequestMethod(nsDependentCString(mRequestHead.Method()));
}
nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
NS_ENSURE_TRUE(httpInternal, NS_ERROR_UNEXPECTED);
// update the DocumentURI indicator since we are being redirected.
// if this was a top-level document channel, then the new channel
// should have its mDocumentURI point to newURI; otherwise, we
// just need to pass along our mDocumentURI to the new channel.
if (newURI && (mURI == mDocumentURI))
httpInternal->SetDocumentURI(newURI);
else
httpInternal->SetDocumentURI(mDocumentURI);
// convey the referrer if one was used for this channel to the next one
if (mReferrer)
httpChannel->SetReferrer(mReferrer);
// convey the mApplyConversion flag (bug 91862)
nsCOMPtr<nsIEncodedChannel> encodedChannel(do_QueryInterface(httpChannel));
NS_ENSURE_TRUE(encodedChannel, NS_ERROR_UNEXPECTED);
encodedChannel->SetApplyConversion(mApplyConversion);
// convey the mAllowPipelining flag
httpChannel->SetAllowPipelining(mAllowPipelining);
// convey the new redirection limit
httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
// if we need to re-send POST data then be sure to ask the user first.
PRBool preserveMethod = (redirectType == 307);
if (preserveMethod && mUploadStream) {
rv = PromptTempRedirect();
if (NS_FAILED(rv)) return rv;
}
rv = ioService->NewChannelFromURI(newURI, getter_AddRefs(newChannel));
if (NS_FAILED(rv)) return rv;
rv = SetupReplacementChannel(newURI, newChannel, preserveMethod);
if (NS_FAILED(rv)) return rv;
// call out to the event sink to notify it of this redirection.
if (mHttpEventSink) {
rv = mHttpEventSink->OnRedirect(this, newChannel);
@ -2987,6 +3034,13 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
return NS_OK;
}
// on proxy errors, try to failover
if (mStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
mStatus == NS_ERROR_UNKNOWN_PROXY_HOST) {
if (NS_SUCCEEDED(ProxyFailover()))
return NS_OK;
}
return CallOnStartRequest();
}
@ -2997,7 +3051,7 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
this, request, status));
// honor the cancelation status even if the underlying transaction completed.
if (mCanceled)
if (mCanceled || NS_FAILED(mStatus))
status = mStatus;
if (mCachedContentIsPartial && NS_SUCCEEDED(status)) {

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

@ -109,8 +109,6 @@ private:
nsresult Connect(PRBool firstTime = PR_TRUE);
nsresult AsyncAbort(nsresult status);
void HandleAsyncRedirect();
void HandleAsyncNotModified();
nsresult SetupTransaction();
void ApplyContentConversions();
nsresult CallOnStartRequest();
@ -120,7 +118,13 @@ private:
nsresult ProcessRedirection(PRUint32 httpStatus);
nsresult ProcessAuthentication(PRUint32 httpStatus);
nsresult GetCallback(const nsIID &aIID, void **aResult);
// redirection specific methods
void HandleAsyncRedirect();
void HandleAsyncNotModified();
nsresult PromptTempRedirect();
nsresult ProxyFailover();
nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
// cache specific methods
nsresult OpenCacheEntry(PRBool offline, PRBool *delayed);

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

@ -38,7 +38,7 @@ nsHttpConnectionInfo::SetOriginServer(const nsACString &host, PRInt32 port)
// NOTE: for transparent proxies (e.g., SOCKS) we need to encode the proxy
// type in the hash key (this ensures that we will continue to speak the
// right protocol even if our proxy preferences change).
if (!mUsingHttpProxy && mProxyInfo)
if (!mUsingHttpProxy && ProxyHost())
mHashKey.Append(NS_LITERAL_CSTRING(" (") +
nsDependentCString(ProxyType()) +
NS_LITERAL_CSTRING(")"));