dom/network/src/TCPSocketParent.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "TCPSocketParent.h"
     6 #include "jsapi.h"
     7 #include "jsfriendapi.h"
     8 #include "nsJSUtils.h"
     9 #include "nsIDOMTCPSocket.h"
    10 #include "nsCxPusher.h"
    11 #include "mozilla/unused.h"
    12 #include "mozilla/AppProcessChecker.h"
    13 #include "mozilla/net/NeckoCommon.h"
    14 #include "mozilla/net/PNeckoParent.h"
    15 #include "mozilla/dom/ContentParent.h"
    16 #include "mozilla/dom/TabParent.h"
    17 #include "nsIScriptSecurityManager.h"
    19 namespace IPC {
    21 //Defined in TCPSocketChild.cpp
    22 extern bool
    23 DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
    24                        const InfallibleTArray<uint8_t>& aBuffer,
    25                        JS::MutableHandle<JS::Value> aVal);
    27 }
    29 namespace mozilla {
    30 namespace dom {
    32 static void
    33 FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
    34 {
    35   mozilla::unused <<
    36       aActor->SendCallback(NS_LITERAL_STRING("onerror"),
    37                            TCPError(NS_LITERAL_STRING("InvalidStateError")),
    38                            NS_LITERAL_STRING("connecting"));
    39 }
    41 NS_IMPL_CYCLE_COLLECTION(TCPSocketParentBase, mSocket, mIntermediary)
    42 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
    43 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
    45 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase)
    46   NS_INTERFACE_MAP_ENTRY(nsITCPSocketParent)
    47   NS_INTERFACE_MAP_ENTRY(nsISupports)
    48 NS_INTERFACE_MAP_END
    50 TCPSocketParentBase::TCPSocketParentBase()
    51 : mIPCOpen(false)
    52 {
    53 }
    55 TCPSocketParentBase::~TCPSocketParentBase()
    56 {
    57 }
    59 void
    60 TCPSocketParentBase::ReleaseIPDLReference()
    61 {
    62   MOZ_ASSERT(mIPCOpen);
    63   mIPCOpen = false;
    64   this->Release();
    65 }
    67 void
    68 TCPSocketParentBase::AddIPDLReference()
    69 {
    70   MOZ_ASSERT(!mIPCOpen);
    71   mIPCOpen = true;
    72   this->AddRef();
    73 }
    75 NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketParent::Release(void)
    76 {
    77   nsrefcnt refcnt = TCPSocketParentBase::Release();
    78   if (refcnt == 1 && mIPCOpen) {
    79     mozilla::unused << PTCPSocketParent::SendRequestDelete();
    80     return 1;
    81   }
    82   return refcnt;
    83 }
    85 bool
    86 TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL,
    87                           const nsString& aBinaryType)
    88 {
    89   // We don't have browser actors in xpcshell, and hence can't run automated
    90   // tests without this loophole.
    91   if (net::UsingNeckoIPCSecurity() &&
    92       !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
    93     FireInteralError(this, __LINE__);
    94     return true;
    95   }
    97   // Obtain App ID
    98   uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
    99   const PContentParent *content = Manager()->Manager();
   100   const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
   101   if (browsers.Length() > 0) {
   102     TabParent *tab = static_cast<TabParent*>(browsers[0]);
   103     appId = tab->OwnAppId();
   104   }
   106   nsresult rv;
   107   mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
   108   if (NS_FAILED(rv)) {
   109     FireInteralError(this, __LINE__);
   110     return true;
   111   }
   113   rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, appId,
   114                            getter_AddRefs(mSocket));
   115   if (NS_FAILED(rv) || !mSocket) {
   116     FireInteralError(this, __LINE__);
   117     return true;
   118   }
   120   return true;
   121 }
   123 NS_IMETHODIMP
   124 TCPSocketParent::InitJS(JS::Handle<JS::Value> aIntermediary, JSContext* aCx)
   125 {
   126   MOZ_ASSERT(aIntermediary.isObject());
   127   mIntermediaryObj = &aIntermediary.toObject();
   128   return NS_OK;
   129 }
   131 bool
   132 TCPSocketParent::RecvStartTLS()
   133 {
   134   NS_ENSURE_TRUE(mSocket, true);
   135   nsresult rv = mSocket->UpgradeToSecure();
   136   NS_ENSURE_SUCCESS(rv, true);
   137   return true;
   138 }
   140 bool
   141 TCPSocketParent::RecvSuspend()
   142 {
   143   NS_ENSURE_TRUE(mSocket, true);
   144   nsresult rv = mSocket->Suspend();
   145   NS_ENSURE_SUCCESS(rv, true);
   146   return true;
   147 }
   149 bool
   150 TCPSocketParent::RecvResume()
   151 {
   152   NS_ENSURE_TRUE(mSocket, true);
   153   nsresult rv = mSocket->Resume();
   154   NS_ENSURE_SUCCESS(rv, true);
   155   return true;
   156 }
   158 bool
   159 TCPSocketParent::RecvData(const SendableData& aData,
   160                           const uint32_t& aTrackingNumber)
   161 {
   162   NS_ENSURE_TRUE(mIntermediary, true);
   164   nsresult rv;
   165   switch (aData.type()) {
   166     case SendableData::TArrayOfuint8_t: {
   167       AutoSafeJSContext cx;
   168       JSAutoRequest ar(cx);
   169       JS::Rooted<JS::Value> val(cx);
   170       JS::Rooted<JSObject*> obj(cx, mIntermediaryObj);
   171       IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val);
   172       rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber);
   173       NS_ENSURE_SUCCESS(rv, true);
   174       break;
   175     }
   177     case SendableData::TnsString:
   178       rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
   179       NS_ENSURE_SUCCESS(rv, true);
   180       break;
   182     default:
   183       MOZ_CRASH("unexpected SendableData type");
   184   }
   185   return true;
   186 }
   188 bool
   189 TCPSocketParent::RecvClose()
   190 {
   191   NS_ENSURE_TRUE(mSocket, true);
   192   nsresult rv = mSocket->Close();
   193   NS_ENSURE_SUCCESS(rv, true);
   194   return true;
   195 }
   197 NS_IMETHODIMP
   198 TCPSocketParent::SendEvent(const nsAString& aType, JS::Handle<JS::Value> aDataVal,
   199                            const nsAString& aReadyState, JSContext* aCx)
   200 {
   201   if (!mIPCOpen) {
   202     NS_WARNING("Dropping callback due to no IPC connection");
   203     return NS_OK;
   204   }
   206   CallbackData data;
   207   if (aDataVal.isString()) {
   208     JSString* jsstr = aDataVal.toString();
   209     nsDependentJSString str;
   210     if (!str.init(aCx, jsstr)) {
   211       FireInteralError(this, __LINE__);
   212       return NS_ERROR_OUT_OF_MEMORY;
   213     }
   214     data = SendableData(str);
   216   } else if (aDataVal.isUndefined() || aDataVal.isNull()) {
   217     data = mozilla::void_t();
   219   } else if (aDataVal.isObject()) {
   220     JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject());
   221     if (JS_IsArrayBufferObject(obj)) {
   222       uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
   223       uint8_t* buffer = JS_GetArrayBufferData(obj);
   224       if (!buffer) {
   225         FireInteralError(this, __LINE__);
   226         return NS_ERROR_OUT_OF_MEMORY;
   227       }
   228       FallibleTArray<uint8_t> fallibleArr;
   229       if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) {
   230         FireInteralError(this, __LINE__);
   231         return NS_ERROR_OUT_OF_MEMORY;
   232       }
   233       InfallibleTArray<uint8_t> arr;
   234       arr.SwapElements(fallibleArr);
   235       data = SendableData(arr);
   237     } else {
   238       nsDependentJSString name;
   240       JS::Rooted<JS::Value> val(aCx);
   241       if (!JS_GetProperty(aCx, obj, "name", &val)) {
   242         NS_ERROR("No name property on supposed error object");
   243       } else if (JSVAL_IS_STRING(val)) {
   244         if (!name.init(aCx, JSVAL_TO_STRING(val))) {
   245           NS_WARNING("couldn't initialize string");
   246         }
   247       }
   249       data = TCPError(name);
   250     }
   251   } else {
   252     NS_ERROR("Unexpected JS value encountered");
   253     FireInteralError(this, __LINE__);
   254     return NS_ERROR_FAILURE;
   255   }
   256   mozilla::unused <<
   257       PTCPSocketParent::SendCallback(nsString(aType), data,
   258                                      nsString(aReadyState));
   259   return NS_OK;
   260 }
   262 NS_IMETHODIMP
   263 TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
   264                                           nsITCPSocketIntermediary *intermediary,
   265                                           JSContext* cx)
   266 {
   267   mSocket = socket;
   268   mIntermediary = intermediary;
   269   return NS_OK;
   270 }
   272 NS_IMETHODIMP
   273 TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
   274                                           uint32_t aTrackingNumber)
   275 {
   276   mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
   277                                                                 aTrackingNumber);
   278   return NS_OK;
   279 }
   281 void
   282 TCPSocketParent::ActorDestroy(ActorDestroyReason why)
   283 {
   284   if (mSocket) {
   285     mSocket->Close();
   286   }
   287   mSocket = nullptr;
   288   mIntermediaryObj = nullptr;
   289   mIntermediary = nullptr;
   290 }
   292 bool
   293 TCPSocketParent::RecvRequestDelete()
   294 {
   295   mozilla::unused << Send__delete__(this);
   296   return true;
   297 }
   299 } // namespace dom
   300 } // namespace mozilla

mercurial