Backed out 2 changesets (bug 1709346) for causing XPCConvert crashes. CLOSED TREE

Backed out changeset 7c1e15680741 (bug 1709346)
Backed out changeset 34eff3430674 (bug 1709346)
This commit is contained in:
Csoregi Natalia 2021-05-26 00:32:25 +03:00
parent 49ef23c2f2
commit 15d4f16e13
18 changed files with 260 additions and 447 deletions

View File

@ -779,10 +779,8 @@ void BrowsingContext::Attach(bool aFromIPC, ContentParent* aOriginProcess) {
}
});
// We want to create a BrowsingContextWebProgress for all content
// BrowsingContexts.
if (IsContent() && !Canonical()->mWebProgress) {
Canonical()->mWebProgress = new BrowsingContextWebProgress(Canonical());
if (IsTopContent() && !Canonical()->GetWebProgress()) {
Canonical()->mWebProgress = new BrowsingContextWebProgress();
}
}

View File

@ -3,44 +3,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BrowsingContextWebProgress.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/Logging.h"
#include "nsCOMPtr.h"
#include "nsIWebProgressListener.h"
#include "nsString.h"
#include "nsPrintfCString.h"
#include "nsIChannel.h"
#include "xptinfo.h"
namespace mozilla {
namespace dom {
static mozilla::LazyLogModule gBCWebProgressLog("BCWebProgress");
NS_IMPL_ADDREF(BrowsingContextWebProgress)
NS_IMPL_RELEASE(BrowsingContextWebProgress)
static nsCString DescribeBrowsingContext(CanonicalBrowsingContext* aContext);
static nsCString DescribeWebProgress(nsIWebProgress* aWebProgress);
static nsCString DescribeRequest(nsIRequest* aRequest);
static nsCString DescribeWebProgressFlags(uint32_t aFlags,
const nsACString& aPrefix);
static nsCString DescribeError(nsresult aError);
NS_IMPL_CYCLE_COLLECTION(BrowsingContextWebProgress, mCurrentBrowsingContext)
NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContextWebProgress)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContextWebProgress)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContextWebProgress)
NS_INTERFACE_MAP_BEGIN(BrowsingContextWebProgress)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebProgress)
NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_END
BrowsingContextWebProgress::BrowsingContextWebProgress(
CanonicalBrowsingContext* aBrowsingContext)
: mCurrentBrowsingContext(aBrowsingContext) {}
BrowsingContextWebProgress::~BrowsingContextWebProgress() = default;
NS_IMETHODIMP BrowsingContextWebProgress::AddProgressListener(
nsIWebProgressListener* aListener, uint32_t aNotifyMask) {
nsWeakPtr listener = do_GetWeakReference(aListener);
@ -73,18 +48,18 @@ NS_IMETHODIMP BrowsingContextWebProgress::GetDOMWindow(
}
NS_IMETHODIMP BrowsingContextWebProgress::GetIsTopLevel(bool* aIsTopLevel) {
*aIsTopLevel = mCurrentBrowsingContext->IsTop();
*aIsTopLevel = true;
return NS_OK;
}
NS_IMETHODIMP BrowsingContextWebProgress::GetIsLoadingDocument(
bool* aIsLoadingDocument) {
*aIsLoadingDocument = mIsLoadingDocument;
*aIsLoadingDocument = false;
return NS_OK;
}
NS_IMETHODIMP BrowsingContextWebProgress::GetLoadType(uint32_t* aLoadType) {
*aLoadType = mLoadType;
*aLoadType = 0;
return NS_OK;
}
@ -119,38 +94,28 @@ void BrowsingContextWebProgress::UpdateAndNotifyListeners(
}
mListenerInfoList.Compact();
// Notify the parent BrowsingContextWebProgress of the event to continue
// propagating.
auto* parent = mCurrentBrowsingContext->GetParent();
if (parent && parent->GetWebProgress()) {
aCallback(parent->GetWebProgress());
}
}
void BrowsingContextWebProgress::ContextDiscarded() {
if (!mIsLoadingDocument) {
if (!mAwaitingStop) {
return;
}
// If our BrowsingContext is being discarded while still loading a document,
// fire a synthetic `STATE_STOP` to end the ongoing load.
MOZ_LOG(gBCWebProgressLog, LogLevel::Info,
("Discarded while loading %s",
DescribeBrowsingContext(mCurrentBrowsingContext).get()));
// This matches what nsDocLoader::doStopDocumentLoad does, except we don't
// bother notifying for `STATE_STOP | STATE_IS_DOCUMENT`,
// nsBrowserStatusFilter would filter it out before it gets to the parent
// process.
OnStateChange(this, mLoadingDocumentRequest,
STATE_STOP | STATE_IS_WINDOW | STATE_IS_NETWORK,
NS_ERROR_ABORT);
}
void BrowsingContextWebProgress::ContextReplaced(
CanonicalBrowsingContext* aNewContext) {
mCurrentBrowsingContext = aNewContext;
const int32_t flags = STATE_STOP | STATE_IS_WINDOW | STATE_IS_NETWORK;
UpdateAndNotifyListeners(((flags >> 16) & nsIWebProgress::NOTIFY_STATE_ALL),
[&](nsIWebProgressListener* listener) {
// TODO(emilio): We might want to stash the
// request from OnStateChange on a member or
// something if having no request causes trouble
// here. Ditto for the webprogress instance.
listener->OnStateChange(this,
/* aRequest = */ nullptr,
flags, NS_ERROR_ABORT);
});
}
////////////////////////////////////////////////////////////////////////////////
@ -161,62 +126,42 @@ BrowsingContextWebProgress::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aStateFlags,
nsresult aStatus) {
MOZ_LOG(
gBCWebProgressLog, LogLevel::Info,
("OnStateChange(%s, %s, %s, %s) on %s",
DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
DescribeWebProgressFlags(aStateFlags, "STATE_"_ns).get(),
DescribeError(aStatus).get(),
DescribeBrowsingContext(mCurrentBrowsingContext).get()));
bool targetIsThis = aWebProgress == this;
// We may receive a request from an in-process nsDocShell which doesn't have
// `aWebProgress == this` which we should still consider as targeting
// ourselves.
if (nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
docShell && docShell->GetBrowsingContext() == mCurrentBrowsingContext) {
targetIsThis = true;
aWebProgress->GetLoadType(&mLoadType);
}
// Track `mIsLoadingDocument` based on the notifications we've received so far
// if the nsIWebProgress being targeted is this one.
if (targetIsThis) {
constexpr uint32_t startFlags = nsIWebProgressListener::STATE_START |
nsIWebProgressListener::STATE_IS_DOCUMENT |
nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_WINDOW |
nsIWebProgressListener::STATE_IS_NETWORK;
constexpr uint32_t stopFlags = nsIWebProgressListener::STATE_STOP |
nsIWebProgressListener::STATE_IS_WINDOW;
constexpr uint32_t redirectFlags =
nsIWebProgressListener::STATE_IS_REDIRECTED_DOCUMENT;
if ((aStateFlags & startFlags) == startFlags) {
if (mIsLoadingDocument) {
// We received a duplicate `STATE_START` notification, silence this
// notification until we receive the matching `STATE_STOP` to not fire
// duplicate `STATE_START` notifications into frontend on process
// switches.
return NS_OK;
}
mIsLoadingDocument = true;
// Record the request we started the load with, so we can emit a synthetic
// `STATE_STOP` notification if the BrowsingContext is discarded before
// the notification arrives.
mLoadingDocumentRequest = aRequest;
} else if ((aStateFlags & stopFlags) == stopFlags) {
// We've received a `STATE_STOP` notification targeting this web progress,
// clear our loading document flag.
mIsLoadingDocument = false;
mLoadingDocumentRequest = nullptr;
} else if (mIsLoadingDocument &&
(aStateFlags & redirectFlags) == redirectFlags) {
// If we see a redirected document load, update the loading request which
// we'll emit the synthetic STATE_STOP notification with.
mLoadingDocumentRequest = aRequest;
const uint32_t startDocumentFlags =
nsIWebProgressListener::STATE_START |
nsIWebProgressListener::STATE_IS_DOCUMENT |
nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_WINDOW |
nsIWebProgressListener::STATE_IS_NETWORK;
bool isTopLevel = false;
nsresult rv = aWebProgress->GetIsTopLevel(&isTopLevel);
NS_ENSURE_SUCCESS(rv, rv);
bool isTopLevelStartDocumentEvent =
(aStateFlags & startDocumentFlags) == startDocumentFlags && isTopLevel;
// If we receive a matching STATE_START for a top-level document event,
// and we are currently not suspending this event, start suspending all
// further matching STATE_START events after this one.
if (isTopLevelStartDocumentEvent && !mAwaitingStop) {
mAwaitingStop = true;
} else if (mAwaitingStop) {
// If we are currently suspending matching STATE_START events, check if this
// is a corresponding STATE_STOP event.
const uint32_t stopWindowFlags = nsIWebProgressListener::STATE_STOP |
nsIWebProgressListener::STATE_IS_WINDOW;
bool isTopLevelStopWindowEvent =
(aStateFlags & stopWindowFlags) == stopWindowFlags && isTopLevel;
if (isTopLevelStopWindowEvent) {
// If this is a STATE_STOP event corresponding to the initial STATE_START
// event, stop suspending matching STATE_START events.
mAwaitingStop = false;
} else if (isTopLevelStartDocumentEvent) {
// We have received a matching STATE_START event at least twice, but
// haven't received the corresponding STATE_STOP event for the first one.
// Don't let this event through. This is probably a duplicate event from
// the new BrowserParent due to a process switch.
return NS_OK;
}
// Allow all other progress events that don't match top-level start document
// flags.
}
UpdateAndNotifyListeners(
@ -234,12 +179,6 @@ BrowsingContextWebProgress::OnProgressChange(nsIWebProgress* aWebProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) {
MOZ_LOG(
gBCWebProgressLog, LogLevel::Info,
("OnProgressChange(%s, %s, %d, %d, %d, %d) on %s",
DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress,
DescribeBrowsingContext(mCurrentBrowsingContext).get()));
UpdateAndNotifyListeners(
nsIWebProgress::NOTIFY_PROGRESS, [&](nsIWebProgressListener* listener) {
listener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress,
@ -254,13 +193,6 @@ BrowsingContextWebProgress::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* aLocation,
uint32_t aFlags) {
MOZ_LOG(
gBCWebProgressLog, LogLevel::Info,
("OnProgressChange(%s, %s, %s, %s) on %s",
DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
aLocation ? aLocation->GetSpecOrDefault().get() : "<null>",
DescribeWebProgressFlags(aFlags, "LOCATION_CHANGE_"_ns).get(),
DescribeBrowsingContext(mCurrentBrowsingContext).get()));
UpdateAndNotifyListeners(
nsIWebProgress::NOTIFY_LOCATION, [&](nsIWebProgressListener* listener) {
listener->OnLocationChange(aWebProgress, aRequest, aLocation, aFlags);
@ -273,12 +205,6 @@ BrowsingContextWebProgress::OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsresult aStatus,
const char16_t* aMessage) {
MOZ_LOG(
gBCWebProgressLog, LogLevel::Info,
("OnStatusChange(%s, %s, %s, \"%s\") on %s",
DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
DescribeError(aStatus).get(), NS_ConvertUTF16toUTF8(aMessage).get(),
DescribeBrowsingContext(mCurrentBrowsingContext).get()));
UpdateAndNotifyListeners(
nsIWebProgress::NOTIFY_STATUS, [&](nsIWebProgressListener* listener) {
listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
@ -290,11 +216,6 @@ NS_IMETHODIMP
BrowsingContextWebProgress::OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aState) {
MOZ_LOG(
gBCWebProgressLog, LogLevel::Info,
("OnSecurityChange(%s, %s, %x) on %s",
DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
aState, DescribeBrowsingContext(mCurrentBrowsingContext).get()));
UpdateAndNotifyListeners(
nsIWebProgress::NOTIFY_SECURITY, [&](nsIWebProgressListener* listener) {
listener->OnSecurityChange(aWebProgress, aRequest, aState);
@ -306,11 +227,6 @@ NS_IMETHODIMP
BrowsingContextWebProgress::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aEvent) {
MOZ_LOG(
gBCWebProgressLog, LogLevel::Info,
("OnContentBlockingEvent(%s, %s, %x) on %s",
DescribeWebProgress(aWebProgress).get(), DescribeRequest(aRequest).get(),
aEvent, DescribeBrowsingContext(mCurrentBrowsingContext).get()));
UpdateAndNotifyListeners(nsIWebProgress::NOTIFY_CONTENT_BLOCKING,
[&](nsIWebProgressListener* listener) {
listener->OnContentBlockingEvent(aWebProgress,
@ -319,97 +235,5 @@ BrowsingContextWebProgress::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// Helper methods for notification logging
static nsCString DescribeBrowsingContext(CanonicalBrowsingContext* aContext) {
if (!aContext) {
return "<null>"_ns;
}
nsCOMPtr<nsIURI> currentURI = aContext->GetCurrentURI();
return nsPrintfCString(
"{top:%d, id:%" PRIx64 ", url:%s}", aContext->IsTop(), aContext->Id(),
currentURI ? currentURI->GetSpecOrDefault().get() : "<null>");
}
static nsCString DescribeWebProgress(nsIWebProgress* aWebProgress) {
if (!aWebProgress) {
return "<null>"_ns;
}
bool isTopLevel = false;
aWebProgress->GetIsTopLevel(&isTopLevel);
bool isLoadingDocument = false;
aWebProgress->GetIsLoadingDocument(&isLoadingDocument);
return nsPrintfCString("{isTopLevel:%d, isLoadingDocument:%d}", isTopLevel,
isLoadingDocument);
}
static nsCString DescribeRequest(nsIRequest* aRequest) {
if (!aRequest) {
return "<null>"_ns;
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (!channel) {
return "<non-channel>"_ns;
}
nsCOMPtr<nsIURI> originalURI;
channel->GetOriginalURI(getter_AddRefs(originalURI));
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
return nsPrintfCString(
"{URI:%s, originalURI:%s}",
uri ? uri->GetSpecOrDefault().get() : "<null>",
originalURI ? originalURI->GetSpecOrDefault().get() : "<null>");
}
static nsCString DescribeWebProgressFlags(uint32_t aFlags,
const nsACString& aPrefix) {
nsCString flags;
uint32_t remaining = aFlags;
// Hackily fetch the names of each constant from the XPT information used for
// reflecting it into JS. This doesn't need to be reliable and just exists as
// a logging aid.
//
// If a change to xpt in the future breaks this code, just delete it and
// replace it with a normal hex log.
if (const auto* ifaceInfo =
nsXPTInterfaceInfo::ByIID(NS_GET_IID(nsIWebProgressListener))) {
for (uint16_t i = 0; i < ifaceInfo->ConstantCount(); ++i) {
const auto& constInfo = ifaceInfo->Constant(i);
nsDependentCString name(constInfo.Name());
if (!StringBeginsWith(name, aPrefix)) {
continue;
}
if (remaining & constInfo.mValue) {
remaining &= ~constInfo.mValue;
if (!flags.IsEmpty()) {
flags.AppendLiteral("|");
}
flags.Append(name);
}
}
}
if (remaining != 0 || flags.IsEmpty()) {
if (!flags.IsEmpty()) {
flags.AppendLiteral("|");
}
flags.AppendInt(remaining, 16);
}
return flags;
}
static nsCString DescribeError(nsresult aError) {
nsCString name;
GetErrorName(aError, name);
return name;
}
} // namespace dom
} // namespace mozilla

View File

@ -9,35 +9,18 @@
#include "nsIWebProgressListener.h"
#include "nsTObserverArray.h"
#include "nsWeakReference.h"
#include "nsCycleCollectionParticipant.h"
namespace mozilla {
namespace dom {
class CanonicalBrowsingContext;
/// Object acting as the nsIWebProgress instance for a BrowsingContext over its
/// lifetime.
///
/// An active toplevel CanonicalBrowsingContext will always have a
/// BrowsingContextWebProgress, which will be moved between contexts as
/// BrowsingContextGroup-changing loads are performed.
///
/// Subframes will only have a `BrowsingContextWebProgress` if they are loaded
/// in a content process, and will use the nsDocShell instead if they are loaded
/// in the parent process, as parent process documents cannot have or be
/// out-of-process iframes.
class BrowsingContextWebProgress final : public nsIWebProgress,
public nsIWebProgressListener {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(BrowsingContextWebProgress,
nsIWebProgress)
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESS
NS_DECL_NSIWEBPROGRESSLISTENER
explicit BrowsingContextWebProgress(
CanonicalBrowsingContext* aBrowsingContext);
BrowsingContextWebProgress() = default;
struct ListenerInfo {
ListenerInfo(nsIWeakReference* aListener, unsigned long aNotifyMask)
@ -58,12 +41,9 @@ class BrowsingContextWebProgress final : public nsIWebProgress,
};
void ContextDiscarded();
void ContextReplaced(CanonicalBrowsingContext* aNewContext);
void SetLoadType(uint32_t aLoadType) { mLoadType = aLoadType; }
private:
virtual ~BrowsingContextWebProgress();
virtual ~BrowsingContextWebProgress() = default;
void UpdateAndNotifyListeners(
uint32_t aFlag,
@ -72,26 +52,16 @@ class BrowsingContextWebProgress final : public nsIWebProgress,
using ListenerArray = nsAutoTObserverArray<ListenerInfo, 4>;
ListenerArray mListenerInfoList;
// The current BrowsingContext which owns this BrowsingContextWebProgress.
// This context may change during navigations and may not be fully attached at
// all times.
RefPtr<CanonicalBrowsingContext> mCurrentBrowsingContext;
// The current request being actively loaded by the BrowsingContext. Only set
// while mIsLoadingDocument is true, and is used to fire STATE_STOP
// notifications if the BrowsingContext is discarded while the load is
// ongoing.
nsCOMPtr<nsIRequest> mLoadingDocumentRequest;
// The most recent load type observed for this BrowsingContextWebProgress.
uint32_t mLoadType = 0;
// Are we currently in the process of loading a document? This is true between
// the `STATE_START` notification from content and the `STATE_STOP`
// notification being received. Duplicate `STATE_START` events may be
// discarded while loading a document to avoid noise caused by process
// switches.
bool mIsLoadingDocument = false;
// This indicates whether we are currently suspending onStateChange top level
// STATE_START events for a document. We start suspending whenever we receive
// the first STATE_START event with the matching flags (see
// ::RecvOnStateChange for details), until we get a corresponding STATE_STOP
// event. In the meantime, if there other onStateChange events, this flag does
// not affect them. We do this to avoid duplicate onStateChange STATE_START
// events that happen during process switch. With this flag, we allow
// onStateChange STATE_START event from the old BrowserParent, but not the
// same event from the new BrowserParent during a process switch.
bool mAwaitingStop = false;
};
} // namespace dom

View File

@ -157,61 +157,16 @@ nsISecureBrowserUI* CanonicalBrowsingContext::GetSecureBrowserUI() {
return mSecureBrowserUI;
}
namespace {
// The DocShellProgressBridge is attached to a root content docshell loaded in
// the parent process. Notifications are paired up with the docshell which they
// came from, so that they can be fired to the correct
// BrowsingContextWebProgress and bubble through this tree separately.
//
// Notifications are filtered by a nsBrowserStatusFilter before being received
// by the DocShellProgressBridge.
class DocShellProgressBridge : public nsIWebProgressListener {
public:
NS_DECL_ISUPPORTS
// NOTE: This relies in the expansion of `NS_FORWARD_SAFE` and all listener
// methods accepting an `aWebProgress` argument. If this changes in the
// future, this may need to be written manually.
NS_FORWARD_SAFE_NSIWEBPROGRESSLISTENER(GetTargetContext(aWebProgress))
explicit DocShellProgressBridge(uint64_t aTopContextId)
: mTopContextId(aTopContextId) {}
private:
virtual ~DocShellProgressBridge() = default;
nsIWebProgressListener* GetTargetContext(nsIWebProgress* aWebProgress) {
RefPtr<CanonicalBrowsingContext> context;
if (nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress)) {
context = docShell->GetBrowsingContext()->Canonical();
} else {
context = CanonicalBrowsingContext::Get(mTopContextId);
}
return context && !context->IsDiscarded() ? context->GetWebProgress()
: nullptr;
}
uint64_t mTopContextId = 0;
};
NS_IMPL_ISUPPORTS(DocShellProgressBridge, nsIWebProgressListener)
} // namespace
void CanonicalBrowsingContext::MaybeAddAsProgressListener(
nsIWebProgress* aWebProgress) {
// Only add as a listener if the created docshell is a toplevel content
// docshell. We'll get notifications for all of our subframes through a single
// listener.
if (!IsTopContent()) {
if (!GetWebProgress()) {
return;
}
if (!mDocShellProgressBridge) {
mDocShellProgressBridge = new DocShellProgressBridge(Id());
if (!mStatusFilter) {
mStatusFilter = new nsBrowserStatusFilter();
mStatusFilter->AddProgressListener(mDocShellProgressBridge,
mStatusFilter->AddProgressListener(GetWebProgress(),
nsIWebProgress::NOTIFY_ALL);
}
aWebProgress->AddProgressListener(mStatusFilter, nsIWebProgress::NOTIFY_ALL);
}
@ -222,10 +177,9 @@ void CanonicalBrowsingContext::ReplacedBy(
MOZ_ASSERT(!aNewContext->mSessionHistory);
MOZ_ASSERT(IsTop() && aNewContext->IsTop());
if (mStatusFilter) {
mStatusFilter->RemoveProgressListener(mDocShellProgressBridge);
mStatusFilter->RemoveProgressListener(mWebProgress);
mStatusFilter = nullptr;
}
mWebProgress->ContextReplaced(aNewContext);
aNewContext->mWebProgress = std::move(mWebProgress);
// Use the Transaction for the fields which need to be updated whether or not
@ -2280,7 +2234,7 @@ bool CanonicalBrowsingContext::AllowedInBFCache(
NS_IMPL_CYCLE_COLLECTION_INHERITED(CanonicalBrowsingContext, BrowsingContext,
mSessionHistory, mContainerFeaturePolicy,
mCurrentBrowserParent, mWebProgress)
mCurrentBrowserParent)
NS_IMPL_ADDREF_INHERITED(CanonicalBrowsingContext, BrowsingContext)
NS_IMPL_RELEASE_INHERITED(CanonicalBrowsingContext, BrowsingContext)

View File

@ -449,8 +449,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
RefPtr<nsSecureBrowserUI> mSecureBrowserUI;
RefPtr<BrowsingContextWebProgress> mWebProgress;
nsCOMPtr<nsIWebProgressListener> mDocShellProgressBridge;
RefPtr<nsBrowserStatusFilter> mStatusFilter;
RefPtr<FeaturePolicy> mContainerFeaturePolicy;

View File

@ -3766,7 +3766,10 @@ nsresult BrowserChild::PrepareProgressListenerData(
}
aWebProgressData.browsingContext() = docShell->GetBrowsingContext();
nsresult rv = aWebProgress->GetLoadType(&aWebProgressData.loadType());
nsresult rv =
aWebProgress->GetIsLoadingDocument(&aWebProgressData.isLoadingDocument());
NS_ENSURE_SUCCESS(rv, rv);
rv = aWebProgress->GetLoadType(&aWebProgressData.loadType());
NS_ENSURE_SUCCESS(rv, rv);
return PrepareRequestData(aRequest, aRequestData);

View File

@ -29,6 +29,7 @@
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/BrowserBridgeParent.h"
#include "mozilla/dom/RemoteDragStartData.h"
#include "mozilla/dom/RemoteWebProgress.h"
#include "mozilla/dom/RemoteWebProgressRequest.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStoreUtils.h"
@ -2682,17 +2683,14 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnStateChange(
const WebProgressData& aWebProgressData, const RequestData& aRequestData,
const uint32_t aStateFlags, const nsresult aStatus,
const Maybe<WebProgressStateChangeData>& aStateChangeData) {
RefPtr<CanonicalBrowsingContext> browsingContext =
BrowsingContextForWebProgress(aWebProgressData);
if (!browsingContext) {
return IPC_OK();
}
nsCOMPtr<nsIWebProgress> webProgress;
nsCOMPtr<nsIRequest> request;
if (aRequestData.requestURI()) {
request = MakeAndAddRef<RemoteWebProgressRequest>(
aRequestData.requestURI(), aRequestData.originalRequestURI(),
aRequestData.matchedList());
RefPtr<CanonicalBrowsingContext> browsingContext;
if (!ReconstructWebProgressAndRequest(
aWebProgressData, aRequestData, getter_AddRefs(webProgress),
getter_AddRefs(request), getter_AddRefs(browsingContext))) {
return IPC_OK();
}
if (aStateChangeData.isSome()) {
@ -2714,8 +2712,9 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnStateChange(
}
}
if (auto* listener = browsingContext->GetWebProgress()) {
listener->OnStateChange(listener, request, aStateFlags, aStatus);
if (nsCOMPtr<nsIWebProgressListener> listener =
GetBrowsingContext()->Top()->GetWebProgress()) {
listener->OnStateChange(webProgress, request, aStateFlags, aStatus);
}
return IPC_OK();
@ -2743,17 +2742,14 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
nsIURI* aLocation, const uint32_t aFlags, const bool aCanGoBack,
const bool aCanGoForward,
const Maybe<WebProgressLocationChangeData>& aLocationChangeData) {
RefPtr<CanonicalBrowsingContext> browsingContext =
BrowsingContextForWebProgress(aWebProgressData);
if (!browsingContext) {
return IPC_OK();
}
nsCOMPtr<nsIWebProgress> webProgress;
nsCOMPtr<nsIRequest> request;
if (aRequestData.requestURI()) {
request = MakeAndAddRef<RemoteWebProgressRequest>(
aRequestData.requestURI(), aRequestData.originalRequestURI(),
aRequestData.matchedList());
RefPtr<CanonicalBrowsingContext> browsingContext;
if (!ReconstructWebProgressAndRequest(
aWebProgressData, aRequestData, getter_AddRefs(webProgress),
getter_AddRefs(request), getter_AddRefs(browsingContext))) {
return IPC_OK();
}
browsingContext->SetCurrentRemoteURI(aLocation);
@ -2788,8 +2784,9 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
}
}
if (auto* listener = browsingContext->GetWebProgress()) {
listener->OnLocationChange(listener, request, aLocation, aFlags);
if (nsCOMPtr<nsIWebProgressListener> listener =
browsingContext->Top()->GetWebProgress()) {
listener->OnLocationChange(webProgress, request, aLocation, aFlags);
}
// Since we've now changed Documents, notify the BrowsingContext that we've
@ -2892,13 +2889,20 @@ already_AddRefed<nsIBrowser> BrowserParent::GetBrowser() {
return browser.forget();
}
already_AddRefed<CanonicalBrowsingContext>
BrowserParent::BrowsingContextForWebProgress(
const WebProgressData& aWebProgressData) {
bool BrowserParent::ReconstructWebProgressAndRequest(
const WebProgressData& aWebProgressData, const RequestData& aRequestData,
nsIWebProgress** aOutWebProgress, nsIRequest** aOutRequest,
CanonicalBrowsingContext** aOutBrowsingContext) {
MOZ_DIAGNOSTIC_ASSERT(aOutWebProgress,
"aOutWebProgress should never be null");
MOZ_DIAGNOSTIC_ASSERT(aOutRequest, "aOutRequest should never be null");
MOZ_DIAGNOSTIC_ASSERT(aOutBrowsingContext,
"aOutBrowsingContext should never be null");
// Look up the BrowsingContext which this notification was fired for.
if (aWebProgressData.browsingContext().IsNullOrDiscarded()) {
NS_WARNING("WebProgress Ignored: BrowsingContext is null or discarded");
return nullptr;
return false;
}
RefPtr<CanonicalBrowsingContext> browsingContext =
aWebProgressData.browsingContext().get_canonical();
@ -2911,7 +2915,7 @@ BrowserParent::BrowsingContextForWebProgress(
WindowGlobalParent* embedder = browsingContext->GetParentWindowContext();
if (!embedder || embedder->GetBrowserParent() != this) {
NS_WARNING("WebProgress Ignored: wrong embedder process");
return nullptr;
return false;
}
}
@ -2922,15 +2926,26 @@ BrowserParent::BrowsingContextForWebProgress(
browsingContext->GetCurrentWindowGlobal();
current && current->GetBrowserParent() != this) {
NS_WARNING("WebProgress Ignored: no longer current window global");
return nullptr;
return false;
}
if (RefPtr<BrowsingContextWebProgress> progress =
browsingContext->GetWebProgress()) {
progress->SetLoadType(aWebProgressData.loadType());
// Construct a temporary RemoteWebProgress and RemoteWebProgressRequest which
// contains relevant state used by our in-parent callbacks.
nsCOMPtr<nsIWebProgress> webProgress = MakeAndAddRef<RemoteWebProgress>(
aWebProgressData.loadType(), aWebProgressData.isLoadingDocument(),
browsingContext->IsTopContent());
nsCOMPtr<nsIRequest> request;
if (aRequestData.requestURI()) {
request = MakeAndAddRef<RemoteWebProgressRequest>(
aRequestData.requestURI(), aRequestData.originalRequestURI(),
aRequestData.matchedList());
}
return browsingContext.forget();
webProgress.forget(aOutWebProgress);
request.forget(aOutRequest);
browsingContext.forget(aOutBrowsingContext);
return true;
}
mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(

View File

@ -307,8 +307,10 @@ class BrowserParent final : public PBrowserParent,
already_AddRefed<nsIBrowser> GetBrowser();
already_AddRefed<CanonicalBrowsingContext> BrowsingContextForWebProgress(
const WebProgressData& aWebProgressData);
bool ReconstructWebProgressAndRequest(
const WebProgressData& aWebProgressData, const RequestData& aRequestData,
nsIWebProgress** aOutWebProgress, nsIRequest** aOutRequest,
CanonicalBrowsingContext** aOutBrowsingContext);
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,

View File

@ -116,6 +116,7 @@ namespace dom {
struct WebProgressData
{
MaybeDiscardedBrowsingContext browsingContext;
bool isLoadingDocument;
uint32_t loadType;
};

View File

@ -0,0 +1,58 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RemoteWebProgress.h"
namespace mozilla::dom {
NS_IMPL_ADDREF(RemoteWebProgress)
NS_IMPL_RELEASE(RemoteWebProgress)
NS_INTERFACE_MAP_BEGIN(RemoteWebProgress)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
NS_INTERFACE_MAP_END
NS_IMETHODIMP RemoteWebProgress::AddProgressListener(
nsIWebProgressListener* aListener, uint32_t aNotifyMask) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP RemoteWebProgress::RemoveProgressListener(
nsIWebProgressListener* aListener) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP RemoteWebProgress::GetDOMWindow(mozIDOMWindowProxy** aDOMWindow) {
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP RemoteWebProgress::GetIsTopLevel(bool* aIsTopLevel) {
NS_ENSURE_ARG_POINTER(aIsTopLevel);
*aIsTopLevel = mIsTopLevel;
return NS_OK;
}
NS_IMETHODIMP RemoteWebProgress::GetIsLoadingDocument(
bool* aIsLoadingDocument) {
NS_ENSURE_ARG_POINTER(aIsLoadingDocument);
*aIsLoadingDocument = mIsLoadingDocument;
return NS_OK;
}
NS_IMETHODIMP RemoteWebProgress::GetLoadType(uint32_t* aLoadType) {
NS_ENSURE_ARG_POINTER(aLoadType);
*aLoadType = mLoadType;
return NS_OK;
}
NS_IMETHODIMP RemoteWebProgress::GetTarget(nsIEventTarget** aTarget) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP RemoteWebProgress::SetTarget(nsIEventTarget* aTarget) {
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace mozilla::dom

View File

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_RemoteWebProgress_h
#define mozilla_dom_RemoteWebProgress_h
#include "nsIWebProgress.h"
#include "nsCOMPtr.h"
namespace mozilla {
namespace dom {
class RemoteWebProgress final : public nsIWebProgress {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESS
RemoteWebProgress()
: mLoadType(0), mIsLoadingDocument(false), mIsTopLevel(false) {}
RemoteWebProgress(uint32_t aLoadType, bool aIsLoadingDocument,
bool aIsTopLevel)
: mLoadType(aLoadType),
mIsLoadingDocument(aIsLoadingDocument),
mIsTopLevel(aIsTopLevel) {}
private:
virtual ~RemoteWebProgress() = default;
uint32_t mLoadType;
bool mIsLoadingDocument;
bool mIsTopLevel;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_RemoteWebProgress_h

View File

@ -22,6 +22,7 @@
#include "mozilla/dom/BrowserHost.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/MediaController.h"
#include "mozilla/dom/RemoteWebProgress.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/ChromeUtils.h"
#include "mozilla/dom/ipc/IdType.h"
@ -524,9 +525,14 @@ void WindowGlobalParent::NotifyContentBlockingEvent(
// Notify the OnContentBlockingEvent if necessary.
if (event) {
if (auto* webProgress = GetBrowsingContext()->GetWebProgress()) {
webProgress->OnContentBlockingEvent(webProgress, aRequest, event.value());
if (!GetBrowsingContext()->GetWebProgress()) {
return;
}
nsCOMPtr<nsIWebProgress> webProgress =
new RemoteWebProgress(0, false, BrowsingContext()->IsTopContent());
GetBrowsingContext()->Top()->GetWebProgress()->OnContentBlockingEvent(
webProgress, aRequest, event.value());
}
}

View File

@ -62,6 +62,7 @@ EXPORTS.mozilla.dom += [
"RefMessageBodyService.h",
"RemoteBrowser.h",
"RemoteType.h",
"RemoteWebProgress.h",
"RemoteWebProgressRequest.h",
"SharedMessageBody.h",
"TabContext.h",
@ -113,6 +114,7 @@ UNIFIED_SOURCES += [
"ReferrerInfoUtils.cpp",
"RefMessageBodyService.cpp",
"RemoteBrowser.cpp",
"RemoteWebProgress.cpp",
"RemoteWebProgressRequest.cpp",
"SharedMap.cpp",
"SharedMessageBody.cpp",

View File

@ -139,7 +139,3 @@ support-files =
support-files =
page_bytecode_cache_asm_js.html
page_bytecode_cache_asm_js.js
[browser_bug1709346.js]
support-files =
load_forever.sjs
file_empty_cross_site_frame.html

View File

@ -1,48 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
add_task(async function remove_subframe_in_cross_site_frame() {
await BrowserTestUtils.withNewTab(
"http://mochi.test:8888/browser/dom/tests/browser/file_empty_cross_site_frame.html",
async browser => {
await TestUtils.waitForCondition(
() => !XULBrowserWindow.isBusy,
"browser is not busy after the tab finishes loading"
);
// Spawn into the cross-site subframe, and begin loading a slow network
// connection. We'll cancel the load before this navigation completes.
await SpecialPowers.spawn(
browser.browsingContext.children[0],
[],
async () => {
let frame = content.document.createElement("iframe");
frame.src = "load_forever.sjs";
content.document.body.appendChild(frame);
frame.addEventListener("load", function() {
ok(false, "load should not finish before the frame is removed");
});
}
);
is(
XULBrowserWindow.isBusy,
true,
"browser should be busy after the load starts"
);
// Remove the outer iframe, ending the load within this frame's subframe
// early.
await SpecialPowers.spawn(browser, [], async () => {
content.document.querySelector("iframe").remove();
});
await TestUtils.waitForCondition(
() => !XULBrowserWindow.isBusy,
"Browser should no longer be busy after the frame is removed"
);
}
);
});

View File

@ -1,2 +0,0 @@
<!doctype html>
<iframe src="http://example.com/browser/dom/tests/browser/file_empty.html"></iframe>

View File

@ -1,15 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let gResponses = [];
function handleRequest(request, response) {
response.seizePower();
response.write("HTTP/1.1 200 OK\r\n");
response.write("Content-Type: text/plain; charset=utf-8\r\n");
response.write("Cache-Control: no-cache, must-revalidate\r\n");
response.write("\r\n");
// Keep the response alive indefinitely.
gResponses.push(response);
}

View File

@ -53,6 +53,7 @@
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/nsHTTPSOnlyUtils.h"
#include "mozilla/dom/RemoteWebProgress.h"
#include "mozilla/dom/RemoteWebProgressRequest.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/ExtensionPolicyService.h"
@ -178,6 +179,13 @@ static auto CreateObjectLoadInfo(nsDocShellLoadState* aLoadState,
return loadInfo.forget();
}
static auto WebProgressForBrowsingContext(
CanonicalBrowsingContext* aBrowsingContext)
-> already_AddRefed<BrowsingContextWebProgress> {
return RefPtr<BrowsingContextWebProgress>(aBrowsingContext->GetWebProgress())
.forget();
}
/**
* An extension to nsDocumentOpenInfo that we run in the parent process, so
* that we can make the decision to retarget to content handlers or the external
@ -858,15 +866,17 @@ auto DocumentLoadListener::OpenInParent(nsDocShellLoadState* aLoadState,
void DocumentLoadListener::FireStateChange(uint32_t aStateFlags,
nsresult aStatus) {
nsCOMPtr<nsIChannel> request = GetChannel();
nsCOMPtr<nsIWebProgress> webProgress =
new RemoteWebProgress(GetLoadType(), true, true);
RefPtr<BrowsingContextWebProgress> webProgress =
GetLoadingBrowsingContext()->GetWebProgress();
RefPtr<BrowsingContextWebProgress> loadingWebProgress =
WebProgressForBrowsingContext(GetLoadingBrowsingContext());
if (webProgress) {
if (loadingWebProgress) {
NS_DispatchToMainThread(
NS_NewRunnableFunction("DocumentLoadListener::FireStateChange", [=]() {
webProgress->OnStateChange(webProgress, request, aStateFlags,
aStatus);
loadingWebProgress->OnStateChange(webProgress, request, aStateFlags,
aStatus);
}));
}
}
@ -2615,16 +2625,18 @@ NS_IMETHODIMP DocumentLoadListener::OnStatus(nsIRequest* aRequest,
nsresult aStatus,
const char16_t* aStatusArg) {
nsCOMPtr<nsIChannel> channel = mChannel;
nsCOMPtr<nsIWebProgress> webProgress =
new RemoteWebProgress(mLoadStateLoadType, true, true);
RefPtr<BrowsingContextWebProgress> webProgress =
GetLoadingBrowsingContext()->GetWebProgress();
RefPtr<BrowsingContextWebProgress> topWebProgress =
WebProgressForBrowsingContext(GetTopBrowsingContext());
const nsString message(aStatusArg);
if (webProgress) {
if (topWebProgress) {
NS_DispatchToMainThread(
NS_NewRunnableFunction("DocumentLoadListener::OnStatus", [=]() {
webProgress->OnStatusChange(webProgress, channel, aStatus,
message.get());
topWebProgress->OnStatusChange(webProgress, channel, aStatus,
message.get());
}));
}
return NS_OK;