mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
fixes bug 174984 "Prefetch requests should send Referer" r=gagan,mstoltz
sr=bzbarsky a=dbaron
This commit is contained in:
parent
15e2521a6d
commit
0194395e7e
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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?
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -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__
|
||||
|
Loading…
Reference in New Issue
Block a user