зеркало из https://github.com/mozilla/pjs.git
fixes bug 84798 "PAC: Failover does not work" r=dougt sr=alecf
This commit is contained in:
Родитель
5cd17198b5
Коммит
a9f3b48e39
|
@ -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(")"));
|
||||
|
|
Загрузка…
Ссылка в новой задаче