1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et tw=80 : */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Josh Matthews <josh@joshmatthews.net>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "WebSocketLog.h"
41 : #include "mozilla/dom/TabChild.h"
42 : #include "mozilla/net/NeckoChild.h"
43 : #include "WebSocketChannelChild.h"
44 : #include "nsITabChild.h"
45 :
46 : namespace mozilla {
47 : namespace net {
48 :
49 0 : NS_IMPL_ADDREF(WebSocketChannelChild)
50 :
51 0 : NS_IMETHODIMP_(nsrefcnt) WebSocketChannelChild::Release()
52 : {
53 0 : NS_PRECONDITION(0 != mRefCnt, "dup release");
54 0 : NS_ASSERT_OWNINGTHREAD(WebSocketChannelChild);
55 0 : --mRefCnt;
56 0 : NS_LOG_RELEASE(this, mRefCnt, "WebSocketChannelChild");
57 :
58 0 : if (mRefCnt == 1 && mIPCOpen) {
59 0 : SendDeleteSelf();
60 0 : return mRefCnt;
61 : }
62 :
63 0 : if (mRefCnt == 0) {
64 0 : mRefCnt = 1; /* stabilize */
65 0 : delete this;
66 0 : return 0;
67 : }
68 0 : return mRefCnt;
69 : }
70 :
71 0 : NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild)
72 0 : NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel)
73 0 : NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
74 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel)
75 0 : NS_INTERFACE_MAP_END
76 :
77 0 : WebSocketChannelChild::WebSocketChannelChild(bool aSecure)
78 : : mEventQ(static_cast<nsIWebSocketChannel*>(this))
79 0 : , mIPCOpen(false)
80 : {
81 0 : LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this));
82 0 : BaseWebSocketChannel::mEncrypted = aSecure;
83 0 : }
84 :
85 0 : WebSocketChannelChild::~WebSocketChannelChild()
86 : {
87 0 : LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this));
88 0 : }
89 :
90 : void
91 0 : WebSocketChannelChild::AddIPDLReference()
92 : {
93 0 : NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
94 0 : mIPCOpen = true;
95 0 : AddRef();
96 0 : }
97 :
98 : void
99 0 : WebSocketChannelChild::ReleaseIPDLReference()
100 : {
101 0 : NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
102 0 : mIPCOpen = false;
103 0 : Release();
104 0 : }
105 :
106 : class StartEvent : public ChannelEvent
107 0 : {
108 : public:
109 0 : StartEvent(WebSocketChannelChild* aChild,
110 : const nsCString& aProtocol,
111 : const nsCString& aExtensions)
112 : : mChild(aChild)
113 : , mProtocol(aProtocol)
114 0 : , mExtensions(aExtensions)
115 0 : {}
116 :
117 0 : void Run()
118 : {
119 0 : mChild->OnStart(mProtocol, mExtensions);
120 0 : }
121 : private:
122 : WebSocketChannelChild* mChild;
123 : nsCString mProtocol;
124 : nsCString mExtensions;
125 : };
126 :
127 : bool
128 0 : WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol,
129 : const nsCString& aExtensions)
130 : {
131 0 : if (mEventQ.ShouldEnqueue()) {
132 0 : mEventQ.Enqueue(new StartEvent(this, aProtocol, aExtensions));
133 : } else {
134 0 : OnStart(aProtocol, aExtensions);
135 : }
136 0 : return true;
137 : }
138 :
139 : void
140 0 : WebSocketChannelChild::OnStart(const nsCString& aProtocol,
141 : const nsCString& aExtensions)
142 : {
143 0 : LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this));
144 0 : SetProtocol(aProtocol);
145 0 : mNegotiatedExtensions = aExtensions;
146 :
147 0 : if (mListener) {
148 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
149 0 : mListener->OnStart(mContext);
150 : }
151 0 : }
152 :
153 : class StopEvent : public ChannelEvent
154 0 : {
155 : public:
156 0 : StopEvent(WebSocketChannelChild* aChild,
157 : const nsresult& aStatusCode)
158 : : mChild(aChild)
159 0 : , mStatusCode(aStatusCode)
160 0 : {}
161 :
162 0 : void Run()
163 : {
164 0 : mChild->OnStop(mStatusCode);
165 0 : }
166 : private:
167 : WebSocketChannelChild* mChild;
168 : nsresult mStatusCode;
169 : };
170 :
171 : bool
172 0 : WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
173 : {
174 0 : if (mEventQ.ShouldEnqueue()) {
175 0 : mEventQ.Enqueue(new StopEvent(this, aStatusCode));
176 : } else {
177 0 : OnStop(aStatusCode);
178 : }
179 0 : return true;
180 : }
181 :
182 : void
183 0 : WebSocketChannelChild::OnStop(const nsresult& aStatusCode)
184 : {
185 0 : LOG(("WebSocketChannelChild::RecvOnStop() %p\n", this));
186 0 : if (mListener) {
187 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
188 0 : mListener->OnStop(mContext, aStatusCode);
189 : }
190 0 : }
191 :
192 : class MessageEvent : public ChannelEvent
193 0 : {
194 : public:
195 0 : MessageEvent(WebSocketChannelChild* aChild,
196 : const nsCString& aMessage,
197 : bool aBinary)
198 : : mChild(aChild)
199 : , mMessage(aMessage)
200 0 : , mBinary(aBinary)
201 0 : {}
202 :
203 0 : void Run()
204 : {
205 0 : if (!mBinary) {
206 0 : mChild->OnMessageAvailable(mMessage);
207 : } else {
208 0 : mChild->OnBinaryMessageAvailable(mMessage);
209 : }
210 0 : }
211 : private:
212 : WebSocketChannelChild* mChild;
213 : nsCString mMessage;
214 : bool mBinary;
215 : };
216 :
217 : bool
218 0 : WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
219 : {
220 0 : if (mEventQ.ShouldEnqueue()) {
221 0 : mEventQ.Enqueue(new MessageEvent(this, aMsg, false));
222 : } else {
223 0 : OnMessageAvailable(aMsg);
224 : }
225 0 : return true;
226 : }
227 :
228 : void
229 0 : WebSocketChannelChild::OnMessageAvailable(const nsCString& aMsg)
230 : {
231 0 : LOG(("WebSocketChannelChild::RecvOnMessageAvailable() %p\n", this));
232 0 : if (mListener) {
233 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
234 0 : mListener->OnMessageAvailable(mContext, aMsg);
235 : }
236 0 : }
237 :
238 : bool
239 0 : WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg)
240 : {
241 0 : if (mEventQ.ShouldEnqueue()) {
242 0 : mEventQ.Enqueue(new MessageEvent(this, aMsg, true));
243 : } else {
244 0 : OnBinaryMessageAvailable(aMsg);
245 : }
246 0 : return true;
247 : }
248 :
249 : void
250 0 : WebSocketChannelChild::OnBinaryMessageAvailable(const nsCString& aMsg)
251 : {
252 0 : LOG(("WebSocketChannelChild::RecvOnBinaryMessageAvailable() %p\n", this));
253 0 : if (mListener) {
254 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
255 0 : mListener->OnBinaryMessageAvailable(mContext, aMsg);
256 : }
257 0 : }
258 :
259 : class AcknowledgeEvent : public ChannelEvent
260 0 : {
261 : public:
262 0 : AcknowledgeEvent(WebSocketChannelChild* aChild,
263 : const PRUint32& aSize)
264 : : mChild(aChild)
265 0 : , mSize(aSize)
266 0 : {}
267 :
268 0 : void Run()
269 : {
270 0 : mChild->OnAcknowledge(mSize);
271 0 : }
272 : private:
273 : WebSocketChannelChild* mChild;
274 : PRUint32 mSize;
275 : };
276 :
277 : bool
278 0 : WebSocketChannelChild::RecvOnAcknowledge(const PRUint32& aSize)
279 : {
280 0 : if (mEventQ.ShouldEnqueue()) {
281 0 : mEventQ.Enqueue(new AcknowledgeEvent(this, aSize));
282 : } else {
283 0 : OnAcknowledge(aSize);
284 : }
285 0 : return true;
286 : }
287 :
288 : void
289 0 : WebSocketChannelChild::OnAcknowledge(const PRUint32& aSize)
290 : {
291 0 : LOG(("WebSocketChannelChild::RecvOnAcknowledge() %p\n", this));
292 0 : if (mListener) {
293 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
294 0 : mListener->OnAcknowledge(mContext, aSize);
295 : }
296 0 : }
297 :
298 : class ServerCloseEvent : public ChannelEvent
299 0 : {
300 : public:
301 0 : ServerCloseEvent(WebSocketChannelChild* aChild,
302 : const PRUint16 aCode,
303 : const nsCString &aReason)
304 : : mChild(aChild)
305 : , mCode(aCode)
306 0 : , mReason(aReason)
307 0 : {}
308 :
309 0 : void Run()
310 : {
311 0 : mChild->OnServerClose(mCode, mReason);
312 0 : }
313 : private:
314 : WebSocketChannelChild* mChild;
315 : PRUint16 mCode;
316 : nsCString mReason;
317 : };
318 :
319 : bool
320 0 : WebSocketChannelChild::RecvOnServerClose(const PRUint16& aCode,
321 : const nsCString& aReason)
322 : {
323 0 : if (mEventQ.ShouldEnqueue()) {
324 0 : mEventQ.Enqueue(new ServerCloseEvent(this, aCode, aReason));
325 : } else {
326 0 : OnServerClose(aCode, aReason);
327 : }
328 0 : return true;
329 : }
330 :
331 : void
332 0 : WebSocketChannelChild::OnServerClose(const PRUint16& aCode,
333 : const nsCString& aReason)
334 : {
335 0 : LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
336 0 : if (mListener) {
337 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);;
338 0 : mListener->OnServerClose(mContext, aCode, aReason);
339 : }
340 0 : }
341 :
342 : NS_IMETHODIMP
343 0 : WebSocketChannelChild::AsyncOpen(nsIURI *aURI,
344 : const nsACString &aOrigin,
345 : nsIWebSocketListener *aListener,
346 : nsISupports *aContext)
347 : {
348 0 : LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this));
349 :
350 0 : NS_ABORT_IF_FALSE(aURI && aListener && !mListener,
351 : "Invalid state for WebSocketChannelChild::AsyncOpen");
352 :
353 0 : mozilla::dom::TabChild* tabChild = nsnull;
354 0 : nsCOMPtr<nsITabChild> iTabChild;
355 : NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
356 : NS_GET_IID(nsITabChild),
357 0 : getter_AddRefs(iTabChild));
358 0 : if (iTabChild) {
359 0 : tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
360 : }
361 :
362 : // Corresponding release in DeallocPWebSocket
363 0 : AddIPDLReference();
364 :
365 0 : gNeckoChild->SendPWebSocketConstructor(this, tabChild);
366 0 : if (!SendAsyncOpen(aURI, nsCString(aOrigin), mProtocol, mEncrypted))
367 0 : return NS_ERROR_UNEXPECTED;
368 :
369 0 : mOriginalURI = aURI;
370 0 : mURI = mOriginalURI;
371 0 : mListener = aListener;
372 0 : mContext = aContext;
373 0 : mOrigin = aOrigin;
374 :
375 0 : return NS_OK;
376 : }
377 :
378 : NS_IMETHODIMP
379 0 : WebSocketChannelChild::Close(PRUint16 code, const nsACString & reason)
380 : {
381 0 : LOG(("WebSocketChannelChild::Close() %p\n", this));
382 :
383 0 : if (!mIPCOpen || !SendClose(code, nsCString(reason)))
384 0 : return NS_ERROR_UNEXPECTED;
385 0 : return NS_OK;
386 : }
387 :
388 : NS_IMETHODIMP
389 0 : WebSocketChannelChild::SendMsg(const nsACString &aMsg)
390 : {
391 0 : LOG(("WebSocketChannelChild::SendMsg() %p\n", this));
392 :
393 0 : if (!mIPCOpen || !SendSendMsg(nsCString(aMsg)))
394 0 : return NS_ERROR_UNEXPECTED;
395 0 : return NS_OK;
396 : }
397 :
398 : NS_IMETHODIMP
399 0 : WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg)
400 : {
401 0 : LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this));
402 :
403 0 : if (!mIPCOpen || !SendSendBinaryMsg(nsCString(aMsg)))
404 0 : return NS_ERROR_UNEXPECTED;
405 0 : return NS_OK;
406 : }
407 :
408 : NS_IMETHODIMP
409 0 : WebSocketChannelChild::SendBinaryStream(nsIInputStream *aStream,
410 : PRUint32 aLength)
411 : {
412 0 : LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this));
413 :
414 0 : if (!mIPCOpen || !SendSendBinaryStream(IPC::InputStream(aStream), aLength))
415 0 : return NS_ERROR_UNEXPECTED;
416 0 : return NS_OK;
417 : }
418 :
419 : NS_IMETHODIMP
420 0 : WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
421 : {
422 0 : LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this));
423 0 : return NS_ERROR_NOT_AVAILABLE;
424 : }
425 :
426 : } // namespace net
427 : } // namespace mozilla
|