fixes bug 174984 "Prefetch requests should send Referer" r=gagan,mstoltz

sr=bzbarsky a=dbaron
This commit is contained in:
darin%netscape.com 2002-10-24 03:17:44 +00:00
parent 15e2521a6d
commit 0194395e7e
4 changed files with 106 additions and 39 deletions

View File

@ -4929,6 +4929,36 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
void
HTMLContentSink::PrefetchHref(const nsAString &aHref)
{
//
// SECURITY CHECK: disable prefetching from mailnews!
//
// walk up the docshell tree to see if any containing
// docshell are of type MAIL.
//
nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(mWebShell));
if (!docshell)
return;
nsCOMPtr<nsIDocShellTreeItem> treeItem, parentItem;
do {
PRUint32 appType;
nsresult rv = docshell->GetAppType(&appType);
if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
return; // do not prefetch from mailnews
if (treeItem = do_QueryInterface(docshell)) {
treeItem->GetParent(getter_AddRefs(parentItem));
if (parentItem) {
treeItem = parentItem;
docshell = do_QueryInterface(treeItem);
if (!docshell) {
NS_ERROR("cannot get a docshell from a treeItem!");
return;
}
}
}
} while (parentItem);
// OK, we passed the security check...
nsCOMPtr<nsIPrefetchService> prefetchService(
do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
if (prefetchService) {
@ -4941,7 +4971,7 @@ HTMLContentSink::PrefetchHref(const nsAString &aHref)
: NS_LossyConvertUCS2toASCII(charset).get(),
mDocumentBaseURL);
if (uri)
prefetchService->PrefetchURI(uri);
prefetchService->PrefetchURI(uri, mDocumentURI);
}
}

View File

@ -44,8 +44,11 @@ interface nsIPrefetchService : nsISupports
{
/**
* Enqueue a request to prefetch the specified URI.
*
* @param aURI the URI of the document to prefetch
* @param aReferrerURI the URI of the referring page
*/
void prefetchURI(in nsIURI aURI);
void prefetchURI(in nsIURI aURI, in nsIURI aReferrerURI);
// XXX do we need a way to cancel prefetch requests?
};

View File

@ -139,30 +139,36 @@ NS_IMETHODIMP
nsPrefetchListener::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
nsCOMPtr<nsICachingChannel> cachingChannel(do_QueryInterface(aRequest));
if (cachingChannel) {
// no need to prefetch a document that is already in the cache
PRBool fromCache;
if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) && fromCache) {
LOG(("document is already in the cache; canceling prefetch\n"));
nsresult rv;
nsCOMPtr<nsICachingChannel> cachingChannel(do_QueryInterface(aRequest, &rv));
if (NS_FAILED(rv)) return rv;
// no need to prefetch a document that is already in the cache
PRBool fromCache;
if (NS_SUCCEEDED(cachingChannel->IsFromCache(&fromCache)) && fromCache) {
LOG(("document is already in the cache; canceling prefetch\n"));
return NS_BINDING_ABORTED;
}
//
// no need to prefetch a document that must be requested fresh each
// and every time.
//
nsCOMPtr<nsISupports> cacheToken;
cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
if (!cacheToken)
return NS_ERROR_ABORT; // bail, no cache entry
nsCOMPtr<nsICacheEntryInfo> entryInfo(do_QueryInterface(cacheToken, &rv));
if (NS_FAILED(rv)) return rv;
PRUint32 expTime;
if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
if (NowInSeconds() >= expTime) {
LOG(("document cannot be reused from cache; canceling prefetch\n"));
return NS_BINDING_ABORTED;
}
// no need to prefetch a document that must be requested fresh each
// and every time.
nsCOMPtr<nsISupports> cacheToken;
cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
if (cacheToken) {
nsCOMPtr<nsICacheEntryInfo> entryInfo(do_QueryInterface(cacheToken));
if (entryInfo) {
PRUint32 expTime;
if (NS_SUCCEEDED(entryInfo->GetExpirationTime(&expTime))) {
if (NowInSeconds() >= expTime) {
LOG(("document cannot be reused from cache; canceling prefetch\n"));
return NS_BINDING_ABORTED;
}
}
}
}
}
return NS_OK;
}
@ -256,7 +262,7 @@ void
nsPrefetchService::ProcessNextURI()
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> uri, referrer;
mCurrentChannel = nsnull;
@ -264,7 +270,7 @@ nsPrefetchService::ProcessNextURI()
if (!listener) return;
do {
rv = DequeueURI(getter_AddRefs(uri));
rv = DequeueURI(getter_AddRefs(uri), getter_AddRefs(referrer));
if (NS_FAILED(rv)) break;
#if defined(PR_LOGGING)
@ -282,6 +288,14 @@ nsPrefetchService::ProcessNextURI()
nsnull, nsIRequest::LOAD_BACKGROUND);
if (NS_FAILED(rv)) continue;
// configure HTTP specific stuff
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mCurrentChannel));
if (httpChannel) {
httpChannel->SetReferrer(referrer);
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
NS_LITERAL_CSTRING("prefetch"));
}
rv = mCurrentChannel->AsyncOpen(listener, nsnull);
}
while (NS_FAILED(rv));
@ -292,9 +306,9 @@ nsPrefetchService::ProcessNextURI()
//-----------------------------------------------------------------------------
nsresult
nsPrefetchService::EnqueueURI(nsIURI *aURI)
nsPrefetchService::EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI)
{
nsPrefetchNode *node = new nsPrefetchNode(aURI);
nsPrefetchNode *node = new nsPrefetchNode(aURI, aReferrerURI);
if (!node)
return NS_ERROR_OUT_OF_MEMORY;
@ -311,13 +325,14 @@ nsPrefetchService::EnqueueURI(nsIURI *aURI)
}
nsresult
nsPrefetchService::DequeueURI(nsIURI **aURI)
nsPrefetchService::DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI)
{
if (!mQueueHead)
return NS_ERROR_NOT_AVAILABLE;
// remove from the head
NS_ADDREF(*aURI = mQueueHead->mURI);
NS_ADDREF(*aReferrerURI = mQueueHead->mReferrerURI);
nsPrefetchNode *node = mQueueHead;
mQueueHead = mQueueHead->mNext;
@ -333,10 +348,11 @@ void
nsPrefetchService::EmptyQueue()
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> uri, referrer;
do {
rv = DequeueURI(getter_AddRefs(uri));
rv = DequeueURI(getter_AddRefs(uri),
getter_AddRefs(referrer));
}
while (NS_SUCCEEDED(rv));
}
@ -392,10 +408,13 @@ NS_IMPL_ISUPPORTS4(nsPrefetchService,
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsPrefetchService::PrefetchURI(nsIURI *aURI)
nsPrefetchService::PrefetchURI(nsIURI *aURI, nsIURI *aReferrerURI)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aReferrerURI);
#if defined(PR_LOGGING)
if (LOG_ENABLED()) {
nsCAutoString spec;
@ -420,13 +439,22 @@ nsPrefetchService::PrefetchURI(nsIURI *aURI)
// or possibly nsIRequest::loadFlags to determine if this URI should be
// prefetched.
//
PRBool isHttp;
rv = aURI->SchemeIs("http", &isHttp);
if (NS_FAILED(rv) || !isHttp) {
PRBool match;
rv = aURI->SchemeIs("http", &match);
if (NS_FAILED(rv) || !match) {
LOG(("rejected: URL is not of type http\n"));
return NS_ERROR_ABORT;
}
//
// the referrer URI must be http:
//
rv = aReferrerURI->SchemeIs("http", &match);
if (NS_FAILED(rv) || !match) {
LOG(("rejected: referrer URL is not of type http\n"));
return NS_ERROR_ABORT;
}
//
// skip URLs that contain query strings. these URLs are likely to result
// in documents that have zero freshness lifetimes, which we'd stop
@ -469,7 +497,7 @@ nsPrefetchService::PrefetchURI(nsIURI *aURI)
}
}
return EnqueueURI(aURI);
return EnqueueURI(aURI, aReferrerURI);
}
//-----------------------------------------------------------------------------

View File

@ -75,8 +75,8 @@ public:
private:
nsresult EnqueueURI(nsIURI *aURI);
nsresult DequeueURI(nsIURI **aURI);
nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI);
nsresult DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI);
void EmptyQueue();
void StartPrefetching();
void StopPrefetching();
@ -116,10 +116,16 @@ private:
class nsPrefetchNode
{
public:
nsPrefetchNode(nsIURI *aURI) : mNext(nsnull), mURI(aURI) { }
nsPrefetchNode(nsIURI *aURI,
nsIURI *aReferrerURI)
: mNext(nsnull)
, mURI(aURI)
, mReferrerURI(aReferrerURI)
{ }
nsPrefetchNode *mNext;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI;
};
#endif // !nsPrefetchService_h__