TCPSocket.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  1. /* -*- Mode: C++; tab-width: 2; 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 file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/ErrorResult.h"
  6. #include "TCPSocket.h"
  7. #include "TCPServerSocket.h"
  8. #include "TCPSocketParent.h"
  9. #include "TCPSocketChild.h"
  10. #include "mozilla/Unused.h"
  11. #include "mozilla/dom/DOMError.h"
  12. #include "mozilla/dom/TCPSocketBinding.h"
  13. #include "mozilla/dom/TCPSocketErrorEvent.h"
  14. #include "mozilla/dom/TCPSocketErrorEventBinding.h"
  15. #include "mozilla/dom/TCPSocketEvent.h"
  16. #include "mozilla/dom/TCPSocketEventBinding.h"
  17. #include "mozilla/dom/ToJSValue.h"
  18. #include "nsContentUtils.h"
  19. #include "nsIArrayBufferInputStream.h"
  20. #include "nsISocketTransportService.h"
  21. #include "nsISocketTransport.h"
  22. #include "nsIMultiplexInputStream.h"
  23. #include "nsIAsyncStreamCopier.h"
  24. #include "nsIInputStream.h"
  25. #include "nsIBinaryInputStream.h"
  26. #include "nsIScriptableInputStream.h"
  27. #include "nsIInputStreamPump.h"
  28. #include "nsIAsyncInputStream.h"
  29. #include "nsISupportsPrimitives.h"
  30. #include "nsITransport.h"
  31. #include "nsIOutputStream.h"
  32. #include "nsINSSErrorsService.h"
  33. #include "nsISSLSocketControl.h"
  34. #include "nsStringStream.h"
  35. #include "secerr.h"
  36. #include "sslerr.h"
  37. #define BUFFER_SIZE 65536
  38. #define NETWORK_STATS_THRESHOLD 65536
  39. using namespace mozilla::dom;
  40. NS_IMPL_CYCLE_COLLECTION(LegacyMozTCPSocket, mGlobal)
  41. NS_IMPL_CYCLE_COLLECTING_ADDREF(LegacyMozTCPSocket)
  42. NS_IMPL_CYCLE_COLLECTING_RELEASE(LegacyMozTCPSocket)
  43. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LegacyMozTCPSocket)
  44. NS_INTERFACE_MAP_ENTRY(nsISupports)
  45. NS_INTERFACE_MAP_END
  46. LegacyMozTCPSocket::LegacyMozTCPSocket(nsPIDOMWindowInner* aWindow)
  47. : mGlobal(do_QueryInterface(aWindow))
  48. {
  49. }
  50. LegacyMozTCPSocket::~LegacyMozTCPSocket()
  51. {
  52. }
  53. already_AddRefed<TCPSocket>
  54. LegacyMozTCPSocket::Open(const nsAString& aHost,
  55. uint16_t aPort,
  56. const SocketOptions& aOptions,
  57. mozilla::ErrorResult& aRv)
  58. {
  59. AutoJSAPI api;
  60. if (NS_WARN_IF(!api.Init(mGlobal))) {
  61. aRv.Throw(NS_ERROR_FAILURE);
  62. return nullptr;
  63. }
  64. GlobalObject globalObj(api.cx(), mGlobal->GetGlobalJSObject());
  65. return TCPSocket::Constructor(globalObj, aHost, aPort, aOptions, aRv);
  66. }
  67. already_AddRefed<TCPServerSocket>
  68. LegacyMozTCPSocket::Listen(uint16_t aPort,
  69. const ServerSocketOptions& aOptions,
  70. uint16_t aBacklog,
  71. mozilla::ErrorResult& aRv)
  72. {
  73. AutoJSAPI api;
  74. if (NS_WARN_IF(!api.Init(mGlobal))) {
  75. return nullptr;
  76. }
  77. GlobalObject globalObj(api.cx(), mGlobal->GetGlobalJSObject());
  78. return TCPServerSocket::Constructor(globalObj, aPort, aOptions, aBacklog, aRv);
  79. }
  80. bool
  81. LegacyMozTCPSocket::WrapObject(JSContext* aCx,
  82. JS::Handle<JSObject*> aGivenProto,
  83. JS::MutableHandle<JSObject*> aReflector)
  84. {
  85. return LegacyMozTCPSocketBinding::Wrap(aCx, this, aGivenProto, aReflector);
  86. }
  87. NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocket)
  88. NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TCPSocket,
  89. DOMEventTargetHelper)
  90. NS_IMPL_CYCLE_COLLECTION_TRACE_END
  91. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TCPSocket,
  92. DOMEventTargetHelper)
  93. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransport)
  94. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketInputStream)
  95. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketOutputStream)
  96. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStreamPump)
  97. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStreamScriptable)
  98. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStreamBinary)
  99. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMultiplexStream)
  100. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMultiplexStreamCopier)
  101. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingDataAfterStartTLS)
  102. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketBridgeChild)
  103. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocketBridgeParent)
  104. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  105. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPSocket,
  106. DOMEventTargetHelper)
  107. NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransport)
  108. NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketInputStream)
  109. NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketOutputStream)
  110. NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStreamPump)
  111. NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStreamScriptable)
  112. NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStreamBinary)
  113. NS_IMPL_CYCLE_COLLECTION_UNLINK(mMultiplexStream)
  114. NS_IMPL_CYCLE_COLLECTION_UNLINK(mMultiplexStreamCopier)
  115. NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingDataAfterStartTLS)
  116. NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketBridgeChild)
  117. NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocketBridgeParent)
  118. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  119. NS_IMPL_ADDREF_INHERITED(TCPSocket, DOMEventTargetHelper)
  120. NS_IMPL_RELEASE_INHERITED(TCPSocket, DOMEventTargetHelper)
  121. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TCPSocket)
  122. NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
  123. NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
  124. NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
  125. NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
  126. NS_INTERFACE_MAP_ENTRY(nsIObserver)
  127. NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  128. NS_INTERFACE_MAP_ENTRY(nsITCPSocketCallback)
  129. NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
  130. TCPSocket::TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t aPort,
  131. bool aSsl, bool aUseArrayBuffers)
  132. : DOMEventTargetHelper(aGlobal)
  133. , mReadyState(TCPReadyState::Closed)
  134. , mUseArrayBuffers(aUseArrayBuffers)
  135. , mHost(aHost)
  136. , mPort(aPort)
  137. , mSsl(aSsl)
  138. , mAsyncCopierActive(false)
  139. , mWaitingForDrain(false)
  140. , mInnerWindowID(0)
  141. , mBufferedAmount(0)
  142. , mSuspendCount(0)
  143. , mTrackingNumber(0)
  144. , mWaitingForStartTLS(false)
  145. , mObserversActive(false)
  146. {
  147. if (aGlobal) {
  148. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
  149. if (window) {
  150. mInnerWindowID = window->WindowID();
  151. }
  152. }
  153. }
  154. TCPSocket::~TCPSocket()
  155. {
  156. if (mObserversActive) {
  157. nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
  158. if (obs) {
  159. obs->RemoveObserver(this, "inner-window-destroyed");
  160. obs->RemoveObserver(this, "profile-change-net-teardown");
  161. }
  162. }
  163. }
  164. nsresult
  165. TCPSocket::CreateStream()
  166. {
  167. nsresult rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(mSocketInputStream));
  168. NS_ENSURE_SUCCESS(rv, rv);
  169. rv = mTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, getter_AddRefs(mSocketOutputStream));
  170. NS_ENSURE_SUCCESS(rv, rv);
  171. // If the other side is not listening, we will
  172. // get an onInputStreamReady callback where available
  173. // raises to indicate the connection was refused.
  174. nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mSocketInputStream);
  175. NS_ENSURE_TRUE(asyncStream, NS_ERROR_NOT_AVAILABLE);
  176. nsCOMPtr<nsIThread> mainThread;
  177. NS_GetMainThread(getter_AddRefs(mainThread));
  178. rv = asyncStream->AsyncWait(this, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0, mainThread);
  179. NS_ENSURE_SUCCESS(rv, rv);
  180. if (mUseArrayBuffers) {
  181. mInputStreamBinary = do_CreateInstance("@mozilla.org/binaryinputstream;1", &rv);
  182. NS_ENSURE_SUCCESS(rv, rv);
  183. rv = mInputStreamBinary->SetInputStream(mSocketInputStream);
  184. NS_ENSURE_SUCCESS(rv, rv);
  185. } else {
  186. mInputStreamScriptable = do_CreateInstance("@mozilla.org/scriptableinputstream;1", &rv);
  187. NS_ENSURE_SUCCESS(rv, rv);
  188. rv = mInputStreamScriptable->Init(mSocketInputStream);
  189. NS_ENSURE_SUCCESS(rv, rv);
  190. }
  191. mMultiplexStream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1", &rv);
  192. NS_ENSURE_SUCCESS(rv, rv);
  193. mMultiplexStreamCopier = do_CreateInstance("@mozilla.org/network/async-stream-copier;1", &rv);
  194. NS_ENSURE_SUCCESS(rv, rv);
  195. nsCOMPtr<nsISocketTransportService> sts =
  196. do_GetService("@mozilla.org/network/socket-transport-service;1");
  197. nsCOMPtr<nsIEventTarget> target = do_QueryInterface(sts);
  198. rv = mMultiplexStreamCopier->Init(mMultiplexStream,
  199. mSocketOutputStream,
  200. target,
  201. true, /* source buffered */
  202. false, /* sink buffered */
  203. BUFFER_SIZE,
  204. false, /* close source */
  205. false); /* close sink */
  206. NS_ENSURE_SUCCESS(rv, rv);
  207. return NS_OK;
  208. }
  209. nsresult
  210. TCPSocket::InitWithUnconnectedTransport(nsISocketTransport* aTransport)
  211. {
  212. mReadyState = TCPReadyState::Connecting;
  213. mTransport = aTransport;
  214. MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Content);
  215. nsCOMPtr<nsIThread> mainThread;
  216. NS_GetMainThread(getter_AddRefs(mainThread));
  217. mTransport->SetEventSink(this, mainThread);
  218. nsresult rv = CreateStream();
  219. NS_ENSURE_SUCCESS(rv, rv);
  220. return NS_OK;
  221. }
  222. nsresult
  223. TCPSocket::Init()
  224. {
  225. nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
  226. if (obs) {
  227. mObserversActive = true;
  228. obs->AddObserver(this, "inner-window-destroyed", true); // weak reference
  229. obs->AddObserver(this, "profile-change-net-teardown", true); // weak ref
  230. }
  231. if (XRE_GetProcessType() == GeckoProcessType_Content) {
  232. mReadyState = TCPReadyState::Connecting;
  233. mSocketBridgeChild = new TCPSocketChild(mHost, mPort);
  234. mSocketBridgeChild->SendOpen(this, mSsl, mUseArrayBuffers);
  235. return NS_OK;
  236. }
  237. nsCOMPtr<nsISocketTransportService> sts =
  238. do_GetService("@mozilla.org/network/socket-transport-service;1");
  239. const char* socketTypes[1];
  240. if (mSsl) {
  241. socketTypes[0] = "ssl";
  242. } else {
  243. socketTypes[0] = "starttls";
  244. }
  245. nsCOMPtr<nsISocketTransport> transport;
  246. nsresult rv = sts->CreateTransport(socketTypes, 1, NS_ConvertUTF16toUTF8(mHost), mPort,
  247. nullptr, getter_AddRefs(transport));
  248. NS_ENSURE_SUCCESS(rv, rv);
  249. return InitWithUnconnectedTransport(transport);
  250. }
  251. void
  252. TCPSocket::InitWithSocketChild(TCPSocketChild* aSocketBridge)
  253. {
  254. mSocketBridgeChild = aSocketBridge;
  255. mReadyState = TCPReadyState::Open;
  256. mSocketBridgeChild->SetSocket(this);
  257. mSocketBridgeChild->GetHost(mHost);
  258. mSocketBridgeChild->GetPort(&mPort);
  259. }
  260. nsresult
  261. TCPSocket::InitWithTransport(nsISocketTransport* aTransport)
  262. {
  263. mTransport = aTransport;
  264. nsresult rv = CreateStream();
  265. NS_ENSURE_SUCCESS(rv, rv);
  266. mReadyState = TCPReadyState::Open;
  267. rv = CreateInputStreamPump();
  268. NS_ENSURE_SUCCESS(rv, rv);
  269. nsAutoCString host;
  270. mTransport->GetHost(host);
  271. mHost = NS_ConvertUTF8toUTF16(host);
  272. int32_t port;
  273. mTransport->GetPort(&port);
  274. mPort = port;
  275. return NS_OK;
  276. }
  277. void
  278. TCPSocket::UpgradeToSecure(mozilla::ErrorResult& aRv)
  279. {
  280. if (mReadyState != TCPReadyState::Open) {
  281. aRv.Throw(NS_ERROR_FAILURE);
  282. return;
  283. }
  284. if (mSsl) {
  285. return;
  286. }
  287. mSsl = true;
  288. if (mSocketBridgeChild) {
  289. mSocketBridgeChild->SendStartTLS();
  290. return;
  291. }
  292. uint32_t count = 0;
  293. mMultiplexStream->GetCount(&count);
  294. if (!count) {
  295. ActivateTLS();
  296. } else {
  297. mWaitingForStartTLS = true;
  298. }
  299. }
  300. namespace {
  301. class CopierCallbacks final : public nsIRequestObserver
  302. {
  303. RefPtr<TCPSocket> mOwner;
  304. public:
  305. explicit CopierCallbacks(TCPSocket* aSocket) : mOwner(aSocket) {}
  306. NS_DECL_ISUPPORTS
  307. NS_DECL_NSIREQUESTOBSERVER
  308. private:
  309. ~CopierCallbacks() {}
  310. };
  311. NS_IMPL_ISUPPORTS(CopierCallbacks, nsIRequestObserver)
  312. NS_IMETHODIMP
  313. CopierCallbacks::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
  314. {
  315. return NS_OK;
  316. }
  317. NS_IMETHODIMP
  318. CopierCallbacks::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
  319. {
  320. mOwner->NotifyCopyComplete(aStatus);
  321. mOwner = nullptr;
  322. return NS_OK;
  323. }
  324. } // unnamed namespace
  325. nsresult
  326. TCPSocket::EnsureCopying()
  327. {
  328. if (mAsyncCopierActive) {
  329. return NS_OK;
  330. }
  331. mAsyncCopierActive = true;
  332. RefPtr<CopierCallbacks> callbacks = new CopierCallbacks(this);
  333. return mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr);
  334. }
  335. void
  336. TCPSocket::NotifyCopyComplete(nsresult aStatus)
  337. {
  338. mAsyncCopierActive = false;
  339. uint32_t countRemaining;
  340. nsresult rvRemaining = mMultiplexStream->GetCount(&countRemaining);
  341. NS_ENSURE_SUCCESS_VOID(rvRemaining);
  342. while (countRemaining--) {
  343. mMultiplexStream->RemoveStream(0);
  344. }
  345. while (!mPendingDataWhileCopierActive.IsEmpty()) {
  346. nsCOMPtr<nsIInputStream> stream = mPendingDataWhileCopierActive[0];
  347. mMultiplexStream->AppendStream(stream);
  348. mPendingDataWhileCopierActive.RemoveElementAt(0);
  349. }
  350. if (mSocketBridgeParent) {
  351. mozilla::Unused << mSocketBridgeParent->SendUpdateBufferedAmount(BufferedAmount(),
  352. mTrackingNumber);
  353. }
  354. if (NS_FAILED(aStatus)) {
  355. MaybeReportErrorAndCloseIfOpen(aStatus);
  356. return;
  357. }
  358. uint32_t count;
  359. nsresult rv = mMultiplexStream->GetCount(&count);
  360. NS_ENSURE_SUCCESS_VOID(rv);
  361. if (count) {
  362. EnsureCopying();
  363. return;
  364. }
  365. // If we are waiting for initiating starttls, we can begin to
  366. // activate tls now.
  367. if (mWaitingForStartTLS && mReadyState == TCPReadyState::Open) {
  368. ActivateTLS();
  369. mWaitingForStartTLS = false;
  370. // If we have pending data, we should send them, or fire
  371. // a drain event if we are waiting for it.
  372. if (!mPendingDataAfterStartTLS.IsEmpty()) {
  373. while (!mPendingDataAfterStartTLS.IsEmpty()) {
  374. nsCOMPtr<nsIInputStream> stream = mPendingDataAfterStartTLS[0];
  375. mMultiplexStream->AppendStream(stream);
  376. mPendingDataAfterStartTLS.RemoveElementAt(0);
  377. }
  378. EnsureCopying();
  379. return;
  380. }
  381. }
  382. // If we have a connected child, we let the child decide whether
  383. // ondrain should be dispatched.
  384. if (mWaitingForDrain && !mSocketBridgeParent) {
  385. mWaitingForDrain = false;
  386. FireEvent(NS_LITERAL_STRING("drain"));
  387. }
  388. if (mReadyState == TCPReadyState::Closing) {
  389. if (mSocketOutputStream) {
  390. mSocketOutputStream->Close();
  391. mSocketOutputStream = nullptr;
  392. }
  393. mReadyState = TCPReadyState::Closed;
  394. FireEvent(NS_LITERAL_STRING("close"));
  395. }
  396. }
  397. void
  398. TCPSocket::ActivateTLS()
  399. {
  400. nsCOMPtr<nsISupports> securityInfo;
  401. mTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
  402. nsCOMPtr<nsISSLSocketControl> socketControl = do_QueryInterface(securityInfo);
  403. if (socketControl) {
  404. socketControl->StartTLS();
  405. }
  406. }
  407. NS_IMETHODIMP
  408. TCPSocket::FireErrorEvent(const nsAString& aName, const nsAString& aType)
  409. {
  410. if (mSocketBridgeParent) {
  411. mSocketBridgeParent->FireErrorEvent(aName, aType, mReadyState);
  412. return NS_OK;
  413. }
  414. TCPSocketErrorEventInit init;
  415. init.mBubbles = false;
  416. init.mCancelable = false;
  417. init.mName = aName;
  418. init.mMessage = aType;
  419. RefPtr<TCPSocketErrorEvent> event =
  420. TCPSocketErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init);
  421. MOZ_ASSERT(event);
  422. event->SetTrusted(true);
  423. bool dummy;
  424. DispatchEvent(event, &dummy);
  425. return NS_OK;
  426. }
  427. NS_IMETHODIMP
  428. TCPSocket::FireEvent(const nsAString& aType)
  429. {
  430. if (mSocketBridgeParent) {
  431. mSocketBridgeParent->FireEvent(aType, mReadyState);
  432. return NS_OK;
  433. }
  434. AutoJSAPI api;
  435. if (NS_WARN_IF(!api.Init(GetOwnerGlobal()))) {
  436. return NS_ERROR_FAILURE;
  437. }
  438. JS::Rooted<JS::Value> val(api.cx());
  439. return FireDataEvent(api.cx(), aType, val);
  440. }
  441. NS_IMETHODIMP
  442. TCPSocket::FireDataArrayEvent(const nsAString& aType,
  443. const InfallibleTArray<uint8_t>& buffer)
  444. {
  445. AutoJSAPI api;
  446. if (NS_WARN_IF(!api.Init(GetOwnerGlobal()))) {
  447. return NS_ERROR_FAILURE;
  448. }
  449. JSContext* cx = api.cx();
  450. JS::Rooted<JS::Value> val(cx);
  451. bool ok = IPC::DeserializeArrayBuffer(cx, buffer, &val);
  452. if (ok) {
  453. return FireDataEvent(cx, aType, val);
  454. }
  455. return NS_ERROR_FAILURE;
  456. }
  457. NS_IMETHODIMP
  458. TCPSocket::FireDataStringEvent(const nsAString& aType,
  459. const nsACString& aString)
  460. {
  461. AutoJSAPI api;
  462. if (NS_WARN_IF(!api.Init(GetOwnerGlobal()))) {
  463. return NS_ERROR_FAILURE;
  464. }
  465. JSContext* cx = api.cx();
  466. JS::Rooted<JS::Value> val(cx);
  467. bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(aString), &val);
  468. if (ok) {
  469. return FireDataEvent(cx, aType, val);
  470. }
  471. return NS_ERROR_FAILURE;
  472. }
  473. nsresult
  474. TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData)
  475. {
  476. MOZ_ASSERT(!mSocketBridgeParent);
  477. RootedDictionary<TCPSocketEventInit> init(aCx);
  478. init.mBubbles = false;
  479. init.mCancelable = false;
  480. init.mData = aData;
  481. RefPtr<TCPSocketEvent> event =
  482. TCPSocketEvent::Constructor(this, aType, init);
  483. event->SetTrusted(true);
  484. bool dummy;
  485. DispatchEvent(event, &dummy);
  486. return NS_OK;
  487. }
  488. JSObject*
  489. TCPSocket::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  490. {
  491. return TCPSocketBinding::Wrap(aCx, this, aGivenProto);
  492. }
  493. void
  494. TCPSocket::GetHost(nsAString& aHost)
  495. {
  496. aHost.Assign(mHost);
  497. }
  498. uint32_t
  499. TCPSocket::Port()
  500. {
  501. return mPort;
  502. }
  503. bool
  504. TCPSocket::Ssl()
  505. {
  506. return mSsl;
  507. }
  508. uint64_t
  509. TCPSocket::BufferedAmount()
  510. {
  511. if (mSocketBridgeChild) {
  512. return mBufferedAmount;
  513. }
  514. if (mMultiplexStream) {
  515. uint64_t available = 0;
  516. mMultiplexStream->Available(&available);
  517. return available;
  518. }
  519. return 0;
  520. }
  521. void
  522. TCPSocket::Suspend()
  523. {
  524. if (mSocketBridgeChild) {
  525. mSocketBridgeChild->SendSuspend();
  526. return;
  527. }
  528. if (mInputStreamPump) {
  529. mInputStreamPump->Suspend();
  530. }
  531. mSuspendCount++;
  532. }
  533. void
  534. TCPSocket::Resume(mozilla::ErrorResult& aRv)
  535. {
  536. if (mSocketBridgeChild) {
  537. mSocketBridgeChild->SendResume();
  538. return;
  539. }
  540. if (!mSuspendCount) {
  541. aRv.Throw(NS_ERROR_FAILURE);
  542. return;
  543. }
  544. if (mInputStreamPump) {
  545. mInputStreamPump->Resume();
  546. }
  547. mSuspendCount--;
  548. }
  549. nsresult
  550. TCPSocket::MaybeReportErrorAndCloseIfOpen(nsresult status) {
  551. // If we're closed, we've already reported the error or just don't need to
  552. // report the error.
  553. if (mReadyState == TCPReadyState::Closed) {
  554. return NS_OK;
  555. }
  556. // go through ::Closing state and then mark ::Closed
  557. Close();
  558. mReadyState = TCPReadyState::Closed;
  559. if (NS_FAILED(status)) {
  560. // Convert the status code to an appropriate error message.
  561. nsString errorType, errName;
  562. // security module? (and this is an error)
  563. if ((static_cast<uint32_t>(status) & 0xFF0000) == 0x5a0000) {
  564. nsCOMPtr<nsINSSErrorsService> errSvc = do_GetService("@mozilla.org/nss_errors_service;1");
  565. // getErrorClass will throw a generic NS_ERROR_FAILURE if the error code is
  566. // somehow not in the set of covered errors.
  567. uint32_t errorClass;
  568. nsresult rv = errSvc->GetErrorClass(status, &errorClass);
  569. if (NS_FAILED(rv)) {
  570. errorType.AssignLiteral("SecurityProtocol");
  571. } else {
  572. switch (errorClass) {
  573. case nsINSSErrorsService::ERROR_CLASS_BAD_CERT:
  574. errorType.AssignLiteral("SecurityCertificate");
  575. break;
  576. default:
  577. errorType.AssignLiteral("SecurityProtocol");
  578. break;
  579. }
  580. }
  581. // NSS_SEC errors (happen below the base value because of negative vals)
  582. if ((static_cast<int32_t>(status) & 0xFFFF) < abs(nsINSSErrorsService::NSS_SEC_ERROR_BASE)) {
  583. switch (static_cast<SECErrorCodes>(status)) {
  584. case SEC_ERROR_EXPIRED_CERTIFICATE:
  585. errName.AssignLiteral("SecurityExpiredCertificateError");
  586. break;
  587. case SEC_ERROR_REVOKED_CERTIFICATE:
  588. errName.AssignLiteral("SecurityRevokedCertificateError");
  589. break;
  590. // per bsmith, we will be unable to tell these errors apart very soon,
  591. // so it makes sense to just folder them all together already.
  592. case SEC_ERROR_UNKNOWN_ISSUER:
  593. case SEC_ERROR_UNTRUSTED_ISSUER:
  594. case SEC_ERROR_UNTRUSTED_CERT:
  595. case SEC_ERROR_CA_CERT_INVALID:
  596. errName.AssignLiteral("SecurityUntrustedCertificateIssuerError");
  597. break;
  598. case SEC_ERROR_INADEQUATE_KEY_USAGE:
  599. errName.AssignLiteral("SecurityInadequateKeyUsageError");
  600. break;
  601. case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
  602. errName.AssignLiteral("SecurityCertificateSignatureAlgorithmDisabledError");
  603. break;
  604. default:
  605. errName.AssignLiteral("SecurityError");
  606. break;
  607. }
  608. } else {
  609. // NSS_SSL errors
  610. switch (static_cast<SSLErrorCodes>(status)) {
  611. case SSL_ERROR_NO_CERTIFICATE:
  612. errName.AssignLiteral("SecurityNoCertificateError");
  613. break;
  614. case SSL_ERROR_BAD_CERTIFICATE:
  615. errName.AssignLiteral("SecurityBadCertificateError");
  616. break;
  617. case SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE:
  618. errName.AssignLiteral("SecurityUnsupportedCertificateTypeError");
  619. break;
  620. case SSL_ERROR_UNSUPPORTED_VERSION:
  621. errName.AssignLiteral("SecurityUnsupportedTLSVersionError");
  622. break;
  623. case SSL_ERROR_BAD_CERT_DOMAIN:
  624. errName.AssignLiteral("SecurityCertificateDomainMismatchError");
  625. break;
  626. default:
  627. errName.AssignLiteral("SecurityError");
  628. break;
  629. }
  630. }
  631. } else {
  632. // must be network
  633. errorType.AssignLiteral("Network");
  634. switch (status) {
  635. // connect to host:port failed
  636. case NS_ERROR_CONNECTION_REFUSED:
  637. errName.AssignLiteral("ConnectionRefusedError");
  638. break;
  639. // network timeout error
  640. case NS_ERROR_NET_TIMEOUT:
  641. errName.AssignLiteral("NetworkTimeoutError");
  642. break;
  643. // hostname lookup failed
  644. case NS_ERROR_UNKNOWN_HOST:
  645. errName.AssignLiteral("DomainNotFoundError");
  646. break;
  647. case NS_ERROR_NET_INTERRUPT:
  648. errName.AssignLiteral("NetworkInterruptError");
  649. break;
  650. default:
  651. errName.AssignLiteral("NetworkError");
  652. break;
  653. }
  654. }
  655. Unused << NS_WARN_IF(NS_FAILED(FireErrorEvent(errName, errorType)));
  656. }
  657. return FireEvent(NS_LITERAL_STRING("close"));
  658. }
  659. void
  660. TCPSocket::Close()
  661. {
  662. CloseHelper(true);
  663. }
  664. void
  665. TCPSocket::CloseImmediately()
  666. {
  667. CloseHelper(false);
  668. }
  669. void
  670. TCPSocket::CloseHelper(bool waitForUnsentData)
  671. {
  672. if (mReadyState == TCPReadyState::Closed || mReadyState == TCPReadyState::Closing) {
  673. return;
  674. }
  675. mReadyState = TCPReadyState::Closing;
  676. if (mSocketBridgeChild) {
  677. mSocketBridgeChild->SendClose();
  678. return;
  679. }
  680. uint32_t count = 0;
  681. if (mMultiplexStream) {
  682. mMultiplexStream->GetCount(&count);
  683. }
  684. if (!count || !waitForUnsentData) {
  685. if (mSocketOutputStream) {
  686. mSocketOutputStream->Close();
  687. mSocketOutputStream = nullptr;
  688. }
  689. }
  690. if (mSocketInputStream) {
  691. mSocketInputStream->Close();
  692. mSocketInputStream = nullptr;
  693. }
  694. }
  695. void
  696. TCPSocket::SendWithTrackingNumber(const nsACString& aData,
  697. const uint32_t& aTrackingNumber,
  698. mozilla::ErrorResult& aRv)
  699. {
  700. MOZ_ASSERT(mSocketBridgeParent);
  701. mTrackingNumber = aTrackingNumber;
  702. // The JSContext isn't necessary for string values; it's a codegen limitation.
  703. Send(nullptr, aData, aRv);
  704. }
  705. bool
  706. TCPSocket::Send(JSContext* aCx, const nsACString& aData, mozilla::ErrorResult& aRv)
  707. {
  708. if (mReadyState != TCPReadyState::Open) {
  709. aRv.Throw(NS_ERROR_FAILURE);
  710. return false;
  711. }
  712. uint64_t byteLength;
  713. nsCOMPtr<nsIInputStream> stream;
  714. if (mSocketBridgeChild) {
  715. mSocketBridgeChild->SendSend(aData, ++mTrackingNumber);
  716. byteLength = aData.Length();
  717. } else {
  718. nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), aData);
  719. if (NS_FAILED(rv)) {
  720. aRv.Throw(rv);
  721. return false;
  722. }
  723. rv = stream->Available(&byteLength);
  724. if (NS_FAILED(rv)) {
  725. aRv.Throw(rv);
  726. return false;
  727. }
  728. }
  729. return Send(stream, byteLength);
  730. }
  731. void
  732. TCPSocket::SendWithTrackingNumber(JSContext* aCx,
  733. const ArrayBuffer& aData,
  734. uint32_t aByteOffset,
  735. const Optional<uint32_t>& aByteLength,
  736. const uint32_t& aTrackingNumber,
  737. mozilla::ErrorResult& aRv)
  738. {
  739. MOZ_ASSERT(mSocketBridgeParent);
  740. mTrackingNumber = aTrackingNumber;
  741. Send(aCx, aData, aByteOffset, aByteLength, aRv);
  742. }
  743. bool
  744. TCPSocket::Send(JSContext* aCx,
  745. const ArrayBuffer& aData,
  746. uint32_t aByteOffset,
  747. const Optional<uint32_t>& aByteLength,
  748. mozilla::ErrorResult& aRv)
  749. {
  750. if (mReadyState != TCPReadyState::Open) {
  751. aRv.Throw(NS_ERROR_FAILURE);
  752. return false;
  753. }
  754. nsCOMPtr<nsIArrayBufferInputStream> stream;
  755. aData.ComputeLengthAndData();
  756. uint32_t byteLength = aByteLength.WasPassed() ? aByteLength.Value() : aData.Length();
  757. if (mSocketBridgeChild) {
  758. nsresult rv = mSocketBridgeChild->SendSend(aData, aByteOffset, byteLength, ++mTrackingNumber);
  759. if (NS_WARN_IF(NS_FAILED(rv))) {
  760. aRv.Throw(rv);
  761. return false;
  762. }
  763. } else {
  764. JS::Rooted<JSObject*> obj(aCx, aData.Obj());
  765. JSAutoCompartment ac(aCx, obj);
  766. JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*obj));
  767. stream = do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
  768. nsresult rv = stream->SetData(value, aByteOffset, byteLength, aCx);
  769. if (NS_WARN_IF(NS_FAILED(rv))) {
  770. aRv.Throw(rv);
  771. return false;
  772. }
  773. }
  774. return Send(stream, byteLength);
  775. }
  776. bool
  777. TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength)
  778. {
  779. uint64_t newBufferedAmount = BufferedAmount() + aByteLength;
  780. bool bufferFull = newBufferedAmount > BUFFER_SIZE;
  781. if (bufferFull) {
  782. // If we buffered more than some arbitrary amount of data,
  783. // (65535 right now) we should tell the caller so they can
  784. // wait until ondrain is called if they so desire. Once all the
  785. // buffered data has been written to the socket, ondrain is
  786. // called.
  787. mWaitingForDrain = true;
  788. }
  789. if (mSocketBridgeChild) {
  790. // In the child, we just add the buffer length to our bufferedAmount and let
  791. // the parent update our bufferedAmount when the data have been sent.
  792. mBufferedAmount = newBufferedAmount;
  793. return !bufferFull;
  794. }
  795. if (mWaitingForStartTLS) {
  796. // When we are waiting for starttls, newStream is added to pendingData
  797. // and will be appended to multiplexStream after tls had been set up.
  798. mPendingDataAfterStartTLS.AppendElement(aStream);
  799. } else if (mAsyncCopierActive) {
  800. // While the AsyncCopier is still active..
  801. mPendingDataWhileCopierActive.AppendElement(aStream);
  802. } else {
  803. mMultiplexStream->AppendStream(aStream);
  804. }
  805. EnsureCopying();
  806. return !bufferFull;
  807. }
  808. TCPReadyState
  809. TCPSocket::ReadyState()
  810. {
  811. return mReadyState;
  812. }
  813. TCPSocketBinaryType
  814. TCPSocket::BinaryType()
  815. {
  816. if (mUseArrayBuffers) {
  817. return TCPSocketBinaryType::Arraybuffer;
  818. } else {
  819. return TCPSocketBinaryType::String;
  820. }
  821. }
  822. already_AddRefed<TCPSocket>
  823. TCPSocket::CreateAcceptedSocket(nsIGlobalObject* aGlobal,
  824. nsISocketTransport* aTransport,
  825. bool aUseArrayBuffers)
  826. {
  827. RefPtr<TCPSocket> socket = new TCPSocket(aGlobal, EmptyString(), 0, false, aUseArrayBuffers);
  828. nsresult rv = socket->InitWithTransport(aTransport);
  829. NS_ENSURE_SUCCESS(rv, nullptr);
  830. return socket.forget();
  831. }
  832. already_AddRefed<TCPSocket>
  833. TCPSocket::CreateAcceptedSocket(nsIGlobalObject* aGlobal,
  834. TCPSocketChild* aBridge,
  835. bool aUseArrayBuffers)
  836. {
  837. RefPtr<TCPSocket> socket = new TCPSocket(aGlobal, EmptyString(), 0, false, aUseArrayBuffers);
  838. socket->InitWithSocketChild(aBridge);
  839. return socket.forget();
  840. }
  841. already_AddRefed<TCPSocket>
  842. TCPSocket::Constructor(const GlobalObject& aGlobal,
  843. const nsAString& aHost,
  844. uint16_t aPort,
  845. const SocketOptions& aOptions,
  846. mozilla::ErrorResult& aRv)
  847. {
  848. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
  849. RefPtr<TCPSocket> socket =
  850. new TCPSocket(global, aHost, aPort, aOptions.mUseSecureTransport,
  851. aOptions.mBinaryType == TCPSocketBinaryType::Arraybuffer);
  852. nsresult rv = socket->Init();
  853. if (NS_WARN_IF(NS_FAILED(rv))) {
  854. aRv.Throw(rv);
  855. return nullptr;
  856. }
  857. return socket.forget();
  858. }
  859. nsresult
  860. TCPSocket::CreateInputStreamPump()
  861. {
  862. if (!mSocketInputStream) {
  863. return NS_ERROR_NOT_AVAILABLE;
  864. }
  865. nsresult rv;
  866. mInputStreamPump = do_CreateInstance("@mozilla.org/network/input-stream-pump;1", &rv);
  867. NS_ENSURE_SUCCESS(rv, rv);
  868. rv = mInputStreamPump->Init(mSocketInputStream, -1, -1, 0, 0, false);
  869. NS_ENSURE_SUCCESS(rv, rv);
  870. uint64_t suspendCount = mSuspendCount;
  871. while (suspendCount--) {
  872. mInputStreamPump->Suspend();
  873. }
  874. rv = mInputStreamPump->AsyncRead(this, nullptr);
  875. NS_ENSURE_SUCCESS(rv, rv);
  876. return NS_OK;
  877. }
  878. NS_IMETHODIMP
  879. TCPSocket::OnTransportStatus(nsITransport* aTransport, nsresult aStatus,
  880. int64_t aProgress, int64_t aProgressMax)
  881. {
  882. if (static_cast<uint32_t>(aStatus) != nsISocketTransport::STATUS_CONNECTED_TO) {
  883. return NS_OK;
  884. }
  885. mReadyState = TCPReadyState::Open;
  886. FireEvent(NS_LITERAL_STRING("open"));
  887. nsresult rv = CreateInputStreamPump();
  888. NS_ENSURE_SUCCESS(rv, rv);
  889. return NS_OK;
  890. }
  891. NS_IMETHODIMP
  892. TCPSocket::OnInputStreamReady(nsIAsyncInputStream* aStream)
  893. {
  894. // Only used for detecting if the connection was refused.
  895. uint64_t dummy;
  896. nsresult rv = aStream->Available(&dummy);
  897. if (NS_FAILED(rv)) {
  898. MaybeReportErrorAndCloseIfOpen(NS_ERROR_CONNECTION_REFUSED);
  899. }
  900. return NS_OK;
  901. }
  902. NS_IMETHODIMP
  903. TCPSocket::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
  904. {
  905. return NS_OK;
  906. }
  907. NS_IMETHODIMP
  908. TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream,
  909. uint64_t aOffset, uint32_t aCount)
  910. {
  911. if (mUseArrayBuffers) {
  912. nsTArray<uint8_t> buffer;
  913. buffer.SetCapacity(aCount);
  914. uint32_t actual;
  915. nsresult rv = aStream->Read(reinterpret_cast<char*>(buffer.Elements()), aCount, &actual);
  916. NS_ENSURE_SUCCESS(rv, rv);
  917. MOZ_ASSERT(actual == aCount);
  918. buffer.SetLength(actual);
  919. if (mSocketBridgeParent) {
  920. mSocketBridgeParent->FireArrayBufferDataEvent(buffer, mReadyState);
  921. return NS_OK;
  922. }
  923. AutoJSAPI api;
  924. if (!api.Init(GetOwnerGlobal())) {
  925. return NS_ERROR_FAILURE;
  926. }
  927. JSContext* cx = api.cx();
  928. JS::Rooted<JS::Value> value(cx);
  929. if (!ToJSValue(cx, TypedArrayCreator<ArrayBuffer>(buffer), &value)) {
  930. return NS_ERROR_FAILURE;
  931. }
  932. FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
  933. return NS_OK;
  934. }
  935. nsCString data;
  936. nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
  937. NS_ENSURE_SUCCESS(rv, rv);
  938. if (mSocketBridgeParent) {
  939. mSocketBridgeParent->FireStringDataEvent(data, mReadyState);
  940. return NS_OK;
  941. }
  942. AutoJSAPI api;
  943. if (!api.Init(GetOwnerGlobal())) {
  944. return NS_ERROR_FAILURE;
  945. }
  946. JSContext* cx = api.cx();
  947. JS::Rooted<JS::Value> value(cx);
  948. if (!ToJSValue(cx, NS_ConvertASCIItoUTF16(data), &value)) {
  949. return NS_ERROR_FAILURE;
  950. }
  951. FireDataEvent(cx, NS_LITERAL_STRING("data"), value);
  952. return NS_OK;
  953. }
  954. NS_IMETHODIMP
  955. TCPSocket::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
  956. {
  957. uint32_t count;
  958. nsresult rv = mMultiplexStream->GetCount(&count);
  959. NS_ENSURE_SUCCESS(rv, rv);
  960. bool bufferedOutput = count != 0;
  961. mInputStreamPump = nullptr;
  962. if (bufferedOutput && NS_SUCCEEDED(aStatus)) {
  963. // If we have some buffered output still, and status is not an
  964. // error, the other side has done a half-close, but we don't
  965. // want to be in the close state until we are done sending
  966. // everything that was buffered. We also don't want to call onclose
  967. // yet.
  968. return NS_OK;
  969. }
  970. // We call this even if there is no error.
  971. MaybeReportErrorAndCloseIfOpen(aStatus);
  972. return NS_OK;
  973. }
  974. void
  975. TCPSocket::SetSocketBridgeParent(TCPSocketParent* aBridgeParent)
  976. {
  977. mSocketBridgeParent = aBridgeParent;
  978. }
  979. void
  980. TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInIsolatedMozBrowser)
  981. {
  982. /*** STUB ***/
  983. }
  984. NS_IMETHODIMP
  985. TCPSocket::UpdateReadyState(uint32_t aReadyState)
  986. {
  987. MOZ_ASSERT(mSocketBridgeChild);
  988. mReadyState = static_cast<TCPReadyState>(aReadyState);
  989. return NS_OK;
  990. }
  991. NS_IMETHODIMP
  992. TCPSocket::UpdateBufferedAmount(uint32_t aBufferedAmount, uint32_t aTrackingNumber)
  993. {
  994. if (aTrackingNumber != mTrackingNumber) {
  995. return NS_OK;
  996. }
  997. mBufferedAmount = aBufferedAmount;
  998. if (!mBufferedAmount) {
  999. if (mWaitingForDrain) {
  1000. mWaitingForDrain = false;
  1001. return FireEvent(NS_LITERAL_STRING("drain"));
  1002. }
  1003. }
  1004. return NS_OK;
  1005. }
  1006. NS_IMETHODIMP
  1007. TCPSocket::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
  1008. {
  1009. if (!strcmp(aTopic, "inner-window-destroyed")) {
  1010. nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
  1011. NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
  1012. uint64_t innerID;
  1013. nsresult rv = wrapper->GetData(&innerID);
  1014. if (NS_WARN_IF(NS_FAILED(rv))) {
  1015. return rv;
  1016. }
  1017. if (innerID == mInnerWindowID) {
  1018. Close();
  1019. }
  1020. } else if (!strcmp(aTopic, "profile-change-net-teardown")) {
  1021. Close();
  1022. }
  1023. return NS_OK;
  1024. }
  1025. /* static */
  1026. bool
  1027. TCPSocket::ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal)
  1028. {
  1029. JS::Rooted<JSObject*> global(aCx, aGlobal);
  1030. return nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
  1031. }