зеркало из https://github.com/mozilla/gecko-dev.git
fixes bug 174984 "Prefetch requests should send Referer" r=gagan,mstoltz
sr=bzbarsky a=dbaron
This commit is contained in:
Родитель
15e2521a6d
Коммит
0194395e7e
|
@ -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__
|
||||||
|
|
Загрузка…
Ссылка в новой задаче