LCOV - code coverage report
Current view: top level - dom/network - TCPSocket.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 597 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 75 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13