diff --git a/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp
index d47a841e0f7b..212e62372a04 100644
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -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 docshell(do_QueryInterface(mWebShell));
+ if (!docshell)
+ return;
+ nsCOMPtr 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 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);
}
}
diff --git a/uriloader/prefetch/nsIPrefetchService.idl b/uriloader/prefetch/nsIPrefetchService.idl
index b2e027bee9b5..36e9c56321ea 100644
--- a/uriloader/prefetch/nsIPrefetchService.idl
+++ b/uriloader/prefetch/nsIPrefetchService.idl
@@ -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?
};
diff --git a/uriloader/prefetch/nsPrefetchService.cpp b/uriloader/prefetch/nsPrefetchService.cpp
index 0316559bf6d5..7679b51e7184 100644
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -139,30 +139,36 @@ NS_IMETHODIMP
nsPrefetchListener::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
- nsCOMPtr 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 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 cacheToken;
+ cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
+ if (!cacheToken)
+ return NS_ERROR_ABORT; // bail, no cache entry
+
+ nsCOMPtr 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 cacheToken;
- cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
- if (cacheToken) {
- nsCOMPtr 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 uri;
+ nsCOMPtr 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 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 uri;
+ nsCOMPtr 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);
}
//-----------------------------------------------------------------------------
diff --git a/uriloader/prefetch/nsPrefetchService.h b/uriloader/prefetch/nsPrefetchService.h
index 0802aec29c8c..acdba2b7d21f 100644
--- a/uriloader/prefetch/nsPrefetchService.h
+++ b/uriloader/prefetch/nsPrefetchService.h
@@ -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 mURI;
+ nsCOMPtr mReferrerURI;
};
#endif // !nsPrefetchService_h__