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 : }
|