Bug 311007 - Add onLocationChange2 which distinguishes between same-document and different-document location changes to web progress listeners. r=smaug, sr=bzbarsky

This commit is contained in:
Oonishi Atsushi 2011-06-04 05:31:07 +09:00
parent 70f5d4d89e
commit a32cac7d4c
13 changed files with 169 additions and 25 deletions

View File

@ -4366,6 +4366,10 @@ var XULBrowserWindow = {
}
},
onLocationChange2: function (aWebProgress, aRequest, aLocationURI, aFlags) {
onLocationChange(aWebProgress, aRequest, aLocationURI);
},
onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
var location = aLocationURI ? aLocationURI.spec : "";
this._hostChanged = true;

View File

@ -1726,17 +1726,20 @@ nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
return NS_OK;
}
/* [noscript] void setCurrentURI (in nsIURI uri); */
/* void setCurrentURI (in nsIURI uri); */
NS_IMETHODIMP
nsDocShell::SetCurrentURI(nsIURI *aURI)
{
SetCurrentURI(aURI, nsnull, PR_TRUE);
// Note that securityUI will set STATE_IS_INSECURE, even if
// the scheme of |aURI| is "https".
SetCurrentURI(aURI, nsnull, PR_TRUE,
nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
return NS_OK;
}
PRBool
nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
PRBool aFireOnLocationChange)
PRBool aFireOnLocationChange, PRUint32 aLocationFlags)
{
#ifdef PR_LOGGING
if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
@ -1780,7 +1783,7 @@ nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
}
if (aFireOnLocationChange) {
FireOnLocationChange(this, aRequest, aURI);
FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
}
return !aFireOnLocationChange;
}
@ -5870,7 +5873,8 @@ nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
// a new DOM here.
rv = AddToSessionHistory(uri, wcwgChannel, nsnull, PR_FALSE,
getter_AddRefs(mLSHE));
SetCurrentURI(uri, aRequest, PR_TRUE);
SetCurrentURI(uri, aRequest, PR_TRUE,
nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
// Save history state of the previous page
rv = PersistLayoutHistoryState();
// We'll never get an Embed() for this load, so just go ahead
@ -6523,7 +6527,8 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
viewer->SetContainer(static_cast<nsIContentViewerContainer *>(this));
Embed(viewer, "", 0);
SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, PR_TRUE);
SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, PR_TRUE,
nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
}
}
@ -7174,7 +7179,8 @@ nsDocShell::RestoreFromHistory()
// is still mLSHE or whether it's now mOSHE.
nsCOMPtr<nsIURI> uri;
origLSHE->GetURI(getter_AddRefs(uri));
SetCurrentURI(uri, document->GetChannel(), PR_TRUE);
SetCurrentURI(uri, document->GetChannel(), PR_TRUE,
nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
}
// This is the end of our CreateContentViewer() replacement.
@ -7513,7 +7519,8 @@ nsDocShell::CreateContentViewer(const char *aContentType,
}
if (onLocationChangeNeeded) {
FireOnLocationChange(this, request, mCurrentURI);
FireOnLocationChange(this, request, mCurrentURI,
nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
}
return NS_OK;
@ -8384,6 +8391,11 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// Pass true for aCloneSHChildren, since we're not
// changing documents here, so all of our subframes are
// still relevant to the new session history entry.
//
// It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
// flag on firing onLocationChange(...).
// Anyway, aCloneSHChildren param is simply reflecting
// doShortCircuitedLoad in this scope.
OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE, PR_TRUE, PR_TRUE);
nsCOMPtr<nsIInputStream> postData;
@ -9459,8 +9471,14 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
#endif
}
}
// aCloneSHChildren exactly means "we are not loading a new document".
PRUint32 locationFlags = aCloneSHChildren?
PRUint32(nsIWebProgressListener2::LOCATION_CHANGE_SAME_DOCUMENT) :
PRUint32(nsIWebProgressListener2::LOCATION_CHANGE_NORMAL);
PRBool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
aFireOnLocationChange);
aFireOnLocationChange,
locationFlags);
// Make sure to store the referrer from the channel, if any
SetupReferrerFromChannel(aChannel);
return onLocationChangeNeeded;
@ -9764,8 +9782,15 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
// gets updated and the back button is enabled, but we only need to
// explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
// since SetCurrentURI will call FireOnLocationChange for us.
//
// Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
// nsnull for aRequest param to FireOnLocationChange(...). Such an update
// notification is allowed only when we know docshell is not loading a new
// document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
// FireOnLocationChange(...) breaks security UI.
if (!equalURIs) {
SetCurrentURI(newURI, nsnull, PR_TRUE);
SetCurrentURI(newURI, nsnull, PR_TRUE,
nsIWebProgressListener2::LOCATION_CHANGE_SAME_DOCUMENT);
document->SetDocumentURI(newURI);
AddURIVisit(newURI, oldURI, oldURI, 0);

View File

@ -94,7 +94,7 @@
#include "nsISupportsArray.h"
#include "nsIWebNavigation.h"
#include "nsIWebPageDescriptor.h"
#include "nsIWebProgressListener.h"
#include "nsIWebProgressListener2.h"
#include "nsISHContainer.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIDocShellHistory.h"
@ -268,10 +268,13 @@ public:
friend class OnLinkClickEvent;
// We need dummy OnLocationChange in some cases to update the UI.
// We need dummy OnLocationChange in some cases to update the UI without
// updating security info.
void FireDummyOnLocationChange()
{
FireOnLocationChange(this, nsnull, mCurrentURI);
FireOnLocationChange
(this, nsnull, mCurrentURI,
nsIWebProgressListener2::LOCATION_CHANGE_SAME_DOCUMENT);
}
nsresult HistoryTransactionRemoved(PRInt32 aIndex);
@ -592,7 +595,8 @@ protected:
// FireOnLocationChange is called.
// In all other cases PR_FALSE is returned.
PRBool SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
PRBool aFireOnLocationChange);
PRBool aFireOnLocationChange,
PRUint32 aLocationFlags);
// The following methods deal with saving and restoring content viewers
// in session history.

View File

@ -192,9 +192,10 @@ nsSecureBrowserUIImpl::~nsSecureBrowserUIImpl()
}
}
NS_IMPL_THREADSAFE_ISUPPORTS6(nsSecureBrowserUIImpl,
NS_IMPL_THREADSAFE_ISUPPORTS7(nsSecureBrowserUIImpl,
nsISecureBrowserUI,
nsIWebProgressListener,
nsIWebProgressListener2,
nsIFormSubmitObserver,
nsIObserver,
nsISupportsWeakReference,
@ -1516,6 +1517,39 @@ NS_IMETHODIMP
nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* aLocation)
{
NS_NOTREACHED("onLocationChange2(...) should be called instead.");
return NS_OK;
}
// nsIWebProgressListener2
NS_IMETHODIMP
nsSecureBrowserUIImpl::OnProgressChange64(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
PRInt64 aCurSelfProgress,
PRInt64 aMaxSelfProgress,
PRInt64 aCurTotalProgress,
PRInt64 aMaxTotalProgress)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsSecureBrowserUIImpl::OnRefreshAttempted(nsIWebProgress* aWebProgress,
nsIURI* aRefreshURI, PRInt32 aMillis,
PRBool aSameURI, PRBool* aResult)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
*aResult = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsSecureBrowserUIImpl::OnLocationChange2(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* aLocation,
PRUint32 aFlags)
{
#ifdef DEBUG
nsAutoAtomic atomic(mOnStateLocationChangeReentranceDetection);
@ -1555,9 +1589,10 @@ nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
NS_ASSERTION(window, "Window has gone away?!");
}
// If the location change does not have a corresponding request, then we
// assume that it does not impact the security state.
if (!aRequest)
// When |aRequest| is null, basically we don't trust that document. But if
// docshell insists that the document has not changed at all, we will reuse
// the previous security state, no matter what |aRequest| may be.
if (aFlags & LOCATION_CHANGE_SAME_DOCUMENT)
return NS_OK;
// The location bar has changed, so we must update the security state. The

View File

@ -53,7 +53,7 @@
#include "nsIStringBundle.h"
#include "nsISecureBrowserUI.h"
#include "nsIDocShell.h"
#include "nsIWebProgressListener.h"
#include "nsIWebProgressListener2.h"
#include "nsIFormSubmitObserver.h"
#include "nsIURI.h"
#include "nsISecurityEventSink.h"
@ -72,7 +72,7 @@ class nsIChannel;
class nsSecureBrowserUIImpl : public nsISecureBrowserUI,
public nsIWebProgressListener,
public nsIWebProgressListener2,
public nsIFormSubmitObserver,
public nsIObserver,
public nsSupportsWeakReference,
@ -85,6 +85,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
NS_DECL_NSIWEBPROGRESSLISTENER2
NS_DECL_NSISECUREBROWSERUI
// nsIObserver

View File

@ -2437,6 +2437,14 @@ nsDownload::OnRefreshAttempted(nsIWebProgress *aWebProgress,
return NS_OK;
}
NS_IMETHODIMP
nsDownload::OnLocationChange2(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation,
PRUint32 aFlags)
{
return OnLocationChange(aWebProgress, aRequest, aLocation);
}
////////////////////////////////////////////////////////////////////////////////
//// nsIWebProgressListener

View File

@ -128,6 +128,13 @@ public:
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
return mInner->OnLocationChange(aWebProgress, aRequest, aLocation);
}
NS_IMETHODIMP OnLocationChange2(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation,
PRUint32 aFlags)
{
return OnLocationChange(aWebProgress, aRequest, aLocation);
}
NS_IMETHODIMP OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,

View File

@ -309,6 +309,15 @@ nsBrowserStatusFilter::OnRefreshAttempted(nsIWebProgress *aWebProgress,
allowRefresh);
}
NS_IMETHODIMP
nsBrowserStatusFilter::OnLocationChange2(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
nsIURI *aLocation,
PRUint32 aFlags)
{
return OnLocationChange(aWebProgress, aRequest, aLocation);
}
//-----------------------------------------------------------------------------
// nsBrowserStatusFilter <private>
//-----------------------------------------------------------------------------

View File

@ -88,6 +88,7 @@ MockTransferForContinuing.prototype = {
aMaxTotalProgress) { },
onRefreshAttempted: function(aWebProgress, aRefreshURI, aMillis,
aSameURI) { },
onLocationChange2: function(aWebProgress, aRequest, aLocation, aFlags) { },
//////////////////////////////////////////////////////////////////////////////
//// nsITransfer

View File

@ -116,6 +116,9 @@ nsUnkownContentTypeDialogProgressListener.prototype = {
onRefreshAttempted: function( aWebProgress, aURI, aDelay, aSameURI ) {
return true;
},
onLocationChange2: function( aWebProgress, aRequest, aLocation, aFlags ) {
}
};

View File

@ -1352,7 +1352,8 @@ void nsDocLoader::FireOnStateChange(nsIWebProgress *aProgress,
void
nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI *aUri)
nsIURI *aUri,
PRUint32 aFlags)
{
/*
* First notify any listeners of the new state info...
@ -1379,14 +1380,21 @@ nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress,
continue;
}
listener->OnLocationChange(aWebProgress, aRequest, aUri);
nsCOMPtr<nsIWebProgressListener2>
listener2(do_QueryReferent(info->mWeakListener));
if (listener2) {
listener2->OnLocationChange2(aWebProgress, aRequest, aUri, aFlags);
} else {
listener->OnLocationChange(aWebProgress, aRequest, aUri);
}
}
mListenerInfoList.Compact();
// Pass the notification up to the parent...
if (mParent) {
mParent->FireOnLocationChange(aWebProgress, aRequest, aUri);
mParent->FireOnLocationChange(aWebProgress, aRequest, aUri, aFlags);
}
}

View File

@ -165,7 +165,8 @@ protected:
void FireOnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI *aUri);
nsIURI *aUri,
PRUint32 aFlags);
PRBool RefreshAttempted(nsIWebProgress* aWebProgress,
nsIURI *aURI,

View File

@ -40,7 +40,7 @@
/**
* An extended version of nsIWebProgressListener.
*/
[scriptable, uuid(dde39de0-e4e0-11da-8ad9-0800200c9a66)]
[scriptable, uuid(9fad5966-62ea-11e0-966c-001320257da5)]
interface nsIWebProgressListener2 : nsIWebProgressListener {
/**
* Notification that the progress has changed for one of the requests
@ -99,4 +99,42 @@ interface nsIWebProgressListener2 : nsIWebProgressListener {
in nsIURI aRefreshURI,
in long aMillis,
in boolean aSameURI);
/**
* Flags for onLocationChange2
*
* LOCATION_CHANGE_NORMAL
* Nothing special.
*
* LOCATION_CHANGE_SAME_DOCUMENT
* This flag is on when |aWebProgress| did not load a new document.
* For example,
* 1. The user clicks that anchor in a document which is linking to
* [1.a.] the document itself.
* [1.b.] a location only <#hash> portion changed.
* 2. The user inputs [1.b.]'s URI in the location bar.
* 3. Session history navigation.
* [3.a.] history.pushState(...), history.replaceState(...) or
* history.popState(...) is called and |aWebProgress| wants to
* update the UI.
* [3.b.] Back/Forward/Go to URI of [1.a.], [1.b.] or [3.a.].
* [3.c.] After session history is cleared.
*/
const unsigned long LOCATION_CHANGE_NORMAL = 0x00000001;
const unsigned long LOCATION_CHANGE_SAME_DOCUMENT = 0x00000002;
/**
* This function is identical to nsIWebProgressListener::onLocationChange,
* except for aFlags argument.
*
* @param aFlags
* This is a value which explains the situation or the reason why
* the location has changed.
*/
void onLocationChange2(in nsIWebProgress aWebProgress,
in nsIRequest aRequest,
in nsIURI aLocation,
in unsigned long aFlags);
};