WebSocketEventService.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "WebSocketEventListenerChild.h"
  6. #include "WebSocketEventService.h"
  7. #include "WebSocketFrame.h"
  8. #include "mozilla/net/NeckoChild.h"
  9. #include "mozilla/StaticPtr.h"
  10. #include "nsISupportsPrimitives.h"
  11. #include "nsIObserverService.h"
  12. #include "nsXULAppAPI.h"
  13. #include "nsSocketTransportService2.h"
  14. #include "nsThreadUtils.h"
  15. #include "mozilla/Services.h"
  16. namespace mozilla {
  17. namespace net {
  18. namespace {
  19. StaticRefPtr<WebSocketEventService> gWebSocketEventService;
  20. bool
  21. IsChildProcess()
  22. {
  23. return XRE_GetProcessType() != GeckoProcessType_Default;
  24. }
  25. } // anonymous namespace
  26. class WebSocketBaseRunnable : public Runnable
  27. {
  28. public:
  29. WebSocketBaseRunnable(uint32_t aWebSocketSerialID,
  30. uint64_t aInnerWindowID)
  31. : mWebSocketSerialID(aWebSocketSerialID)
  32. , mInnerWindowID(aInnerWindowID)
  33. {}
  34. NS_IMETHOD Run() override
  35. {
  36. MOZ_ASSERT(NS_IsMainThread());
  37. RefPtr<WebSocketEventService> service = WebSocketEventService::GetOrCreate();
  38. MOZ_ASSERT(service);
  39. WebSocketEventService::WindowListeners listeners;
  40. service->GetListeners(mInnerWindowID, listeners);
  41. for (uint32_t i = 0; i < listeners.Length(); ++i) {
  42. DoWork(listeners[i]);
  43. }
  44. return NS_OK;
  45. }
  46. protected:
  47. ~WebSocketBaseRunnable()
  48. {}
  49. virtual void DoWork(nsIWebSocketEventListener* aListener) = 0;
  50. uint32_t mWebSocketSerialID;
  51. uint64_t mInnerWindowID;
  52. };
  53. class WebSocketFrameRunnable final : public WebSocketBaseRunnable
  54. {
  55. public:
  56. WebSocketFrameRunnable(uint32_t aWebSocketSerialID,
  57. uint64_t aInnerWindowID,
  58. already_AddRefed<WebSocketFrame> aFrame,
  59. bool aFrameSent)
  60. : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
  61. , mFrame(Move(aFrame))
  62. , mFrameSent(aFrameSent)
  63. {}
  64. private:
  65. virtual void DoWork(nsIWebSocketEventListener* aListener) override
  66. {
  67. DebugOnly<nsresult> rv;
  68. if (mFrameSent) {
  69. rv = aListener->FrameSent(mWebSocketSerialID, mFrame);
  70. } else {
  71. rv = aListener->FrameReceived(mWebSocketSerialID, mFrame);
  72. }
  73. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Frame op failed");
  74. }
  75. RefPtr<WebSocketFrame> mFrame;
  76. bool mFrameSent;
  77. };
  78. class WebSocketCreatedRunnable final : public WebSocketBaseRunnable
  79. {
  80. public:
  81. WebSocketCreatedRunnable(uint32_t aWebSocketSerialID,
  82. uint64_t aInnerWindowID,
  83. const nsAString& aURI,
  84. const nsACString& aProtocols)
  85. : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
  86. , mURI(aURI)
  87. , mProtocols(aProtocols)
  88. {}
  89. private:
  90. virtual void DoWork(nsIWebSocketEventListener* aListener) override
  91. {
  92. DebugOnly<nsresult> rv =
  93. aListener->WebSocketCreated(mWebSocketSerialID, mURI, mProtocols);
  94. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketCreated failed");
  95. }
  96. const nsString mURI;
  97. const nsCString mProtocols;
  98. };
  99. class WebSocketOpenedRunnable final : public WebSocketBaseRunnable
  100. {
  101. public:
  102. WebSocketOpenedRunnable(uint32_t aWebSocketSerialID,
  103. uint64_t aInnerWindowID,
  104. const nsAString& aEffectiveURI,
  105. const nsACString& aProtocols,
  106. const nsACString& aExtensions)
  107. : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
  108. , mEffectiveURI(aEffectiveURI)
  109. , mProtocols(aProtocols)
  110. , mExtensions(aExtensions)
  111. {}
  112. private:
  113. virtual void DoWork(nsIWebSocketEventListener* aListener) override
  114. {
  115. DebugOnly<nsresult> rv = aListener->WebSocketOpened(mWebSocketSerialID,
  116. mEffectiveURI,
  117. mProtocols,
  118. mExtensions);
  119. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketOpened failed");
  120. }
  121. const nsString mEffectiveURI;
  122. const nsCString mProtocols;
  123. const nsCString mExtensions;
  124. };
  125. class WebSocketMessageAvailableRunnable final : public WebSocketBaseRunnable
  126. {
  127. public:
  128. WebSocketMessageAvailableRunnable(uint32_t aWebSocketSerialID,
  129. uint64_t aInnerWindowID,
  130. const nsACString& aData,
  131. uint16_t aMessageType)
  132. : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
  133. , mData(aData)
  134. , mMessageType(aMessageType)
  135. {}
  136. private:
  137. virtual void DoWork(nsIWebSocketEventListener* aListener) override
  138. {
  139. DebugOnly<nsresult> rv =
  140. aListener->WebSocketMessageAvailable(mWebSocketSerialID, mData,
  141. mMessageType);
  142. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketMessageAvailable failed");
  143. }
  144. const nsCString mData;
  145. uint16_t mMessageType;
  146. };
  147. class WebSocketClosedRunnable final : public WebSocketBaseRunnable
  148. {
  149. public:
  150. WebSocketClosedRunnable(uint32_t aWebSocketSerialID,
  151. uint64_t aInnerWindowID,
  152. bool aWasClean,
  153. uint16_t aCode,
  154. const nsAString& aReason)
  155. : WebSocketBaseRunnable(aWebSocketSerialID, aInnerWindowID)
  156. , mWasClean(aWasClean)
  157. , mCode(aCode)
  158. , mReason(aReason)
  159. {}
  160. private:
  161. virtual void DoWork(nsIWebSocketEventListener* aListener) override
  162. {
  163. DebugOnly<nsresult> rv =
  164. aListener->WebSocketClosed(mWebSocketSerialID, mWasClean, mCode, mReason);
  165. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WebSocketClosed failed");
  166. }
  167. bool mWasClean;
  168. uint16_t mCode;
  169. const nsString mReason;
  170. };
  171. /* static */ already_AddRefed<WebSocketEventService>
  172. WebSocketEventService::GetOrCreate()
  173. {
  174. MOZ_ASSERT(NS_IsMainThread());
  175. if (!gWebSocketEventService) {
  176. gWebSocketEventService = new WebSocketEventService();
  177. }
  178. RefPtr<WebSocketEventService> service = gWebSocketEventService.get();
  179. return service.forget();
  180. }
  181. NS_INTERFACE_MAP_BEGIN(WebSocketEventService)
  182. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketEventService)
  183. NS_INTERFACE_MAP_ENTRY(nsIObserver)
  184. NS_INTERFACE_MAP_ENTRY(nsIWebSocketEventService)
  185. NS_INTERFACE_MAP_END
  186. NS_IMPL_ADDREF(WebSocketEventService)
  187. NS_IMPL_RELEASE(WebSocketEventService)
  188. WebSocketEventService::WebSocketEventService()
  189. : mCountListeners(0)
  190. {
  191. MOZ_ASSERT(NS_IsMainThread());
  192. nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
  193. if (obs) {
  194. obs->AddObserver(this, "xpcom-shutdown", false);
  195. obs->AddObserver(this, "inner-window-destroyed", false);
  196. }
  197. }
  198. WebSocketEventService::~WebSocketEventService()
  199. {
  200. MOZ_ASSERT(NS_IsMainThread());
  201. }
  202. void
  203. WebSocketEventService::WebSocketCreated(uint32_t aWebSocketSerialID,
  204. uint64_t aInnerWindowID,
  205. const nsAString& aURI,
  206. const nsACString& aProtocols)
  207. {
  208. // Let's continue only if we have some listeners.
  209. if (!HasListeners()) {
  210. return;
  211. }
  212. RefPtr<WebSocketCreatedRunnable> runnable =
  213. new WebSocketCreatedRunnable(aWebSocketSerialID, aInnerWindowID,
  214. aURI, aProtocols);
  215. DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
  216. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
  217. }
  218. void
  219. WebSocketEventService::WebSocketOpened(uint32_t aWebSocketSerialID,
  220. uint64_t aInnerWindowID,
  221. const nsAString& aEffectiveURI,
  222. const nsACString& aProtocols,
  223. const nsACString& aExtensions)
  224. {
  225. // Let's continue only if we have some listeners.
  226. if (!HasListeners()) {
  227. return;
  228. }
  229. RefPtr<WebSocketOpenedRunnable> runnable =
  230. new WebSocketOpenedRunnable(aWebSocketSerialID, aInnerWindowID,
  231. aEffectiveURI, aProtocols, aExtensions);
  232. DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
  233. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
  234. }
  235. void
  236. WebSocketEventService::WebSocketMessageAvailable(uint32_t aWebSocketSerialID,
  237. uint64_t aInnerWindowID,
  238. const nsACString& aData,
  239. uint16_t aMessageType)
  240. {
  241. // Let's continue only if we have some listeners.
  242. if (!HasListeners()) {
  243. return;
  244. }
  245. RefPtr<WebSocketMessageAvailableRunnable> runnable =
  246. new WebSocketMessageAvailableRunnable(aWebSocketSerialID, aInnerWindowID,
  247. aData, aMessageType);
  248. DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
  249. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
  250. }
  251. void
  252. WebSocketEventService::WebSocketClosed(uint32_t aWebSocketSerialID,
  253. uint64_t aInnerWindowID,
  254. bool aWasClean,
  255. uint16_t aCode,
  256. const nsAString& aReason)
  257. {
  258. // Let's continue only if we have some listeners.
  259. if (!HasListeners()) {
  260. return;
  261. }
  262. RefPtr<WebSocketClosedRunnable> runnable =
  263. new WebSocketClosedRunnable(aWebSocketSerialID, aInnerWindowID,
  264. aWasClean, aCode, aReason);
  265. DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
  266. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
  267. }
  268. void
  269. WebSocketEventService::FrameReceived(uint32_t aWebSocketSerialID,
  270. uint64_t aInnerWindowID,
  271. already_AddRefed<WebSocketFrame> aFrame)
  272. {
  273. RefPtr<WebSocketFrame> frame(Move(aFrame));
  274. MOZ_ASSERT(frame);
  275. // Let's continue only if we have some listeners.
  276. if (!HasListeners()) {
  277. return;
  278. }
  279. RefPtr<WebSocketFrameRunnable> runnable =
  280. new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID,
  281. frame.forget(), false /* frameSent */);
  282. DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
  283. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
  284. }
  285. void
  286. WebSocketEventService::FrameSent(uint32_t aWebSocketSerialID,
  287. uint64_t aInnerWindowID,
  288. already_AddRefed<WebSocketFrame> aFrame)
  289. {
  290. RefPtr<WebSocketFrame> frame(Move(aFrame));
  291. MOZ_ASSERT(frame);
  292. // Let's continue only if we have some listeners.
  293. if (!HasListeners()) {
  294. return;
  295. }
  296. RefPtr<WebSocketFrameRunnable> runnable =
  297. new WebSocketFrameRunnable(aWebSocketSerialID, aInnerWindowID,
  298. frame.forget(), true /* frameSent */);
  299. DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
  300. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
  301. }
  302. NS_IMETHODIMP
  303. WebSocketEventService::AddListener(uint64_t aInnerWindowID,
  304. nsIWebSocketEventListener* aListener)
  305. {
  306. MOZ_ASSERT(NS_IsMainThread());
  307. if (!aListener) {
  308. return NS_ERROR_FAILURE;
  309. }
  310. ++mCountListeners;
  311. WindowListener* listener = mWindows.Get(aInnerWindowID);
  312. if (!listener) {
  313. listener = new WindowListener();
  314. if (IsChildProcess()) {
  315. PWebSocketEventListenerChild* actor =
  316. gNeckoChild->SendPWebSocketEventListenerConstructor(aInnerWindowID);
  317. listener->mActor = static_cast<WebSocketEventListenerChild*>(actor);
  318. MOZ_ASSERT(listener->mActor);
  319. }
  320. mWindows.Put(aInnerWindowID, listener);
  321. }
  322. listener->mListeners.AppendElement(aListener);
  323. return NS_OK;
  324. }
  325. NS_IMETHODIMP
  326. WebSocketEventService::RemoveListener(uint64_t aInnerWindowID,
  327. nsIWebSocketEventListener* aListener)
  328. {
  329. MOZ_ASSERT(NS_IsMainThread());
  330. if (!aListener) {
  331. return NS_ERROR_FAILURE;
  332. }
  333. WindowListener* listener = mWindows.Get(aInnerWindowID);
  334. if (!listener) {
  335. return NS_ERROR_FAILURE;
  336. }
  337. if (!listener->mListeners.RemoveElement(aListener)) {
  338. return NS_ERROR_FAILURE;
  339. }
  340. // The last listener for this window.
  341. if (listener->mListeners.IsEmpty()) {
  342. if (IsChildProcess()) {
  343. ShutdownActorListener(listener);
  344. }
  345. mWindows.Remove(aInnerWindowID);
  346. }
  347. MOZ_ASSERT(mCountListeners);
  348. --mCountListeners;
  349. return NS_OK;
  350. }
  351. NS_IMETHODIMP
  352. WebSocketEventService::Observe(nsISupports* aSubject, const char* aTopic,
  353. const char16_t* aData)
  354. {
  355. MOZ_ASSERT(NS_IsMainThread());
  356. if (!strcmp(aTopic, "xpcom-shutdown")) {
  357. Shutdown();
  358. return NS_OK;
  359. }
  360. if (!strcmp(aTopic, "inner-window-destroyed") && HasListeners()) {
  361. nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
  362. NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
  363. uint64_t innerID;
  364. nsresult rv = wrapper->GetData(&innerID);
  365. NS_ENSURE_SUCCESS(rv, rv);
  366. WindowListener* listener = mWindows.Get(innerID);
  367. if (!listener) {
  368. return NS_OK;
  369. }
  370. MOZ_ASSERT(mCountListeners >= listener->mListeners.Length());
  371. mCountListeners -= listener->mListeners.Length();
  372. if (IsChildProcess()) {
  373. ShutdownActorListener(listener);
  374. }
  375. mWindows.Remove(innerID);
  376. }
  377. // This should not happen.
  378. return NS_ERROR_FAILURE;
  379. }
  380. void
  381. WebSocketEventService::Shutdown()
  382. {
  383. MOZ_ASSERT(NS_IsMainThread());
  384. if (gWebSocketEventService) {
  385. nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
  386. if (obs) {
  387. obs->RemoveObserver(gWebSocketEventService, "xpcom-shutdown");
  388. obs->RemoveObserver(gWebSocketEventService, "inner-window-destroyed");
  389. }
  390. mWindows.Clear();
  391. gWebSocketEventService = nullptr;
  392. }
  393. }
  394. bool
  395. WebSocketEventService::HasListeners() const
  396. {
  397. return !!mCountListeners;
  398. }
  399. void
  400. WebSocketEventService::GetListeners(uint64_t aInnerWindowID,
  401. WebSocketEventService::WindowListeners& aListeners) const
  402. {
  403. aListeners.Clear();
  404. WindowListener* listener = mWindows.Get(aInnerWindowID);
  405. if (!listener) {
  406. return;
  407. }
  408. aListeners.AppendElements(listener->mListeners);
  409. }
  410. void
  411. WebSocketEventService::ShutdownActorListener(WindowListener* aListener)
  412. {
  413. MOZ_ASSERT(aListener);
  414. MOZ_ASSERT(aListener->mActor);
  415. aListener->mActor->Close();
  416. aListener->mActor = nullptr;
  417. }
  418. already_AddRefed<WebSocketFrame>
  419. WebSocketEventService::CreateFrameIfNeeded(bool aFinBit, bool aRsvBit1,
  420. bool aRsvBit2, bool aRsvBit3,
  421. uint8_t aOpCode, bool aMaskBit,
  422. uint32_t aMask,
  423. const nsCString& aPayload)
  424. {
  425. if (!HasListeners()) {
  426. return nullptr;
  427. }
  428. return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
  429. aOpCode, aMaskBit, aMask, aPayload);
  430. }
  431. already_AddRefed<WebSocketFrame>
  432. WebSocketEventService::CreateFrameIfNeeded(bool aFinBit, bool aRsvBit1,
  433. bool aRsvBit2, bool aRsvBit3,
  434. uint8_t aOpCode, bool aMaskBit,
  435. uint32_t aMask, uint8_t* aPayload,
  436. uint32_t aPayloadLength)
  437. {
  438. if (!HasListeners()) {
  439. return nullptr;
  440. }
  441. nsAutoCString payloadStr;
  442. if (NS_WARN_IF(!(payloadStr.Assign((const char*) aPayload, aPayloadLength,
  443. mozilla::fallible)))) {
  444. return nullptr;
  445. }
  446. return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
  447. aOpCode, aMaskBit, aMask, payloadStr);
  448. }
  449. already_AddRefed<WebSocketFrame>
  450. WebSocketEventService::CreateFrameIfNeeded(bool aFinBit, bool aRsvBit1,
  451. bool aRsvBit2, bool aRsvBit3,
  452. uint8_t aOpCode, bool aMaskBit,
  453. uint32_t aMask,
  454. uint8_t* aPayloadInHdr,
  455. uint32_t aPayloadInHdrLength,
  456. uint8_t* aPayload,
  457. uint32_t aPayloadLength)
  458. {
  459. if (!HasListeners()) {
  460. return nullptr;
  461. }
  462. uint32_t payloadLength = aPayloadLength + aPayloadInHdrLength;
  463. nsAutoCString payload;
  464. if (NS_WARN_IF(!payload.SetLength(payloadLength, fallible))) {
  465. return nullptr;
  466. }
  467. char* payloadPtr = payload.BeginWriting();
  468. if (aPayloadInHdrLength) {
  469. memcpy(payloadPtr, aPayloadInHdr, aPayloadInHdrLength);
  470. }
  471. memcpy(payloadPtr + aPayloadInHdrLength, aPayload, aPayloadLength);
  472. return MakeAndAddRef<WebSocketFrame>(aFinBit, aRsvBit1, aRsvBit2, aRsvBit3,
  473. aOpCode, aMaskBit, aMask, payload);
  474. }
  475. } // net namespace
  476. } // mozilla namespace