Coverage Report

Created: 2018-09-25 14:53

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