1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/network/src/TCPSocketParent.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,300 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "TCPSocketParent.h" 1.9 +#include "jsapi.h" 1.10 +#include "jsfriendapi.h" 1.11 +#include "nsJSUtils.h" 1.12 +#include "nsIDOMTCPSocket.h" 1.13 +#include "nsCxPusher.h" 1.14 +#include "mozilla/unused.h" 1.15 +#include "mozilla/AppProcessChecker.h" 1.16 +#include "mozilla/net/NeckoCommon.h" 1.17 +#include "mozilla/net/PNeckoParent.h" 1.18 +#include "mozilla/dom/ContentParent.h" 1.19 +#include "mozilla/dom/TabParent.h" 1.20 +#include "nsIScriptSecurityManager.h" 1.21 + 1.22 +namespace IPC { 1.23 + 1.24 +//Defined in TCPSocketChild.cpp 1.25 +extern bool 1.26 +DeserializeArrayBuffer(JS::Handle<JSObject*> aObj, 1.27 + const InfallibleTArray<uint8_t>& aBuffer, 1.28 + JS::MutableHandle<JS::Value> aVal); 1.29 + 1.30 +} 1.31 + 1.32 +namespace mozilla { 1.33 +namespace dom { 1.34 + 1.35 +static void 1.36 +FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo) 1.37 +{ 1.38 + mozilla::unused << 1.39 + aActor->SendCallback(NS_LITERAL_STRING("onerror"), 1.40 + TCPError(NS_LITERAL_STRING("InvalidStateError")), 1.41 + NS_LITERAL_STRING("connecting")); 1.42 +} 1.43 + 1.44 +NS_IMPL_CYCLE_COLLECTION(TCPSocketParentBase, mSocket, mIntermediary) 1.45 +NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase) 1.46 +NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase) 1.47 + 1.48 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase) 1.49 + NS_INTERFACE_MAP_ENTRY(nsITCPSocketParent) 1.50 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.51 +NS_INTERFACE_MAP_END 1.52 + 1.53 +TCPSocketParentBase::TCPSocketParentBase() 1.54 +: mIPCOpen(false) 1.55 +{ 1.56 +} 1.57 + 1.58 +TCPSocketParentBase::~TCPSocketParentBase() 1.59 +{ 1.60 +} 1.61 + 1.62 +void 1.63 +TCPSocketParentBase::ReleaseIPDLReference() 1.64 +{ 1.65 + MOZ_ASSERT(mIPCOpen); 1.66 + mIPCOpen = false; 1.67 + this->Release(); 1.68 +} 1.69 + 1.70 +void 1.71 +TCPSocketParentBase::AddIPDLReference() 1.72 +{ 1.73 + MOZ_ASSERT(!mIPCOpen); 1.74 + mIPCOpen = true; 1.75 + this->AddRef(); 1.76 +} 1.77 + 1.78 +NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketParent::Release(void) 1.79 +{ 1.80 + nsrefcnt refcnt = TCPSocketParentBase::Release(); 1.81 + if (refcnt == 1 && mIPCOpen) { 1.82 + mozilla::unused << PTCPSocketParent::SendRequestDelete(); 1.83 + return 1; 1.84 + } 1.85 + return refcnt; 1.86 +} 1.87 + 1.88 +bool 1.89 +TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL, 1.90 + const nsString& aBinaryType) 1.91 +{ 1.92 + // We don't have browser actors in xpcshell, and hence can't run automated 1.93 + // tests without this loophole. 1.94 + if (net::UsingNeckoIPCSecurity() && 1.95 + !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) { 1.96 + FireInteralError(this, __LINE__); 1.97 + return true; 1.98 + } 1.99 + 1.100 + // Obtain App ID 1.101 + uint32_t appId = nsIScriptSecurityManager::NO_APP_ID; 1.102 + const PContentParent *content = Manager()->Manager(); 1.103 + const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent(); 1.104 + if (browsers.Length() > 0) { 1.105 + TabParent *tab = static_cast<TabParent*>(browsers[0]); 1.106 + appId = tab->OwnAppId(); 1.107 + } 1.108 + 1.109 + nsresult rv; 1.110 + mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv); 1.111 + if (NS_FAILED(rv)) { 1.112 + FireInteralError(this, __LINE__); 1.113 + return true; 1.114 + } 1.115 + 1.116 + rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, appId, 1.117 + getter_AddRefs(mSocket)); 1.118 + if (NS_FAILED(rv) || !mSocket) { 1.119 + FireInteralError(this, __LINE__); 1.120 + return true; 1.121 + } 1.122 + 1.123 + return true; 1.124 +} 1.125 + 1.126 +NS_IMETHODIMP 1.127 +TCPSocketParent::InitJS(JS::Handle<JS::Value> aIntermediary, JSContext* aCx) 1.128 +{ 1.129 + MOZ_ASSERT(aIntermediary.isObject()); 1.130 + mIntermediaryObj = &aIntermediary.toObject(); 1.131 + return NS_OK; 1.132 +} 1.133 + 1.134 +bool 1.135 +TCPSocketParent::RecvStartTLS() 1.136 +{ 1.137 + NS_ENSURE_TRUE(mSocket, true); 1.138 + nsresult rv = mSocket->UpgradeToSecure(); 1.139 + NS_ENSURE_SUCCESS(rv, true); 1.140 + return true; 1.141 +} 1.142 + 1.143 +bool 1.144 +TCPSocketParent::RecvSuspend() 1.145 +{ 1.146 + NS_ENSURE_TRUE(mSocket, true); 1.147 + nsresult rv = mSocket->Suspend(); 1.148 + NS_ENSURE_SUCCESS(rv, true); 1.149 + return true; 1.150 +} 1.151 + 1.152 +bool 1.153 +TCPSocketParent::RecvResume() 1.154 +{ 1.155 + NS_ENSURE_TRUE(mSocket, true); 1.156 + nsresult rv = mSocket->Resume(); 1.157 + NS_ENSURE_SUCCESS(rv, true); 1.158 + return true; 1.159 +} 1.160 + 1.161 +bool 1.162 +TCPSocketParent::RecvData(const SendableData& aData, 1.163 + const uint32_t& aTrackingNumber) 1.164 +{ 1.165 + NS_ENSURE_TRUE(mIntermediary, true); 1.166 + 1.167 + nsresult rv; 1.168 + switch (aData.type()) { 1.169 + case SendableData::TArrayOfuint8_t: { 1.170 + AutoSafeJSContext cx; 1.171 + JSAutoRequest ar(cx); 1.172 + JS::Rooted<JS::Value> val(cx); 1.173 + JS::Rooted<JSObject*> obj(cx, mIntermediaryObj); 1.174 + IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val); 1.175 + rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber); 1.176 + NS_ENSURE_SUCCESS(rv, true); 1.177 + break; 1.178 + } 1.179 + 1.180 + case SendableData::TnsString: 1.181 + rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber); 1.182 + NS_ENSURE_SUCCESS(rv, true); 1.183 + break; 1.184 + 1.185 + default: 1.186 + MOZ_CRASH("unexpected SendableData type"); 1.187 + } 1.188 + return true; 1.189 +} 1.190 + 1.191 +bool 1.192 +TCPSocketParent::RecvClose() 1.193 +{ 1.194 + NS_ENSURE_TRUE(mSocket, true); 1.195 + nsresult rv = mSocket->Close(); 1.196 + NS_ENSURE_SUCCESS(rv, true); 1.197 + return true; 1.198 +} 1.199 + 1.200 +NS_IMETHODIMP 1.201 +TCPSocketParent::SendEvent(const nsAString& aType, JS::Handle<JS::Value> aDataVal, 1.202 + const nsAString& aReadyState, JSContext* aCx) 1.203 +{ 1.204 + if (!mIPCOpen) { 1.205 + NS_WARNING("Dropping callback due to no IPC connection"); 1.206 + return NS_OK; 1.207 + } 1.208 + 1.209 + CallbackData data; 1.210 + if (aDataVal.isString()) { 1.211 + JSString* jsstr = aDataVal.toString(); 1.212 + nsDependentJSString str; 1.213 + if (!str.init(aCx, jsstr)) { 1.214 + FireInteralError(this, __LINE__); 1.215 + return NS_ERROR_OUT_OF_MEMORY; 1.216 + } 1.217 + data = SendableData(str); 1.218 + 1.219 + } else if (aDataVal.isUndefined() || aDataVal.isNull()) { 1.220 + data = mozilla::void_t(); 1.221 + 1.222 + } else if (aDataVal.isObject()) { 1.223 + JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject()); 1.224 + if (JS_IsArrayBufferObject(obj)) { 1.225 + uint32_t nbytes = JS_GetArrayBufferByteLength(obj); 1.226 + uint8_t* buffer = JS_GetArrayBufferData(obj); 1.227 + if (!buffer) { 1.228 + FireInteralError(this, __LINE__); 1.229 + return NS_ERROR_OUT_OF_MEMORY; 1.230 + } 1.231 + FallibleTArray<uint8_t> fallibleArr; 1.232 + if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) { 1.233 + FireInteralError(this, __LINE__); 1.234 + return NS_ERROR_OUT_OF_MEMORY; 1.235 + } 1.236 + InfallibleTArray<uint8_t> arr; 1.237 + arr.SwapElements(fallibleArr); 1.238 + data = SendableData(arr); 1.239 + 1.240 + } else { 1.241 + nsDependentJSString name; 1.242 + 1.243 + JS::Rooted<JS::Value> val(aCx); 1.244 + if (!JS_GetProperty(aCx, obj, "name", &val)) { 1.245 + NS_ERROR("No name property on supposed error object"); 1.246 + } else if (JSVAL_IS_STRING(val)) { 1.247 + if (!name.init(aCx, JSVAL_TO_STRING(val))) { 1.248 + NS_WARNING("couldn't initialize string"); 1.249 + } 1.250 + } 1.251 + 1.252 + data = TCPError(name); 1.253 + } 1.254 + } else { 1.255 + NS_ERROR("Unexpected JS value encountered"); 1.256 + FireInteralError(this, __LINE__); 1.257 + return NS_ERROR_FAILURE; 1.258 + } 1.259 + mozilla::unused << 1.260 + PTCPSocketParent::SendCallback(nsString(aType), data, 1.261 + nsString(aReadyState)); 1.262 + return NS_OK; 1.263 +} 1.264 + 1.265 +NS_IMETHODIMP 1.266 +TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket, 1.267 + nsITCPSocketIntermediary *intermediary, 1.268 + JSContext* cx) 1.269 +{ 1.270 + mSocket = socket; 1.271 + mIntermediary = intermediary; 1.272 + return NS_OK; 1.273 +} 1.274 + 1.275 +NS_IMETHODIMP 1.276 +TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount, 1.277 + uint32_t aTrackingNumber) 1.278 +{ 1.279 + mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount, 1.280 + aTrackingNumber); 1.281 + return NS_OK; 1.282 +} 1.283 + 1.284 +void 1.285 +TCPSocketParent::ActorDestroy(ActorDestroyReason why) 1.286 +{ 1.287 + if (mSocket) { 1.288 + mSocket->Close(); 1.289 + } 1.290 + mSocket = nullptr; 1.291 + mIntermediaryObj = nullptr; 1.292 + mIntermediary = nullptr; 1.293 +} 1.294 + 1.295 +bool 1.296 +TCPSocketParent::RecvRequestDelete() 1.297 +{ 1.298 + mozilla::unused << Send__delete__(this); 1.299 + return true; 1.300 +} 1.301 + 1.302 +} // namespace dom 1.303 +} // namespace mozilla