Line data Source code
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/FTPChannelParent.h"
9 : #include "nsStringStream.h"
10 : #include "mozilla/net/ChannelEventQueue.h"
11 : #include "mozilla/dom/TabParent.h"
12 : #include "nsFTPChannel.h"
13 : #include "nsNetCID.h"
14 : #include "nsNetUtil.h"
15 : #include "nsQueryObject.h"
16 : #include "nsFtpProtocolHandler.h"
17 : #include "nsIAuthPrompt.h"
18 : #include "nsIAuthPromptProvider.h"
19 : #include "nsIEncodedChannel.h"
20 : #include "nsIHttpChannelInternal.h"
21 : #include "nsIForcePendingChannel.h"
22 : #include "mozilla/ipc/IPCStreamUtils.h"
23 : #include "mozilla/ipc/URIUtils.h"
24 : #include "mozilla/Unused.h"
25 : #include "SerializedLoadContext.h"
26 : #include "nsIContentPolicy.h"
27 : #include "mozilla/ipc/BackgroundUtils.h"
28 : #include "mozilla/LoadInfo.h"
29 : #include "mozilla/dom/ContentParent.h"
30 :
31 : using namespace mozilla::dom;
32 : using namespace mozilla::ipc;
33 :
34 : #undef LOG
35 : #define LOG(args) MOZ_LOG(gFTPLog, mozilla::LogLevel::Debug, args)
36 :
37 : namespace mozilla {
38 : namespace net {
39 :
40 0 : FTPChannelParent::FTPChannelParent(const PBrowserOrId& aIframeEmbedding,
41 : nsILoadContext* aLoadContext,
42 0 : PBOverrideStatus aOverrideStatus)
43 : : mIPCClosed(false)
44 : , mLoadContext(aLoadContext)
45 : , mPBOverride(aOverrideStatus)
46 : , mStatus(NS_OK)
47 : , mDivertingFromChild(false)
48 : , mDivertedOnStartRequest(false)
49 : , mSuspendedForDiversion(false)
50 0 : , mUseUTF8(false)
51 : {
52 : nsIProtocolHandler* handler;
53 0 : CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler);
54 0 : MOZ_ASSERT(handler, "no ftp handler");
55 :
56 0 : if (aIframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
57 0 : mTabParent = static_cast<dom::TabParent*>(aIframeEmbedding.get_PBrowserParent());
58 : }
59 :
60 0 : mEventQ = new ChannelEventQueue(static_cast<nsIParentChannel*>(this));
61 0 : }
62 :
63 0 : FTPChannelParent::~FTPChannelParent()
64 : {
65 0 : gFtpHandler->Release();
66 0 : }
67 :
68 : void
69 0 : FTPChannelParent::ActorDestroy(ActorDestroyReason why)
70 : {
71 : // We may still have refcount>0 if the channel hasn't called OnStopRequest
72 : // yet, but we must not send any more msgs to child.
73 0 : mIPCClosed = true;
74 0 : }
75 :
76 : //-----------------------------------------------------------------------------
77 : // FTPChannelParent::nsISupports
78 : //-----------------------------------------------------------------------------
79 :
80 0 : NS_IMPL_ISUPPORTS(FTPChannelParent,
81 : nsIStreamListener,
82 : nsIParentChannel,
83 : nsIInterfaceRequestor,
84 : nsIRequestObserver,
85 : nsIChannelEventSink,
86 : nsIFTPChannelParentInternal)
87 :
88 : //-----------------------------------------------------------------------------
89 : // FTPChannelParent::PFTPChannelParent
90 : //-----------------------------------------------------------------------------
91 :
92 : //-----------------------------------------------------------------------------
93 : // FTPChannelParent methods
94 : //-----------------------------------------------------------------------------
95 :
96 : bool
97 0 : FTPChannelParent::Init(const FTPChannelCreationArgs& aArgs)
98 : {
99 0 : switch (aArgs.type()) {
100 : case FTPChannelCreationArgs::TFTPChannelOpenArgs:
101 : {
102 0 : const FTPChannelOpenArgs& a = aArgs.get_FTPChannelOpenArgs();
103 0 : return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream(),
104 0 : a.loadInfo());
105 : }
106 : case FTPChannelCreationArgs::TFTPChannelConnectArgs:
107 : {
108 0 : const FTPChannelConnectArgs& cArgs = aArgs.get_FTPChannelConnectArgs();
109 0 : return ConnectChannel(cArgs.channelId());
110 : }
111 : default:
112 0 : NS_NOTREACHED("unknown open type");
113 0 : return false;
114 : }
115 : }
116 :
117 : bool
118 0 : FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
119 : const uint64_t& aStartPos,
120 : const nsCString& aEntityID,
121 : const OptionalIPCStream& aUploadStream,
122 : const OptionalLoadInfoArgs& aLoadInfoArgs)
123 : {
124 : nsresult rv;
125 :
126 0 : nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
127 0 : if (!uri)
128 0 : return false;
129 :
130 : #ifdef DEBUG
131 0 : LOG(("FTPChannelParent DoAsyncOpen [this=%p uri=%s]\n",
132 : this, uri->GetSpecOrDefault().get()));
133 : #endif
134 :
135 0 : nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
136 0 : if (NS_FAILED(rv)) {
137 0 : return SendFailedAsyncOpen(rv);
138 : }
139 :
140 0 : nsCOMPtr<nsILoadInfo> loadInfo;
141 0 : rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs,
142 0 : getter_AddRefs(loadInfo));
143 0 : if (NS_FAILED(rv)) {
144 0 : return SendFailedAsyncOpen(rv);
145 : }
146 :
147 0 : OriginAttributes attrs;
148 0 : rv = loadInfo->GetOriginAttributes(&attrs);
149 0 : if (NS_FAILED(rv)) {
150 0 : return SendFailedAsyncOpen(rv);
151 : }
152 :
153 0 : nsCOMPtr<nsIChannel> chan;
154 0 : rv = NS_NewChannelInternal(getter_AddRefs(chan), uri, loadInfo,
155 : nullptr, nullptr,
156 : nsIRequest::LOAD_NORMAL, ios);
157 :
158 0 : if (NS_FAILED(rv))
159 0 : return SendFailedAsyncOpen(rv);
160 :
161 0 : mChannel = chan;
162 :
163 : // later on mChannel may become an HTTP channel (we'll be redirected to one
164 : // if we're using a proxy), but for now this is safe
165 0 : nsFtpChannel* ftpChan = static_cast<nsFtpChannel*>(mChannel.get());
166 :
167 0 : if (mPBOverride != kPBOverride_Unset) {
168 0 : ftpChan->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
169 : }
170 0 : rv = ftpChan->SetNotificationCallbacks(this);
171 0 : if (NS_FAILED(rv))
172 0 : return SendFailedAsyncOpen(rv);
173 :
174 0 : nsCOMPtr<nsIInputStream> upload = DeserializeIPCStream(aUploadStream);
175 0 : if (upload) {
176 : // contentType and contentLength are ignored
177 0 : rv = ftpChan->SetUploadStream(upload, EmptyCString(), 0);
178 0 : if (NS_FAILED(rv))
179 0 : return SendFailedAsyncOpen(rv);
180 : }
181 :
182 0 : rv = ftpChan->ResumeAt(aStartPos, aEntityID);
183 0 : if (NS_FAILED(rv))
184 0 : return SendFailedAsyncOpen(rv);
185 :
186 0 : if (loadInfo && loadInfo->GetEnforceSecurity()) {
187 0 : rv = ftpChan->AsyncOpen2(this);
188 : }
189 : else {
190 0 : rv = ftpChan->AsyncOpen(this, nullptr);
191 : }
192 :
193 0 : if (NS_FAILED(rv))
194 0 : return SendFailedAsyncOpen(rv);
195 :
196 0 : return true;
197 : }
198 :
199 : bool
200 0 : FTPChannelParent::ConnectChannel(const uint32_t& channelId)
201 : {
202 : nsresult rv;
203 :
204 0 : LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId));
205 :
206 0 : nsCOMPtr<nsIChannel> channel;
207 0 : rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
208 0 : if (NS_SUCCEEDED(rv))
209 0 : mChannel = channel;
210 :
211 0 : LOG((" found channel %p, rv=%08" PRIx32, mChannel.get(), static_cast<uint32_t>(rv)));
212 :
213 0 : return true;
214 : }
215 :
216 : mozilla::ipc::IPCResult
217 0 : FTPChannelParent::RecvCancel(const nsresult& status)
218 : {
219 0 : if (mChannel)
220 0 : mChannel->Cancel(status);
221 :
222 0 : return IPC_OK();
223 : }
224 :
225 : mozilla::ipc::IPCResult
226 0 : FTPChannelParent::RecvSuspend()
227 : {
228 0 : if (mChannel) {
229 0 : SuspendChannel();
230 : }
231 0 : return IPC_OK();
232 : }
233 :
234 : mozilla::ipc::IPCResult
235 0 : FTPChannelParent::RecvResume()
236 : {
237 0 : if (mChannel) {
238 0 : ResumeChannel();
239 : }
240 0 : return IPC_OK();
241 : }
242 :
243 0 : class FTPDivertDataAvailableEvent : public MainThreadChannelEvent
244 : {
245 : public:
246 0 : FTPDivertDataAvailableEvent(FTPChannelParent* aParent,
247 : const nsCString& data,
248 : const uint64_t& offset,
249 : const uint32_t& count)
250 0 : : mParent(aParent)
251 : , mData(data)
252 0 : , mOffset(offset)
253 0 : , mCount(count)
254 : {
255 0 : }
256 :
257 0 : void Run()
258 : {
259 0 : mParent->DivertOnDataAvailable(mData, mOffset, mCount);
260 0 : }
261 :
262 : private:
263 : FTPChannelParent* mParent;
264 : nsCString mData;
265 : uint64_t mOffset;
266 : uint32_t mCount;
267 : };
268 :
269 : mozilla::ipc::IPCResult
270 0 : FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
271 : const uint64_t& offset,
272 : const uint32_t& count)
273 : {
274 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
275 0 : MOZ_ASSERT(mDivertingFromChild,
276 : "Cannot RecvDivertOnDataAvailable if diverting is not set!");
277 0 : FailDiversion(NS_ERROR_UNEXPECTED);
278 0 : return IPC_FAIL_NO_REASON(this);
279 : }
280 :
281 : // Drop OnDataAvailables if the parent was canceled already.
282 0 : if (NS_FAILED(mStatus)) {
283 0 : return IPC_OK();
284 : }
285 :
286 0 : mEventQ->RunOrEnqueue(new FTPDivertDataAvailableEvent(this, data, offset,
287 0 : count));
288 0 : return IPC_OK();
289 : }
290 :
291 : void
292 0 : FTPChannelParent::DivertOnDataAvailable(const nsCString& data,
293 : const uint64_t& offset,
294 : const uint32_t& count)
295 : {
296 0 : LOG(("FTPChannelParent::DivertOnDataAvailable [this=%p]\n", this));
297 :
298 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
299 0 : MOZ_ASSERT(mDivertingFromChild,
300 : "Cannot DivertOnDataAvailable if diverting is not set!");
301 0 : FailDiversion(NS_ERROR_UNEXPECTED);
302 0 : return;
303 : }
304 :
305 : // Drop OnDataAvailables if the parent was canceled already.
306 0 : if (NS_FAILED(mStatus)) {
307 0 : return;
308 : }
309 :
310 0 : nsCOMPtr<nsIInputStream> stringStream;
311 0 : nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
312 0 : count, NS_ASSIGNMENT_DEPEND);
313 0 : if (NS_FAILED(rv)) {
314 0 : if (mChannel) {
315 0 : mChannel->Cancel(rv);
316 : }
317 0 : mStatus = rv;
318 0 : return;
319 : }
320 :
321 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
322 :
323 0 : rv = OnDataAvailable(mChannel, nullptr, stringStream, offset, count);
324 :
325 0 : stringStream->Close();
326 0 : if (NS_FAILED(rv)) {
327 0 : if (mChannel) {
328 0 : mChannel->Cancel(rv);
329 : }
330 0 : mStatus = rv;
331 : }
332 : }
333 :
334 0 : class FTPDivertStopRequestEvent : public MainThreadChannelEvent
335 : {
336 : public:
337 0 : FTPDivertStopRequestEvent(FTPChannelParent* aParent,
338 : const nsresult& statusCode)
339 0 : : mParent(aParent)
340 0 : , mStatusCode(statusCode)
341 : {
342 0 : }
343 :
344 0 : void Run() {
345 0 : mParent->DivertOnStopRequest(mStatusCode);
346 0 : }
347 :
348 : private:
349 : FTPChannelParent* mParent;
350 : nsresult mStatusCode;
351 : };
352 :
353 : mozilla::ipc::IPCResult
354 0 : FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
355 : {
356 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
357 0 : MOZ_ASSERT(mDivertingFromChild,
358 : "Cannot RecvDivertOnStopRequest if diverting is not set!");
359 0 : FailDiversion(NS_ERROR_UNEXPECTED);
360 0 : return IPC_FAIL_NO_REASON(this);
361 : }
362 :
363 0 : mEventQ->RunOrEnqueue(new FTPDivertStopRequestEvent(this, statusCode));
364 0 : return IPC_OK();
365 : }
366 :
367 : void
368 0 : FTPChannelParent::DivertOnStopRequest(const nsresult& statusCode)
369 : {
370 0 : LOG(("FTPChannelParent::DivertOnStopRequest [this=%p]\n", this));
371 :
372 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
373 0 : MOZ_ASSERT(mDivertingFromChild,
374 : "Cannot DivertOnStopRequest if diverting is not set!");
375 0 : FailDiversion(NS_ERROR_UNEXPECTED);
376 0 : return;
377 : }
378 :
379 : // Honor the channel's status even if the underlying transaction completed.
380 0 : nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
381 :
382 : // Reset fake pending status in case OnStopRequest has already been called.
383 0 : if (mChannel) {
384 0 : nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
385 0 : if (forcePendingIChan) {
386 0 : forcePendingIChan->ForcePending(false);
387 : }
388 : }
389 :
390 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
391 0 : OnStopRequest(mChannel, nullptr, status);
392 : }
393 :
394 0 : class FTPDivertCompleteEvent : public MainThreadChannelEvent
395 : {
396 : public:
397 0 : explicit FTPDivertCompleteEvent(FTPChannelParent* aParent)
398 0 : : mParent(aParent)
399 : {
400 0 : }
401 :
402 0 : void Run() {
403 0 : mParent->DivertComplete();
404 0 : }
405 :
406 : private:
407 : FTPChannelParent* mParent;
408 : };
409 :
410 : mozilla::ipc::IPCResult
411 0 : FTPChannelParent::RecvDivertComplete()
412 : {
413 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
414 0 : MOZ_ASSERT(mDivertingFromChild,
415 : "Cannot RecvDivertComplete if diverting is not set!");
416 0 : FailDiversion(NS_ERROR_UNEXPECTED);
417 0 : return IPC_FAIL_NO_REASON(this);
418 : }
419 :
420 0 : mEventQ->RunOrEnqueue(new FTPDivertCompleteEvent(this));
421 0 : return IPC_OK();
422 : }
423 :
424 : void
425 0 : FTPChannelParent::DivertComplete()
426 : {
427 0 : LOG(("FTPChannelParent::DivertComplete [this=%p]\n", this));
428 :
429 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
430 0 : MOZ_ASSERT(mDivertingFromChild,
431 : "Cannot DivertComplete if diverting is not set!");
432 0 : FailDiversion(NS_ERROR_UNEXPECTED);
433 0 : return;
434 : }
435 :
436 0 : nsresult rv = ResumeForDiversion();
437 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
438 0 : FailDiversion(NS_ERROR_UNEXPECTED);
439 : }
440 : }
441 :
442 : //-----------------------------------------------------------------------------
443 : // FTPChannelParent::nsIRequestObserver
444 : //-----------------------------------------------------------------------------
445 :
446 : NS_IMETHODIMP
447 0 : FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
448 : {
449 0 : LOG(("FTPChannelParent::OnStartRequest [this=%p]\n", this));
450 :
451 0 : if (mDivertingFromChild) {
452 0 : MOZ_RELEASE_ASSERT(mDivertToListener,
453 : "Cannot divert if listener is unset!");
454 0 : return mDivertToListener->OnStartRequest(aRequest, aContext);
455 : }
456 :
457 0 : nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest);
458 0 : MOZ_ASSERT(chan);
459 0 : NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
460 :
461 : // Send down any permissions which are relevant to this URL if we are
462 : // performing a document load.
463 0 : PContentParent* pcp = Manager()->Manager();
464 : DebugOnly<nsresult> rv =
465 0 : static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
466 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
467 :
468 : int64_t contentLength;
469 0 : chan->GetContentLength(&contentLength);
470 0 : nsCString contentType;
471 0 : chan->GetContentType(contentType);
472 :
473 0 : nsCString entityID;
474 0 : nsCOMPtr<nsIResumableChannel> resChan = do_QueryInterface(aRequest);
475 0 : MOZ_ASSERT(resChan); // both FTP and HTTP should implement nsIResumableChannel
476 0 : if (resChan) {
477 0 : resChan->GetEntityID(entityID);
478 : }
479 :
480 0 : PRTime lastModified = 0;
481 0 : nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest);
482 0 : if (ftpChan) {
483 0 : ftpChan->GetLastModifiedTime(&lastModified);
484 : }
485 0 : nsCOMPtr<nsIHttpChannelInternal> httpChan = do_QueryInterface(aRequest);
486 0 : if (httpChan) {
487 0 : DebugOnly<nsresult> rv = httpChan->GetLastModifiedTime(&lastModified);
488 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
489 : }
490 :
491 0 : URIParams uriparam;
492 0 : nsCOMPtr<nsIURI> uri;
493 0 : chan->GetURI(getter_AddRefs(uri));
494 0 : SerializeURI(uri, uriparam);
495 :
496 0 : if (mIPCClosed || !SendOnStartRequest(mStatus, contentLength, contentType,
497 : lastModified, entityID, uriparam)) {
498 0 : return NS_ERROR_UNEXPECTED;
499 : }
500 :
501 0 : return NS_OK;
502 : }
503 :
504 : NS_IMETHODIMP
505 0 : FTPChannelParent::OnStopRequest(nsIRequest* aRequest,
506 : nsISupports* aContext,
507 : nsresult aStatusCode)
508 : {
509 0 : LOG(("FTPChannelParent::OnStopRequest: [this=%p status=%" PRIu32 "]\n",
510 : this, static_cast<uint32_t>(aStatusCode)));
511 :
512 0 : if (mDivertingFromChild) {
513 0 : MOZ_RELEASE_ASSERT(mDivertToListener,
514 : "Cannot divert if listener is unset!");
515 0 : return mDivertToListener->OnStopRequest(aRequest, aContext, aStatusCode);
516 : }
517 :
518 0 : if (mIPCClosed || !SendOnStopRequest(aStatusCode, mErrorMsg, mUseUTF8)) {
519 0 : return NS_ERROR_UNEXPECTED;
520 : }
521 :
522 0 : return NS_OK;
523 : }
524 :
525 : //-----------------------------------------------------------------------------
526 : // FTPChannelParent::nsIStreamListener
527 : //-----------------------------------------------------------------------------
528 :
529 : NS_IMETHODIMP
530 0 : FTPChannelParent::OnDataAvailable(nsIRequest* aRequest,
531 : nsISupports* aContext,
532 : nsIInputStream* aInputStream,
533 : uint64_t aOffset,
534 : uint32_t aCount)
535 : {
536 0 : LOG(("FTPChannelParent::OnDataAvailable [this=%p]\n", this));
537 :
538 0 : if (mDivertingFromChild) {
539 0 : MOZ_RELEASE_ASSERT(mDivertToListener,
540 : "Cannot divert if listener is unset!");
541 0 : return mDivertToListener->OnDataAvailable(aRequest, aContext, aInputStream,
542 0 : aOffset, aCount);
543 : }
544 :
545 0 : nsCString data;
546 0 : nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
547 0 : if (NS_FAILED(rv))
548 0 : return rv;
549 :
550 0 : if (mIPCClosed || !SendOnDataAvailable(mStatus, data, aOffset, aCount))
551 0 : return NS_ERROR_UNEXPECTED;
552 :
553 0 : return NS_OK;
554 : }
555 :
556 : //-----------------------------------------------------------------------------
557 : // FTPChannelParent::nsIParentChannel
558 : //-----------------------------------------------------------------------------
559 :
560 : NS_IMETHODIMP
561 0 : FTPChannelParent::SetParentListener(HttpChannelParentListener* aListener)
562 : {
563 : // Do not need ptr to HttpChannelParentListener.
564 0 : return NS_OK;
565 : }
566 :
567 : NS_IMETHODIMP
568 0 : FTPChannelParent::NotifyTrackingProtectionDisabled()
569 : {
570 : // One day, this should probably be filled in.
571 0 : return NS_OK;
572 : }
573 :
574 : NS_IMETHODIMP
575 0 : FTPChannelParent::NotifyTrackingResource()
576 : {
577 : // One day, this should probably be filled in.
578 0 : return NS_OK;
579 : }
580 :
581 : NS_IMETHODIMP
582 0 : FTPChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
583 : const nsACString& aProvider,
584 : const nsACString& aPrefix)
585 : {
586 : // One day, this should probably be filled in.
587 0 : return NS_OK;
588 : }
589 :
590 : NS_IMETHODIMP
591 0 : FTPChannelParent::Delete()
592 : {
593 0 : if (mIPCClosed || !SendDeleteSelf())
594 0 : return NS_ERROR_UNEXPECTED;
595 :
596 0 : return NS_OK;
597 : }
598 :
599 : //-----------------------------------------------------------------------------
600 : // FTPChannelParent::nsIInterfaceRequestor
601 : //-----------------------------------------------------------------------------
602 :
603 : NS_IMETHODIMP
604 0 : FTPChannelParent::GetInterface(const nsIID& uuid, void** result)
605 : {
606 0 : if (uuid.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
607 0 : uuid.Equals(NS_GET_IID(nsISecureBrowserUI))) {
608 0 : if (mTabParent) {
609 0 : return mTabParent->QueryInterface(uuid, result);
610 : }
611 0 : } else if (uuid.Equals(NS_GET_IID(nsIAuthPrompt)) ||
612 0 : uuid.Equals(NS_GET_IID(nsIAuthPrompt2))) {
613 0 : nsCOMPtr<nsIAuthPromptProvider> provider(do_QueryObject(mTabParent));
614 0 : if (provider) {
615 0 : return provider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
616 : uuid,
617 0 : result);
618 : }
619 : }
620 :
621 : // Only support nsILoadContext if child channel's callbacks did too
622 0 : if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
623 0 : nsCOMPtr<nsILoadContext> copy = mLoadContext;
624 0 : copy.forget(result);
625 0 : return NS_OK;
626 : }
627 :
628 0 : return QueryInterface(uuid, result);
629 : }
630 :
631 : nsresult
632 0 : FTPChannelParent::SuspendChannel()
633 : {
634 : nsCOMPtr<nsIChannelWithDivertableParentListener> chan =
635 0 : do_QueryInterface(mChannel);
636 0 : if (chan) {
637 0 : return chan->SuspendInternal();
638 : } else {
639 0 : return mChannel->Suspend();
640 : }
641 : }
642 :
643 : nsresult
644 0 : FTPChannelParent::ResumeChannel()
645 : {
646 : nsCOMPtr<nsIChannelWithDivertableParentListener> chan =
647 0 : do_QueryInterface(mChannel);
648 0 : if (chan) {
649 0 : return chan->ResumeInternal();
650 : } else {
651 0 : return mChannel->Resume();
652 : }
653 : }
654 :
655 : //-----------------------------------------------------------------------------
656 : // FTPChannelParent::ADivertableParentChannel
657 : //-----------------------------------------------------------------------------
658 : nsresult
659 0 : FTPChannelParent::SuspendForDiversion()
660 : {
661 0 : MOZ_ASSERT(mChannel);
662 0 : if (NS_WARN_IF(mDivertingFromChild)) {
663 0 : MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!");
664 0 : return NS_ERROR_UNEXPECTED;
665 : }
666 :
667 : // Try suspending the channel. Allow it to fail, since OnStopRequest may have
668 : // been called and thus the channel may not be pending.
669 0 : nsresult rv = SuspendChannel();
670 0 : MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE);
671 0 : mSuspendedForDiversion = NS_SUCCEEDED(rv);
672 :
673 : // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent
674 : // to the child.
675 0 : mDivertingFromChild = true;
676 :
677 : nsCOMPtr<nsIChannelWithDivertableParentListener> chan =
678 0 : do_QueryInterface(mChannel);
679 0 : if (chan) {
680 0 : chan->MessageDiversionStarted(this);
681 : }
682 :
683 0 : return NS_OK;
684 : }
685 :
686 : /* private, supporting function for ADivertableParentChannel */
687 : nsresult
688 0 : FTPChannelParent::ResumeForDiversion()
689 : {
690 0 : MOZ_ASSERT(mChannel);
691 0 : MOZ_ASSERT(mDivertToListener);
692 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
693 0 : MOZ_ASSERT(mDivertingFromChild,
694 : "Cannot ResumeForDiversion if not diverting!");
695 0 : return NS_ERROR_UNEXPECTED;
696 : }
697 :
698 : nsCOMPtr<nsIChannelWithDivertableParentListener> chan =
699 0 : do_QueryInterface(mChannel);
700 0 : if (chan) {
701 0 : chan->MessageDiversionStop();
702 : }
703 :
704 0 : if (mSuspendedForDiversion) {
705 0 : nsresult rv = ResumeChannel();
706 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
707 0 : FailDiversion(NS_ERROR_UNEXPECTED, true);
708 0 : return rv;
709 : }
710 0 : mSuspendedForDiversion = false;
711 : }
712 :
713 : // Delete() will tear down IPDL, but ref from underlying nsFTPChannel will
714 : // keep us alive if there's more data to be delivered to listener.
715 0 : if (NS_WARN_IF(NS_FAILED(Delete()))) {
716 0 : FailDiversion(NS_ERROR_UNEXPECTED);
717 0 : return NS_ERROR_UNEXPECTED;
718 : }
719 0 : return NS_OK;
720 : }
721 :
722 : nsresult
723 0 : FTPChannelParent::SuspendMessageDiversion()
724 : {
725 : // This only need to suspend message queue.
726 0 : mEventQ->Suspend();
727 0 : return NS_OK;
728 : }
729 :
730 : nsresult
731 0 : FTPChannelParent::ResumeMessageDiversion()
732 : {
733 : // This only need to resumes message queue.
734 0 : mEventQ->Resume();
735 0 : return NS_OK;
736 : }
737 :
738 : void
739 0 : FTPChannelParent::DivertTo(nsIStreamListener *aListener)
740 : {
741 0 : MOZ_ASSERT(aListener);
742 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
743 0 : MOZ_ASSERT(mDivertingFromChild,
744 : "Cannot DivertTo new listener if diverting is not set!");
745 0 : return;
746 : }
747 :
748 0 : if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
749 0 : FailDiversion(NS_ERROR_UNEXPECTED);
750 0 : return;
751 : }
752 :
753 0 : mDivertToListener = aListener;
754 :
755 : // Call OnStartRequest and SendDivertMessages asynchronously to avoid
756 : // reentering client context.
757 0 : NS_DispatchToCurrentThread(
758 0 : NewRunnableMethod("net::FTPChannelParent::StartDiversion",
759 : this,
760 0 : &FTPChannelParent::StartDiversion));
761 0 : return;
762 : }
763 :
764 : void
765 0 : FTPChannelParent::StartDiversion()
766 : {
767 0 : if (NS_WARN_IF(!mDivertingFromChild)) {
768 0 : MOZ_ASSERT(mDivertingFromChild,
769 : "Cannot StartDiversion if diverting is not set!");
770 0 : return;
771 : }
772 :
773 : // Fake pending status in case OnStopRequest has already been called.
774 0 : if (mChannel) {
775 0 : nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
776 0 : if (forcePendingIChan) {
777 0 : forcePendingIChan->ForcePending(true);
778 : }
779 : }
780 :
781 : {
782 0 : AutoEventEnqueuer ensureSerialDispatch(mEventQ);
783 : // Call OnStartRequest for the "DivertTo" listener.
784 0 : nsresult rv = OnStartRequest(mChannel, nullptr);
785 0 : if (NS_FAILED(rv)) {
786 0 : if (mChannel) {
787 0 : mChannel->Cancel(rv);
788 : }
789 0 : mStatus = rv;
790 0 : return;
791 : }
792 : }
793 :
794 : // After OnStartRequest has been called, tell FTPChannelChild to divert the
795 : // OnDataAvailables and OnStopRequest to this FTPChannelParent.
796 0 : if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
797 0 : FailDiversion(NS_ERROR_UNEXPECTED);
798 0 : return;
799 : }
800 : }
801 :
802 0 : class FTPFailDiversionEvent : public Runnable
803 : {
804 : public:
805 0 : FTPFailDiversionEvent(FTPChannelParent* aChannelParent,
806 : nsresult aErrorCode,
807 : bool aSkipResume)
808 0 : : Runnable("net::FTPFailDiversionEvent")
809 : , mChannelParent(aChannelParent)
810 : , mErrorCode(aErrorCode)
811 0 : , mSkipResume(aSkipResume)
812 : {
813 0 : MOZ_RELEASE_ASSERT(aChannelParent);
814 0 : MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
815 0 : }
816 0 : NS_IMETHOD Run() override
817 : {
818 0 : mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume);
819 0 : return NS_OK;
820 : }
821 : private:
822 : RefPtr<FTPChannelParent> mChannelParent;
823 : nsresult mErrorCode;
824 : bool mSkipResume;
825 : };
826 :
827 : void
828 0 : FTPChannelParent::FailDiversion(nsresult aErrorCode,
829 : bool aSkipResume)
830 : {
831 0 : MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
832 0 : MOZ_RELEASE_ASSERT(mDivertingFromChild);
833 0 : MOZ_RELEASE_ASSERT(mDivertToListener);
834 0 : MOZ_RELEASE_ASSERT(mChannel);
835 :
836 : NS_DispatchToCurrentThread(
837 0 : new FTPFailDiversionEvent(this, aErrorCode, aSkipResume));
838 0 : }
839 :
840 : void
841 0 : FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
842 : bool aSkipResume)
843 : {
844 0 : MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
845 0 : MOZ_RELEASE_ASSERT(mDivertingFromChild);
846 0 : MOZ_RELEASE_ASSERT(mDivertToListener);
847 0 : MOZ_RELEASE_ASSERT(mChannel);
848 :
849 0 : mChannel->Cancel(aErrorCode);
850 0 : nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
851 0 : if (forcePendingIChan) {
852 0 : forcePendingIChan->ForcePending(false);
853 : }
854 :
855 0 : bool isPending = false;
856 0 : nsresult rv = mChannel->IsPending(&isPending);
857 0 : MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
858 :
859 : // Resume only we suspended earlier.
860 0 : if (mSuspendedForDiversion) {
861 0 : ResumeChannel();
862 : }
863 : // Channel has already sent OnStartRequest to the child, so ensure that we
864 : // call it here if it hasn't already been called.
865 0 : if (!mDivertedOnStartRequest) {
866 0 : nsCOMPtr<nsIForcePendingChannel> forcePendingIChan = do_QueryInterface(mChannel);
867 0 : if (forcePendingIChan) {
868 0 : forcePendingIChan->ForcePending(true);
869 : }
870 0 : mDivertToListener->OnStartRequest(mChannel, nullptr);
871 :
872 0 : if (forcePendingIChan) {
873 0 : forcePendingIChan->ForcePending(false);
874 : }
875 : }
876 : // If the channel is pending, it will call OnStopRequest itself; otherwise, do
877 : // it here.
878 0 : if (!isPending) {
879 0 : mDivertToListener->OnStopRequest(mChannel, nullptr, aErrorCode);
880 : }
881 0 : mDivertToListener = nullptr;
882 0 : mChannel = nullptr;
883 :
884 0 : if (!mIPCClosed) {
885 0 : Unused << SendDeleteSelf();
886 : }
887 0 : }
888 :
889 : //-----------------------------------------------------------------------------
890 : // FTPChannelParent::nsIChannelEventSink
891 : //-----------------------------------------------------------------------------
892 :
893 : NS_IMETHODIMP
894 0 : FTPChannelParent::AsyncOnChannelRedirect(
895 : nsIChannel *oldChannel,
896 : nsIChannel *newChannel,
897 : uint32_t redirectFlags,
898 : nsIAsyncVerifyRedirectCallback* callback)
899 : {
900 0 : nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(newChannel);
901 0 : if (!ftpChan) {
902 : // when FTP is set to use HTTP proxying, we wind up getting redirected to an HTTP channel.
903 0 : nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(newChannel);
904 0 : if (!httpChan)
905 0 : return NS_ERROR_UNEXPECTED;
906 : }
907 0 : mChannel = newChannel;
908 0 : callback->OnRedirectVerifyCallback(NS_OK);
909 0 : return NS_OK;
910 : }
911 :
912 : NS_IMETHODIMP
913 0 : FTPChannelParent::SetErrorMsg(const char *aMsg, bool aUseUTF8)
914 : {
915 0 : mErrorMsg = aMsg;
916 0 : mUseUTF8 = aUseUTF8;
917 0 : return NS_OK;
918 : }
919 :
920 : //---------------------
921 : } // namespace net
922 : } // namespace mozilla
923 :
|