Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/websocket/WebSocketEventService.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 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
#include "WebSocketEventListenerChild.h"
8
#include "WebSocketEventService.h"
9
#include "WebSocketFrame.h"
10
11
#include "mozilla/net/NeckoChild.h"
12
#include "mozilla/StaticPtr.h"
13
#include "nsISupportsPrimitives.h"
14
#include "nsIObserverService.h"
15
#include "nsXULAppAPI.h"
16
#include "nsSocketTransportService2.h"
17
#include "nsThreadUtils.h"
18
#include "mozilla/Services.h"
19
20
namespace mozilla {
21
namespace net {
22
23
namespace {
24
25
StaticRefPtr<WebSocketEventService> gWebSocketEventService;
26
27
bool
28
IsChildProcess()
29
0
{
30
0
  return XRE_GetProcessType() != GeckoProcessType_Default;
31
0
}
32
33
} // anonymous namespace
34
35
class WebSocketBaseRunnable : public Runnable
36
{
37
public:
38
  WebSocketBaseRunnable(uint32_t aWebSocketSerialID, uint64_t aInnerWindowID)
39
    : Runnable("net::WebSocketBaseRunnable")
40
    , mWebSocketSerialID(aWebSocketSerialID)
41
    , mInnerWindowID(aInnerWindowID)
42
0
  {}
43
44
  NS_IMETHOD Run() override
45
0
  {
46
0
    MOZ_ASSERT(NS_IsMainThread());
47
0
48
0
    RefPtr<WebSocketEventService> service = WebSocketEventService::GetOrCreate();
49
0
    MOZ_ASSERT(service);
50
0
51
0
    WebSocketEventService::WindowListeners listeners;
52
0
    service->GetListeners(mInnerWindowID, listeners);
53
0
54
0
    for (uint32_t i = 0; i < listeners.Length(); ++i) {
55
0
      DoWork(listeners[i]);
56
0
    }
57
0
58
0
    return NS_OK;
59
0
  }
60
61
protected:
62
  ~WebSocketBaseRunnable() = default;
63
64
  virtual void DoWork(nsIWebSocketEventListener* aListener) = 0;
65
66
  uint32_t mWebSocketSerialID;
67
  uint64_t mInnerWindowID;
68
};
69
70
class WebSocketFrameRunnable final : public WebSocketBaseRunnable
71
{
72
public:
73
  WebSocketFrameRunnable(uint32_t aWebSocketSerialID,
74
                         uint64_t aInnerWindowID,
75
                         already_AddRefed<WebSocketFrame> aFrame,
76
                         bool aFrameSent)
77
    : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
78
    , mFrame(std::move(aFrame))
79
    , mFrameSent(aFrameSent)
80
0
  {}
81
82
private:
83
  virtual void DoWork(nsIWebSocketEventListener* aListener) override
84
0
  {
85
0
    DebugOnly<nsresult> rv;
86
0
    if (mFrameSent) {
87
0
      rv = aListener->FrameSent(mWebSocketSerialID, mFrame);
88
0
    } else {
89
0
      rv = aListener->FrameReceived(mWebSocketSerialID, mFrame);
90
0
    }
91
0
92
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Frame op failed");
93
0
  }
94
95
  RefPtr<WebSocketFrame> mFrame;
96
  bool mFrameSent;
97
};
98
99
class WebSocketCreatedRunnable final : public WebSocketBaseRunnable
100
{
101
public:
102
  WebSocketCreatedRunnable(uint32_t aWebSocketSerialID,
103
                           uint64_t aInnerWindowID,
104
                           const nsAString& aURI,
105
                           const nsACString& aProtocols)
106
    : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
107
    , mURI(aURI)
108
    , mProtocols(aProtocols)
109
0
  {}
110
111
private:
112
  virtual void DoWork(nsIWebSocketEventListener* aListener) override
113
0
  {
114
0
    DebugOnly<nsresult> rv =
115
0
      aListener->WebSocketCreated(mWebSocketSerialID, mURI, mProtocols);
116
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketCreated failed");
117
0
  }
118
119
  const nsString mURI;
120
  const nsCString mProtocols;
121
};
122
123
class WebSocketOpenedRunnable final : public WebSocketBaseRunnable
124
{
125
public:
126
  WebSocketOpenedRunnable(uint32_t aWebSocketSerialID,
127
                           uint64_t aInnerWindowID,
128
                           const nsAString& aEffectiveURI,
129
                           const nsACString& aProtocols,
130
                           const nsACString& aExtensions)
131
    : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
132
    , mEffectiveURI(aEffectiveURI)
133
    , mProtocols(aProtocols)
134
    , mExtensions(aExtensions)
135
0
  {}
136
137
private:
138
  virtual void DoWork(nsIWebSocketEventListener* aListener) override
139
0
  {
140
0
    DebugOnly<nsresult> rv = aListener->WebSocketOpened(mWebSocketSerialID,
141
0
                                                        mEffectiveURI,
142
0
                                                        mProtocols,
143
0
                                                        mExtensions);
144
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketOpened failed");
145
0
  }
146
147
  const nsString mEffectiveURI;
148
  const nsCString mProtocols;
149
  const nsCString mExtensions;
150
};
151
152
class WebSocketMessageAvailableRunnable final : public WebSocketBaseRunnable
153
{
154
public:
155
  WebSocketMessageAvailableRunnable(uint32_t aWebSocketSerialID,
156
                          uint64_t aInnerWindowID,
157
                          const nsACString& aData,
158
                          uint16_t aMessageType)
159
    : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
160
    , mData(aData)
161
    , mMessageType(aMessageType)
162
0
  {}
163
164
private:
165
  virtual void DoWork(nsIWebSocketEventListener* aListener) override
166
0
  {
167
0
    DebugOnly<nsresult> rv =
168
0
      aListener->WebSocketMessageAvailable(mWebSocketSerialID, mData,
169
0
                                           mMessageType);
170
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketMessageAvailable failed");
171
0
  }
172
173
  const nsCString mData;
174
  uint16_t mMessageType;
175
};
176
177
class WebSocketClosedRunnable final : public WebSocketBaseRunnable
178
{
179
public:
180
  WebSocketClosedRunnable(uint32_t aWebSocketSerialID,
181
                          uint64_t aInnerWindowID,
182
                          bool aWasClean,
183
                          uint16_t aCode,
184
                          const nsAString& aReason)
185
    : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
186
    , mWasClean(aWasClean)
187
    , mCode(aCode)
188
    , mReason(aReason)
189
0
  {}
190
191
private:
192
  virtual void DoWork(nsIWebSocketEventListener* aListener) override
193
0
  {
194
0
    DebugOnly<nsresult> rv =
195
0
      aListener->WebSocketClosed(mWebSocketSerialID, mWasClean, mCode, mReason);
196
0
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketClosed failed");
197
0
  }
198
199
  bool mWasClean;
200
  uint16_t mCode;
201
  const nsString mReason;
202
};
203
204
/* static */ already_AddRefed<WebSocketEventService>
205
WebSocketEventService::Get()
206
0
{
207
0
  MOZ_ASSERT(NS_IsMainThread());
208
0
  RefPtr<WebSocketEventService> service = gWebSocketEventService.get();
209
0
  return service.forget();
210
0
}
211
212
/* static */ already_AddRefed<WebSocketEventService>
213
WebSocketEventService::GetOrCreate()
214
2
{
215
2
  MOZ_ASSERT(NS_IsMainThread());
216
2
217
2
  if (!gWebSocketEventService) {
218
1
    gWebSocketEventService = new WebSocketEventService();
219
1
  }
220
2
221
2
  RefPtr<WebSocketEventService> service = gWebSocketEventService.get();
222
2
  return service.forget();
223
2
}
224
225
0
NS_INTERFACE_MAP_BEGIN(WebSocketEventService)
226
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketEventService)
227
0
  NS_INTERFACE_MAP_ENTRY(nsIObserver)
228
0
  NS_INTERFACE_MAP_ENTRY(nsIWebSocketEventService)
229
0
NS_INTERFACE_MAP_END
230
231
NS_IMPL_ADDREF(WebSocketEventService)
232
NS_IMPL_RELEASE(WebSocketEventService)
233
234
WebSocketEventService::WebSocketEventService()
235
  : mCountListeners(0)
236
1
{
237
1
  MOZ_ASSERT(NS_IsMainThread());
238
1
239
1
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
240
1
  if (obs) {
241
1
    obs->AddObserver(this, "xpcom-shutdown", false);
242
1
    obs->AddObserver(this, "inner-window-destroyed", false);
243
1
  }
244
1
}
245
246
WebSocketEventService::~WebSocketEventService()
247
0
{
248
0
  MOZ_ASSERT(NS_IsMainThread());
249
0
}
250
251
void
252
WebSocketEventService::WebSocketCreated(uint32_t aWebSocketSerialID,
253
                                        uint64_t aInnerWindowID,
254
                                        const nsAString& aURI,
255
                                        const nsACString& aProtocols,
256
                                        nsIEventTarget* aTarget)
257
0
{
258
0
  // Let's continue only if we have some listeners.
259
0
  if (!HasListeners()) {
260
0
    return;
261
0
  }
262
0
263
0
  RefPtr<WebSocketCreatedRunnable> runnable =
264
0
    new WebSocketCreatedRunnable(aWebSocketSerialID, aInnerWindowID,
265
0
                                 aURI, aProtocols);
266
0
  DebugOnly<nsresult> rv = aTarget
267
0
    ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
268
0
    : NS_DispatchToMainThread(runnable);
269
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
270
0
}
271
272
void
273
WebSocketEventService::WebSocketOpened(uint32_t aWebSocketSerialID,
274
                                       uint64_t aInnerWindowID,
275
                                       const nsAString& aEffectiveURI,
276
                                       const nsACString& aProtocols,
277
                                       const nsACString& aExtensions,
278
                                       nsIEventTarget* aTarget)
279
0
{
280
0
  // Let's continue only if we have some listeners.
281
0
  if (!HasListeners()) {
282
0
    return;
283
0
  }
284
0
285
0
  RefPtr<WebSocketOpenedRunnable> runnable =
286
0
    new WebSocketOpenedRunnable(aWebSocketSerialID, aInnerWindowID,
287
0
                                aEffectiveURI, aProtocols, aExtensions);
288
0
  DebugOnly<nsresult> rv = aTarget
289
0
    ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
290
0
    : NS_DispatchToMainThread(runnable);
291
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
292
0
}
293
294
void
295
WebSocketEventService::WebSocketMessageAvailable(uint32_t aWebSocketSerialID,
296
                                                 uint64_t aInnerWindowID,
297
                                                 const nsACString& aData,
298
                                                 uint16_t aMessageType,
299
                                                 nsIEventTarget* aTarget)
300
0
{
301
0
  // Let's continue only if we have some listeners.
302
0
  if (!HasListeners()) {
303
0
    return;
304
0
  }
305
0
306
0
  RefPtr<WebSocketMessageAvailableRunnable> runnable =
307
0
    new WebSocketMessageAvailableRunnable(aWebSocketSerialID, aInnerWindowID,
308
0
                                          aData, aMessageType);
309
0
  DebugOnly<nsresult> rv = aTarget
310
0
    ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
311
0
    : NS_DispatchToMainThread(runnable);
312
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
313
0
}
314
315
void
316
WebSocketEventService::WebSocketClosed(uint32_t aWebSocketSerialID,
317
                                       uint64_t aInnerWindowID,
318
                                       bool aWasClean,
319
                                       uint16_t aCode,
320
                                       const nsAString& aReason,
321
                                       nsIEventTarget* aTarget)
322
0
{
323
0
  // Let's continue only if we have some listeners.
324
0
  if (!HasListeners()) {
325
0
    return;
326
0
  }
327
0
328
0
  RefPtr<WebSocketClosedRunnable> runnable =
329
0
    new WebSocketClosedRunnable(aWebSocketSerialID, aInnerWindowID,
330
0
                                aWasClean, aCode, aReason);
331
0
  DebugOnly<nsresult> rv = aTarget
332
0
    ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
333
0
    : NS_DispatchToMainThread(runnable);
334
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
335
0
}
336
337
void
338
WebSocketEventService::FrameReceived(uint32_t aWebSocketSerialID,
339
                                     uint64_t aInnerWindowID,
340
                                     already_AddRefed<WebSocketFrame> aFrame,
341
                                     nsIEventTarget* aTarget)
342
0
{
343
0
  RefPtr<WebSocketFrame> frame(std::move(aFrame));
344
0
  MOZ_ASSERT(frame);
345
0
346
0
  // Let's continue only if we have some listeners.
347
0
  if (!HasListeners()) {
348
0
    return;
349
0
  }
350
0
351
0
  RefPtr<WebSocketFrameRunnable> runnable =
352
0
    new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID,
353
0
                               frame.forget(), false /* frameSent */);
354
0
  DebugOnly<nsresult> rv = aTarget
355
0
    ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
356
0
    : NS_DispatchToMainThread(runnable);
357
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
358
0
}
359
360
void
361
WebSocketEventService::FrameSent(uint32_t aWebSocketSerialID,
362
                                 uint64_t aInnerWindowID,
363
                                 already_AddRefed<WebSocketFrame> aFrame,
364
                                 nsIEventTarget* aTarget)
365
0
{
366
0
  RefPtr<WebSocketFrame> frame(std::move(aFrame));
367
0
  MOZ_ASSERT(frame);
368
0
369
0
  // Let's continue only if we have some listeners.
370
0
  if (!HasListeners()) {
371
0
    return;
372
0
  }
373
0
374
0
  RefPtr<WebSocketFrameRunnable> runnable =
375
0
    new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID,
376
0
                               frame.forget(), true /* frameSent */);
377
0
378
0
  DebugOnly<nsresult> rv = aTarget
379
0
    ? aTarget->Dispatch(runnable, NS_DISPATCH_NORMAL)
380
0
    : NS_DispatchToMainThread(runnable);
381
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
382
0
}
383
384
NS_IMETHODIMP
385
WebSocketEventService::AddListener(uint64_t aInnerWindowID,
386
                                   nsIWebSocketEventListener* aListener)
387
0
{
388
0
  MOZ_ASSERT(NS_IsMainThread());
389
0
390
0
  if (!aListener) {
391
0
    return NS_ERROR_FAILURE;
392
0
  }
393
0
394
0
  ++mCountListeners;
395
0
396
0
  WindowListener* listener = mWindows.Get(aInnerWindowID);
397
0
  if (!listener) {
398
0
    listener = new WindowListener();
399
0
400
0
    if (IsChildProcess()) {
401
0
      PWebSocketEventListenerChild* actor =
402
0
        gNeckoChild->SendPWebSocketEventListenerConstructor(aInnerWindowID);
403
0
404
0
      listener->mActor = static_cast<WebSocketEventListenerChild*>(actor);
405
0
      MOZ_ASSERT(listener->mActor);
406
0
    }
407
0
408
0
    mWindows.Put(aInnerWindowID, listener);
409
0
  }
410
0
411
0
  listener->mListeners.AppendElement(aListener);
412
0
413
0
  return NS_OK;
414
0
}
415
416
NS_IMETHODIMP
417
WebSocketEventService::RemoveListener(uint64_t aInnerWindowID,
418
                                      nsIWebSocketEventListener* aListener)
419
0
{
420
0
  MOZ_ASSERT(NS_IsMainThread());
421
0
422
0
  if (!aListener) {
423
0
    return NS_ERROR_FAILURE;
424
0
  }
425
0
426
0
  WindowListener* listener = mWindows.Get(aInnerWindowID);
427
0
  if (!listener) {
428
0
    return NS_ERROR_FAILURE;
429
0
  }
430
0
431
0
  if (!listener->mListeners.RemoveElement(aListener)) {
432
0
    return NS_ERROR_FAILURE;
433
0
  }
434
0
435
0
  // The last listener for this window.
436
0
  if (listener->mListeners.IsEmpty()) {
437
0
    if (IsChildProcess()) {
438
0
      ShutdownActorListener(listener);
439
0
    }
440
0
441
0
    mWindows.Remove(aInnerWindowID);
442
0
  }
443
0
444
0
  MOZ_ASSERT(mCountListeners);
445
0
  --mCountListeners;
446
0
447
0
  return NS_OK;
448
0
}
449
450
NS_IMETHODIMP
451
WebSocketEventService::HasListenerFor(uint64_t aInnerWindowID,
452
                                      bool* aResult)
453
0
{
454
0
  MOZ_ASSERT(NS_IsMainThread());
455
0
456
0
  *aResult = mWindows.Get(aInnerWindowID);
457
0
458
0
  return NS_OK;
459
0
}
460
461
NS_IMETHODIMP
462
WebSocketEventService::Observe(nsISupports* aSubject, const char* aTopic,
463
                               const char16_t* aData)
464
0
{
465
0
  MOZ_ASSERT(NS_IsMainThread());
466
0
467
0
  if (!strcmp(aTopic, "xpcom-shutdown")) {
468
0
    Shutdown();
469
0
    return NS_OK;
470
0
  }
471
0
472
0
  if (!strcmp(aTopic, "inner-window-destroyed") && HasListeners()) {
473
0
    nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
474
0
    NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
475
0
476
0
    uint64_t innerID;
477
0
    nsresult rv = wrapper->GetData(&innerID);
478
0
    NS_ENSURE_SUCCESS(rv, rv);
479
0
480
0
    WindowListener* listener = mWindows.Get(innerID);
481
0
    if (!listener) {
482
0
      return NS_OK;
483
0
    }
484
0
485
0
    MOZ_ASSERT(mCountListeners >= listener->mListeners.Length());
486
0
    mCountListeners -= listener->mListeners.Length();
487
0
488
0
    if (IsChildProcess()) {
489
0
      ShutdownActorListener(listener);
490
0
    }
491
0
492
0
    mWindows.Remove(innerID);
493
0
  }
494
0
495
0
  // This should not happen.
496
0
  return NS_ERROR_FAILURE;
497
0
}
498
499
void
500
WebSocketEventService::Shutdown()
501
0
{
502
0
  MOZ_ASSERT(NS_IsMainThread());
503
0
504
0
  if (gWebSocketEventService) {
505
0
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
506
0
    if (obs) {
507
0
      obs->RemoveObserver(gWebSocketEventService, "xpcom-shutdown");
508
0
      obs->RemoveObserver(gWebSocketEventService, "inner-window-destroyed");
509
0
    }
510
0
511
0
    mWindows.Clear();
512
0
    gWebSocketEventService = nullptr;
513
0
  }
514
0
}
515
516
bool
517
WebSocketEventService::HasListeners() const
518
0
{
519
0
  return !!mCountListeners;
520
0
}
521
522
void
523
WebSocketEventService::GetListeners(uint64_t aInnerWindowID,
524
                                    WebSocketEventService::WindowListeners& aListeners) const
525
0
{
526
0
  aListeners.Clear();
527
0
528
0
  WindowListener* listener = mWindows.Get(aInnerWindowID);
529
0
  if (!listener) {
530
0
    return;
531
0
  }
532
0
533
0
  aListeners.AppendElements(listener->mListeners);
534
0
}
535
536
void
537
WebSocketEventService::ShutdownActorListener(WindowListener* aListener)
538
0
{
539
0
  MOZ_ASSERT(aListener);
540
0
  MOZ_ASSERT(aListener->mActor);
541
0
  aListener->mActor->Close();
542
0
  aListener->mActor = nullptr;
543
0
}
544
545
already_AddRefed<WebSocketFrame>
546
WebSocketEventService::CreateFrameIfNeeded(bool aFinBit, bool aRsvBit1,
547
                                           bool aRsvBit2, bool aRsvBit3,
548
                                           uint8_t aOpCode, bool aMaskBit,
549
                                           uint32_t aMask,
550
                                           const nsCString& aPayload)
551
0
{
552
0
  if (!HasListeners()) {
553
0
    return nullptr;
554
0
  }
555
0
556
0
  return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
557
0
                                       aOpCode, aMaskBit, aMask, aPayload);
558
0
}
559
560
already_AddRefed<WebSocketFrame>
561
WebSocketEventService::CreateFrameIfNeeded(bool aFinBit, bool aRsvBit1,
562
                                           bool aRsvBit2, bool aRsvBit3,
563
                                           uint8_t aOpCode, bool aMaskBit,
564
                                           uint32_t aMask, uint8_t* aPayload,
565
                                           uint32_t aPayloadLength)
566
0
{
567
0
  if (!HasListeners()) {
568
0
    return nullptr;
569
0
  }
570
0
571
0
  nsAutoCString payloadStr;
572
0
  if (NS_WARN_IF(!(payloadStr.Assign((const char*) aPayload, aPayloadLength,
573
0
                                     mozilla::fallible)))) {
574
0
    return nullptr;
575
0
  }
576
0
577
0
  return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
578
0
                                       aOpCode, aMaskBit, aMask, payloadStr);
579
0
}
580
581
already_AddRefed<WebSocketFrame>
582
WebSocketEventService::CreateFrameIfNeeded(bool aFinBit, bool aRsvBit1,
583
                                           bool aRsvBit2, bool aRsvBit3,
584
                                           uint8_t aOpCode, bool aMaskBit,
585
                                           uint32_t aMask,
586
                                           uint8_t* aPayloadInHdr,
587
                                           uint32_t aPayloadInHdrLength,
588
                                           uint8_t* aPayload,
589
                                           uint32_t aPayloadLength)
590
0
{
591
0
  if (!HasListeners()) {
592
0
    return nullptr;
593
0
  }
594
0
595
0
  uint32_t payloadLength = aPayloadLength + aPayloadInHdrLength;
596
0
597
0
  nsAutoCString payload;
598
0
  if (NS_WARN_IF(!payload.SetLength(payloadLength, fallible))) {
599
0
    return nullptr;
600
0
  }
601
0
602
0
  char* payloadPtr = payload.BeginWriting();
603
0
  if (aPayloadInHdrLength) {
604
0
    memcpy(payloadPtr, aPayloadInHdr, aPayloadInHdrLength);
605
0
  }
606
0
607
0
  memcpy(payloadPtr + aPayloadInHdrLength, aPayload, aPayloadLength);
608
0
609
0
  return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
610
0
                                       aOpCode, aMaskBit, aMask, payload);
611
0
}
612
613
} // net namespace
614
} // mozilla namespace