Line data Source code
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 : /* 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 : #include "WebSocketLog.h"
8 : #include "base/compiler_specific.h"
9 : #include "mozilla/dom/TabChild.h"
10 : #include "mozilla/net/NeckoChild.h"
11 : #include "WebSocketChannelChild.h"
12 : #include "nsContentUtils.h"
13 : #include "nsITabChild.h"
14 : #include "nsNetUtil.h"
15 : #include "mozilla/ipc/IPCStreamUtils.h"
16 : #include "mozilla/ipc/URIUtils.h"
17 : #include "mozilla/ipc/BackgroundUtils.h"
18 : #include "mozilla/net/ChannelEventQueue.h"
19 : #include "SerializedLoadContext.h"
20 :
21 : using namespace mozilla::ipc;
22 :
23 : namespace mozilla {
24 : namespace net {
25 :
26 0 : NS_IMPL_ADDREF(WebSocketChannelChild)
27 :
28 0 : NS_IMETHODIMP_(MozExternalRefCountType) WebSocketChannelChild::Release()
29 : {
30 0 : NS_PRECONDITION(0 != mRefCnt, "dup release");
31 0 : --mRefCnt;
32 0 : NS_LOG_RELEASE(this, mRefCnt, "WebSocketChannelChild");
33 :
34 0 : if (mRefCnt == 1) {
35 0 : MaybeReleaseIPCObject();
36 0 : return mRefCnt;
37 : }
38 :
39 0 : if (mRefCnt == 0) {
40 0 : mRefCnt = 1; /* stabilize */
41 0 : delete this;
42 0 : return 0;
43 : }
44 0 : return mRefCnt;
45 : }
46 :
47 0 : NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild)
48 0 : NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel)
49 0 : NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler)
50 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel)
51 0 : NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
52 0 : NS_INTERFACE_MAP_END
53 :
54 0 : WebSocketChannelChild::WebSocketChannelChild(bool aEncrypted)
55 : : NeckoTargetHolder(nullptr)
56 : , mIPCState(Closed)
57 0 : , mMutex("WebSocketChannelChild::mMutex")
58 : {
59 0 : MOZ_ASSERT(NS_IsMainThread(), "not main thread");
60 :
61 0 : LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this));
62 0 : mEncrypted = aEncrypted;
63 0 : mEventQ = new ChannelEventQueue(static_cast<nsIWebSocketChannel*>(this));
64 0 : }
65 :
66 0 : WebSocketChannelChild::~WebSocketChannelChild()
67 : {
68 0 : LOG(("WebSocketChannelChild::~WebSocketChannelChild() %p\n", this));
69 0 : }
70 :
71 : void
72 0 : WebSocketChannelChild::AddIPDLReference()
73 : {
74 0 : MOZ_ASSERT(NS_IsMainThread());
75 :
76 : {
77 0 : MutexAutoLock lock(mMutex);
78 0 : MOZ_ASSERT(mIPCState == Closed, "Attempt to retain more than one IPDL reference");
79 0 : mIPCState = Opened;
80 : }
81 :
82 0 : AddRef();
83 0 : }
84 :
85 : void
86 0 : WebSocketChannelChild::ReleaseIPDLReference()
87 : {
88 0 : MOZ_ASSERT(NS_IsMainThread());
89 :
90 : {
91 0 : MutexAutoLock lock(mMutex);
92 0 : MOZ_ASSERT(mIPCState != Closed, "Attempt to release nonexistent IPDL reference");
93 0 : mIPCState = Closed;
94 : }
95 :
96 0 : Release();
97 0 : }
98 :
99 : void
100 0 : WebSocketChannelChild::MaybeReleaseIPCObject()
101 : {
102 : {
103 0 : MutexAutoLock lock(mMutex);
104 0 : if (mIPCState != Opened) {
105 0 : return;
106 : }
107 :
108 0 : mIPCState = Closing;
109 : }
110 :
111 0 : if (!NS_IsMainThread()) {
112 0 : nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
113 0 : MOZ_ALWAYS_SUCCEEDS(
114 : target->Dispatch(NewRunnableMethod("WebSocketChannelChild::MaybeReleaseIPCObject",
115 : this,
116 : &WebSocketChannelChild::MaybeReleaseIPCObject),
117 : NS_DISPATCH_NORMAL));
118 0 : return;
119 : }
120 :
121 0 : SendDeleteSelf();
122 : }
123 :
124 : void
125 0 : WebSocketChannelChild::GetEffectiveURL(nsAString& aEffectiveURL) const
126 : {
127 0 : aEffectiveURL = mEffectiveURL;
128 0 : }
129 :
130 : bool
131 0 : WebSocketChannelChild::IsEncrypted() const
132 : {
133 0 : return mEncrypted;
134 : }
135 :
136 0 : class WrappedChannelEvent : public Runnable
137 : {
138 : public:
139 0 : explicit WrappedChannelEvent(ChannelEvent* aChannelEvent)
140 0 : : Runnable("net::WrappedChannelEvent")
141 0 : , mChannelEvent(aChannelEvent)
142 : {
143 0 : MOZ_RELEASE_ASSERT(aChannelEvent);
144 0 : }
145 0 : NS_IMETHOD Run() override
146 : {
147 0 : mChannelEvent->Run();
148 0 : return NS_OK;
149 : }
150 : private:
151 : nsAutoPtr<ChannelEvent> mChannelEvent;
152 : };
153 :
154 : void
155 0 : WebSocketChannelChild::DispatchToTargetThread(ChannelEvent *aChannelEvent)
156 : {
157 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
158 0 : MOZ_RELEASE_ASSERT(mTargetThread);
159 0 : MOZ_RELEASE_ASSERT(aChannelEvent);
160 :
161 0 : mTargetThread->Dispatch(new WrappedChannelEvent(aChannelEvent),
162 0 : NS_DISPATCH_NORMAL);
163 0 : }
164 :
165 0 : class EventTargetDispatcher : public ChannelEvent
166 : {
167 : public:
168 0 : EventTargetDispatcher(ChannelEvent* aChannelEvent,
169 : nsIEventTarget* aEventTarget)
170 0 : : mChannelEvent(aChannelEvent)
171 0 : , mEventTarget(aEventTarget)
172 0 : {}
173 :
174 0 : void Run()
175 : {
176 0 : if (mEventTarget) {
177 0 : mEventTarget->Dispatch(new WrappedChannelEvent(mChannelEvent.forget()),
178 0 : NS_DISPATCH_NORMAL);
179 0 : return;
180 : }
181 :
182 0 : mChannelEvent->Run();
183 : }
184 :
185 0 : already_AddRefed<nsIEventTarget> GetEventTarget()
186 : {
187 0 : nsCOMPtr<nsIEventTarget> target = mEventTarget;
188 0 : if (!target) {
189 0 : target = GetMainThreadEventTarget();
190 : }
191 0 : return target.forget();
192 : }
193 :
194 : private:
195 : nsAutoPtr<ChannelEvent> mChannelEvent;
196 : nsCOMPtr<nsIEventTarget> mEventTarget;
197 : };
198 :
199 0 : class StartEvent : public ChannelEvent
200 : {
201 : public:
202 0 : StartEvent(WebSocketChannelChild* aChild,
203 : const nsCString& aProtocol,
204 : const nsCString& aExtensions,
205 : const nsString& aEffectiveURL,
206 : bool aEncrypted)
207 0 : : mChild(aChild)
208 : , mProtocol(aProtocol)
209 : , mExtensions(aExtensions)
210 : , mEffectiveURL(aEffectiveURL)
211 0 : , mEncrypted(aEncrypted)
212 0 : {}
213 :
214 0 : void Run()
215 : {
216 0 : mChild->OnStart(mProtocol, mExtensions, mEffectiveURL, mEncrypted);
217 0 : }
218 :
219 0 : already_AddRefed<nsIEventTarget> GetEventTarget()
220 : {
221 0 : return do_AddRef(GetCurrentThreadEventTarget());
222 : }
223 :
224 : private:
225 : RefPtr<WebSocketChannelChild> mChild;
226 : nsCString mProtocol;
227 : nsCString mExtensions;
228 : nsString mEffectiveURL;
229 : bool mEncrypted;
230 : };
231 :
232 : mozilla::ipc::IPCResult
233 0 : WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol,
234 : const nsCString& aExtensions,
235 : const nsString& aEffectiveURL,
236 : const bool& aEncrypted)
237 : {
238 0 : mEventQ->RunOrEnqueue(
239 0 : new EventTargetDispatcher(new StartEvent(this, aProtocol, aExtensions,
240 0 : aEffectiveURL, aEncrypted),
241 0 : mTargetThread));
242 :
243 0 : return IPC_OK();
244 : }
245 :
246 : void
247 0 : WebSocketChannelChild::OnStart(const nsCString& aProtocol,
248 : const nsCString& aExtensions,
249 : const nsString& aEffectiveURL,
250 : const bool& aEncrypted)
251 : {
252 0 : LOG(("WebSocketChannelChild::RecvOnStart() %p\n", this));
253 0 : SetProtocol(aProtocol);
254 0 : mNegotiatedExtensions = aExtensions;
255 0 : mEffectiveURL = aEffectiveURL;
256 0 : mEncrypted = aEncrypted;
257 :
258 0 : if (mListenerMT) {
259 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
260 0 : nsresult rv = mListenerMT->mListener->OnStart(mListenerMT->mContext);
261 0 : if (NS_FAILED(rv)) {
262 0 : LOG(("WebSocketChannelChild::OnStart "
263 : "mListenerMT->mListener->OnStart() failed with error 0x%08" PRIx32,
264 : static_cast<uint32_t>(rv)));
265 : }
266 : }
267 0 : }
268 :
269 0 : class StopEvent : public ChannelEvent
270 : {
271 : public:
272 0 : StopEvent(WebSocketChannelChild* aChild,
273 : const nsresult& aStatusCode)
274 0 : : mChild(aChild)
275 0 : , mStatusCode(aStatusCode)
276 0 : {}
277 :
278 0 : void Run()
279 : {
280 0 : mChild->OnStop(mStatusCode);
281 0 : }
282 :
283 0 : already_AddRefed<nsIEventTarget> GetEventTarget()
284 : {
285 0 : return do_AddRef(GetCurrentThreadEventTarget());
286 : }
287 :
288 : private:
289 : RefPtr<WebSocketChannelChild> mChild;
290 : nsresult mStatusCode;
291 : };
292 :
293 : mozilla::ipc::IPCResult
294 0 : WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
295 : {
296 0 : mEventQ->RunOrEnqueue(
297 0 : new EventTargetDispatcher(new StopEvent(this, aStatusCode),
298 0 : mTargetThread));
299 :
300 0 : return IPC_OK();
301 : }
302 :
303 : void
304 0 : WebSocketChannelChild::OnStop(const nsresult& aStatusCode)
305 : {
306 0 : LOG(("WebSocketChannelChild::RecvOnStop() %p\n", this));
307 0 : if (mListenerMT) {
308 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
309 : nsresult rv =
310 0 : mListenerMT->mListener->OnStop(mListenerMT->mContext, aStatusCode);
311 0 : if (NS_FAILED(rv)) {
312 0 : LOG(("WebSocketChannel::OnStop "
313 : "mListenerMT->mListener->OnStop() failed with error 0x%08" PRIx32,
314 : static_cast<uint32_t>(rv)));
315 : }
316 : }
317 0 : }
318 :
319 0 : class MessageEvent : public ChannelEvent
320 : {
321 : public:
322 0 : MessageEvent(WebSocketChannelChild* aChild,
323 : const nsCString& aMessage,
324 : bool aBinary)
325 0 : : mChild(aChild)
326 : , mMessage(aMessage)
327 0 : , mBinary(aBinary)
328 0 : {}
329 :
330 0 : void Run()
331 : {
332 0 : if (!mBinary) {
333 0 : mChild->OnMessageAvailable(mMessage);
334 : } else {
335 0 : mChild->OnBinaryMessageAvailable(mMessage);
336 : }
337 0 : }
338 :
339 0 : already_AddRefed<nsIEventTarget> GetEventTarget()
340 : {
341 0 : return do_AddRef(GetCurrentThreadEventTarget());
342 : }
343 :
344 : private:
345 : RefPtr<WebSocketChannelChild> mChild;
346 : nsCString mMessage;
347 : bool mBinary;
348 : };
349 :
350 : mozilla::ipc::IPCResult
351 0 : WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
352 : {
353 0 : mEventQ->RunOrEnqueue(
354 0 : new EventTargetDispatcher(new MessageEvent(this, aMsg, false),
355 0 : mTargetThread));
356 :
357 0 : return IPC_OK();
358 : }
359 :
360 : void
361 0 : WebSocketChannelChild::OnMessageAvailable(const nsCString& aMsg)
362 : {
363 0 : LOG(("WebSocketChannelChild::RecvOnMessageAvailable() %p\n", this));
364 0 : if (mListenerMT) {
365 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
366 : nsresult rv =
367 0 : mListenerMT->mListener->OnMessageAvailable(mListenerMT->mContext, aMsg);
368 0 : if (NS_FAILED(rv)) {
369 0 : LOG(("WebSocketChannelChild::OnMessageAvailable "
370 : "mListenerMT->mListener->OnMessageAvailable() "
371 : "failed with error 0x%08" PRIx32, static_cast<uint32_t>(rv)));
372 : }
373 : }
374 0 : }
375 :
376 : mozilla::ipc::IPCResult
377 0 : WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg)
378 : {
379 0 : mEventQ->RunOrEnqueue(
380 0 : new EventTargetDispatcher(new MessageEvent(this, aMsg, true),
381 0 : mTargetThread));
382 :
383 0 : return IPC_OK();
384 : }
385 :
386 : void
387 0 : WebSocketChannelChild::OnBinaryMessageAvailable(const nsCString& aMsg)
388 : {
389 0 : LOG(("WebSocketChannelChild::RecvOnBinaryMessageAvailable() %p\n", this));
390 0 : if (mListenerMT) {
391 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
392 : nsresult rv =
393 0 : mListenerMT->mListener->OnBinaryMessageAvailable(mListenerMT->mContext,
394 0 : aMsg);
395 0 : if (NS_FAILED(rv)) {
396 0 : LOG(("WebSocketChannelChild::OnBinaryMessageAvailable "
397 : "mListenerMT->mListener->OnBinaryMessageAvailable() "
398 : "failed with error 0x%08" PRIx32, static_cast<uint32_t>(rv)));
399 : }
400 : }
401 0 : }
402 :
403 0 : class AcknowledgeEvent : public ChannelEvent
404 : {
405 : public:
406 0 : AcknowledgeEvent(WebSocketChannelChild* aChild,
407 : const uint32_t& aSize)
408 0 : : mChild(aChild)
409 0 : , mSize(aSize)
410 0 : {}
411 :
412 0 : void Run()
413 : {
414 0 : mChild->OnAcknowledge(mSize);
415 0 : }
416 :
417 0 : already_AddRefed<nsIEventTarget> GetEventTarget()
418 : {
419 0 : return do_AddRef(GetCurrentThreadEventTarget());
420 : }
421 :
422 : private:
423 : RefPtr<WebSocketChannelChild> mChild;
424 : uint32_t mSize;
425 : };
426 :
427 : mozilla::ipc::IPCResult
428 0 : WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize)
429 : {
430 0 : mEventQ->RunOrEnqueue(
431 0 : new EventTargetDispatcher(new AcknowledgeEvent(this, aSize),
432 0 : mTargetThread));
433 :
434 0 : return IPC_OK();
435 : }
436 :
437 : void
438 0 : WebSocketChannelChild::OnAcknowledge(const uint32_t& aSize)
439 : {
440 0 : LOG(("WebSocketChannelChild::RecvOnAcknowledge() %p\n", this));
441 0 : if (mListenerMT) {
442 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
443 : nsresult rv =
444 0 : mListenerMT->mListener->OnAcknowledge(mListenerMT->mContext, aSize);
445 0 : if (NS_FAILED(rv)) {
446 0 : LOG(("WebSocketChannel::OnAcknowledge "
447 : "mListenerMT->mListener->OnAcknowledge() "
448 : "failed with error 0x%08" PRIx32, static_cast<uint32_t>(rv)));
449 : }
450 : }
451 0 : }
452 :
453 0 : class ServerCloseEvent : public ChannelEvent
454 : {
455 : public:
456 0 : ServerCloseEvent(WebSocketChannelChild* aChild,
457 : const uint16_t aCode,
458 : const nsCString &aReason)
459 0 : : mChild(aChild)
460 : , mCode(aCode)
461 0 : , mReason(aReason)
462 0 : {}
463 :
464 0 : void Run()
465 : {
466 0 : mChild->OnServerClose(mCode, mReason);
467 0 : }
468 :
469 0 : already_AddRefed<nsIEventTarget> GetEventTarget()
470 : {
471 0 : return do_AddRef(GetCurrentThreadEventTarget());
472 : }
473 :
474 : private:
475 : RefPtr<WebSocketChannelChild> mChild;
476 : uint16_t mCode;
477 : nsCString mReason;
478 : };
479 :
480 : mozilla::ipc::IPCResult
481 0 : WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode,
482 : const nsCString& aReason)
483 : {
484 0 : mEventQ->RunOrEnqueue(
485 0 : new EventTargetDispatcher(new ServerCloseEvent(this, aCode, aReason),
486 0 : mTargetThread));
487 :
488 0 : return IPC_OK();
489 : }
490 :
491 : void
492 0 : WebSocketChannelChild::OnServerClose(const uint16_t& aCode,
493 : const nsCString& aReason)
494 : {
495 0 : LOG(("WebSocketChannelChild::RecvOnServerClose() %p\n", this));
496 0 : if (mListenerMT) {
497 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
498 : DebugOnly<nsresult> rv =
499 0 : mListenerMT->mListener->OnServerClose(mListenerMT->mContext, aCode,
500 0 : aReason);
501 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
502 : }
503 0 : }
504 :
505 : void
506 0 : WebSocketChannelChild::SetupNeckoTarget()
507 : {
508 0 : mNeckoTarget = nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, TaskCategory::Network);
509 0 : if (!mNeckoTarget) {
510 0 : return;
511 : }
512 :
513 0 : gNeckoChild->SetEventTargetForActor(this, mNeckoTarget);
514 : }
515 :
516 : NS_IMETHODIMP
517 0 : WebSocketChannelChild::AsyncOpen(nsIURI *aURI,
518 : const nsACString &aOrigin,
519 : uint64_t aInnerWindowID,
520 : nsIWebSocketListener *aListener,
521 : nsISupports *aContext)
522 : {
523 0 : LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this));
524 :
525 0 : MOZ_ASSERT(NS_IsMainThread(), "not main thread");
526 0 : MOZ_ASSERT((aURI && !mIsServerSide) || (!aURI && mIsServerSide),
527 : "Invalid aURI for WebSocketChannelChild::AsyncOpen");
528 0 : MOZ_ASSERT(aListener && !mListenerMT,
529 : "Invalid state for WebSocketChannelChild::AsyncOpen");
530 :
531 0 : mozilla::dom::TabChild* tabChild = nullptr;
532 0 : nsCOMPtr<nsITabChild> iTabChild;
533 0 : NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
534 : NS_GET_IID(nsITabChild),
535 0 : getter_AddRefs(iTabChild));
536 0 : if (iTabChild) {
537 0 : tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
538 : }
539 0 : if (MissingRequiredTabChild(tabChild, "websocket")) {
540 0 : return NS_ERROR_ILLEGAL_VALUE;
541 : }
542 :
543 0 : ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
544 0 : if (cc->IsShuttingDown()) {
545 0 : return NS_ERROR_FAILURE;
546 : }
547 :
548 : // Corresponding release in DeallocPWebSocket
549 0 : AddIPDLReference();
550 :
551 0 : OptionalURIParams uri;
552 0 : OptionalLoadInfoArgs loadInfoArgs;
553 0 : OptionalTransportProvider transportProvider;
554 :
555 0 : if (!mIsServerSide) {
556 0 : uri = URIParams();
557 0 : SerializeURI(aURI, uri.get_URIParams());
558 0 : nsresult rv = LoadInfoToLoadInfoArgs(mLoadInfo, &loadInfoArgs);
559 0 : NS_ENSURE_SUCCESS(rv, rv);
560 :
561 0 : transportProvider = void_t();
562 : } else {
563 0 : uri = void_t();
564 0 : loadInfoArgs = void_t();
565 :
566 0 : MOZ_ASSERT(mServerTransportProvider);
567 : PTransportProviderChild *ipcChild;
568 0 : nsresult rv = mServerTransportProvider->GetIPCChild(&ipcChild);
569 0 : NS_ENSURE_SUCCESS(rv, rv);
570 :
571 0 : transportProvider = ipcChild;
572 : }
573 :
574 : // This must be called before sending constructor message.
575 0 : SetupNeckoTarget();
576 :
577 0 : gNeckoChild->SendPWebSocketConstructor(this, tabChild,
578 0 : IPC::SerializedLoadContext(this),
579 0 : mSerial);
580 0 : if (!SendAsyncOpen(uri, nsCString(aOrigin), aInnerWindowID, mProtocol,
581 : mEncrypted, mPingInterval, mClientSetPingInterval,
582 : mPingResponseTimeout, mClientSetPingTimeout, loadInfoArgs,
583 0 : transportProvider, mNegotiatedExtensions)) {
584 0 : return NS_ERROR_UNEXPECTED;
585 : }
586 :
587 0 : if (mIsServerSide) {
588 0 : mServerTransportProvider = nullptr;
589 : }
590 :
591 0 : mOriginalURI = aURI;
592 0 : mURI = mOriginalURI;
593 0 : mListenerMT = new ListenerAndContextContainer(aListener, aContext);
594 0 : mOrigin = aOrigin;
595 0 : mWasOpened = 1;
596 :
597 0 : return NS_OK;
598 : }
599 :
600 0 : class CloseEvent : public Runnable
601 : {
602 : public:
603 0 : CloseEvent(WebSocketChannelChild* aChild,
604 : uint16_t aCode,
605 : const nsACString& aReason)
606 0 : : Runnable("net::CloseEvent")
607 : , mChild(aChild)
608 : , mCode(aCode)
609 0 : , mReason(aReason)
610 : {
611 0 : MOZ_RELEASE_ASSERT(!NS_IsMainThread());
612 0 : MOZ_ASSERT(aChild);
613 0 : }
614 0 : NS_IMETHOD Run() override
615 : {
616 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
617 0 : mChild->Close(mCode, mReason);
618 0 : return NS_OK;
619 : }
620 : private:
621 : RefPtr<WebSocketChannelChild> mChild;
622 : uint16_t mCode;
623 : nsCString mReason;
624 : };
625 :
626 : NS_IMETHODIMP
627 0 : WebSocketChannelChild::Close(uint16_t code, const nsACString & reason)
628 : {
629 0 : if (!NS_IsMainThread()) {
630 0 : MOZ_RELEASE_ASSERT(mTargetThread->IsOnCurrentThread());
631 0 : nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
632 0 : return target->Dispatch(new CloseEvent(this, code, reason),
633 0 : NS_DISPATCH_NORMAL);
634 : }
635 0 : LOG(("WebSocketChannelChild::Close() %p\n", this));
636 :
637 : {
638 0 : MutexAutoLock lock(mMutex);
639 0 : if (mIPCState != Opened) {
640 0 : return NS_ERROR_UNEXPECTED;
641 : }
642 : }
643 :
644 0 : if (!SendClose(code, nsCString(reason))) {
645 0 : return NS_ERROR_UNEXPECTED;
646 : }
647 :
648 0 : return NS_OK;
649 : }
650 :
651 0 : class MsgEvent : public Runnable
652 : {
653 : public:
654 0 : MsgEvent(WebSocketChannelChild* aChild,
655 : const nsACString& aMsg,
656 : bool aBinaryMsg)
657 0 : : Runnable("net::MsgEvent")
658 : , mChild(aChild)
659 : , mMsg(aMsg)
660 0 : , mBinaryMsg(aBinaryMsg)
661 : {
662 0 : MOZ_RELEASE_ASSERT(!NS_IsMainThread());
663 0 : MOZ_ASSERT(aChild);
664 0 : }
665 0 : NS_IMETHOD Run() override
666 : {
667 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
668 0 : if (mBinaryMsg) {
669 0 : mChild->SendBinaryMsg(mMsg);
670 : } else {
671 0 : mChild->SendMsg(mMsg);
672 : }
673 0 : return NS_OK;
674 : }
675 : private:
676 : RefPtr<WebSocketChannelChild> mChild;
677 : nsCString mMsg;
678 : bool mBinaryMsg;
679 : };
680 :
681 : NS_IMETHODIMP
682 0 : WebSocketChannelChild::SendMsg(const nsACString &aMsg)
683 : {
684 0 : if (!NS_IsMainThread()) {
685 0 : MOZ_RELEASE_ASSERT(IsOnTargetThread());
686 0 : nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
687 0 : return target->Dispatch(new MsgEvent(this, aMsg, false),
688 0 : NS_DISPATCH_NORMAL);
689 : }
690 0 : LOG(("WebSocketChannelChild::SendMsg() %p\n", this));
691 :
692 : {
693 0 : MutexAutoLock lock(mMutex);
694 0 : if (mIPCState != Opened) {
695 0 : return NS_ERROR_UNEXPECTED;
696 : }
697 : }
698 :
699 0 : if (!SendSendMsg(nsCString(aMsg))) {
700 0 : return NS_ERROR_UNEXPECTED;
701 : }
702 :
703 0 : return NS_OK;
704 : }
705 :
706 : NS_IMETHODIMP
707 0 : WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg)
708 : {
709 0 : if (!NS_IsMainThread()) {
710 0 : MOZ_RELEASE_ASSERT(IsOnTargetThread());
711 0 : nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
712 0 : return target->Dispatch(new MsgEvent(this, aMsg, true),
713 0 : NS_DISPATCH_NORMAL);
714 : }
715 0 : LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this));
716 :
717 : {
718 0 : MutexAutoLock lock(mMutex);
719 0 : if (mIPCState != Opened) {
720 0 : return NS_ERROR_UNEXPECTED;
721 : }
722 : }
723 :
724 0 : if (!SendSendBinaryMsg(nsCString(aMsg))) {
725 0 : return NS_ERROR_UNEXPECTED;
726 : }
727 :
728 0 : return NS_OK;
729 : }
730 :
731 0 : class BinaryStreamEvent : public Runnable
732 : {
733 : public:
734 0 : BinaryStreamEvent(WebSocketChannelChild* aChild,
735 : nsIInputStream* aStream,
736 : uint32_t aLength)
737 0 : : Runnable("net::BinaryStreamEvent")
738 : , mChild(aChild)
739 : , mStream(aStream)
740 0 : , mLength(aLength)
741 : {
742 0 : MOZ_RELEASE_ASSERT(!NS_IsMainThread());
743 0 : MOZ_ASSERT(aChild);
744 0 : }
745 0 : NS_IMETHOD Run() override
746 : {
747 0 : MOZ_ASSERT(NS_IsMainThread());
748 0 : nsresult rv = mChild->SendBinaryStream(mStream, mLength);
749 0 : if (NS_FAILED(rv)) {
750 0 : LOG(("WebSocketChannelChild::BinaryStreamEvent %p "
751 : "SendBinaryStream failed (%08" PRIx32 ")\n", this, static_cast<uint32_t>(rv)));
752 : }
753 0 : return NS_OK;
754 : }
755 : private:
756 : RefPtr<WebSocketChannelChild> mChild;
757 : nsCOMPtr<nsIInputStream> mStream;
758 : uint32_t mLength;
759 : };
760 :
761 : NS_IMETHODIMP
762 0 : WebSocketChannelChild::SendBinaryStream(nsIInputStream *aStream,
763 : uint32_t aLength)
764 : {
765 0 : if (!NS_IsMainThread()) {
766 0 : MOZ_RELEASE_ASSERT(mTargetThread->IsOnCurrentThread());
767 0 : nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
768 0 : return target->Dispatch(new BinaryStreamEvent(this, aStream, aLength),
769 0 : NS_DISPATCH_NORMAL);
770 : }
771 :
772 0 : LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this));
773 :
774 0 : AutoIPCStream autoStream;
775 0 : autoStream.Serialize(aStream,
776 0 : static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager()));
777 :
778 : {
779 0 : MutexAutoLock lock(mMutex);
780 0 : if (mIPCState != Opened) {
781 0 : return NS_ERROR_UNEXPECTED;
782 : }
783 : }
784 :
785 0 : if (!SendSendBinaryStream(autoStream.TakeValue(), aLength)) {
786 0 : return NS_ERROR_UNEXPECTED;
787 : }
788 :
789 0 : return NS_OK;
790 : }
791 :
792 : NS_IMETHODIMP
793 0 : WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
794 : {
795 0 : LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this));
796 0 : return NS_ERROR_NOT_AVAILABLE;
797 : }
798 :
799 : bool
800 0 : WebSocketChannelChild::IsOnTargetThread()
801 : {
802 0 : MOZ_ASSERT(mTargetThread);
803 0 : bool isOnTargetThread = false;
804 0 : nsresult rv = mTargetThread->IsOnCurrentThread(&isOnTargetThread);
805 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
806 0 : return NS_FAILED(rv) ? false : isOnTargetThread;
807 : }
808 :
809 : } // namespace net
810 : } // namespace mozilla
|