dom/network/src/TCPSocketParent.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:8f102695c424
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/. */
4
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"
18
19 namespace IPC {
20
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);
26
27 }
28
29 namespace mozilla {
30 namespace dom {
31
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 }
40
41 NS_IMPL_CYCLE_COLLECTION(TCPSocketParentBase, mSocket, mIntermediary)
42 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
43 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
44
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
49
50 TCPSocketParentBase::TCPSocketParentBase()
51 : mIPCOpen(false)
52 {
53 }
54
55 TCPSocketParentBase::~TCPSocketParentBase()
56 {
57 }
58
59 void
60 TCPSocketParentBase::ReleaseIPDLReference()
61 {
62 MOZ_ASSERT(mIPCOpen);
63 mIPCOpen = false;
64 this->Release();
65 }
66
67 void
68 TCPSocketParentBase::AddIPDLReference()
69 {
70 MOZ_ASSERT(!mIPCOpen);
71 mIPCOpen = true;
72 this->AddRef();
73 }
74
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 }
84
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 }
96
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 }
105
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 }
112
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 }
119
120 return true;
121 }
122
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 }
130
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 }
139
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 }
148
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 }
157
158 bool
159 TCPSocketParent::RecvData(const SendableData& aData,
160 const uint32_t& aTrackingNumber)
161 {
162 NS_ENSURE_TRUE(mIntermediary, true);
163
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 }
176
177 case SendableData::TnsString:
178 rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
179 NS_ENSURE_SUCCESS(rv, true);
180 break;
181
182 default:
183 MOZ_CRASH("unexpected SendableData type");
184 }
185 return true;
186 }
187
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 }
196
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 }
205
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);
215
216 } else if (aDataVal.isUndefined() || aDataVal.isNull()) {
217 data = mozilla::void_t();
218
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);
236
237 } else {
238 nsDependentJSString name;
239
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 }
248
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 }
261
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 }
271
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 }
280
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 }
291
292 bool
293 TCPSocketParent::RecvRequestDelete()
294 {
295 mozilla::unused << Send__delete__(this);
296 return true;
297 }
298
299 } // namespace dom
300 } // namespace mozilla

mercurial