Bug 457825 - Support access control headers when downloading fonts. r=jonas,dbaron, sr=jonas

This commit is contained in:
John Daggett 2008-11-06 09:32:12 +09:00
parent 7c9a9141d5
commit e5a0f4c565
8 changed files with 127 additions and 52 deletions

View File

@ -140,6 +140,7 @@ NS_CP_ContentTypeName(PRUint32 contentType)
CASE_RETURN( TYPE_XMLHTTPREQUEST );
CASE_RETURN( TYPE_OBJECT_SUBREQUEST );
CASE_RETURN( TYPE_DTD );
CASE_RETURN( TYPE_FONT );
default:
return "<Unknown Type>";
}

View File

@ -126,6 +126,11 @@ interface nsIContentPolicy : nsISupports
*/
const unsigned long TYPE_DTD = 13;
/**
* Indicates a font loaded via @font-face rule.
*/
const unsigned long TYPE_FONT = 14;
//////////////////////////////////////////////////////////////////////
/**

View File

@ -41,9 +41,6 @@
#include "nsString.h"
#include "nsIURI.h"
#include "nsTArray.h"
#include "nsIContentSink.h"
#include "nsIXMLContentSink.h"
#include "nsIExpatSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"

View File

@ -56,6 +56,7 @@ struct gfxFontFaceSrc {
PRPackedBool mIsLocal; // url or local
nsString mLocalName; // full font name if local
nsCOMPtr<nsIURI> mURI; // uri if url
nsCOMPtr<nsIURI> mReferrer; // referrer url if url
// format hint flags, union of all possible formats
// (e.g. TrueType, EOT, SVG, etc.)
@ -146,8 +147,10 @@ class THEBES_API gfxUserFontSet {
public:
class LoaderContext;
typedef PRBool (*LoaderCallback) (gfxFontEntry *aFontToLoad, nsIURI *aSrcURL,
LoaderContext *aContextData);
typedef nsresult (*LoaderCallback) (gfxFontEntry *aFontToLoad,
nsIURI *aSrcURL,
nsIURI *aReferrerURI,
LoaderContext *aContextData);
class LoaderContext {
public:

View File

@ -321,9 +321,12 @@ gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry)
else {
if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
currSrc.mFormatFlags)) {
PRBool loadOK = mLoaderContext->mLoaderProc(aProxyEntry,
currSrc.mURI,
mLoaderContext);
nsresult rv = mLoaderContext->mLoaderProc(aProxyEntry,
currSrc.mURI,
currSrc.mReferrer,
mLoaderContext);
PRBool loadOK = NS_SUCCEEDED(rv);
if (loadOK) {
#ifdef PR_LOGGING
if (LOG_ENABLED()) {

View File

@ -2403,6 +2403,8 @@ InsertFontFaceRule(nsICSSRule* aRule, gfxUserFontSet* fs)
case eCSSUnit_URL:
face->mIsLocal = PR_FALSE;
face->mURI = val.GetURLValue();
NS_ASSERTION(face->mURI, "null url in @font-face rule");
face->mReferrer = val.GetURLStructValue()->mReferrer;
face->mLocalName.Truncate();
face->mFormatFlags = 0;
while (i + 1 < numSrc && (val = srcArr->Item(i+1),

View File

@ -46,6 +46,7 @@
#include "nsFontFaceLoader.h"
#include "nsError.h"
#include "nsIFile.h"
#include "nsILocalFile.h"
#include "nsIStreamListener.h"
@ -63,7 +64,10 @@
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIContentPolicy.h"
#include "nsContentPolicyUtils.h"
#include "nsContentErrors.h"
#include "nsCrossSiteListenerProxy.h"
#ifdef PR_LOGGING
static PRLogModuleInfo *gFontDownloaderLog = PR_NewLogModule("fontdownloader");
@ -73,31 +77,6 @@ static PRLogModuleInfo *gFontDownloaderLog = PR_NewLogModule("fontdownloader");
#define LOG_ENABLED() PR_LOG_TEST(gFontDownloaderLog, PR_LOG_DEBUG)
#define ENFORCE_SAME_SITE_ORIGIN "gfx.downloadable_fonts.enforce_same_site_origin"
static PRBool gEnforceSameSiteOrigin = PR_TRUE;
static PRBool
CheckMayLoad(nsIDocument* aDoc, nsIURI* aURI)
{
// allow this to be disabled via a pref
static PRBool init = PR_FALSE;
if (!init) {
init = PR_TRUE;
nsContentUtils::AddBoolPrefVarCache(ENFORCE_SAME_SITE_ORIGIN, &gEnforceSameSiteOrigin);
}
if (!gEnforceSameSiteOrigin)
return PR_TRUE;
if (!aDoc)
return PR_FALSE;
nsresult rv = aDoc->NodePrincipal()->CheckMayLoad(aURI, PR_TRUE);
return NS_SUCCEEDED(rv);
}
nsFontFaceLoader::nsFontFaceLoader(gfxFontEntry *aFontToLoad, nsIURI *aFontURI,
gfxUserFontSet::LoaderContext *aContext)
: mFontEntry(aFontToLoad), mFontURI(aFontURI), mLoaderContext(aContext)
@ -157,45 +136,122 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
return aStatus;
}
PRBool
nsFontFaceLoader::CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI,
nsresult
nsFontFaceLoader::CreateHandler(gfxFontEntry *aFontToLoad,
nsIURI *aFontURI,
nsIURI *aReferrerURI,
gfxUserFontSet::LoaderContext *aContext)
{
nsresult rv;
// check same-site origin
nsFontFaceLoaderContext *loaderCtx
= static_cast<nsFontFaceLoaderContext*> (aContext);
nsIPresShell *ps = loaderCtx->mPresContext->PresShell();
if (!ps)
return PR_FALSE;
return NS_ERROR_FAILURE;
NS_ASSERTION(aFontURI, "null font uri");
if (!aFontURI)
return NS_ERROR_FAILURE;
if (!CheckMayLoad(ps->GetDocument(), aFontURI))
return PR_FALSE;
// xxx - need to detect system principal here
nsCOMPtr<nsIPrincipal> principal = ps->GetDocument()->NodePrincipal();
rv = CheckLoadAllowed(principal, aFontURI, ps->GetDocument());
if (NS_FAILED(rv)) {
nsCAutoString fontURI, referrerURI;
aFontURI->GetSpec(fontURI);
if (aReferrerURI)
aReferrerURI->GetSpec(referrerURI);
LOG(("fontdownloader download blocked - font uri: (%s) "
"referrer uri: (%s) err: %8.8x\n",
fontURI.get(), referrerURI.get(), rv));
return rv;
}
nsRefPtr<nsFontFaceLoader> fontLoader = new nsFontFaceLoader(aFontToLoad,
aFontURI,
aContext);
if (!fontLoader)
return PR_FALSE;
return NS_ERROR_OUT_OF_MEMORY;
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
nsCAutoString fontURI;
nsCAutoString fontURI, referrerURI;
aFontURI->GetSpec(fontURI);
LOG(("fontdownloader (%p) download start - font uri: (%s)\n",
fontLoader.get(), fontURI.get()));
if (aReferrerURI)
aReferrerURI->GetSpec(referrerURI);
LOG(("fontdownloader (%p) download start - font uri: (%s) "
"referrer uri: (%s)\n",
fontLoader.get(), fontURI.get(), referrerURI.get()));
}
#endif
nsCOMPtr<nsIStreamLoader> streamLoader;
nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker
= nsContentUtils::GetSameOriginChecker();
nsresult rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), aFontURI,
fontLoader, nsnull, loadGroup,
sameOriginChecker);
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel),
aFontURI,
nsnull,
loadGroup,
nsnull,
nsIRequest::LOAD_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return NS_SUCCEEDED(rv);
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel)
httpChannel->SetReferrer(aReferrerURI);
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
NS_ENSURE_SUCCESS(rv, rv);
// unless data url, open with cross-site listener
PRBool isData = PR_FALSE;
if (NS_SUCCEEDED(aFontURI->SchemeIs("data", &isData)) && isData) {
rv = channel->AsyncOpen(streamLoader, nsnull);
} else {
nsCOMPtr<nsIStreamListener> listener =
new nsCrossSiteListenerProxy(streamLoader, principal, channel,
PR_FALSE, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
rv = channel->AsyncOpen(listener, nsnull);
}
return rv;
}
nsresult
nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext)
{
nsresult rv;
if (!aSourcePrincipal)
return NS_OK;
// check content policy
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
aTargetURI,
aSourcePrincipal,
aContext,
EmptyCString(), // mime type
nsnull,
&shouldLoad,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
return NS_ERROR_CONTENT_BLOCKED;
}
return NS_OK;
}

View File

@ -49,6 +49,7 @@
class nsIRequest;
class nsISupports;
class nsPresContext;
class nsIPrincipal;
class nsFontFaceLoader : public nsIStreamLoaderObserver
{
@ -65,10 +66,17 @@ public:
nsresult Init();
// returns whether create succeeded or not
static PRBool CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI,
gfxUserFontSet::LoaderContext *aContext);
static nsresult CreateHandler(gfxFontEntry *aFontToLoad,
nsIURI *aFontURI,
nsIURI *aReferrerURI,
gfxUserFontSet::LoaderContext *aContext);
private:
static nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext);
nsRefPtr<gfxFontEntry> mFontEntry;
nsCOMPtr<nsIURI> mFontURI;
gfxUserFontSet::LoaderContext* mLoaderContext;