Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  WebSocketEventService.cpp   Sprache: 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

99%


¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge