Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/websocket/BaseWebSocketChannel.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 "BaseWebSocketChannel.h"
9
#include "MainThreadUtils.h"
10
#include "nsILoadGroup.h"
11
#include "nsINode.h"
12
#include "nsIInterfaceRequestor.h"
13
#include "nsAutoPtr.h"
14
#include "nsProxyRelease.h"
15
#include "nsStandardURL.h"
16
#include "LoadInfo.h"
17
#include "mozilla/dom/ContentChild.h"
18
#include "nsITransportProvider.h"
19
20
using mozilla::dom::ContentChild;
21
22
namespace mozilla {
23
namespace net {
24
25
LazyLogModule webSocketLog("nsWebSocket");
26
static uint64_t gNextWebSocketID = 0;
27
28
// We use only 53 bits for the WebSocket serial ID so that it can be converted
29
// to and from a JS value without loss of precision. The upper bits of the
30
// WebSocket serial ID hold the process ID. The lower bits identify the
31
// WebSocket.
32
static const uint64_t kWebSocketIDTotalBits = 53;
33
static const uint64_t kWebSocketIDProcessBits = 22;
34
static const uint64_t kWebSocketIDWebSocketBits = kWebSocketIDTotalBits - kWebSocketIDProcessBits;
35
36
BaseWebSocketChannel::BaseWebSocketChannel()
37
  : mWasOpened(0)
38
  , mClientSetPingInterval(0)
39
  , mClientSetPingTimeout(0)
40
  , mEncrypted(false)
41
  , mPingForced(false)
42
  , mIsServerSide(false)
43
  , mPingInterval(0)
44
  , mPingResponseTimeout(10000)
45
2
{
46
2
  // Generation of a unique serial ID.
47
2
  uint64_t processID = 0;
48
2
  if (XRE_IsContentProcess()) {
49
0
    ContentChild* cc = ContentChild::GetSingleton();
50
0
    processID = cc->GetID();
51
0
  }
52
2
53
2
  uint64_t processBits = processID & ((uint64_t(1) << kWebSocketIDProcessBits) - 1);
54
2
55
2
  // Make sure no actual webSocket ends up with mWebSocketID == 0 but less then
56
2
  // what the kWebSocketIDProcessBits allows.
57
2
  if (++gNextWebSocketID >= (uint64_t(1) << kWebSocketIDWebSocketBits)) {
58
0
    gNextWebSocketID = 1;
59
0
  }
60
2
61
2
  uint64_t webSocketBits = gNextWebSocketID & ((uint64_t(1) << kWebSocketIDWebSocketBits) - 1);
62
2
  mSerial = (processBits << kWebSocketIDWebSocketBits) | webSocketBits;
63
2
}
64
65
//-----------------------------------------------------------------------------
66
// BaseWebSocketChannel::nsIWebSocketChannel
67
//-----------------------------------------------------------------------------
68
69
NS_IMETHODIMP
70
BaseWebSocketChannel::GetOriginalURI(nsIURI **aOriginalURI)
71
0
{
72
0
  LOG(("BaseWebSocketChannel::GetOriginalURI() %p\n", this));
73
0
74
0
  if (!mOriginalURI)
75
0
    return NS_ERROR_NOT_INITIALIZED;
76
0
  NS_ADDREF(*aOriginalURI = mOriginalURI);
77
0
  return NS_OK;
78
0
}
79
80
NS_IMETHODIMP
81
BaseWebSocketChannel::GetURI(nsIURI **aURI)
82
0
{
83
0
  LOG(("BaseWebSocketChannel::GetURI() %p\n", this));
84
0
85
0
  if (!mOriginalURI)
86
0
    return NS_ERROR_NOT_INITIALIZED;
87
0
  if (mURI)
88
0
    NS_ADDREF(*aURI = mURI);
89
0
  else
90
0
    NS_ADDREF(*aURI = mOriginalURI);
91
0
  return NS_OK;
92
0
}
93
94
NS_IMETHODIMP
95
BaseWebSocketChannel::
96
GetNotificationCallbacks(nsIInterfaceRequestor **aNotificationCallbacks)
97
0
{
98
0
  LOG(("BaseWebSocketChannel::GetNotificationCallbacks() %p\n", this));
99
0
  NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks);
100
0
  return NS_OK;
101
0
}
102
103
NS_IMETHODIMP
104
BaseWebSocketChannel::
105
SetNotificationCallbacks(nsIInterfaceRequestor *aNotificationCallbacks)
106
0
{
107
0
  LOG(("BaseWebSocketChannel::SetNotificationCallbacks() %p\n", this));
108
0
  mCallbacks = aNotificationCallbacks;
109
0
  return NS_OK;
110
0
}
111
112
NS_IMETHODIMP
113
BaseWebSocketChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
114
0
{
115
0
  LOG(("BaseWebSocketChannel::GetLoadGroup() %p\n", this));
116
0
  NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
117
0
  return NS_OK;
118
0
}
119
120
NS_IMETHODIMP
121
BaseWebSocketChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
122
0
{
123
0
  LOG(("BaseWebSocketChannel::SetLoadGroup() %p\n", this));
124
0
  mLoadGroup = aLoadGroup;
125
0
  return NS_OK;
126
0
}
127
128
NS_IMETHODIMP
129
BaseWebSocketChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
130
0
{
131
0
  mLoadInfo = aLoadInfo;
132
0
  return NS_OK;
133
0
}
134
135
NS_IMETHODIMP
136
BaseWebSocketChannel::GetLoadInfo(nsILoadInfo** aLoadInfo)
137
0
{
138
0
  NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
139
0
  return NS_OK;
140
0
}
141
142
NS_IMETHODIMP
143
BaseWebSocketChannel::GetExtensions(nsACString &aExtensions)
144
0
{
145
0
  LOG(("BaseWebSocketChannel::GetExtensions() %p\n", this));
146
0
  aExtensions = mNegotiatedExtensions;
147
0
  return NS_OK;
148
0
}
149
150
NS_IMETHODIMP
151
BaseWebSocketChannel::GetProtocol(nsACString &aProtocol)
152
0
{
153
0
  LOG(("BaseWebSocketChannel::GetProtocol() %p\n", this));
154
0
  aProtocol = mProtocol;
155
0
  return NS_OK;
156
0
}
157
158
NS_IMETHODIMP
159
BaseWebSocketChannel::SetProtocol(const nsACString &aProtocol)
160
0
{
161
0
  LOG(("BaseWebSocketChannel::SetProtocol() %p\n", this));
162
0
  mProtocol = aProtocol;                        /* the sub protocol */
163
0
  return NS_OK;
164
0
}
165
166
NS_IMETHODIMP
167
BaseWebSocketChannel::GetPingInterval(uint32_t *aSeconds)
168
0
{
169
0
  // stored in ms but should only have second resolution
170
0
  MOZ_ASSERT(!(mPingInterval % 1000));
171
0
172
0
  *aSeconds = mPingInterval / 1000;
173
0
  return NS_OK;
174
0
}
175
176
NS_IMETHODIMP
177
BaseWebSocketChannel::SetPingInterval(uint32_t aSeconds)
178
0
{
179
0
  MOZ_ASSERT(NS_IsMainThread());
180
0
181
0
  if (mWasOpened) {
182
0
    return NS_ERROR_IN_PROGRESS;
183
0
  }
184
0
185
0
  mPingInterval = aSeconds * 1000;
186
0
  mClientSetPingInterval = 1;
187
0
188
0
  return NS_OK;
189
0
}
190
191
NS_IMETHODIMP
192
BaseWebSocketChannel::GetPingTimeout(uint32_t *aSeconds)
193
0
{
194
0
  // stored in ms but should only have second resolution
195
0
  MOZ_ASSERT(!(mPingResponseTimeout % 1000));
196
0
197
0
  *aSeconds = mPingResponseTimeout / 1000;
198
0
  return NS_OK;
199
0
}
200
201
NS_IMETHODIMP
202
BaseWebSocketChannel::SetPingTimeout(uint32_t aSeconds)
203
0
{
204
0
  MOZ_ASSERT(NS_IsMainThread());
205
0
206
0
  if (mWasOpened) {
207
0
    return NS_ERROR_IN_PROGRESS;
208
0
  }
209
0
210
0
  mPingResponseTimeout = aSeconds * 1000;
211
0
  mClientSetPingTimeout = 1;
212
0
213
0
  return NS_OK;
214
0
}
215
216
NS_IMETHODIMP
217
BaseWebSocketChannel::InitLoadInfo(nsINode* aLoadingNode,
218
                                   nsIPrincipal* aLoadingPrincipal,
219
                                   nsIPrincipal* aTriggeringPrincipal,
220
                                   uint32_t aSecurityFlags,
221
                                   uint32_t aContentPolicyType)
222
0
{
223
0
  mLoadInfo = new LoadInfo(aLoadingPrincipal, aTriggeringPrincipal,
224
0
                           aLoadingNode, aSecurityFlags, aContentPolicyType);
225
0
  return NS_OK;
226
0
}
227
228
NS_IMETHODIMP
229
BaseWebSocketChannel::GetSerial(uint32_t* aSerial)
230
0
{
231
0
  if (!aSerial) {
232
0
    return NS_ERROR_FAILURE;
233
0
  }
234
0
235
0
  *aSerial = mSerial;
236
0
  return NS_OK;
237
0
}
238
239
NS_IMETHODIMP
240
BaseWebSocketChannel::SetSerial(uint32_t aSerial)
241
0
{
242
0
  mSerial = aSerial;
243
0
  return NS_OK;
244
0
}
245
246
NS_IMETHODIMP
247
BaseWebSocketChannel::SetServerParameters(nsITransportProvider* aProvider,
248
                                          const nsACString& aNegotiatedExtensions)
249
0
{
250
0
  MOZ_ASSERT(aProvider);
251
0
  mServerTransportProvider = aProvider;
252
0
  mNegotiatedExtensions = aNegotiatedExtensions;
253
0
  mIsServerSide = true;
254
0
  return NS_OK;
255
0
}
256
257
//-----------------------------------------------------------------------------
258
// BaseWebSocketChannel::nsIProtocolHandler
259
//-----------------------------------------------------------------------------
260
261
262
NS_IMETHODIMP
263
BaseWebSocketChannel::GetScheme(nsACString &aScheme)
264
0
{
265
0
  LOG(("BaseWebSocketChannel::GetScheme() %p\n", this));
266
0
267
0
  if (mEncrypted)
268
0
    aScheme.AssignLiteral("wss");
269
0
  else
270
0
    aScheme.AssignLiteral("ws");
271
0
  return NS_OK;
272
0
}
273
274
NS_IMETHODIMP
275
BaseWebSocketChannel::GetDefaultPort(int32_t *aDefaultPort)
276
20.7k
{
277
20.7k
  LOG(("BaseWebSocketChannel::GetDefaultPort() %p\n", this));
278
20.7k
279
20.7k
  if (mEncrypted)
280
393
    *aDefaultPort = kDefaultWSSPort;
281
20.3k
  else
282
20.3k
    *aDefaultPort = kDefaultWSPort;
283
20.7k
  return NS_OK;
284
20.7k
}
285
286
NS_IMETHODIMP
287
BaseWebSocketChannel::GetProtocolFlags(uint32_t *aProtocolFlags)
288
0
{
289
0
  LOG(("BaseWebSocketChannel::GetProtocolFlags() %p\n", this));
290
0
291
0
  *aProtocolFlags = URI_NORELATIVE | URI_NON_PERSISTABLE | ALLOWS_PROXY |
292
0
      ALLOWS_PROXY_HTTP | URI_DOES_NOT_RETURN_DATA | URI_DANGEROUS_TO_LOAD;
293
0
  if (mEncrypted) {
294
0
    *aProtocolFlags |= URI_IS_POTENTIALLY_TRUSTWORTHY;
295
0
  }
296
0
  return NS_OK;
297
0
}
298
299
NS_IMETHODIMP
300
BaseWebSocketChannel::NewURI(const nsACString & aSpec, const char *aOriginCharset,
301
                             nsIURI *aBaseURI, nsIURI **_retval)
302
20.7k
{
303
20.7k
  LOG(("BaseWebSocketChannel::NewURI() %p\n", this));
304
20.7k
305
20.7k
  int32_t port;
306
20.7k
  nsresult rv = GetDefaultPort(&port);
307
20.7k
  if (NS_FAILED(rv))
308
20.7k
    return rv;
309
20.7k
310
20.7k
  nsCOMPtr<nsIURI> base(aBaseURI);
311
20.7k
  return NS_MutateURI(new nsStandardURL::Mutator())
312
20.7k
    .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
313
20.7k
                            nsIStandardURL::URLTYPE_AUTHORITY,
314
20.7k
                            port, nsCString(aSpec), aOriginCharset,
315
20.7k
                            base, nullptr))
316
20.7k
    .Finalize(_retval);
317
20.7k
}
318
319
NS_IMETHODIMP
320
BaseWebSocketChannel::NewChannel2(nsIURI* aURI,
321
                                  nsILoadInfo* aLoadInfo,
322
                                  nsIChannel** outChannel)
323
0
{
324
0
  LOG(("BaseWebSocketChannel::NewChannel2() %p\n", this));
325
0
  return NS_ERROR_NOT_IMPLEMENTED;
326
0
}
327
328
NS_IMETHODIMP
329
BaseWebSocketChannel::NewChannel(nsIURI *aURI, nsIChannel **_retval)
330
0
{
331
0
  LOG(("BaseWebSocketChannel::NewChannel() %p\n", this));
332
0
  return NS_ERROR_NOT_IMPLEMENTED;
333
0
}
334
335
NS_IMETHODIMP
336
BaseWebSocketChannel::AllowPort(int32_t port, const char *scheme,
337
                                bool *_retval)
338
0
{
339
0
  LOG(("BaseWebSocketChannel::AllowPort() %p\n", this));
340
0
341
0
  // do not override any blacklisted ports
342
0
  *_retval = false;
343
0
  return NS_OK;
344
0
}
345
346
//-----------------------------------------------------------------------------
347
// BaseWebSocketChannel::nsIThreadRetargetableRequest
348
//-----------------------------------------------------------------------------
349
350
NS_IMETHODIMP
351
BaseWebSocketChannel::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
352
0
{
353
0
  MOZ_ASSERT(NS_IsMainThread());
354
0
  MOZ_ASSERT(aTargetThread);
355
0
  MOZ_ASSERT(!mTargetThread, "Delivery target should be set once, before AsyncOpen");
356
0
  MOZ_ASSERT(!mWasOpened, "Should not be called after AsyncOpen!");
357
0
358
0
  mTargetThread = do_QueryInterface(aTargetThread);
359
0
  MOZ_ASSERT(mTargetThread);
360
0
  return NS_OK;
361
0
}
362
363
NS_IMETHODIMP
364
BaseWebSocketChannel::GetDeliveryTarget(nsIEventTarget** aTargetThread)
365
0
{
366
0
  MOZ_ASSERT(NS_IsMainThread());
367
0
368
0
  nsCOMPtr<nsIEventTarget> target = mTargetThread;
369
0
  if (!target) {
370
0
    target = GetCurrentThreadEventTarget();
371
0
  }
372
0
  target.forget(aTargetThread);
373
0
  return NS_OK;
374
0
}
375
376
BaseWebSocketChannel::ListenerAndContextContainer::ListenerAndContextContainer(
377
                                               nsIWebSocketListener* aListener,
378
                                               nsISupports* aContext)
379
  : mListener(aListener)
380
  , mContext(aContext)
381
0
{
382
0
  MOZ_ASSERT(NS_IsMainThread());
383
0
  MOZ_ASSERT(mListener);
384
0
}
385
386
BaseWebSocketChannel::ListenerAndContextContainer::~ListenerAndContextContainer()
387
0
{
388
0
  MOZ_ASSERT(mListener);
389
0
390
0
  NS_ReleaseOnMainThreadSystemGroup(
391
0
    "BaseWebSocketChannel::ListenerAndContextContainer::mListener",
392
0
    mListener.forget());
393
0
  NS_ReleaseOnMainThreadSystemGroup(
394
0
    "BaseWebSocketChannel::ListenerAndContextContainer::mContext",
395
0
    mContext.forget());
396
0
}
397
398
} // namespace net
399
} // namespace mozilla