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