netwerk/protocol/ftp/FTPChannelChild.cpp

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:30018d2f2d2e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "mozilla/net/NeckoChild.h"
9 #include "mozilla/net/ChannelDiverterChild.h"
10 #include "mozilla/net/FTPChannelChild.h"
11 #include "mozilla/dom/TabChild.h"
12 #include "nsFtpProtocolHandler.h"
13 #include "nsITabChild.h"
14 #include "nsStringStream.h"
15 #include "nsNetUtil.h"
16 #include "base/compiler_specific.h"
17 #include "mozilla/ipc/InputStreamUtils.h"
18 #include "mozilla/ipc/URIUtils.h"
19 #include "SerializedLoadContext.h"
20
21 using namespace mozilla::ipc;
22
23 #undef LOG
24 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
25
26 namespace mozilla {
27 namespace net {
28
29 FTPChannelChild::FTPChannelChild(nsIURI* uri)
30 : mIPCOpen(false)
31 , mCanceled(false)
32 , mSuspendCount(0)
33 , mIsPending(false)
34 , mWasOpened(false)
35 , mLastModifiedTime(0)
36 , mStartPos(0)
37 , mDivertingToParent(false)
38 , mFlushedForDiversion(false)
39 , mSuspendSent(false)
40 {
41 LOG(("Creating FTPChannelChild @%x\n", this));
42 // grab a reference to the handler to ensure that it doesn't go away.
43 NS_ADDREF(gFtpHandler);
44 SetURI(uri);
45 mEventQ = new ChannelEventQueue(static_cast<nsIFTPChannel*>(this));
46 }
47
48 FTPChannelChild::~FTPChannelChild()
49 {
50 LOG(("Destroying FTPChannelChild @%x\n", this));
51 gFtpHandler->Release();
52 }
53
54 void
55 FTPChannelChild::AddIPDLReference()
56 {
57 NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
58 mIPCOpen = true;
59 AddRef();
60 }
61
62 void
63 FTPChannelChild::ReleaseIPDLReference()
64 {
65 NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
66 mIPCOpen = false;
67 Release();
68 }
69
70 //-----------------------------------------------------------------------------
71 // FTPChannelChild::nsISupports
72 //-----------------------------------------------------------------------------
73
74 NS_IMPL_ISUPPORTS_INHERITED(FTPChannelChild,
75 nsBaseChannel,
76 nsIFTPChannel,
77 nsIUploadChannel,
78 nsIResumableChannel,
79 nsIProxiedChannel,
80 nsIChildChannel,
81 nsIDivertableChannel)
82
83 //-----------------------------------------------------------------------------
84
85 NS_IMETHODIMP
86 FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
87 {
88 *lastModifiedTime = mLastModifiedTime;
89 return NS_OK;
90 }
91
92 NS_IMETHODIMP
93 FTPChannelChild::SetLastModifiedTime(PRTime lastModifiedTime)
94 {
95 return NS_ERROR_NOT_AVAILABLE;
96 }
97
98 NS_IMETHODIMP
99 FTPChannelChild::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
100 {
101 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
102 mStartPos = aStartPos;
103 mEntityID = aEntityID;
104 return NS_OK;
105 }
106
107 NS_IMETHODIMP
108 FTPChannelChild::GetEntityID(nsACString& entityID)
109 {
110 entityID = mEntityID;
111 return NS_OK;
112 }
113
114 NS_IMETHODIMP
115 FTPChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo)
116 {
117 DROP_DEAD();
118 }
119
120 NS_IMETHODIMP
121 FTPChannelChild::SetUploadStream(nsIInputStream* stream,
122 const nsACString& contentType,
123 int64_t contentLength)
124 {
125 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
126 mUploadStream = stream;
127 // NOTE: contentLength is intentionally ignored here.
128 return NS_OK;
129 }
130
131 NS_IMETHODIMP
132 FTPChannelChild::GetUploadStream(nsIInputStream** stream)
133 {
134 NS_ENSURE_ARG_POINTER(stream);
135 *stream = mUploadStream;
136 NS_IF_ADDREF(*stream);
137 return NS_OK;
138 }
139
140 //-----------------------------------------------------------------------------
141
142 NS_IMETHODIMP
143 FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
144 {
145 LOG(("FTPChannelChild::AsyncOpen [this=%p]\n", this));
146
147 NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
148 NS_ENSURE_ARG_POINTER(listener);
149 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
150 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
151
152 // Port checked in parent, but duplicate here so we can return with error
153 // immediately, as we've done since before e10s.
154 nsresult rv;
155 rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
156 // because in the child ipdl,
157 // a typedef URI is defined...
158 if (NS_FAILED(rv))
159 return rv;
160
161 mozilla::dom::TabChild* tabChild = nullptr;
162 nsCOMPtr<nsITabChild> iTabChild;
163 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
164 NS_GET_IID(nsITabChild),
165 getter_AddRefs(iTabChild));
166 GetCallback(iTabChild);
167 if (iTabChild) {
168 tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
169 }
170 if (MissingRequiredTabChild(tabChild, "ftp")) {
171 return NS_ERROR_ILLEGAL_VALUE;
172 }
173
174 mListener = listener;
175 mListenerContext = aContext;
176
177 // add ourselves to the load group.
178 if (mLoadGroup)
179 mLoadGroup->AddRequest(this, nullptr);
180
181 OptionalInputStreamParams uploadStream;
182 nsTArray<mozilla::ipc::FileDescriptor> fds;
183 SerializeInputStream(mUploadStream, uploadStream, fds);
184
185 MOZ_ASSERT(fds.IsEmpty());
186
187 FTPChannelOpenArgs openArgs;
188 SerializeURI(nsBaseChannel::URI(), openArgs.uri());
189 openArgs.startPos() = mStartPos;
190 openArgs.entityID() = mEntityID;
191 openArgs.uploadStream() = uploadStream;
192
193 gNeckoChild->
194 SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this),
195 openArgs);
196
197 // The socket transport layer in the chrome process now has a logical ref to
198 // us until OnStopRequest is called.
199 AddIPDLReference();
200
201 mIsPending = true;
202 mWasOpened = true;
203
204 return rv;
205 }
206
207 NS_IMETHODIMP
208 FTPChannelChild::IsPending(bool* result)
209 {
210 *result = mIsPending;
211 return NS_OK;
212 }
213
214 nsresult
215 FTPChannelChild::OpenContentStream(bool async,
216 nsIInputStream** stream,
217 nsIChannel** channel)
218 {
219 NS_RUNTIMEABORT("FTPChannel*Child* should never have OpenContentStream called!");
220 return NS_OK;
221 }
222
223 //-----------------------------------------------------------------------------
224 // FTPChannelChild::PFTPChannelChild
225 //-----------------------------------------------------------------------------
226
227 class FTPStartRequestEvent : public ChannelEvent
228 {
229 public:
230 FTPStartRequestEvent(FTPChannelChild* aChild,
231 const nsresult& aChannelStatus,
232 const int64_t& aContentLength,
233 const nsCString& aContentType,
234 const PRTime& aLastModified,
235 const nsCString& aEntityID,
236 const URIParams& aURI)
237 : mChild(aChild)
238 , mChannelStatus(aChannelStatus)
239 , mContentLength(aContentLength)
240 , mContentType(aContentType)
241 , mLastModified(aLastModified)
242 , mEntityID(aEntityID)
243 , mURI(aURI)
244 {
245 }
246 void Run()
247 {
248 mChild->DoOnStartRequest(mChannelStatus, mContentLength, mContentType,
249 mLastModified, mEntityID, mURI);
250 }
251
252 private:
253 FTPChannelChild* mChild;
254 nsresult mChannelStatus;
255 int64_t mContentLength;
256 nsCString mContentType;
257 PRTime mLastModified;
258 nsCString mEntityID;
259 URIParams mURI;
260 };
261
262 bool
263 FTPChannelChild::RecvOnStartRequest(const nsresult& aChannelStatus,
264 const int64_t& aContentLength,
265 const nsCString& aContentType,
266 const PRTime& aLastModified,
267 const nsCString& aEntityID,
268 const URIParams& aURI)
269 {
270 // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
271 // stage, as they are set in the listener's OnStartRequest.
272 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
273 "mFlushedForDiversion should be unset before OnStartRequest!");
274 MOZ_RELEASE_ASSERT(!mDivertingToParent,
275 "mDivertingToParent should be unset before OnStartRequest!");
276
277 if (mEventQ->ShouldEnqueue()) {
278 mEventQ->Enqueue(new FTPStartRequestEvent(this, aChannelStatus,
279 aContentLength, aContentType,
280 aLastModified, aEntityID, aURI));
281 } else {
282 DoOnStartRequest(aChannelStatus, aContentLength, aContentType,
283 aLastModified, aEntityID, aURI);
284 }
285 return true;
286 }
287
288 void
289 FTPChannelChild::DoOnStartRequest(const nsresult& aChannelStatus,
290 const int64_t& aContentLength,
291 const nsCString& aContentType,
292 const PRTime& aLastModified,
293 const nsCString& aEntityID,
294 const URIParams& aURI)
295 {
296 LOG(("FTPChannelChild::RecvOnStartRequest [this=%p]\n", this));
297
298 // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
299 // stage, as they are set in the listener's OnStartRequest.
300 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
301 "mFlushedForDiversion should be unset before OnStartRequest!");
302 MOZ_RELEASE_ASSERT(!mDivertingToParent,
303 "mDivertingToParent should be unset before OnStartRequest!");
304
305 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
306 mStatus = aChannelStatus;
307 }
308
309 mContentLength = aContentLength;
310 SetContentType(aContentType);
311 mLastModifiedTime = aLastModified;
312 mEntityID = aEntityID;
313
314 nsCString spec;
315 nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
316 uri->GetSpec(spec);
317 nsBaseChannel::URI()->SetSpec(spec);
318
319 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
320 nsresult rv = mListener->OnStartRequest(this, mListenerContext);
321 if (NS_FAILED(rv))
322 Cancel(rv);
323
324 if (mDivertingToParent) {
325 mListener = nullptr;
326 mListenerContext = nullptr;
327 if (mLoadGroup) {
328 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
329 }
330 }
331 }
332
333 class FTPDataAvailableEvent : public ChannelEvent
334 {
335 public:
336 FTPDataAvailableEvent(FTPChannelChild* aChild,
337 const nsresult& aChannelStatus,
338 const nsCString& aData,
339 const uint64_t& aOffset,
340 const uint32_t& aCount)
341 : mChild(aChild)
342 , mChannelStatus(aChannelStatus)
343 , mData(aData)
344 , mOffset(aOffset)
345 , mCount(aCount)
346 {
347 }
348 void Run()
349 {
350 mChild->DoOnDataAvailable(mChannelStatus, mData, mOffset, mCount);
351 }
352
353 private:
354 FTPChannelChild* mChild;
355 nsresult mChannelStatus;
356 nsCString mData;
357 uint64_t mOffset;
358 uint32_t mCount;
359 };
360
361 bool
362 FTPChannelChild::RecvOnDataAvailable(const nsresult& channelStatus,
363 const nsCString& data,
364 const uint64_t& offset,
365 const uint32_t& count)
366 {
367 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
368 "Should not be receiving any more callbacks from parent!");
369
370 if (mEventQ->ShouldEnqueue()) {
371 mEventQ->Enqueue(
372 new FTPDataAvailableEvent(this, channelStatus, data, offset, count));
373 } else {
374 MOZ_RELEASE_ASSERT(!mDivertingToParent,
375 "ShouldEnqueue when diverting to parent!");
376
377 DoOnDataAvailable(channelStatus, data, offset, count);
378 }
379 return true;
380 }
381
382 void
383 FTPChannelChild::DoOnDataAvailable(const nsresult& channelStatus,
384 const nsCString& data,
385 const uint64_t& offset,
386 const uint32_t& count)
387 {
388 LOG(("FTPChannelChild::RecvOnDataAvailable [this=%p]\n", this));
389
390 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
391 mStatus = channelStatus;
392 }
393
394 if (mDivertingToParent) {
395 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
396 "Should not be processing any more callbacks from parent!");
397
398 SendDivertOnDataAvailable(data, offset, count);
399 return;
400 }
401
402 if (mCanceled)
403 return;
404
405 // NOTE: the OnDataAvailable contract requires the client to read all the data
406 // in the inputstream. This code relies on that ('data' will go away after
407 // this function). Apparently the previous, non-e10s behavior was to actually
408 // support only reading part of the data, allowing later calls to read the
409 // rest.
410 nsCOMPtr<nsIInputStream> stringStream;
411 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
412 data.get(),
413 count,
414 NS_ASSIGNMENT_DEPEND);
415 if (NS_FAILED(rv)) {
416 Cancel(rv);
417 return;
418 }
419
420 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
421 rv = mListener->OnDataAvailable(this, mListenerContext,
422 stringStream, offset, count);
423 if (NS_FAILED(rv))
424 Cancel(rv);
425 stringStream->Close();
426 }
427
428 class FTPStopRequestEvent : public ChannelEvent
429 {
430 public:
431 FTPStopRequestEvent(FTPChannelChild* aChild,
432 const nsresult& aChannelStatus)
433 : mChild(aChild)
434 , mChannelStatus(aChannelStatus)
435 {
436 }
437 void Run()
438 {
439 mChild->DoOnStopRequest(mChannelStatus);
440 }
441
442 private:
443 FTPChannelChild* mChild;
444 nsresult mChannelStatus;
445 };
446
447 bool
448 FTPChannelChild::RecvOnStopRequest(const nsresult& aChannelStatus)
449 {
450 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
451 "Should not be receiving any more callbacks from parent!");
452
453 if (mEventQ->ShouldEnqueue()) {
454 mEventQ->Enqueue(new FTPStopRequestEvent(this, aChannelStatus));
455 } else {
456 DoOnStopRequest(aChannelStatus);
457 }
458 return true;
459 }
460
461 void
462 FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus)
463 {
464 LOG(("FTPChannelChild::RecvOnStopRequest [this=%p status=%u]\n",
465 this, aChannelStatus));
466
467 if (mDivertingToParent) {
468 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
469 "Should not be processing any more callbacks from parent!");
470
471 SendDivertOnStopRequest(aChannelStatus);
472 return;
473 }
474
475 if (!mCanceled)
476 mStatus = aChannelStatus;
477
478 { // Ensure that all queued ipdl events are dispatched before
479 // we initiate protocol deletion below.
480 mIsPending = false;
481 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
482 (void)mListener->OnStopRequest(this, mListenerContext, aChannelStatus);
483 mListener = nullptr;
484 mListenerContext = nullptr;
485
486 if (mLoadGroup)
487 mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
488 }
489
490 // This calls NeckoChild::DeallocPFTPChannelChild(), which deletes |this| if IPDL
491 // holds the last reference. Don't rely on |this| existing after here!
492 Send__delete__(this);
493 }
494
495 class FTPFailedAsyncOpenEvent : public ChannelEvent
496 {
497 public:
498 FTPFailedAsyncOpenEvent(FTPChannelChild* aChild, nsresult aStatus)
499 : mChild(aChild), mStatus(aStatus) {}
500 void Run() { mChild->DoFailedAsyncOpen(mStatus); }
501 private:
502 FTPChannelChild* mChild;
503 nsresult mStatus;
504 };
505
506 bool
507 FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode)
508 {
509 if (mEventQ->ShouldEnqueue()) {
510 mEventQ->Enqueue(new FTPFailedAsyncOpenEvent(this, statusCode));
511 } else {
512 DoFailedAsyncOpen(statusCode);
513 }
514 return true;
515 }
516
517 void
518 FTPChannelChild::DoFailedAsyncOpen(const nsresult& statusCode)
519 {
520 mStatus = statusCode;
521
522 if (mLoadGroup)
523 mLoadGroup->RemoveRequest(this, nullptr, statusCode);
524
525 if (mListener) {
526 mListener->OnStartRequest(this, mListenerContext);
527 mIsPending = false;
528 mListener->OnStopRequest(this, mListenerContext, statusCode);
529 } else {
530 mIsPending = false;
531 }
532
533 mListener = nullptr;
534 mListenerContext = nullptr;
535
536 if (mIPCOpen)
537 Send__delete__(this);
538 }
539
540 class FTPFlushedForDiversionEvent : public ChannelEvent
541 {
542 public:
543 FTPFlushedForDiversionEvent(FTPChannelChild* aChild)
544 : mChild(aChild)
545 {
546 MOZ_RELEASE_ASSERT(aChild);
547 }
548
549 void Run()
550 {
551 mChild->FlushedForDiversion();
552 }
553 private:
554 FTPChannelChild* mChild;
555 };
556
557 bool
558 FTPChannelChild::RecvFlushedForDiversion()
559 {
560 MOZ_ASSERT(mDivertingToParent);
561
562 if (mEventQ->ShouldEnqueue()) {
563 mEventQ->Enqueue(new FTPFlushedForDiversionEvent(this));
564 } else {
565 MOZ_CRASH();
566 }
567 return true;
568 }
569
570 void
571 FTPChannelChild::FlushedForDiversion()
572 {
573 MOZ_RELEASE_ASSERT(mDivertingToParent);
574
575 // Once this is set, it should not be unset before FTPChannelChild is taken
576 // down. After it is set, no OnStart/OnData/OnStop callbacks should be
577 // received from the parent channel, nor dequeued from the ChannelEventQueue.
578 mFlushedForDiversion = true;
579
580 SendDivertComplete();
581 }
582
583 bool
584 FTPChannelChild::RecvDivertMessages()
585 {
586 MOZ_RELEASE_ASSERT(mDivertingToParent);
587 MOZ_RELEASE_ASSERT(mSuspendCount > 0);
588
589 // DivertTo() has been called on parent, so we can now start sending queued
590 // IPDL messages back to parent listener.
591 if (NS_WARN_IF(NS_FAILED(Resume()))) {
592 return false;
593 }
594 return true;
595 }
596
597 class FTPDeleteSelfEvent : public ChannelEvent
598 {
599 public:
600 FTPDeleteSelfEvent(FTPChannelChild* aChild)
601 : mChild(aChild) {}
602 void Run() { mChild->DoDeleteSelf(); }
603 private:
604 FTPChannelChild* mChild;
605 };
606
607 bool
608 FTPChannelChild::RecvDeleteSelf()
609 {
610 if (mEventQ->ShouldEnqueue()) {
611 mEventQ->Enqueue(new FTPDeleteSelfEvent(this));
612 } else {
613 DoDeleteSelf();
614 }
615 return true;
616 }
617
618 void
619 FTPChannelChild::DoDeleteSelf()
620 {
621 if (mIPCOpen)
622 Send__delete__(this);
623 }
624
625 NS_IMETHODIMP
626 FTPChannelChild::Cancel(nsresult status)
627 {
628 if (mCanceled)
629 return NS_OK;
630
631 mCanceled = true;
632 mStatus = status;
633 if (mIPCOpen)
634 SendCancel(status);
635 return NS_OK;
636 }
637
638 NS_IMETHODIMP
639 FTPChannelChild::Suspend()
640 {
641 NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
642
643 // SendSuspend only once, when suspend goes from 0 to 1.
644 // Don't SendSuspend at all if we're diverting callbacks to the parent;
645 // suspend will be called at the correct time in the parent itself.
646 if (!mSuspendCount++ && !mDivertingToParent) {
647 SendSuspend();
648 mSuspendSent = true;
649 }
650 mEventQ->Suspend();
651
652 return NS_OK;
653 }
654
655 NS_IMETHODIMP
656 FTPChannelChild::Resume()
657 {
658 NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
659
660 // SendResume only once, when suspend count drops to 0.
661 // Don't SendResume at all if we're diverting callbacks to the parent (unless
662 // suspend was sent earlier); otherwise, resume will be called at the correct
663 // time in the parent itself.
664 if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
665 SendResume();
666 }
667 mEventQ->Resume();
668
669 return NS_OK;
670 }
671
672 //-----------------------------------------------------------------------------
673 // FTPChannelChild::nsIChildChannel
674 //-----------------------------------------------------------------------------
675
676 NS_IMETHODIMP
677 FTPChannelChild::ConnectParent(uint32_t id)
678 {
679 mozilla::dom::TabChild* tabChild = nullptr;
680 nsCOMPtr<nsITabChild> iTabChild;
681 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
682 NS_GET_IID(nsITabChild),
683 getter_AddRefs(iTabChild));
684 GetCallback(iTabChild);
685 if (iTabChild) {
686 tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
687 }
688
689 // The socket transport in the chrome process now holds a logical ref to us
690 // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
691 AddIPDLReference();
692
693 FTPChannelConnectArgs connectArgs(id);
694
695 if (!gNeckoChild->SendPFTPChannelConstructor(this, tabChild,
696 IPC::SerializedLoadContext(this),
697 connectArgs)) {
698 return NS_ERROR_FAILURE;
699 }
700
701 return NS_OK;
702 }
703
704 NS_IMETHODIMP
705 FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
706 nsISupports *aContext)
707 {
708 LOG(("FTPChannelChild::CompleteRedirectSetup [this=%p]\n", this));
709
710 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
711 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
712
713 mIsPending = true;
714 mWasOpened = true;
715 mListener = listener;
716 mListenerContext = aContext;
717
718 // add ourselves to the load group.
719 if (mLoadGroup)
720 mLoadGroup->AddRequest(this, nullptr);
721
722 // We already have an open IPDL connection to the parent. If on-modify-request
723 // listeners or load group observers canceled us, let the parent handle it
724 // and send it back to us naturally.
725 return NS_OK;
726 }
727
728 //-----------------------------------------------------------------------------
729 // FTPChannelChild::nsIDivertableChannel
730 //-----------------------------------------------------------------------------
731 NS_IMETHODIMP
732 FTPChannelChild::DivertToParent(ChannelDiverterChild **aChild)
733 {
734 MOZ_RELEASE_ASSERT(aChild);
735 MOZ_RELEASE_ASSERT(gNeckoChild);
736 MOZ_RELEASE_ASSERT(!mDivertingToParent);
737
738 // We must fail DivertToParent() if there's no parent end of the channel (and
739 // won't be!) due to early failure.
740 if (NS_FAILED(mStatus) && !mIPCOpen) {
741 return mStatus;
742 }
743
744 nsresult rv = Suspend();
745 if (NS_WARN_IF(NS_FAILED(rv))) {
746 return rv;
747 }
748
749 // Once this is set, it should not be unset before the child is taken down.
750 mDivertingToParent = true;
751
752 PChannelDiverterChild* diverter =
753 gNeckoChild->SendPChannelDiverterConstructor(this);
754 MOZ_RELEASE_ASSERT(diverter);
755
756 *aChild = static_cast<ChannelDiverterChild*>(diverter);
757
758 return NS_OK;
759 }
760
761 } // namespace net
762 } // namespace mozilla
763

mercurial