forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			566 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			566 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "WebSocketEventListenerChild.h"
 | |
| #include "WebSocketEventService.h"
 | |
| #include "WebSocketFrame.h"
 | |
| 
 | |
| #include "mozilla/net/NeckoChild.h"
 | |
| #include "mozilla/StaticPtr.h"
 | |
| #include "nsISupportsPrimitives.h"
 | |
| #include "nsIObserverService.h"
 | |
| #include "nsXULAppAPI.h"
 | |
| #include "nsSocketTransportService2.h"
 | |
| #include "nsThreadUtils.h"
 | |
| #include "mozilla/Services.h"
 | |
| #include "nsIWebSocketImpl.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace net {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| StaticRefPtr<WebSocketEventService> gWebSocketEventService;
 | |
| 
 | |
| bool IsChildProcess() {
 | |
|   return XRE_GetProcessType() != GeckoProcessType_Default;
 | |
| }
 | |
| 
 | |
| }  // anonymous namespace
 | |
| 
 | |
| class WebSocketBaseRunnable : public Runnable {
 | |
|  public:
 | |
|   WebSocketBaseRunnable(uint32_t aWebSocketSerialID, uint64_t aInnerWindowID)
 | |
|       : Runnable("net::WebSocketBaseRunnable"),
 | |
|         mWebSocketSerialID(aWebSocketSerialID),
 | |
|         mInnerWindowID(aInnerWindowID) {}
 | |
| 
 | |
|   NS_IMETHOD Run() override {
 | |
|     MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|     RefPtr<WebSocketEventService> service =
 | |
|         WebSocketEventService::GetOrCreate();
 | |
|     MOZ_ASSERT(service);
 | |
| 
 | |
|     WebSocketEventService::WindowListeners listeners;
 | |
|     service->GetListeners(mInnerWindowID, listeners);
 | |
| 
 | |
|     for (uint32_t i = 0; i < listeners.Length(); ++i) {
 | |
|       DoWork(listeners[i]);
 | |
|     }
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   ~WebSocketBaseRunnable() = default;
 | |
| 
 | |
|   virtual void DoWork(nsIWebSocketEventListener* aListener) = 0;
 | |
| 
 | |
|   uint32_t mWebSocketSerialID;
 | |
|   uint64_t mInnerWindowID;
 | |
| };
 | |
| 
 | |
| class WebSocketFrameRunnable final : public WebSocketBaseRunnable {
 | |
|  public:
 | |
|   WebSocketFrameRunnable(uint32_t aWebSocketSerialID, uint64_t aInnerWindowID,
 | |
|                          already_AddRefed<WebSocketFrame> aFrame,
 | |
|                          bool aFrameSent)
 | |
|       : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID),
 | |
|         mFrame(std::move(aFrame)),
 | |
|         mFrameSent(aFrameSent) {}
 | |
| 
 | |
|  private:
 | |
|   virtual void DoWork(nsIWebSocketEventListener* aListener) override {
 | |
|     DebugOnly<nsresult> rv{};
 | |
|     if (mFrameSent) {
 | |
|       rv = aListener->FrameSent(mWebSocketSerialID, mFrame);
 | |
|     } else {
 | |
|       rv = aListener->FrameReceived(mWebSocketSerialID, mFrame);
 | |
|     }
 | |
| 
 | |
|     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Frame op failed");
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketFrame> mFrame;
 | |
|   bool mFrameSent;
 | |
| };
 | |
| 
 | |
| class WebSocketCreatedRunnable final : public WebSocketBaseRunnable {
 | |
|  public:
 | |
|   WebSocketCreatedRunnable(uint32_t aWebSocketSerialID, uint64_t aInnerWindowID,
 | |
|                            const nsAString& aURI, const nsACString& aProtocols)
 | |
|       : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID),
 | |
|         mURI(aURI),
 | |
|         mProtocols(aProtocols) {}
 | |
| 
 | |
|  private:
 | |
|   virtual void DoWork(nsIWebSocketEventListener* aListener) override {
 | |
|     DebugOnly<nsresult> rv =
 | |
|         aListener->WebSocketCreated(mWebSocketSerialID, mURI, mProtocols);
 | |
|     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketCreated failed");
 | |
|   }
 | |
| 
 | |
|   const nsString mURI;
 | |
|   const nsCString mProtocols;
 | |
| };
 | |
| 
 | |
| class WebSocketOpenedRunnable final : public WebSocketBaseRunnable {
 | |
|  public:
 | |
|   WebSocketOpenedRunnable(uint32_t aWebSocketSerialID, uint64_t aInnerWindowID,
 | |
|                           const nsAString& aEffectiveURI,
 | |
|                           const nsACString& aProtocols,
 | |
|                           const nsACString& aExtensions,
 | |
|                           uint64_t aHttpChannelId)
 | |
|       : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID),
 | |
|         mEffectiveURI(aEffectiveURI),
 | |
|         mProtocols(aProtocols),
 | |
|         mExtensions(aExtensions),
 | |
|         mHttpChannelId(aHttpChannelId) {}
 | |
| 
 | |
|  private:
 | |
|   virtual void DoWork(nsIWebSocketEventListener* aListener) override {
 | |
|     DebugOnly<nsresult> rv =
 | |
|         aListener->WebSocketOpened(mWebSocketSerialID, mEffectiveURI,
 | |
|                                    mProtocols, mExtensions, mHttpChannelId);
 | |
|     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketOpened failed");
 | |
|   }
 | |
| 
 | |
|   const nsString mEffectiveURI;
 | |
|   const nsCString mProtocols;
 | |
|   const nsCString mExtensions;
 | |
|   uint64_t mHttpChannelId;
 | |
| };
 | |
| 
 | |
| class WebSocketMessageAvailableRunnable final : public WebSocketBaseRunnable {
 | |
|  public:
 | |
|   WebSocketMessageAvailableRunnable(uint32_t aWebSocketSerialID,
 | |
|                                     uint64_t aInnerWindowID,
 | |
|                                     const nsACString& aData,
 | |
|                                     uint16_t aMessageType)
 | |
|       : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID),
 | |
|         mData(aData),
 | |
|         mMessageType(aMessageType) {}
 | |
| 
 | |
|  private:
 | |
|   virtual void DoWork(nsIWebSocketEventListener* aListener) override {
 | |
|     DebugOnly<nsresult> rv = aListener->WebSocketMessageAvailable(
 | |
|         mWebSocketSerialID, mData, mMessageType);
 | |
|     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketMessageAvailable failed");
 | |
|   }
 | |
| 
 | |
|   const nsCString mData;
 | |
|   uint16_t mMessageType;
 | |
| };
 | |
| 
 | |
| class WebSocketClosedRunnable final : public WebSocketBaseRunnable {
 | |
|  public:
 | |
|   WebSocketClosedRunnable(uint32_t aWebSocketSerialID, uint64_t aInnerWindowID,
 | |
|                           bool aWasClean, uint16_t aCode,
 | |
|                           const nsAString& aReason)
 | |
|       : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID),
 | |
|         mWasClean(aWasClean),
 | |
|         mCode(aCode),
 | |
|         mReason(aReason) {}
 | |
| 
 | |
|  private:
 | |
|   virtual void DoWork(nsIWebSocketEventListener* aListener) override {
 | |
|     DebugOnly<nsresult> rv = aListener->WebSocketClosed(
 | |
|         mWebSocketSerialID, mWasClean, mCode, mReason);
 | |
|     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketClosed failed");
 | |
|   }
 | |
| 
 | |
|   bool mWasClean;
 | |
|   uint16_t mCode;
 | |
|   const nsString mReason;
 | |
| };
 | |
| 
 | |
| /* static */
 | |
| already_AddRefed<WebSocketEventService> WebSocketEventService::Get() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   RefPtr<WebSocketEventService> service = gWebSocketEventService.get();
 | |
|   return service.forget();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| already_AddRefed<WebSocketEventService> WebSocketEventService::GetOrCreate() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   if (!gWebSocketEventService) {
 | |
|     gWebSocketEventService = new WebSocketEventService();
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketEventService> service = gWebSocketEventService.get();
 | |
|   return service.forget();
 | |
| }
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN(WebSocketEventService)
 | |
|   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketEventService)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIObserver)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIWebSocketEventService)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| NS_IMPL_ADDREF(WebSocketEventService)
 | |
| NS_IMPL_RELEASE(WebSocketEventService)
 | |
| 
 | |
| WebSocketEventService::WebSocketEventService() : mCountListeners(0) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     obs->AddObserver(this, "xpcom-shutdown", false);
 | |
|     obs->AddObserver(this, "inner-window-destroyed", false);
 | |
|   }
 | |
| }
 | |
| 
 | |
| WebSocketEventService::~WebSocketEventService() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::WebSocketCreated(uint32_t aWebSocketSerialID,
 | |
|                                              uint64_t aInnerWindowID,
 | |
|                                              const nsAString& aURI,
 | |
|                                              const nsACString& aProtocols,
 | |
|                                              nsIEventTarget* aTarget) {
 | |
|   // Let's continue only if we have some listeners.
 | |
|   if (!HasListeners()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketCreatedRunnable> runnable = new WebSocketCreatedRunnable(
 | |
|       aWebSocketSerialID, aInnerWindowID, aURI, aProtocols);
 | |
|   DebugOnly<nsresult> rv = aTarget
 | |
|                                ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
 | |
|                                : NS_DispatchToMainThread(runnable);
 | |
|   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::WebSocketOpened(uint32_t aWebSocketSerialID,
 | |
|                                             uint64_t aInnerWindowID,
 | |
|                                             const nsAString& aEffectiveURI,
 | |
|                                             const nsACString& aProtocols,
 | |
|                                             const nsACString& aExtensions,
 | |
|                                             uint64_t aHttpChannelId,
 | |
|                                             nsIEventTarget* aTarget) {
 | |
|   // Let's continue only if we have some listeners.
 | |
|   if (!HasListeners()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketOpenedRunnable> runnable = new WebSocketOpenedRunnable(
 | |
|       aWebSocketSerialID, aInnerWindowID, aEffectiveURI, aProtocols,
 | |
|       aExtensions, aHttpChannelId);
 | |
|   DebugOnly<nsresult> rv = aTarget
 | |
|                                ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
 | |
|                                : NS_DispatchToMainThread(runnable);
 | |
|   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::WebSocketMessageAvailable(
 | |
|     uint32_t aWebSocketSerialID, uint64_t aInnerWindowID,
 | |
|     const nsACString& aData, uint16_t aMessageType, nsIEventTarget* aTarget) {
 | |
|   // Let's continue only if we have some listeners.
 | |
|   if (!HasListeners()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketMessageAvailableRunnable> runnable =
 | |
|       new WebSocketMessageAvailableRunnable(aWebSocketSerialID, aInnerWindowID,
 | |
|                                             aData, aMessageType);
 | |
|   DebugOnly<nsresult> rv = aTarget
 | |
|                                ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
 | |
|                                : NS_DispatchToMainThread(runnable);
 | |
|   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::WebSocketClosed(uint32_t aWebSocketSerialID,
 | |
|                                             uint64_t aInnerWindowID,
 | |
|                                             bool aWasClean, uint16_t aCode,
 | |
|                                             const nsAString& aReason,
 | |
|                                             nsIEventTarget* aTarget) {
 | |
|   // Let's continue only if we have some listeners.
 | |
|   if (!HasListeners()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketClosedRunnable> runnable = new WebSocketClosedRunnable(
 | |
|       aWebSocketSerialID, aInnerWindowID, aWasClean, aCode, aReason);
 | |
|   DebugOnly<nsresult> rv = aTarget
 | |
|                                ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
 | |
|                                : NS_DispatchToMainThread(runnable);
 | |
|   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::FrameReceived(
 | |
|     uint32_t aWebSocketSerialID, uint64_t aInnerWindowID,
 | |
|     already_AddRefed<WebSocketFrame> aFrame, nsIEventTarget* aTarget) {
 | |
|   RefPtr<WebSocketFrame> frame(std::move(aFrame));
 | |
|   MOZ_ASSERT(frame);
 | |
| 
 | |
|   // Let's continue only if we have some listeners.
 | |
|   if (!HasListeners()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketFrameRunnable> runnable =
 | |
|       new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID,
 | |
|                                  frame.forget(), false /* frameSent */);
 | |
|   DebugOnly<nsresult> rv = aTarget
 | |
|                                ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
 | |
|                                : NS_DispatchToMainThread(runnable);
 | |
|   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::FrameSent(uint32_t aWebSocketSerialID,
 | |
|                                       uint64_t aInnerWindowID,
 | |
|                                       already_AddRefed<WebSocketFrame> aFrame,
 | |
|                                       nsIEventTarget* aTarget) {
 | |
|   RefPtr<WebSocketFrame> frame(std::move(aFrame));
 | |
|   MOZ_ASSERT(frame);
 | |
| 
 | |
|   // Let's continue only if we have some listeners.
 | |
|   if (!HasListeners()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<WebSocketFrameRunnable> runnable = new WebSocketFrameRunnable(
 | |
|       aWebSocketSerialID, aInnerWindowID, frame.forget(), true /* frameSent */);
 | |
| 
 | |
|   DebugOnly<nsresult> rv = aTarget
 | |
|                                ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
 | |
|                                : NS_DispatchToMainThread(runnable);
 | |
|   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::AssociateWebSocketImplWithSerialID(
 | |
|     nsIWebSocketImpl* aWebSocketImpl, uint32_t aWebSocketSerialID) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   mWebSocketImplMap.InsertOrUpdate(aWebSocketSerialID,
 | |
|                                    do_GetWeakReference(aWebSocketImpl));
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| WebSocketEventService::SendMessage(uint32_t aWebSocketSerialID,
 | |
|                                    const nsAString& aMessage) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   nsWeakPtr weakPtr = mWebSocketImplMap.Get(aWebSocketSerialID);
 | |
|   nsCOMPtr<nsIWebSocketImpl> webSocketImpl = do_QueryReferent(weakPtr);
 | |
| 
 | |
|   if (!webSocketImpl) {
 | |
|     return NS_ERROR_NOT_AVAILABLE;
 | |
|   }
 | |
| 
 | |
|   return webSocketImpl->SendMessage(aMessage);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| WebSocketEventService::AddListener(uint64_t aInnerWindowID,
 | |
|                                    nsIWebSocketEventListener* aListener) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   if (!aListener) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   ++mCountListeners;
 | |
| 
 | |
|   mWindows
 | |
|       .LookupOrInsertWith(
 | |
|           aInnerWindowID,
 | |
|           [&] {
 | |
|             auto listener = MakeUnique<WindowListener>();
 | |
| 
 | |
|             if (IsChildProcess()) {
 | |
|               PWebSocketEventListenerChild* actor =
 | |
|                   gNeckoChild->SendPWebSocketEventListenerConstructor(
 | |
|                       aInnerWindowID);
 | |
| 
 | |
|               listener->mActor =
 | |
|                   static_cast<WebSocketEventListenerChild*>(actor);
 | |
|               MOZ_ASSERT(listener->mActor);
 | |
|             }
 | |
| 
 | |
|             return listener;
 | |
|           })
 | |
|       ->mListeners.AppendElement(aListener);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| WebSocketEventService::RemoveListener(uint64_t aInnerWindowID,
 | |
|                                       nsIWebSocketEventListener* aListener) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   if (!aListener) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   WindowListener* listener = mWindows.Get(aInnerWindowID);
 | |
|   if (!listener) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   if (!listener->mListeners.RemoveElement(aListener)) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   // The last listener for this window.
 | |
|   if (listener->mListeners.IsEmpty()) {
 | |
|     if (IsChildProcess()) {
 | |
|       ShutdownActorListener(listener);
 | |
|     }
 | |
| 
 | |
|     mWindows.Remove(aInnerWindowID);
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(mCountListeners);
 | |
|   --mCountListeners;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| WebSocketEventService::HasListenerFor(uint64_t aInnerWindowID, bool* aResult) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   *aResult = mWindows.Get(aInnerWindowID);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| WebSocketEventService::Observe(nsISupports* aSubject, const char* aTopic,
 | |
|                                const char16_t* aData) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   if (!strcmp(aTopic, "xpcom-shutdown")) {
 | |
|     Shutdown();
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (!strcmp(aTopic, "inner-window-destroyed") && HasListeners()) {
 | |
|     nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
 | |
|     NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
 | |
| 
 | |
|     uint64_t innerID;
 | |
|     nsresult rv = wrapper->GetData(&innerID);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     WindowListener* listener = mWindows.Get(innerID);
 | |
|     if (!listener) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     MOZ_ASSERT(mCountListeners >= listener->mListeners.Length());
 | |
|     mCountListeners -= listener->mListeners.Length();
 | |
| 
 | |
|     if (IsChildProcess()) {
 | |
|       ShutdownActorListener(listener);
 | |
|     }
 | |
| 
 | |
|     mWindows.Remove(innerID);
 | |
|   }
 | |
| 
 | |
|   // This should not happen.
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::Shutdown() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   if (gWebSocketEventService) {
 | |
|     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|     if (obs) {
 | |
|       obs->RemoveObserver(gWebSocketEventService, "xpcom-shutdown");
 | |
|       obs->RemoveObserver(gWebSocketEventService, "inner-window-destroyed");
 | |
|     }
 | |
| 
 | |
|     mWindows.Clear();
 | |
|     gWebSocketEventService = nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool WebSocketEventService::HasListeners() const { return !!mCountListeners; }
 | |
| 
 | |
| void WebSocketEventService::GetListeners(
 | |
|     uint64_t aInnerWindowID,
 | |
|     WebSocketEventService::WindowListeners& aListeners) const {
 | |
|   aListeners.Clear();
 | |
| 
 | |
|   WindowListener* listener = mWindows.Get(aInnerWindowID);
 | |
|   if (!listener) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aListeners.AppendElements(listener->mListeners);
 | |
| }
 | |
| 
 | |
| void WebSocketEventService::ShutdownActorListener(WindowListener* aListener) {
 | |
|   MOZ_ASSERT(aListener);
 | |
|   MOZ_ASSERT(aListener->mActor);
 | |
|   aListener->mActor->Close();
 | |
|   aListener->mActor = nullptr;
 | |
| }
 | |
| 
 | |
| already_AddRefed<WebSocketFrame> WebSocketEventService::CreateFrameIfNeeded(
 | |
|     bool aFinBit, bool aRsvBit1, bool aRsvBit2, bool aRsvBit3, uint8_t aOpCode,
 | |
|     bool aMaskBit, uint32_t aMask, const nsCString& aPayload) {
 | |
|   if (!HasListeners()) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
 | |
|                                        aOpCode, aMaskBit, aMask, aPayload);
 | |
| }
 | |
| 
 | |
| already_AddRefed<WebSocketFrame> WebSocketEventService::CreateFrameIfNeeded(
 | |
|     bool aFinBit, bool aRsvBit1, bool aRsvBit2, bool aRsvBit3, uint8_t aOpCode,
 | |
|     bool aMaskBit, uint32_t aMask, uint8_t* aPayload, uint32_t aPayloadLength) {
 | |
|   if (!HasListeners()) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   nsAutoCString payloadStr;
 | |
|   if (NS_WARN_IF(!(payloadStr.Assign((const char*)aPayload, aPayloadLength,
 | |
|                                      mozilla::fallible)))) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
 | |
|                                        aOpCode, aMaskBit, aMask, payloadStr);
 | |
| }
 | |
| 
 | |
| already_AddRefed<WebSocketFrame> WebSocketEventService::CreateFrameIfNeeded(
 | |
|     bool aFinBit, bool aRsvBit1, bool aRsvBit2, bool aRsvBit3, uint8_t aOpCode,
 | |
|     bool aMaskBit, uint32_t aMask, uint8_t* aPayloadInHdr,
 | |
|     uint32_t aPayloadInHdrLength, uint8_t* aPayload, uint32_t aPayloadLength) {
 | |
|   if (!HasListeners()) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   uint32_t payloadLength = aPayloadLength + aPayloadInHdrLength;
 | |
| 
 | |
|   nsAutoCString payload;
 | |
|   if (NS_WARN_IF(!payload.SetLength(payloadLength, fallible))) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   char* payloadPtr = payload.BeginWriting();
 | |
|   if (aPayloadInHdrLength) {
 | |
|     memcpy(payloadPtr, aPayloadInHdr, aPayloadInHdrLength);
 | |
|   }
 | |
| 
 | |
|   memcpy(payloadPtr + aPayloadInHdrLength, aPayload, aPayloadLength);
 | |
| 
 | |
|   return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
 | |
|                                        aOpCode, aMaskBit, aMask, payload);
 | |
| }
 | |
| 
 | |
| }  // namespace net
 | |
| }  // namespace mozilla
 | 
