author Andreea Pavel <>
Tue, 27 Nov 2018 18:28:30 +0200
changeset 507538 f343188bdcf2a7566fc943bbae4a3ec5e7856c29
parent 507537 11d6688b953f800e234162bc8ed5842954de087f
child 507594 2320933cb7bc8255b7e484df1ef27718154362d5
permissions -rw-r--r--
Backed out changeset 11d6688b953f (bug 1508472) for build bustages on a CLOSED TREE

/* -*- 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 */

#ifndef WebSocket_h__
#define WebSocket_h__

#include "mozilla/Attributes.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/dom/WebSocketBinding.h" // for BinaryType
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Mutex.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
#include "nsISupportsUtils.h"
#include "nsString.h"
#include "nsWrapperCache.h"


class nsIInputStream;
class nsITransportProvider;

namespace mozilla {
namespace dom {

class Blob;

class WebSocketImpl;

class WebSocket final : public DOMEventTargetHelper
  friend class WebSocketImpl;

  enum {
    OPEN       = 1,
    CLOSING    = 2,
    CLOSED     = 3

  virtual bool IsCertainlyAliveForCC() const override;

  // EventTarget
  using EventTarget::EventListenerAdded;
  virtual void EventListenerAdded(nsAtom* aType) override;

  using EventTarget::EventListenerRemoved;
  virtual void EventListenerRemoved(nsAtom* aType) override;

  virtual void DisconnectFromOwner() override;

  // nsWrapperCache
  nsPIDOMWindowInner* GetParentObject() { return GetOwner(); }

  virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override;

  // DOMEventTargetHelper
  void BindToOwner(nsIGlobalObject* aNew) override;

public: // static helpers:

  // Determine if preferences allow WebSocket
  static bool PrefEnabled(JSContext* aCx = nullptr, JSObject* aGlobal = nullptr);

public: // WebIDL interface:

  // Constructor:
  static already_AddRefed<WebSocket> Constructor(const GlobalObject& aGlobal,
                                                 const nsAString& aUrl,
                                                 ErrorResult& rv);

  static already_AddRefed<WebSocket> Constructor(const GlobalObject& aGlobal,
                                                 const nsAString& aUrl,
                                                 const nsAString& aProtocol,
                                                 ErrorResult& rv);

  static already_AddRefed<WebSocket> Constructor(const GlobalObject& aGlobal,
                                                 const nsAString& aUrl,
                                                 const Sequence<nsString>& aProtocols,
                                                 ErrorResult& rv);

  static already_AddRefed<WebSocket> CreateServerWebSocket(const GlobalObject& aGlobal,
                                                           const nsAString& aUrl,
                                                           const Sequence<nsString>& aProtocols,
                                                           nsITransportProvider* aTransportProvider,
                                                           const nsAString& aNegotiatedExtensions,
                                                           ErrorResult& rv);

  static already_AddRefed<WebSocket> ConstructorCommon(const GlobalObject& aGlobal,
                                                       const nsAString& aUrl,
                                                       const Sequence<nsString>& aProtocols,
                                                       nsITransportProvider* aTransportProvider,
                                                       const nsACString& aNegotiatedExtensions,
                                                       ErrorResult& rv);

  // webIDL: readonly attribute DOMString url
  void GetUrl(nsAString& aResult);

  // webIDL: readonly attribute unsigned short readyState;
  uint16_t ReadyState();

  // webIDL: readonly attribute unsigned long bufferedAmount;
  uint32_t BufferedAmount() const;

  // webIDL: attribute Function? onopen;

  // webIDL: attribute Function? onerror;

  // webIDL: attribute Function? onclose;

  // webIDL: readonly attribute DOMString extensions;
  void GetExtensions(nsAString& aResult);

  // webIDL: readonly attribute DOMString protocol;
  void GetProtocol(nsAString& aResult);

  // webIDL: void close(optional unsigned short code, optional DOMString reason):
  void Close(const Optional<uint16_t>& aCode,
             const Optional<nsAString>& aReason,
             ErrorResult& aRv);

  // webIDL: attribute Function? onmessage;

  // webIDL: attribute DOMString binaryType;
  dom::BinaryType BinaryType() const;
  void SetBinaryType(dom::BinaryType aData);

  // webIDL: void send(DOMString|Blob|ArrayBufferView data);
  void Send(const nsAString& aData,
            ErrorResult& aRv);
  void Send(Blob& aData,
            ErrorResult& aRv);
  void Send(const ArrayBuffer& aData,
            ErrorResult& aRv);
  void Send(const ArrayBufferView& aData,
            ErrorResult& aRv);

private: // constructor && destructor
  explicit WebSocket(nsPIDOMWindowInner* aOwnerWindow);
  virtual ~WebSocket();

  void SetReadyState(uint16_t aReadyState);

  // These methods actually do the dispatch for various events.
  nsresult CreateAndDispatchSimpleEvent(const nsAString& aName);
  nsresult CreateAndDispatchMessageEvent(const nsACString& aData,
                                         bool aIsBinary);
  nsresult CreateAndDispatchCloseEvent(bool aWasClean,
                                       uint16_t aCode,
                                       const nsAString& aReason);

  // if there are "strong event listeners" (see comment in WebSocket.cpp) or
  // outgoing not sent messages then this method keeps the object alive
  // when js doesn't have strong references to it.
  void UpdateMustKeepAlive();
  // ATTENTION, when calling this method the object can be released
  // (and possibly collected).
  void DontKeepAliveAnyMore();

  WebSocket(const WebSocket& x) = delete;   // prevent bad usage
  WebSocket& operator=(const WebSocket& x) = delete;

  void Send(nsIInputStream* aMsgStream,
            const nsACString& aMsgString,
            uint32_t aMsgLength,
            bool aIsBinary,
            ErrorResult& aRv);

  void AssertIsOnTargetThread() const;

  // Raw pointer because this WebSocketImpl is created, managed and destroyed by
  // WebSocket.
  WebSocketImpl* mImpl;

  bool mIsMainThread;

  bool mKeepingAlive;
  bool mCheckMustKeepAlive;

  CheckedUint32 mOutgoingBufferedAmount;

  // related to the WebSocket constructor steps
  nsString mURI;
  nsString mEffectiveURL;   // after redirects
  nsCString mEstablishedExtensions;
  nsCString mEstablishedProtocol;

  dom::BinaryType mBinaryType;

  // This mutex protects mReadyState that is the only variable that is used in
  // different threads.
  mozilla::Mutex mMutex;

  // This value should not be used directly but use ReadyState() instead.
  uint16_t mReadyState;

} //namespace dom
} //namespace mozilla