Allow certain restricted loads in unload events. Bug 409888, r+sr=jst

This commit is contained in:
bzbarsky%mit.edu 2008-01-25 20:31:44 +00:00
Родитель 3ce4adc841
Коммит 5e87eed68a
3 изменённых файлов: 129 добавлений и 9 удалений

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

@ -678,7 +678,9 @@ nsDocShell::LoadURI(nsIURI * aURI,
PRUint32 aLoadFlags,
PRBool aFirstParty)
{
if (!IsNavigationAllowed()) {
// Note: we allow loads to get through here even if mFiredUnloadEvent is
// true; that case will get handled in LoadInternal or LoadHistoryEntry.
if (IsPrintingOrPP()) {
return NS_OK; // JS may not handle returning of an error code
}
nsresult rv;
@ -3603,6 +3605,10 @@ nsDocShell::Destroy()
}
}
// Make sure to blow away our mLoadingURI just in case. No loads
// from inside this pagehide.
mLoadingURI = nsnull;
// Fire unload event before we blow anything away.
(void) FirePageHideNotification(PR_TRUE);
@ -5138,6 +5144,10 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
mSavingOldViewer = CanSavePresentation(LOAD_NORMAL, nsnull, nsnull);
// Make sure to blow away our mLoadingURI just in case. No loads
// from inside this pagehide.
mLoadingURI = nsnull;
// Notify the current document that it is about to be unloaded!!
//
// It is important to fire the unload() notification *before* any state
@ -5554,6 +5564,10 @@ nsDocShell::RestoreFromHistory()
// pagehide or unload.
nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
// Make sure to blow away our mLoadingURI just in case. No loads
// from inside this pagehide.
mLoadingURI = nsnull;
// Notify the old content viewer that it's being hidden.
FirePageHideNotification(!mSavingOldViewer);
@ -5916,7 +5930,14 @@ nsDocShell::CreateContentViewer(const char *aContentType,
mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
}
NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
if (aOpenedChannel) {
aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
}
FirePageHideNotification(!mSavingOldViewer);
mLoadingURI = nsnull;
// Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the
// *new* document will fire.
@ -5927,8 +5948,6 @@ nsDocShell::CreateContentViewer(const char *aContentType,
// notifications before we've called Embed(). See bug 284993.
mURIResultedInDocument = PR_TRUE;
nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(request);
PRBool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, PR_FALSE);
// let's try resetting the load group if we need to...
@ -6450,6 +6469,60 @@ nsDocShell::CheckLoadingPermissions()
//*****************************************************************************
// nsDocShell: Site Loading
//*****************************************************************************
class InternalLoadEvent : public nsRunnable
{
public:
InternalLoadEvent(nsDocShell* aDocShell, nsIURI * aURI, nsIURI * aReferrer,
nsISupports * aOwner, PRUint32 aFlags,
const PRUnichar *aWindowTarget, const char* aTypeHint,
nsIInputStream * aPostData,
nsIInputStream * aHeadersData, PRUint32 aLoadType,
nsISHEntry * aSHEntry, PRBool aFirstParty) :
mDocShell(aDocShell),
mURI(aURI),
mReferrer(aReferrer),
mOwner(aOwner),
mFlags(aFlags),
mPostData(aPostData),
mHeadersData(aHeadersData),
mLoadType(aLoadType),
mSHEntry(aSHEntry),
mFirstParty(aFirstParty)
{
// Make sure to keep null things null as needed
if (aWindowTarget) {
mWindowTarget = aWindowTarget;
}
if (aTypeHint) {
mTypeHint = aTypeHint;
}
}
NS_IMETHOD Run() {
return mDocShell->InternalLoad(mURI, mReferrer, mOwner, mFlags,
mWindowTarget.get(), mTypeHint.get(),
mPostData, mHeadersData, mLoadType,
mSHEntry, mFirstParty, nsnull, nsnull);
}
private:
nsRefPtr<nsDocShell> mDocShell;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrer;
nsCOMPtr<nsISupports> mOwner;
PRUint32 mFlags;
// Use IDL strings so .get() returns null by default
nsXPIDLString mWindowTarget;
nsXPIDLCString mTypeHint;
nsCOMPtr<nsIInputStream> mPostData;
nsCOMPtr<nsIInputStream> mHeadersData;
PRUint32 mLoadType;
nsCOMPtr<nsISHEntry> mSHEntry;
PRBool mFirstParty;
};
NS_IMETHODIMP
nsDocShell::InternalLoad(nsIURI * aURI,
nsIURI * aReferrer,
@ -6465,10 +6538,6 @@ nsDocShell::InternalLoad(nsIURI * aURI,
nsIDocShell** aDocShell,
nsIRequest** aRequest)
{
if (mFiredUnloadEvent) {
return NS_OK; // JS may not handle returning of an error code
}
nsresult rv = NS_OK;
#ifdef PR_LOGGING
@ -6496,6 +6565,21 @@ nsDocShell::InternalLoad(nsIURI * aURI,
NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
if (mFiredUnloadEvent) {
if (IsOKToLoadURI(aURI)) {
// Do this asynchronously
nsCOMPtr<nsIRunnable> ev =
new InternalLoadEvent(this, aURI, aReferrer, aOwner, aFlags,
aWindowTarget, aTypeHint,
aPostData, aHeadersData, aLoadType,
aSHEntry, aFirstParty);
return NS_DispatchToCurrentThread(ev);
}
// Just ignore this load attempt
return NS_OK;
}
// wyciwyg urls can only be loaded through history. Any normal load of
// wyciwyg through docshell is illegal. Disallow such loads.
if (aLoadType & LOAD_CMD_NORMAL) {
@ -8064,6 +8148,10 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI,
NS_IMETHODIMP
nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType)
{
if (!IsNavigationAllowed()) {
return NS_OK;
}
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIInputStream> postData;
nsCOMPtr<nsIURI> referrerURI;
@ -9211,6 +9299,26 @@ nsDocShell::IsAboutBlank(nsIURI* aURI)
return str.EqualsLiteral("about:blank");
}
PRBool
nsDocShell::IsOKToLoadURI(nsIURI* aURI)
{
NS_PRECONDITION(aURI, "Must have a URI!");
if (!mFiredUnloadEvent) {
return PR_TRUE;
}
if (!mLoadingURI) {
return PR_FALSE;
}
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
return
secMan &&
NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, PR_FALSE));
}
//*****************************************************************************
// nsClassifierCallback
//*****************************************************************************

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

@ -512,6 +512,11 @@ protected:
// Check whether aURI is about:blank
static PRBool IsAboutBlank(nsIURI* aURI);
// Call this when a URI load is handed to us (via OnLinkClick or
// InternalLoad). This makes sure that we're not inside unload, or that if
// we are it's still OK to load this URI.
PRBool IsOKToLoadURI(nsIURI* aURI);
protected:
// Override the parent setter from nsDocLoader
@ -642,6 +647,13 @@ protected:
// Suspends/resumes channels based on the URI classifier.
nsRefPtr<nsClassifierCallback> mClassifier;
// The URI we're currently loading. This is only relevant during the
// firing of a pagehide/unload. The caller of FirePageHideNotification()
// is responsible for setting it and unsetting it. It may be null if the
// pagehide/unload is happening for some reason other than just loading a
// new URI.
nsCOMPtr<nsIURI> mLoadingURI;
// WEAK REFERENCES BELOW HERE.
// Note these are intentionally not addrefd. Doing so will create a cycle.
// For that reasons don't use nsCOMPtr.

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

@ -766,7 +766,7 @@ nsWebShell::OnLinkClick(nsIContent* aContent,
{
NS_ASSERTION(NS_IsMainThread(), "wrong thread");
if (mFiredUnloadEvent) {
if (!IsOKToLoadURI(aURI)) {
return NS_OK;
}
@ -797,7 +797,7 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
*aRequest = nsnull;
}
if (mFiredUnloadEvent) {
if (!IsOKToLoadURI(aURI)) {
return NS_OK;
}