1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef WebSocket_h__
8 #define WebSocket_h__
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/CheckedInt.h"
12 #include "mozilla/dom/TypedArray.h"
13 #include "mozilla/dom/WebSocketBinding.h"  // for BinaryType
14 #include "mozilla/DOMEventTargetHelper.h"
15 #include "mozilla/ErrorResult.h"
16 #include "mozilla/Mutex.h"
17 #include "nsCOMPtr.h"
18 #include "nsCycleCollectionParticipant.h"
19 #include "nsISupports.h"
20 #include "nsISupportsUtils.h"
21 #include "nsString.h"
22 #include "nsWrapperCache.h"
23 
24 #define DEFAULT_WS_SCHEME_PORT 80
25 #define DEFAULT_WSS_SCHEME_PORT 443
26 
27 class nsIInputStream;
28 class nsITransportProvider;
29 
30 namespace mozilla {
31 namespace dom {
32 
33 class Blob;
34 
35 class WebSocketImpl;
36 
37 class WebSocket final : public DOMEventTargetHelper {
38   friend class WebSocketImpl;
39 
40  public:
41   enum { CONNECTING = 0, OPEN = 1, CLOSING = 2, CLOSED = 3 };
42 
43  public:
44   NS_DECL_ISUPPORTS_INHERITED
45   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WebSocket, DOMEventTargetHelper)
46   virtual bool IsCertainlyAliveForCC() const override;
47 
48   // EventTarget
49   using EventTarget::EventListenerAdded;
50   virtual void EventListenerAdded(nsAtom* aType) override;
51 
52   using EventTarget::EventListenerRemoved;
53   virtual void EventListenerRemoved(nsAtom* aType) override;
54 
55   virtual void DisconnectFromOwner() override;
56 
57   // nsWrapperCache
GetParentObject()58   nsPIDOMWindowInner* GetParentObject() { return GetOwner(); }
59 
60   virtual JSObject* WrapObject(JSContext* cx,
61                                JS::Handle<JSObject*> aGivenProto) override;
62 
63  public:  // static helpers:
64   // Determine if preferences allow WebSocket
65   static bool PrefEnabled(JSContext* aCx = nullptr,
66                           JSObject* aGlobal = nullptr);
67 
68  public:  // WebIDL interface:
69   // Constructor:
70   static already_AddRefed<WebSocket> Constructor(const GlobalObject& aGlobal,
71                                                  const nsAString& aUrl,
72                                                  ErrorResult& rv);
73 
74   static already_AddRefed<WebSocket> Constructor(const GlobalObject& aGlobal,
75                                                  const nsAString& aUrl,
76                                                  const nsAString& aProtocol,
77                                                  ErrorResult& rv);
78 
79   static already_AddRefed<WebSocket> Constructor(
80       const GlobalObject& aGlobal, const nsAString& aUrl,
81       const Sequence<nsString>& aProtocols, ErrorResult& rv);
82 
83   static already_AddRefed<WebSocket> CreateServerWebSocket(
84       const GlobalObject& aGlobal, const nsAString& aUrl,
85       const Sequence<nsString>& aProtocols,
86       nsITransportProvider* aTransportProvider,
87       const nsAString& aNegotiatedExtensions, ErrorResult& rv);
88 
89   static already_AddRefed<WebSocket> ConstructorCommon(
90       const GlobalObject& aGlobal, const nsAString& aUrl,
91       const Sequence<nsString>& aProtocols,
92       nsITransportProvider* aTransportProvider,
93       const nsACString& aNegotiatedExtensions, ErrorResult& rv);
94 
95   // webIDL: readonly attribute DOMString url
96   void GetUrl(nsAString& aResult);
97 
98   // webIDL: readonly attribute unsigned short readyState;
99   uint16_t ReadyState();
100 
101   // webIDL: readonly attribute unsigned long bufferedAmount;
102   uint32_t BufferedAmount() const;
103 
104   // webIDL: attribute Function? onopen;
105   IMPL_EVENT_HANDLER(open)
106 
107   // webIDL: attribute Function? onerror;
108   IMPL_EVENT_HANDLER(error)
109 
110   // webIDL: attribute Function? onclose;
111   IMPL_EVENT_HANDLER(close)
112 
113   // webIDL: readonly attribute DOMString extensions;
114   void GetExtensions(nsAString& aResult);
115 
116   // webIDL: readonly attribute DOMString protocol;
117   void GetProtocol(nsAString& aResult);
118 
119   // webIDL: void close(optional unsigned short code,
120   //                    optional DOMString reason):
121   void Close(const Optional<uint16_t>& aCode,
122              const Optional<nsAString>& aReason, ErrorResult& aRv);
123 
124   // webIDL: attribute Function? onmessage;
125   IMPL_EVENT_HANDLER(message)
126 
127   // webIDL: attribute DOMString binaryType;
128   dom::BinaryType BinaryType() const;
129   void SetBinaryType(dom::BinaryType aData);
130 
131   // webIDL: void send(DOMString|Blob|ArrayBufferView data);
132   void Send(const nsAString& aData, ErrorResult& aRv);
133   void Send(Blob& aData, ErrorResult& aRv);
134   void Send(const ArrayBuffer& aData, ErrorResult& aRv);
135   void Send(const ArrayBufferView& aData, ErrorResult& aRv);
136 
137  private:  // constructor && destructor
138   explicit WebSocket(nsPIDOMWindowInner* aOwnerWindow);
139   virtual ~WebSocket();
140 
141   void SetReadyState(uint16_t aReadyState);
142 
143   // These methods actually do the dispatch for various events.
144   nsresult CreateAndDispatchSimpleEvent(const nsAString& aName);
145   nsresult CreateAndDispatchMessageEvent(const nsACString& aData,
146                                          bool aIsBinary);
147   nsresult CreateAndDispatchCloseEvent(bool aWasClean, uint16_t aCode,
148                                        const nsAString& aReason);
149 
150   // if there are "strong event listeners" (see comment in WebSocket.cpp) or
151   // outgoing not sent messages then this method keeps the object alive
152   // when js doesn't have strong references to it.
153   void UpdateMustKeepAlive();
154   // ATTENTION, when calling this method the object can be released
155   // (and possibly collected).
156   void DontKeepAliveAnyMore();
157 
158  private:
159   WebSocket(const WebSocket& x) = delete;  // prevent bad usage
160   WebSocket& operator=(const WebSocket& x) = delete;
161 
162   void Send(nsIInputStream* aMsgStream, const nsACString& aMsgString,
163             uint32_t aMsgLength, bool aIsBinary, ErrorResult& aRv);
164 
165   void AssertIsOnTargetThread() const;
166 
167   // Raw pointer because this WebSocketImpl is created, managed and destroyed by
168   // WebSocket.
169   WebSocketImpl* mImpl;
170 
171   bool mIsMainThread;
172 
173   bool mKeepingAlive;
174   bool mCheckMustKeepAlive;
175 
176   CheckedUint32 mOutgoingBufferedAmount;
177 
178   // related to the WebSocket constructor steps
179   nsString mURI;
180   nsString mEffectiveURL;  // after redirects
181   nsCString mEstablishedExtensions;
182   nsCString mEstablishedProtocol;
183 
184   dom::BinaryType mBinaryType;
185 
186   // This mutex protects mReadyState that is the only variable that is used in
187   // different threads.
188   mozilla::Mutex mMutex;
189 
190   // This value should not be used directly but use ReadyState() instead.
191   uint16_t mReadyState;
192 };
193 
194 }  // namespace dom
195 }  // namespace mozilla
196 
197 #endif
198