summaryrefslogtreecommitdiffstats
path: root/dom/flyweb/FlyWebPublishedServer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/flyweb/FlyWebPublishedServer.cpp')
-rw-r--r--dom/flyweb/FlyWebPublishedServer.cpp675
1 files changed, 675 insertions, 0 deletions
diff --git a/dom/flyweb/FlyWebPublishedServer.cpp b/dom/flyweb/FlyWebPublishedServer.cpp
new file mode 100644
index 000000000..375df332f
--- /dev/null
+++ b/dom/flyweb/FlyWebPublishedServer.cpp
@@ -0,0 +1,675 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "mozilla/dom/FlyWebPublishedServerIPC.h"
+#include "mozilla/dom/FlyWebPublishBinding.h"
+#include "mozilla/dom/FlyWebService.h"
+#include "mozilla/dom/Request.h"
+#include "mozilla/dom/FlyWebServerEvents.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/InternalResponse.h"
+#include "mozilla/ipc/IPCStreamUtils.h"
+#include "mozilla/net/NeckoParent.h"
+#include "mozilla/net/IPCTransportProvider.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
+#include "nsCharSeparatedTokenizer.h"
+#include "nsGlobalWindow.h"
+#include "WebSocketChannel.h"
+
+namespace mozilla {
+namespace dom {
+
+static LazyLogModule gFlyWebPublishedServerLog("FlyWebPublishedServer");
+#undef LOG_I
+#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebPublishedServerLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
+#undef LOG_E
+#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebPublishedServerLog, mozilla::LogLevel::Error, (__VA_ARGS__))
+
+/******** FlyWebPublishedServer ********/
+
+FlyWebPublishedServer::FlyWebPublishedServer(nsPIDOMWindowInner* aOwner,
+ const nsAString& aName,
+ const FlyWebPublishOptions& aOptions)
+ : mozilla::DOMEventTargetHelper(aOwner)
+ , mOwnerWindowID(aOwner ? aOwner->WindowID() : 0)
+ , mName(aName)
+ , mUiUrl(aOptions.mUiUrl)
+ , mIsRegistered(true) // Registered by the FlyWebService
+{
+}
+
+void
+FlyWebPublishedServer::LastRelease()
+{
+ // Make sure to unregister to avoid dangling pointers. Use the LastRelease
+ // hook rather than dtor since calling virtual functions during dtor
+ // wouldn't do what we want. Also, LastRelease is called earlier than dtor
+ // for CC objects.
+ Close();
+}
+
+JSObject*
+FlyWebPublishedServer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return FlyWebPublishedServerBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FlyWebPublishedServer::Close()
+{
+ LOG_I("FlyWebPublishedServer::Close(%p)", this);
+
+ // Unregister from server.
+ if (mIsRegistered) {
+ MOZ_ASSERT(FlyWebService::GetExisting());
+ FlyWebService::GetExisting()->UnregisterServer(this);
+ mIsRegistered = false;
+
+ DispatchTrustedEvent(NS_LITERAL_STRING("close"));
+ }
+}
+
+void
+FlyWebPublishedServer::FireFetchEvent(InternalRequest* aRequest)
+{
+ nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+ RefPtr<FlyWebFetchEvent> e = new FlyWebFetchEvent(this,
+ new Request(global, aRequest),
+ aRequest);
+ e->Init(this);
+ e->InitEvent(NS_LITERAL_STRING("fetch"), false, false);
+
+ DispatchTrustedEvent(e);
+}
+
+void
+FlyWebPublishedServer::FireWebsocketEvent(InternalRequest* aConnectRequest)
+{
+ nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+ RefPtr<FlyWebFetchEvent> e = new FlyWebWebSocketEvent(this,
+ new Request(global, aConnectRequest),
+ aConnectRequest);
+ e->Init(this);
+ e->InitEvent(NS_LITERAL_STRING("websocket"), false, false);
+
+ DispatchTrustedEvent(e);
+}
+
+void
+FlyWebPublishedServer::PublishedServerStarted(nsresult aStatus)
+{
+ LOG_I("FlyWebPublishedServer::PublishedServerStarted(%p)", this);
+
+ RefPtr<FlyWebPublishPromise> promise = mPublishPromise.Ensure(__func__);
+ if (NS_SUCCEEDED(aStatus)) {
+ mPublishPromise.Resolve(this, __func__);
+ } else {
+ Close();
+ mPublishPromise.Reject(aStatus, __func__);
+ }
+}
+
+already_AddRefed<WebSocket>
+FlyWebPublishedServer::OnWebSocketAccept(InternalRequest* aConnectRequest,
+ const Optional<nsAString>& aProtocol,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(aConnectRequest);
+
+ LOG_I("FlyWebPublishedServer::OnWebSocketAccept(%p)", this);
+
+ nsCOMPtr<nsITransportProvider> provider =
+ OnWebSocketAcceptInternal(aConnectRequest,
+ aProtocol,
+ aRv);
+ if (aRv.Failed()) {
+ return nullptr;
+ }
+ MOZ_ASSERT(provider);
+
+ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetOwner());
+ AutoJSContext cx;
+ GlobalObject global(cx, nsGlobalWindow::Cast(window)->FastGetGlobalJSObject());
+
+ nsAutoCString extensions, negotiatedExtensions;
+ aConnectRequest->Headers()->
+ GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions, aRv);
+ mozilla::net::ProcessServerWebSocketExtensions(extensions,
+ negotiatedExtensions);
+
+ nsCString url;
+ aConnectRequest->GetURL(url);
+ Sequence<nsString> protocols;
+ if (aProtocol.WasPassed() &&
+ !protocols.AppendElement(aProtocol.Value(), fallible)) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return nullptr;
+ }
+
+ return WebSocket::ConstructorCommon(global,
+ NS_ConvertUTF8toUTF16(url),
+ protocols,
+ provider,
+ negotiatedExtensions,
+ aRv);
+}
+
+/******** FlyWebPublishedServerImpl ********/
+
+NS_IMPL_ISUPPORTS_INHERITED0(FlyWebPublishedServerImpl, mozilla::DOMEventTargetHelper)
+
+FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner,
+ const nsAString& aName,
+ const FlyWebPublishOptions& aOptions)
+ : FlyWebPublishedServer(aOwner, aName, aOptions)
+ , mHttpServer(new HttpServer())
+{
+ LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this);
+}
+
+void
+FlyWebPublishedServerImpl::PermissionGranted(bool aGranted)
+{
+ LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted);
+ if (!aGranted) {
+ PublishedServerStarted(NS_ERROR_FAILURE);
+ return;
+ }
+
+ mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this);
+}
+
+void
+FlyWebPublishedServerImpl::Close()
+{
+ FlyWebPublishedServer::Close();
+
+ if (mMDNSCancelRegister) {
+ mMDNSCancelRegister->Cancel(NS_BINDING_ABORTED);
+ mMDNSCancelRegister = nullptr;
+ }
+
+ if (mHttpServer) {
+ RefPtr<HttpServer> server = mHttpServer.forget();
+ server->Close();
+ }
+}
+
+void
+FlyWebPublishedServerImpl::OnServerStarted(nsresult aStatus)
+{
+ if (NS_SUCCEEDED(aStatus)) {
+ FlyWebService::GetOrCreate()->StartDiscoveryOf(this);
+ } else {
+ PublishedServerStarted(aStatus);
+ }
+}
+
+void
+FlyWebPublishedServerImpl::OnFetchResponse(InternalRequest* aRequest,
+ InternalResponse* aResponse)
+{
+ MOZ_ASSERT(aRequest);
+ MOZ_ASSERT(aResponse);
+
+ LOG_I("FlyWebPublishedServerImpl::OnFetchResponse(%p)", this);
+
+ if (mHttpServer) {
+ mHttpServer->SendResponse(aRequest, aResponse);
+ }
+}
+
+void
+FlyWebPublishedServerImpl::OnWebSocketResponse(InternalRequest* aConnectRequest,
+ InternalResponse* aResponse)
+{
+ MOZ_ASSERT(aConnectRequest);
+ MOZ_ASSERT(aResponse);
+
+ LOG_I("FlyWebPublishedMDNSServer::OnWebSocketResponse(%p)", this);
+
+ if (mHttpServer) {
+ mHttpServer->SendWebSocketResponse(aConnectRequest, aResponse);
+ }
+}
+
+already_AddRefed<nsITransportProvider>
+FlyWebPublishedServerImpl::OnWebSocketAcceptInternal(InternalRequest* aConnectRequest,
+ const Optional<nsAString>& aProtocol,
+ ErrorResult& aRv)
+{
+ LOG_I("FlyWebPublishedServerImpl::OnWebSocketAcceptInternal(%p)", this);
+
+ if (!mHttpServer) {
+ aRv.Throw(NS_ERROR_UNEXPECTED);
+ return nullptr;
+ }
+
+ return mHttpServer->AcceptWebSocket(aConnectRequest,
+ aProtocol,
+ aRv);
+}
+
+/******** FlyWebPublishedServerChild ********/
+
+FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner,
+ const nsAString& aName,
+ const FlyWebPublishOptions& aOptions)
+ : FlyWebPublishedServer(aOwner, aName, aOptions)
+ , mActorExists(false)
+{
+ LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this);
+
+ // The matching release happens when the actor is destroyed, in
+ // ContentChild::DeallocPFlyWebPublishedServerChild
+ NS_ADDREF_THIS();
+}
+
+void
+FlyWebPublishedServerChild::PermissionGranted(bool aGranted)
+{
+ if (!aGranted) {
+ PublishedServerStarted(NS_ERROR_FAILURE);
+ return;
+ }
+
+ mActorExists = true;
+ FlyWebPublishOptions options;
+ options.mUiUrl = mUiUrl;
+
+ // Proceed with initialization.
+ ContentChild::GetSingleton()->
+ SendPFlyWebPublishedServerConstructor(this, mName, options);
+}
+
+bool
+FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus)
+{
+ LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this);
+ MOZ_ASSERT(mActorExists);
+
+ PublishedServerStarted(aStatus);
+ return true;
+}
+
+bool
+FlyWebPublishedServerChild::RecvServerClose()
+{
+ LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this);
+ MOZ_ASSERT(mActorExists);
+
+ Close();
+
+ return true;
+}
+
+bool
+FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest,
+ const uint64_t& aRequestId)
+{
+ LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this);
+ MOZ_ASSERT(mActorExists);
+
+ RefPtr<InternalRequest> request = new InternalRequest(aRequest);
+ mPendingRequests.Put(request, aRequestId);
+ FireFetchEvent(request);
+
+ return true;
+}
+
+bool
+FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequest,
+ const uint64_t& aRequestId,
+ PTransportProviderChild* aProvider)
+{
+ LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this);
+ MOZ_ASSERT(mActorExists);
+
+ RefPtr<InternalRequest> request = new InternalRequest(aRequest);
+ mPendingRequests.Put(request, aRequestId);
+
+ // Not addreffing here. The addref was already done when the
+ // PTransportProvider child constructor original ran.
+ mPendingTransportProviders.Put(aRequestId,
+ dont_AddRef(static_cast<TransportProviderChild*>(aProvider)));
+
+ FireWebsocketEvent(request);
+
+ return true;
+}
+
+void
+FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+ LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this);
+
+ mActorExists = false;
+}
+
+void
+FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest,
+ InternalResponse* aResponse)
+{
+ LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
+
+ if (!mActorExists) {
+ LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
+ return;
+ }
+
+ uint64_t id = mPendingRequests.Get(aRequest);
+ MOZ_ASSERT(id);
+ mPendingRequests.Remove(aRequest);
+
+ IPCInternalResponse ipcResp;
+ UniquePtr<mozilla::ipc::AutoIPCStream> autoStream;
+ nsIContentChild* cc = static_cast<ContentChild*>(Manager());
+ aResponse->ToIPC(&ipcResp, cc, autoStream);
+ Unused << SendFetchResponse(ipcResp, id);
+ if (autoStream) {
+ autoStream->TakeOptionalValue();
+ }
+}
+
+already_AddRefed<nsITransportProvider>
+FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest,
+ const Optional<nsAString>& aProtocol,
+ ErrorResult& aRv)
+{
+ LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this);
+
+ if (!mActorExists) {
+ LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this);
+ return nullptr;
+ }
+
+ uint64_t id = mPendingRequests.Get(aRequest);
+ MOZ_ASSERT(id);
+ mPendingRequests.Remove(aRequest);
+
+ RefPtr<TransportProviderChild> provider;
+ mPendingTransportProviders.Remove(id, getter_AddRefs(provider));
+
+ nsString protocol;
+ if (aProtocol.WasPassed()) {
+ protocol = aProtocol.Value();
+
+ nsAutoCString reqProtocols;
+ aRequest->Headers()->
+ GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"), reqProtocols, aRv);
+ if (!ContainsToken(reqProtocols, NS_ConvertUTF16toUTF8(protocol))) {
+ // Should throw a better error here
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+ } else {
+ protocol.SetIsVoid(true);
+ }
+
+ Unused << SendWebSocketAccept(protocol, id);
+
+ return provider.forget();
+}
+
+void
+FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest,
+ InternalResponse* aResponse)
+{
+ LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this);
+
+ if (!mActorExists) {
+ LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this);
+ return;
+ }
+
+ uint64_t id = mPendingRequests.Get(aRequest);
+ MOZ_ASSERT(id);
+ mPendingRequests.Remove(aRequest);
+
+ mPendingTransportProviders.Remove(id);
+
+ IPCInternalResponse ipcResp;
+ UniquePtr<mozilla::ipc::AutoIPCStream> autoStream;
+ nsIContentChild* cc = static_cast<ContentChild*>(Manager());
+ aResponse->ToIPC(&ipcResp, cc, autoStream);
+
+ Unused << SendWebSocketResponse(ipcResp, id);
+ if (autoStream) {
+ autoStream->TakeOptionalValue();
+ }
+}
+
+void
+FlyWebPublishedServerChild::Close()
+{
+ LOG_I("FlyWebPublishedServerChild::Close(%p)", this);
+
+ FlyWebPublishedServer::Close();
+
+ if (mActorExists) {
+ LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this);
+
+ Send__delete__(this);
+ }
+}
+
+/******** FlyWebPublishedServerParent ********/
+
+NS_IMPL_ISUPPORTS(FlyWebPublishedServerParent, nsIDOMEventListener)
+
+FlyWebPublishedServerParent::FlyWebPublishedServerParent(const nsAString& aName,
+ const FlyWebPublishOptions& aOptions)
+ : mActorDestroyed(false)
+ , mNextRequestId(1)
+{
+ LOG_I("FlyWebPublishedServerParent::FlyWebPublishedServerParent(%p)", this);
+
+ RefPtr<FlyWebService> service = FlyWebService::GetOrCreate();
+ if (!service) {
+ Unused << SendServerReady(NS_ERROR_FAILURE);
+ return;
+ }
+
+ RefPtr<FlyWebPublishPromise> mozPromise =
+ service->PublishServer(aName, aOptions, nullptr);
+ if (!mozPromise) {
+ Unused << SendServerReady(NS_ERROR_FAILURE);
+ return;
+ }
+
+ RefPtr<FlyWebPublishedServerParent> self = this;
+
+ mozPromise->Then(
+ AbstractThread::MainThread(),
+ __func__,
+ [this, self] (FlyWebPublishedServer* aServer) {
+ mPublishedServer = static_cast<FlyWebPublishedServerImpl*>(aServer);
+ if (mActorDestroyed) {
+ mPublishedServer->Close();
+ return;
+ }
+
+ mPublishedServer->AddEventListener(NS_LITERAL_STRING("fetch"),
+ this, false, false, 2);
+ mPublishedServer->AddEventListener(NS_LITERAL_STRING("websocket"),
+ this, false, false, 2);
+ mPublishedServer->AddEventListener(NS_LITERAL_STRING("close"),
+ this, false, false, 2);
+ Unused << SendServerReady(NS_OK);
+ },
+ [this, self] (nsresult aStatus) {
+ MOZ_ASSERT(NS_FAILED(aStatus));
+ if (!mActorDestroyed) {
+ Unused << SendServerReady(aStatus);
+ }
+ });
+}
+
+NS_IMETHODIMP
+FlyWebPublishedServerParent::HandleEvent(nsIDOMEvent* aEvent)
+{
+ if (mActorDestroyed) {
+ return NS_OK;
+ }
+
+ nsAutoString type;
+ aEvent->GetType(type);
+ if (type.EqualsLiteral("close")) {
+ Unused << SendServerClose();
+ return NS_OK;
+ }
+
+ if (type.EqualsLiteral("fetch")) {
+ RefPtr<InternalRequest> request =
+ static_cast<FlyWebFetchEvent*>(aEvent)->Request()->GetInternalRequest();
+ uint64_t id = mNextRequestId++;
+ mPendingRequests.Put(id, request);
+
+ IPCInternalRequest ipcReq;
+ request->ToIPC(&ipcReq);
+ Unused << SendFetchRequest(ipcReq, id);
+ return NS_OK;
+ }
+
+ if (type.EqualsLiteral("websocket")) {
+ RefPtr<InternalRequest> request =
+ static_cast<FlyWebWebSocketEvent*>(aEvent)->Request()->GetInternalRequest();
+ uint64_t id = mNextRequestId++;
+ mPendingRequests.Put(id, request);
+
+ nsTArray<PNeckoParent*> neckoParents;
+ Manager()->ManagedPNeckoParent(neckoParents);
+ if (neckoParents.Length() != 1) {
+ MOZ_CRASH("Expected exactly 1 PNeckoParent instance per PNeckoChild");
+ }
+
+ RefPtr<TransportProviderParent> provider =
+ static_cast<TransportProviderParent*>(
+ neckoParents[0]->SendPTransportProviderConstructor());
+
+ IPCInternalRequest ipcReq;
+ request->ToIPC(&ipcReq);
+ Unused << SendWebSocketRequest(ipcReq, id, provider);
+
+ mPendingTransportProviders.Put(id, provider.forget());
+ return NS_OK;
+ }
+
+ MOZ_CRASH("Unknown event type");
+
+ return NS_OK;
+}
+
+bool
+FlyWebPublishedServerParent::RecvFetchResponse(const IPCInternalResponse& aResponse,
+ const uint64_t& aRequestId)
+{
+ MOZ_ASSERT(!mActorDestroyed);
+
+ RefPtr<InternalRequest> request;
+ mPendingRequests.Remove(aRequestId, getter_AddRefs(request));
+ if (!request) {
+ static_cast<ContentParent*>(Manager())->KillHard("unknown request id");
+ return false;
+ }
+
+ RefPtr<InternalResponse> response = InternalResponse::FromIPC(aResponse);
+
+ mPublishedServer->OnFetchResponse(request, response);
+
+ return true;
+}
+
+bool
+FlyWebPublishedServerParent::RecvWebSocketResponse(const IPCInternalResponse& aResponse,
+ const uint64_t& aRequestId)
+{
+ MOZ_ASSERT(!mActorDestroyed);
+
+ mPendingTransportProviders.Remove(aRequestId);
+
+ RefPtr<InternalRequest> request;
+ mPendingRequests.Remove(aRequestId, getter_AddRefs(request));
+ if (!request) {
+ static_cast<ContentParent*>(Manager())->KillHard("unknown websocket request id");
+ return false;
+ }
+
+ RefPtr<InternalResponse> response = InternalResponse::FromIPC(aResponse);
+
+ mPublishedServer->OnWebSocketResponse(request, response);
+
+ return true;
+}
+
+bool
+FlyWebPublishedServerParent::RecvWebSocketAccept(const nsString& aProtocol,
+ const uint64_t& aRequestId)
+{
+ MOZ_ASSERT(!mActorDestroyed);
+
+ RefPtr<TransportProviderParent> providerIPC;
+ mPendingTransportProviders.Remove(aRequestId, getter_AddRefs(providerIPC));
+
+ RefPtr<InternalRequest> request;
+ mPendingRequests.Remove(aRequestId, getter_AddRefs(request));
+
+ if (!request || !providerIPC) {
+ static_cast<ContentParent*>(Manager())->KillHard("unknown websocket request id");
+ return false;
+ }
+
+ Optional<nsAString> protocol;
+ if (!aProtocol.IsVoid()) {
+ protocol = &aProtocol;
+ }
+
+ ErrorResult result;
+ nsCOMPtr<nsITransportProvider> providerServer =
+ mPublishedServer->OnWebSocketAcceptInternal(request, protocol, result);
+ if (result.Failed()) {
+ return false;
+ }
+
+ providerServer->SetListener(providerIPC);
+
+ return true;
+}
+
+void
+FlyWebPublishedServerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ LOG_I("FlyWebPublishedServerParent::ActorDestroy(%p)", this);
+
+ mActorDestroyed = true;
+}
+
+bool
+FlyWebPublishedServerParent::Recv__delete__()
+{
+ LOG_I("FlyWebPublishedServerParent::Recv__delete__(%p)", this);
+ MOZ_ASSERT(!mActorDestroyed);
+
+ if (mPublishedServer) {
+ mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("fetch"),
+ this, false);
+ mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("websocket"),
+ this, false);
+ mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("close"),
+ this, false);
+ mPublishedServer->Close();
+ mPublishedServer = nullptr;
+ }
+ return true;
+}
+
+} // namespace dom
+} // namespace mozilla
+
+