/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 |