Bug 1908729 - Part 2: Replace nsIObserver with GlobalObservers in EventSource r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D217128
This commit is contained in:
Kagami Sascha Rosylight 2024-07-30 13:53:59 +00:00
parent 137e8b83ee
commit 12446358df

View file

@ -10,6 +10,7 @@
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/LoadInfo.h" #include "mozilla/LoadInfo.h"
#include "mozilla/DOMEventTargetHelper.h" #include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/GlobalFreezeObserver.h"
#include "mozilla/dom/EventSource.h" #include "mozilla/dom/EventSource.h"
#include "mozilla/dom/EventSourceBinding.h" #include "mozilla/dom/EventSourceBinding.h"
#include "mozilla/dom/MessageEvent.h" #include "mozilla/dom/MessageEvent.h"
@ -39,7 +40,6 @@
#include "nsContentPolicyUtils.h" #include "nsContentPolicyUtils.h"
#include "nsIStringBundle.h" #include "nsIStringBundle.h"
#include "nsIConsoleService.h" #include "nsIConsoleService.h"
#include "nsIObserverService.h"
#include "nsIScriptObjectPrincipal.h" #include "nsIScriptObjectPrincipal.h"
#include "nsJSUtils.h" #include "nsJSUtils.h"
#include "nsIThreadRetargetableRequest.h" #include "nsIThreadRetargetableRequest.h"
@ -72,17 +72,16 @@ static LazyLogModule gEventSourceLog("EventSource");
#define MAX_RECONNECTION_TIME_VALUE \ #define MAX_RECONNECTION_TIME_VALUE \
PR_IntervalToMilliseconds(DELAY_INTERVAL_LIMIT) PR_IntervalToMilliseconds(DELAY_INTERVAL_LIMIT)
class EventSourceImpl final : public nsIObserver, class EventSourceImpl final : public nsIChannelEventSink,
public nsIChannelEventSink,
public nsIInterfaceRequestor, public nsIInterfaceRequestor,
public nsSupportsWeakReference,
public nsISerialEventTarget, public nsISerialEventTarget,
public nsITimerCallback, public nsITimerCallback,
public nsINamed, public nsINamed,
public nsIThreadRetargetableStreamListener { public nsIThreadRetargetableStreamListener,
public GlobalTeardownObserver,
public GlobalFreezeObserver {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
@ -99,7 +98,8 @@ class EventSourceImpl final : public nsIObserver,
void Close(); void Close();
void Init(nsIPrincipal* aPrincipal, const nsAString& aURL, ErrorResult& aRv); void Init(nsIGlobalObject* aWindowGlobal, nsIPrincipal* aPrincipal,
const nsAString& aURL, ErrorResult& aRv);
nsresult GetBaseURI(nsIURI** aBaseURI); nsresult GetBaseURI(nsIURI** aBaseURI);
@ -117,6 +117,19 @@ class EventSourceImpl final : public nsIObserver,
void DispatchFailConnection(); void DispatchFailConnection();
void FailConnection(); void FailConnection();
void DisconnectFromOwner() override {
Close();
GlobalTeardownObserver::DisconnectFromOwner();
}
void FrozenCallback(nsIGlobalObject* aOwner) override {
DebugOnly<nsresult> rv = Freeze();
MOZ_ASSERT(NS_SUCCEEDED(rv), "Freeze() failed");
}
void ThawedCallback(nsIGlobalObject* aOwner) override {
DebugOnly<nsresult> rv = Thaw();
MOZ_ASSERT(NS_SUCCEEDED(rv), "Thaw() failed");
}
nsresult Thaw(); nsresult Thaw();
nsresult Freeze(); nsresult Freeze();
@ -137,7 +150,7 @@ class EventSourceImpl final : public nsIObserver,
nsresult CheckHealthOfRequestCallback(nsIRequest* aRequestCallback); nsresult CheckHealthOfRequestCallback(nsIRequest* aRequestCallback);
nsresult OnRedirectVerifyCallback(nsresult result); nsresult OnRedirectVerifyCallback(nsresult result);
nsresult ParseURL(const nsAString& aURL); nsresult ParseURL(const nsAString& aURL);
nsresult AddWindowObservers(); nsresult AddGlobalObservers(nsIGlobalObject* aGlobal);
void RemoveWindowObservers(); void RemoveWindowObservers();
void CloseInternal(); void CloseInternal();
@ -361,9 +374,8 @@ class EventSourceImpl final : public nsIObserver,
} }
}; };
NS_IMPL_ISUPPORTS(EventSourceImpl, nsIObserver, nsIStreamListener, NS_IMPL_ISUPPORTS(EventSourceImpl, nsIStreamListener, nsIRequestObserver,
nsIRequestObserver, nsIChannelEventSink, nsIChannelEventSink, nsIInterfaceRequestor,
nsIInterfaceRequestor, nsISupportsWeakReference,
nsISerialEventTarget, nsIEventTarget, nsISerialEventTarget, nsIEventTarget,
nsIThreadRetargetableStreamListener, nsITimerCallback, nsIThreadRetargetableStreamListener, nsITimerCallback,
nsINamed) nsINamed)
@ -512,7 +524,7 @@ class InitRunnable final : public WorkerMainThreadRunnable {
return true; return true;
} }
ErrorResult rv; ErrorResult rv;
mESImpl->Init(principal, mURL, rv); mESImpl->Init(nullptr, principal, mURL, rv);
mRv = rv.StealNSResult(); mRv = rv.StealNSResult();
// We want to ensure that EventSourceImpl's lifecycle // We want to ensure that EventSourceImpl's lifecycle
@ -599,19 +611,14 @@ nsresult EventSourceImpl::ParseURL(const nsAString& aURL) {
return NS_OK; return NS_OK;
} }
nsresult EventSourceImpl::AddWindowObservers() { nsresult EventSourceImpl::AddGlobalObservers(nsIGlobalObject* aGlobal) {
AssertIsOnMainThread(); AssertIsOnMainThread();
MOZ_ASSERT(mIsMainThread); MOZ_ASSERT(mIsMainThread);
MOZ_ASSERT(!mIsShutDown); MOZ_ASSERT(!mIsShutDown);
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
NS_ENSURE_STATE(os);
nsresult rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true); GlobalTeardownObserver::BindToOwner(aGlobal);
NS_ENSURE_SUCCESS(rv, rv); GlobalFreezeObserver::BindToOwner(aGlobal);
rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
NS_ENSURE_SUCCESS(rv, rv);
rv = os->AddObserver(this, DOM_WINDOW_THAWED_TOPIC, true);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
@ -619,17 +626,16 @@ void EventSourceImpl::RemoveWindowObservers() {
AssertIsOnMainThread(); AssertIsOnMainThread();
MOZ_ASSERT(mIsMainThread); MOZ_ASSERT(mIsMainThread);
MOZ_ASSERT(IsClosed()); MOZ_ASSERT(IsClosed());
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); GlobalTeardownObserver::DisconnectFromOwner();
if (os) { DisconnectFreezeObserver();
os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
os->RemoveObserver(this, DOM_WINDOW_THAWED_TOPIC);
}
} }
void EventSourceImpl::Init(nsIPrincipal* aPrincipal, const nsAString& aURL, void EventSourceImpl::Init(nsIGlobalObject* aWindowGlobal,
nsIPrincipal* aPrincipal, const nsAString& aURL,
ErrorResult& aRv) { ErrorResult& aRv) {
AssertIsOnMainThread(); AssertIsOnMainThread();
// aWindowGlobal should only exist for main-thread EventSource
MOZ_ASSERT_IF(aWindowGlobal, mIsMainThread);
MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(ReadyState() == CONNECTING); MOZ_ASSERT(ReadyState() == CONNECTING);
mPrincipal = aPrincipal; mPrincipal = aPrincipal;
@ -645,8 +651,14 @@ void EventSourceImpl::Init(nsIPrincipal* aPrincipal, const nsAString& aURL,
} }
if (mIsMainThread) { if (mIsMainThread) {
// we observe when the window freezes and thaws // We observe when the window freezes and thaws.
aRv = AddWindowObservers(); //
// This will store raw pointer of us in GTO, which sounds scary as the
// object can be accessed cross thread. But it should be safe as GTO and
// EventSourceImpl lifetime should be managed in the same main thread.
//
// XXX(krosylight): But what about workers? See bug 1910585.
aRv = AddGlobalObservers(aWindowGlobal);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return; return;
} }
@ -659,42 +671,6 @@ void EventSourceImpl::Init(nsIPrincipal* aPrincipal, const nsAString& aURL,
mUnicodeDecoder = UTF_8_ENCODING->NewDecoderWithBOMRemoval(); mUnicodeDecoder = UTF_8_ENCODING->NewDecoderWithBOMRemoval();
} }
//-----------------------------------------------------------------------------
// EventSourceImpl::nsIObserver
//-----------------------------------------------------------------------------
NS_IMETHODIMP
EventSourceImpl::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
AssertIsOnMainThread();
if (IsClosed()) {
return NS_OK;
}
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aSubject);
MOZ_ASSERT(mIsMainThread);
{
auto lock = mSharedData.Lock();
if (!lock->mEventSource->GetOwnerWindow() ||
window != lock->mEventSource->GetOwnerWindow()) {
return NS_OK;
}
}
DebugOnly<nsresult> rv;
if (strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) {
rv = Freeze();
MOZ_ASSERT(NS_SUCCEEDED(rv), "Freeze() failed");
} else if (strcmp(aTopic, DOM_WINDOW_THAWED_TOPIC) == 0) {
rv = Thaw();
MOZ_ASSERT(NS_SUCCEEDED(rv), "Thaw() failed");
} else if (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0) {
Close();
}
return NS_OK;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// EventSourceImpl::nsIStreamListener // EventSourceImpl::nsIStreamListener
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2032,7 +2008,7 @@ already_AddRefed<EventSource> EventSource::Constructor(
aRv.Throw(NS_ERROR_FAILURE); aRv.Throw(NS_ERROR_FAILURE);
return nullptr; return nullptr;
} }
eventSource->mESImpl->Init(principal, aURL, aRv); eventSource->mESImpl->Init(global, principal, aURL, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }