Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/websocket/WebSocketChannelParent.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 "WebSocketChannelParent.h"
9
#include "nsIAuthPromptProvider.h"
10
#include "mozilla/ipc/InputStreamUtils.h"
11
#include "mozilla/ipc/URIUtils.h"
12
#include "mozilla/ipc/BackgroundUtils.h"
13
#include "SerializedLoadContext.h"
14
#include "mozilla/net/NeckoCommon.h"
15
#include "mozilla/net/WebSocketChannel.h"
16
17
using namespace mozilla::ipc;
18
19
namespace mozilla {
20
namespace net {
21
22
NS_IMPL_ISUPPORTS(WebSocketChannelParent,
23
                  nsIWebSocketListener,
24
                  nsIInterfaceRequestor)
25
26
WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider,
27
                                               nsILoadContext* aLoadContext,
28
                                               PBOverrideStatus aOverrideStatus,
29
                                               uint32_t aSerial)
30
  : mAuthProvider(aAuthProvider)
31
  , mLoadContext(aLoadContext)
32
  , mIPCOpen(true)
33
  , mSerial(aSerial)
34
0
{
35
0
  // Websocket channels can't have a private browsing override
36
0
  MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset);
37
0
}
38
//-----------------------------------------------------------------------------
39
// WebSocketChannelParent::PWebSocketChannelParent
40
//-----------------------------------------------------------------------------
41
42
mozilla::ipc::IPCResult
43
WebSocketChannelParent::RecvDeleteSelf()
44
0
{
45
0
  LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this));
46
0
  mChannel = nullptr;
47
0
  mAuthProvider = nullptr;
48
0
  IProtocol* mgr = Manager();
49
0
  if (mIPCOpen && !Send__delete__(this)) {
50
0
    return IPC_FAIL_NO_REASON(mgr);
51
0
  }
52
0
  return IPC_OK();
53
0
}
54
55
mozilla::ipc::IPCResult
56
WebSocketChannelParent::RecvAsyncOpen(const OptionalURIParams& aURI,
57
                                      const nsCString& aOrigin,
58
                                      const uint64_t& aInnerWindowID,
59
                                      const nsCString& aProtocol,
60
                                      const bool& aSecure,
61
                                      const uint32_t& aPingInterval,
62
                                      const bool& aClientSetPingInterval,
63
                                      const uint32_t& aPingTimeout,
64
                                      const bool& aClientSetPingTimeout,
65
                                      const OptionalLoadInfoArgs& aLoadInfoArgs,
66
                                      const OptionalTransportProvider& aTransportProvider,
67
                                      const nsCString& aNegotiatedExtensions)
68
0
{
69
0
  LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this));
70
0
71
0
  nsresult rv;
72
0
  nsCOMPtr<nsIURI> uri;
73
0
  nsCOMPtr<nsILoadInfo> loadInfo;
74
0
75
0
  rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(loadInfo));
76
0
  if (NS_FAILED(rv)) {
77
0
    goto fail;
78
0
  }
79
0
80
0
  if (aSecure) {
81
0
    mChannel =
82
0
      do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
83
0
  } else {
84
0
    mChannel =
85
0
      do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
86
0
  }
87
0
  if (NS_FAILED(rv))
88
0
    goto fail;
89
0
90
0
  rv = mChannel->SetSerial(mSerial);
91
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
92
0
    goto fail;
93
0
  }
94
0
95
0
  rv = mChannel->SetLoadInfo(loadInfo);
96
0
  if (NS_FAILED(rv)) {
97
0
    goto fail;
98
0
  }
99
0
100
0
  rv = mChannel->SetNotificationCallbacks(this);
101
0
  if (NS_FAILED(rv))
102
0
    goto fail;
103
0
104
0
  rv = mChannel->SetProtocol(aProtocol);
105
0
  if (NS_FAILED(rv))
106
0
    goto fail;
107
0
108
0
  if (aTransportProvider.type() != OptionalTransportProvider::Tvoid_t) {
109
0
    RefPtr<TransportProviderParent> provider =
110
0
      static_cast<TransportProviderParent*>(
111
0
        aTransportProvider.get_PTransportProviderParent());
112
0
    rv = mChannel->SetServerParameters(provider, aNegotiatedExtensions);
113
0
    if (NS_FAILED(rv)) {
114
0
      goto fail;
115
0
    }
116
0
  } else {
117
0
    uri = DeserializeURI(aURI);
118
0
    if (!uri) {
119
0
      rv = NS_ERROR_FAILURE;
120
0
      goto fail;
121
0
    }
122
0
  }
123
0
124
0
  // only use ping values from child if they were overridden by client code.
125
0
  if (aClientSetPingInterval) {
126
0
    // IDL allows setting in seconds, so must be multiple of 1000 ms
127
0
    MOZ_ASSERT(aPingInterval >= 1000 && !(aPingInterval % 1000));
128
0
    DebugOnly<nsresult> rv = mChannel->SetPingInterval(aPingInterval / 1000);
129
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
130
0
  }
131
0
  if (aClientSetPingTimeout) {
132
0
    MOZ_ASSERT(aPingTimeout >= 1000 && !(aPingTimeout % 1000));
133
0
    DebugOnly<nsresult> rv = mChannel->SetPingTimeout(aPingTimeout / 1000);
134
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
135
0
  }
136
0
137
0
  rv = mChannel->AsyncOpen(uri, aOrigin, aInnerWindowID, this, nullptr);
138
0
  if (NS_FAILED(rv))
139
0
    goto fail;
140
0
141
0
  return IPC_OK();
142
0
143
0
fail:
144
0
  mChannel = nullptr;
145
0
  if (!SendOnStop(rv)) {
146
0
    return IPC_FAIL_NO_REASON(this);
147
0
  }
148
0
  return IPC_OK();
149
0
}
150
151
mozilla::ipc::IPCResult
152
WebSocketChannelParent::RecvClose(const uint16_t& code, const nsCString& reason)
153
0
{
154
0
  LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
155
0
  if (mChannel) {
156
0
    nsresult rv = mChannel->Close(code, reason);
157
0
    NS_ENSURE_SUCCESS(rv, IPC_OK());
158
0
  }
159
0
160
0
  return IPC_OK();
161
0
}
162
163
mozilla::ipc::IPCResult
164
WebSocketChannelParent::RecvSendMsg(const nsCString& aMsg)
165
0
{
166
0
  LOG(("WebSocketChannelParent::RecvSendMsg() %p\n", this));
167
0
  if (mChannel) {
168
0
    nsresult rv = mChannel->SendMsg(aMsg);
169
0
    NS_ENSURE_SUCCESS(rv, IPC_OK());
170
0
  }
171
0
  return IPC_OK();
172
0
}
173
174
mozilla::ipc::IPCResult
175
WebSocketChannelParent::RecvSendBinaryMsg(const nsCString& aMsg)
176
0
{
177
0
  LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this));
178
0
  if (mChannel) {
179
0
    nsresult rv = mChannel->SendBinaryMsg(aMsg);
180
0
    NS_ENSURE_SUCCESS(rv, IPC_OK());
181
0
  }
182
0
  return IPC_OK();
183
0
}
184
185
mozilla::ipc::IPCResult
186
WebSocketChannelParent::RecvSendBinaryStream(const IPCStream& aStream,
187
                                             const uint32_t& aLength)
188
0
{
189
0
  LOG(("WebSocketChannelParent::RecvSendBinaryStream() %p\n", this));
190
0
  if (mChannel) {
191
0
    nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStream);
192
0
    if (!stream) {
193
0
      return IPC_FAIL_NO_REASON(this);
194
0
    }
195
0
    nsresult rv = mChannel->SendBinaryStream(stream, aLength);
196
0
    NS_ENSURE_SUCCESS(rv, IPC_OK());
197
0
  }
198
0
  return IPC_OK();
199
0
}
200
201
//-----------------------------------------------------------------------------
202
// WebSocketChannelParent::nsIRequestObserver
203
//-----------------------------------------------------------------------------
204
205
NS_IMETHODIMP
206
WebSocketChannelParent::OnStart(nsISupports *aContext)
207
0
{
208
0
  LOG(("WebSocketChannelParent::OnStart() %p\n", this));
209
0
  nsAutoCString protocol, extensions;
210
0
  nsString effectiveURL;
211
0
  bool encrypted = false;
212
0
  if (mChannel) {
213
0
    DebugOnly<nsresult> rv = mChannel->GetProtocol(protocol);
214
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
215
0
    rv = mChannel->GetExtensions(extensions);
216
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
217
0
218
0
    RefPtr<WebSocketChannel> channel;
219
0
    channel = static_cast<WebSocketChannel*>(mChannel.get());
220
0
    MOZ_ASSERT(channel);
221
0
222
0
    channel->GetEffectiveURL(effectiveURL);
223
0
    encrypted = channel->IsEncrypted();
224
0
  }
225
0
  if (!mIPCOpen || !SendOnStart(protocol, extensions, effectiveURL, encrypted)) {
226
0
    return NS_ERROR_FAILURE;
227
0
  }
228
0
  return NS_OK;
229
0
}
230
231
NS_IMETHODIMP
232
WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode)
233
0
{
234
0
  LOG(("WebSocketChannelParent::OnStop() %p\n", this));
235
0
  if (!mIPCOpen || !SendOnStop(aStatusCode)) {
236
0
    return NS_ERROR_FAILURE;
237
0
  }
238
0
  return NS_OK;
239
0
}
240
241
NS_IMETHODIMP
242
WebSocketChannelParent::OnMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
243
0
{
244
0
  LOG(("WebSocketChannelParent::OnMessageAvailable() %p\n", this));
245
0
  if (!mIPCOpen || !SendOnMessageAvailable(nsCString(aMsg))) {
246
0
    return NS_ERROR_FAILURE;
247
0
  }
248
0
  return NS_OK;
249
0
}
250
251
NS_IMETHODIMP
252
WebSocketChannelParent::OnBinaryMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
253
0
{
254
0
  LOG(("WebSocketChannelParent::OnBinaryMessageAvailable() %p\n", this));
255
0
  if (!mIPCOpen || !SendOnBinaryMessageAvailable(nsCString(aMsg))) {
256
0
    return NS_ERROR_FAILURE;
257
0
  }
258
0
  return NS_OK;
259
0
}
260
261
NS_IMETHODIMP
262
WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
263
0
{
264
0
  LOG(("WebSocketChannelParent::OnAcknowledge() %p\n", this));
265
0
  if (!mIPCOpen || !SendOnAcknowledge(aSize)) {
266
0
    return NS_ERROR_FAILURE;
267
0
  }
268
0
  return NS_OK;
269
0
}
270
271
NS_IMETHODIMP
272
WebSocketChannelParent::OnServerClose(nsISupports *aContext,
273
                                      uint16_t code, const nsACString & reason)
274
0
{
275
0
  LOG(("WebSocketChannelParent::OnServerClose() %p\n", this));
276
0
  if (!mIPCOpen || !SendOnServerClose(code, nsCString(reason))) {
277
0
    return NS_ERROR_FAILURE;
278
0
  }
279
0
  return NS_OK;
280
0
}
281
282
void
283
WebSocketChannelParent::ActorDestroy(ActorDestroyReason why)
284
0
{
285
0
  LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this));
286
0
287
0
  // Make sure we close the channel if the content process dies without going
288
0
  // through a clean shutdown.
289
0
  if (mChannel) {
290
0
    Unused << mChannel->Close(nsIWebSocketChannel::CLOSE_GOING_AWAY,
291
0
                              NS_LITERAL_CSTRING("Child was killed"));
292
0
  }
293
0
294
0
  mIPCOpen = false;
295
0
}
296
297
//-----------------------------------------------------------------------------
298
// WebSocketChannelParent::nsIInterfaceRequestor
299
//-----------------------------------------------------------------------------
300
301
NS_IMETHODIMP
302
WebSocketChannelParent::GetInterface(const nsIID & iid, void **result)
303
0
{
304
0
  LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
305
0
  if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
306
0
    return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
307
0
                                        iid, result);
308
0
309
0
  // Only support nsILoadContext if child channel's callbacks did too
310
0
  if (iid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
311
0
    nsCOMPtr<nsILoadContext> copy = mLoadContext;
312
0
    copy.forget(result);
313
0
    return NS_OK;
314
0
  }
315
0
316
0
  return QueryInterface(iid, result);
317
0
}
318
319
} // namespace net
320
} // namespace mozilla