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