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
Родитель 15e2521a6d
Коммит 0194395e7e
4 изменённых файлов: 106 добавлений и 39 удалений

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

@ -4929,6 +4929,36 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
void void
HTMLContentSink::PrefetchHref(const nsAString &aHref) 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( nsCOMPtr<nsIPrefetchService> prefetchService(
do_GetService(NS_PREFETCHSERVICE_CONTRACTID)); do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
if (prefetchService) { if (prefetchService) {
@ -4941,7 +4971,7 @@ HTMLContentSink::PrefetchHref(const nsAString &aHref)
: NS_LossyConvertUCS2toASCII(charset).get(), : NS_LossyConvertUCS2toASCII(charset).get(),
mDocumentBaseURL); mDocumentBaseURL);
if (uri) if (uri)
prefetchService->PrefetchURI(uri); prefetchService->PrefetchURI(uri, mDocumentURI);
} }
} }

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

@ -44,8 +44,11 @@ interface nsIPrefetchService : nsISupports
{ {
/** /**
* Enqueue a request to prefetch the specified URI. * 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? // XXX do we need a way to cancel prefetch requests?
}; };

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

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

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

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