fixes bug 100022 "PAC: first page/homepage load fails (b/c automatic proxy configuration is slower than first HTTP request)" r=biesi a=asa

This commit is contained in:
darin%meer.net 2005-06-24 23:58:25 +00:00
Родитель 6e37d41b47
Коммит 5e1daa9a78
8 изменённых файлов: 121 добавлений и 18 удалений

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

@ -94,6 +94,12 @@ interface nsIProtocolProxyService : nsISupports
* the given URI should be loaded using the HTTP protocol handler, which
* also supports nsIProxiedProtocolHandler.
*
* NOTE: If PAC is configured, and the PAC file has not yet been loaded,
* then this method will return a nsIProxyInfo instance with a type of
* "unknown" to indicate to the consumer that asyncResolve should be used
* to wait for the PAC file to finish loading. Otherwise, the consumer
* may choose to treat the result as type "direct" if desired.
*
* @see nsIProxiedProtocolHandler::newProxiedChannel
*/
nsIProxyInfo resolve(in nsIURI aURI, in unsigned long aFlags);
@ -126,10 +132,10 @@ 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
* "direct" - specifies a direct connection (useful for failover)
* "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

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

@ -66,6 +66,7 @@ interface nsIProxyInfo : nsISupports
* "socks" SOCKS v5 proxy
* "socks4" SOCKS v4 proxy
* "direct" no proxy
* "unknown" unknown proxy (see nsIProtocolProxyService::resolve)
*/
readonly attribute ACString type;

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

@ -154,6 +154,7 @@ PendingPACQuery::OnLookupComplete(nsICancelable *request,
nsPACMan::nsPACMan()
: mLoadEvent(nsnull)
, mShutdown(PR_FALSE)
, mStartingToLoad(PR_FALSE)
{
PR_INIT_CLIST(&mPendingQ);
}
@ -180,7 +181,14 @@ nsPACMan::GetProxyForURI(nsIURI *uri, nsACString &result)
{
NS_ENSURE_STATE(!mShutdown);
if (!mPAC || IsLoading())
if (mStartingToLoad) {
result.Truncate();
return NS_OK;
}
if (IsLoading())
return NS_ERROR_IN_PROGRESS;
if (!mPAC)
return NS_ERROR_NOT_AVAILABLE;
nsCAutoString spec, host;
@ -284,7 +292,14 @@ nsPACMan::StartLoading()
nsCOMPtr<nsIIOService> ios = do_GetIOService();
if (ios) {
nsCOMPtr<nsIChannel> channel;
// Calling NewChannel will result in GetProxyForURI being called, and we
// want to make sure that it does not return NS_ERROR_IN_PROGRESS. So,
// we set this flag to cause it to indicate a DIRECT fetch for this URI.
mStartingToLoad = PR_TRUE;
ios->NewChannel(mPACSpec, nsnull, nsnull, getter_AddRefs(channel));
mStartingToLoad = PR_FALSE;
if (channel) {
channel->SetLoadFlags(nsIRequest::LOAD_BYPASS_CACHE);
channel->SetNotificationCallbacks(this);

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

@ -91,7 +91,8 @@ public:
* @param result
* Holds the PAC result string upon return.
*
* @return NS_ERROR_NOT_AVAILABLE if the PAC file is not yet loaded.
* @return NS_ERROR_IN_PROGRESS if the PAC file is not yet loaded.
* @return NS_ERROR_NOT_AVAILABLE if the PAC file could not be loaded.
*/
nsresult GetProxyForURI(nsIURI *uri, nsACString &result);
@ -159,6 +160,7 @@ private:
nsCOMPtr<nsIStreamLoader> mLoader;
PLEvent *mLoadEvent;
PRPackedBool mShutdown;
PRPackedBool mStartingToLoad;
};
#endif // nsPACMan_h__

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

@ -571,12 +571,13 @@ 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";
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";
static const char kProxyType_UNKNOWN[] = "unknown";
const char *
nsProtocolProxyService::ExtractProxyInfo(const char *start, nsProxyInfo **result)
@ -802,10 +803,18 @@ nsProtocolProxyService::Resolve(nsIURI *uri, PRUint32 flags,
// 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
if (NS_SUCCEEDED(rv))
ProcessPACString(pacString, result);
else if (rv == NS_ERROR_IN_PROGRESS) {
// Construct a special UNKNOWN proxy entry that informs the caller
// that the proxy info is yet to be determined.
rv = NewProxyInfo_Internal(kProxyType_UNKNOWN, EmptyCString(), -1,
0, 0, nsnull, result);
if (NS_FAILED(rv))
return rv;
}
else
NS_WARNING("failed querying PAC file; trying DIRECT");
}
ApplyFilters(uri, info, result);

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

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

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

@ -308,6 +308,8 @@ nsHttpChannel::Connect(PRBool firstTime)
ioService->GetOffline(&offline);
if (offline)
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
else if (PL_strcmp(mConnectionInfo->ProxyType(), "unknown") == 0)
return ResolveProxy(); // Lazily resolve proxy info
// Don't allow resuming when cache must be used
if (mResuming && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
@ -920,6 +922,14 @@ nsHttpChannel::ProxyFailover()
if (NS_FAILED(rv))
return rv;
return ReplaceWithProxy(pi);
}
nsresult
nsHttpChannel::ReplaceWithProxy(nsIProxyInfo *pi)
{
nsresult rv;
nsCOMPtr<nsIChannel> newChannel;
rv = gHttpHandler->NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel));
if (NS_FAILED(rv))
@ -940,6 +950,21 @@ nsHttpChannel::ProxyFailover()
return rv;
}
nsresult
nsHttpChannel::ResolveProxy()
{
LOG(("nsHttpChannel::ResolveProxy [this=%x]\n", this));
nsresult rv;
nsCOMPtr<nsIProtocolProxyService> pps =
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
return pps->AsyncResolve(mURI, 0, this, getter_AddRefs(mProxyRequest));
}
PRBool
nsHttpChannel::ResponseWouldVary()
{
@ -2940,6 +2965,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
//-----------------------------------------------------------------------------
@ -2975,7 +3001,9 @@ nsHttpChannel::Cancel(nsresult status)
LOG(("nsHttpChannel::Cancel [this=%x status=%x]\n", this, status));
mCanceled = PR_TRUE;
mStatus = status;
if (mTransaction)
if (mProxyRequest)
mProxyRequest->Cancel(status);
else if (mTransaction)
gHttpHandler->CancelTransaction(mTransaction, status);
else if (mCachePump)
mCachePump->Cancel(status);
@ -3789,6 +3817,38 @@ nsHttpChannel::AdjustPriority(PRInt32 delta)
return SetPriority(mPriority + delta);
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIProtocolProxyCallback
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIURI *uri,
nsIProxyInfo *pi, nsresult status)
{
mProxyRequest = nsnull;
// If status is a failure code, then it means that we failed to resolve
// proxy info. That is a non-fatal error assuming it wasn't because the
// request was canceled. We just failover to DIRECT when proxy resolution
// fails (failure can mean that the PAC URL could not be loaded).
// Need to replace this channel with a new one. It would be complex to try
// to change the value of mConnectionInfo since so much of our state may
// depend on its state.
if (!mCanceled) {
status = ReplaceWithProxy(pi);
// XXX(darin): It'd be nice if removing ourselves from the loadgroup
// could be factored into ReplaceWithProxy somehow.
if (mLoadGroup && NS_SUCCEEDED(status))
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
}
if (NS_FAILED(status))
AsyncAbort(status);
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIRequestObserver
//-----------------------------------------------------------------------------

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

@ -75,6 +75,8 @@
#include "nsIPrompt.h"
#include "nsIResumableChannel.h"
#include "nsISupportsPriority.h"
#include "nsIProtocolProxyCallback.h"
#include "nsICancelable.h"
class nsHttpResponseHead;
class nsAHttpConnection;
@ -96,6 +98,7 @@ class nsHttpChannel : public nsHashPropertyBag
, public nsITransportEventSink
, public nsIResumableChannel
, public nsISupportsPriority
, public nsIProtocolProxyCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -112,6 +115,7 @@ public:
NS_DECL_NSITRANSPORTEVENTSINK
NS_DECL_NSIRESUMABLECHANNEL
NS_DECL_NSISUPPORTSPRIORITY
NS_DECL_NSIPROTOCOLPROXYCALLBACK
nsHttpChannel();
virtual ~nsHttpChannel();
@ -160,9 +164,13 @@ private:
void HandleAsyncRedirect();
void HandleAsyncNotModified();
nsresult PromptTempRedirect();
nsresult ProxyFailover();
nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, PRBool preserveMethod);
// proxy specific methods
nsresult ProxyFailover();
nsresult ReplaceWithProxy(nsIProxyInfo *);
nsresult ResolveProxy();
// cache specific methods
nsresult OpenCacheEntry(PRBool offline, PRBool *delayed);
nsresult GenerateCacheKey(nsACString &key);
@ -216,6 +224,7 @@ private:
nsCOMPtr<nsIURI> mReferrer;
nsCOMPtr<nsISupports> mSecurityInfo;
nsCOMPtr<nsIEventQueue> mEventQ;
nsCOMPtr<nsICancelable> mProxyRequest;
nsHttpRequestHead mRequestHead;
nsHttpResponseHead *mResponseHead;