diff --git a/mozilla/netwerk/base/public/nsIProtocolProxyService.idl b/mozilla/netwerk/base/public/nsIProtocolProxyService.idl index ae4514c4afd..e0abc589922 100644 --- a/mozilla/netwerk/base/public/nsIProtocolProxyService.idl +++ b/mozilla/netwerk/base/public/nsIProtocolProxyService.idl @@ -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 diff --git a/mozilla/netwerk/base/public/nsIProxyInfo.idl b/mozilla/netwerk/base/public/nsIProxyInfo.idl index bbe07b8d4b7..6b5a52541d3 100644 --- a/mozilla/netwerk/base/public/nsIProxyInfo.idl +++ b/mozilla/netwerk/base/public/nsIProxyInfo.idl @@ -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; diff --git a/mozilla/netwerk/base/src/nsPACMan.cpp b/mozilla/netwerk/base/src/nsPACMan.cpp index 3650e5d04ba..fd52d1b90d1 100644 --- a/mozilla/netwerk/base/src/nsPACMan.cpp +++ b/mozilla/netwerk/base/src/nsPACMan.cpp @@ -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 ios = do_GetIOService(); if (ios) { nsCOMPtr 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); diff --git a/mozilla/netwerk/base/src/nsPACMan.h b/mozilla/netwerk/base/src/nsPACMan.h index 41687327b93..f18e7a51860 100644 --- a/mozilla/netwerk/base/src/nsPACMan.h +++ b/mozilla/netwerk/base/src/nsPACMan.h @@ -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 mLoader; PLEvent *mLoadEvent; PRPackedBool mShutdown; + PRPackedBool mStartingToLoad; }; #endif // nsPACMan_h__ diff --git a/mozilla/netwerk/base/src/nsProtocolProxyService.cpp b/mozilla/netwerk/base/src/nsProtocolProxyService.cpp index 12f81093a5c..d873443e053 100644 --- a/mozilla/netwerk/base/src/nsProtocolProxyService.cpp +++ b/mozilla/netwerk/base/src/nsProtocolProxyService.cpp @@ -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); diff --git a/mozilla/netwerk/base/src/nsSocketTransport2.cpp b/mozilla/netwerk/base/src/nsSocketTransport2.cpp index c6750e712ec..c93ee2356bc 100644 --- a/mozilla/netwerk/base/src/nsSocketTransport2.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransport2.cpp @@ -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; } diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp index 3da675c266a..0bccf5ba90b 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -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 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 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 //----------------------------------------------------------------------------- diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h index f82801f422e..150a335b737 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.h @@ -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 mReferrer; nsCOMPtr mSecurityInfo; nsCOMPtr mEventQ; + nsCOMPtr mProxyRequest; nsHttpRequestHead mRequestHead; nsHttpResponseHead *mResponseHead;