LCOV - code coverage report
Current view: top level - netwerk/protocol/ftp - FTPChannelParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 400 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 56 0.0 %
Legend: Lines: hit not hit

          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             : 

Generated by: LCOV version 1.13