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

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "nsAsyncStreamCopier.h"
       6             : #include "nsIOService.h"
       7             : #include "nsIEventTarget.h"
       8             : #include "nsStreamUtils.h"
       9             : #include "nsThreadUtils.h"
      10             : #include "nsNetUtil.h"
      11             : #include "nsNetCID.h"
      12             : #include "nsIBufferedStreams.h"
      13             : #include "nsIRequestObserver.h"
      14             : #include "mozilla/Logging.h"
      15             : 
      16             : using namespace mozilla;
      17             : 
      18             : #undef LOG
      19             : //
      20             : // MOZ_LOG=nsStreamCopier:5
      21             : //
      22             : static LazyLogModule gStreamCopierLog("nsStreamCopier");
      23             : #define LOG(args) MOZ_LOG(gStreamCopierLog, mozilla::LogLevel::Debug, args)
      24             : 
      25             : /**
      26             :  * An event used to perform initialization off the main thread.
      27             :  */
      28           0 : class AsyncApplyBufferingPolicyEvent final: public Runnable
      29             : {
      30             : public:
      31             :     /**
      32             :      * @param aCopier
      33             :      *        The nsAsyncStreamCopier requesting the information.
      34             :      */
      35           0 :     explicit AsyncApplyBufferingPolicyEvent(nsAsyncStreamCopier* aCopier)
      36           0 :       : mozilla::Runnable("AsyncApplyBufferingPolicyEvent")
      37             :       , mCopier(aCopier)
      38           0 :       , mTarget(GetCurrentThreadEventTarget())
      39           0 :     {}
      40             : 
      41           0 :     NS_IMETHOD Run() override
      42             :     {
      43           0 :       nsresult rv = mCopier->ApplyBufferingPolicy();
      44           0 :       if (NS_FAILED(rv)) {
      45           0 :           mCopier->Cancel(rv);
      46           0 :           return NS_OK;
      47             :       }
      48             : 
      49           0 :       rv = mTarget->Dispatch(NewRunnableMethod("nsAsyncStreamCopier::AsyncCopyInternal",
      50             :                                                mCopier,
      51             :                                                &nsAsyncStreamCopier::AsyncCopyInternal),
      52           0 :                              NS_DISPATCH_NORMAL);
      53           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
      54             : 
      55           0 :       if (NS_FAILED(rv)) {
      56           0 :           mCopier->Cancel(rv);
      57             :       }
      58           0 :       return NS_OK;
      59             :     }
      60             : 
      61             : private:
      62             :       RefPtr<nsAsyncStreamCopier> mCopier;
      63             :       nsCOMPtr<nsIEventTarget> mTarget;
      64             : };
      65             : 
      66             : 
      67             : 
      68             : //-----------------------------------------------------------------------------
      69             : 
      70           0 : nsAsyncStreamCopier::nsAsyncStreamCopier()
      71             :     : mLock("nsAsyncStreamCopier.mLock")
      72             :     , mMode(NS_ASYNCCOPY_VIA_READSEGMENTS)
      73             :     , mChunkSize(nsIOService::gDefaultSegmentSize)
      74             :     , mStatus(NS_OK)
      75             :     , mIsPending(false)
      76           0 :     , mShouldSniffBuffering(false)
      77             : {
      78           0 :     LOG(("Creating nsAsyncStreamCopier @%p\n", this));
      79           0 : }
      80             : 
      81           0 : nsAsyncStreamCopier::~nsAsyncStreamCopier()
      82             : {
      83           0 :     LOG(("Destroying nsAsyncStreamCopier @%p\n", this));
      84           0 : }
      85             : 
      86             : bool
      87           0 : nsAsyncStreamCopier::IsComplete(nsresult *status)
      88             : {
      89           0 :     MutexAutoLock lock(mLock);
      90           0 :     if (status)
      91           0 :         *status = mStatus;
      92           0 :     return !mIsPending;
      93             : }
      94             : 
      95             : nsIRequest*
      96           0 : nsAsyncStreamCopier::AsRequest()
      97             : {
      98           0 :     return static_cast<nsIRequest*>(static_cast<nsIAsyncStreamCopier*>(this));
      99             : }
     100             : 
     101             : void
     102           0 : nsAsyncStreamCopier::Complete(nsresult status)
     103             : {
     104           0 :     LOG(("nsAsyncStreamCopier::Complete [this=%p status=%" PRIx32 "]\n", this,
     105             :          static_cast<uint32_t>(status)));
     106             : 
     107           0 :     nsCOMPtr<nsIRequestObserver> observer;
     108           0 :     nsCOMPtr<nsISupports> ctx;
     109             :     {
     110           0 :         MutexAutoLock lock(mLock);
     111           0 :         mCopierCtx = nullptr;
     112             : 
     113           0 :         if (mIsPending) {
     114           0 :             mIsPending = false;
     115           0 :             mStatus = status;
     116             : 
     117             :             // setup OnStopRequest callback and release references...
     118           0 :             observer = mObserver;
     119           0 :             mObserver = nullptr;
     120             :         }
     121             :     }
     122             : 
     123           0 :     if (observer) {
     124           0 :         LOG(("  calling OnStopRequest [status=%" PRIx32 "]\n",
     125             :              static_cast<uint32_t>(status)));
     126           0 :         observer->OnStopRequest(AsRequest(), ctx, status);
     127             :     }
     128           0 : }
     129             : 
     130             : void
     131           0 : nsAsyncStreamCopier::OnAsyncCopyComplete(void *closure, nsresult status)
     132             : {
     133           0 :     nsAsyncStreamCopier *self = (nsAsyncStreamCopier *) closure;
     134           0 :     self->Complete(status);
     135           0 :     NS_RELEASE(self); // addref'd in AsyncCopy
     136           0 : }
     137             : 
     138             : //-----------------------------------------------------------------------------
     139             : // nsISupports
     140             : 
     141             : // We cannot use simply NS_IMPL_ISUPPORTSx as both
     142             : // nsIAsyncStreamCopier and nsIAsyncStreamCopier2 implement nsIRequest
     143             : 
     144           0 : NS_IMPL_ADDREF(nsAsyncStreamCopier)
     145           0 : NS_IMPL_RELEASE(nsAsyncStreamCopier)
     146           0 : NS_INTERFACE_TABLE_HEAD(nsAsyncStreamCopier)
     147             : NS_INTERFACE_TABLE_BEGIN
     148             : NS_INTERFACE_TABLE_ENTRY(nsAsyncStreamCopier, nsIAsyncStreamCopier)
     149             : NS_INTERFACE_TABLE_ENTRY(nsAsyncStreamCopier, nsIAsyncStreamCopier2)
     150             : NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsAsyncStreamCopier, nsIRequest, nsIAsyncStreamCopier)
     151             : NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsAsyncStreamCopier, nsISupports, nsIAsyncStreamCopier)
     152           0 : NS_INTERFACE_TABLE_END
     153           0 : NS_INTERFACE_TABLE_TAIL
     154             : 
     155             : //-----------------------------------------------------------------------------
     156             : // nsIRequest
     157             : 
     158             : NS_IMETHODIMP
     159           0 : nsAsyncStreamCopier::GetName(nsACString &name)
     160             : {
     161           0 :     name.Truncate();
     162           0 :     return NS_OK;
     163             : }
     164             : 
     165             : NS_IMETHODIMP
     166           0 : nsAsyncStreamCopier::IsPending(bool *result)
     167             : {
     168           0 :     *result = !IsComplete();
     169           0 :     return NS_OK;
     170             : }
     171             : 
     172             : NS_IMETHODIMP
     173           0 : nsAsyncStreamCopier::GetStatus(nsresult *status)
     174             : {
     175           0 :     IsComplete(status);
     176           0 :     return NS_OK;
     177             : }
     178             : 
     179             : NS_IMETHODIMP
     180           0 : nsAsyncStreamCopier::Cancel(nsresult status)
     181             : {
     182           0 :     nsCOMPtr<nsISupports> copierCtx;
     183             :     {
     184           0 :         MutexAutoLock lock(mLock);
     185           0 :         if (!mIsPending)
     186           0 :             return NS_OK;
     187           0 :         copierCtx.swap(mCopierCtx);
     188             :     }
     189             : 
     190           0 :     if (NS_SUCCEEDED(status)) {
     191           0 :         NS_WARNING("cancel with non-failure status code");
     192           0 :         status = NS_BASE_STREAM_CLOSED;
     193             :     }
     194             : 
     195           0 :     if (copierCtx)
     196           0 :         NS_CancelAsyncCopy(copierCtx, status);
     197             : 
     198           0 :     return NS_OK;
     199             : }
     200             : 
     201             : NS_IMETHODIMP
     202           0 : nsAsyncStreamCopier::Suspend()
     203             : {
     204           0 :     NS_NOTREACHED("nsAsyncStreamCopier::Suspend");
     205           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     206             : }
     207             : 
     208             : NS_IMETHODIMP
     209           0 : nsAsyncStreamCopier::Resume()
     210             : {
     211           0 :     NS_NOTREACHED("nsAsyncStreamCopier::Resume");
     212           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     213             : }
     214             : 
     215             : NS_IMETHODIMP
     216           0 : nsAsyncStreamCopier::GetLoadFlags(nsLoadFlags *aLoadFlags)
     217             : {
     218           0 :     *aLoadFlags = LOAD_NORMAL;
     219           0 :     return NS_OK;
     220             : }
     221             : 
     222             : NS_IMETHODIMP
     223           0 : nsAsyncStreamCopier::SetLoadFlags(nsLoadFlags aLoadFlags)
     224             : {
     225           0 :     return NS_OK;
     226             : }
     227             : 
     228             : NS_IMETHODIMP
     229           0 : nsAsyncStreamCopier::GetLoadGroup(nsILoadGroup **aLoadGroup)
     230             : {
     231           0 :     *aLoadGroup = nullptr;
     232           0 :     return NS_OK;
     233             : }
     234             : 
     235             : NS_IMETHODIMP
     236           0 : nsAsyncStreamCopier::SetLoadGroup(nsILoadGroup *aLoadGroup)
     237             : {
     238           0 :     return NS_OK;
     239             : }
     240             : 
     241             : nsresult
     242           0 : nsAsyncStreamCopier::InitInternal(nsIInputStream *source,
     243             :                                   nsIOutputStream *sink,
     244             :                                   nsIEventTarget *target,
     245             :                                   uint32_t chunkSize,
     246             :                                   bool closeSource,
     247             :                                   bool closeSink)
     248             : {
     249           0 :     NS_ASSERTION(!mSource && !mSink, "Init() called more than once");
     250           0 :     if (chunkSize == 0) {
     251           0 :         chunkSize = nsIOService::gDefaultSegmentSize;
     252             :     }
     253           0 :     mChunkSize = chunkSize;
     254             : 
     255           0 :     mSource = source;
     256           0 :     mSink = sink;
     257           0 :     mCloseSource = closeSource;
     258           0 :     mCloseSink = closeSink;
     259             : 
     260           0 :     if (target) {
     261           0 :         mTarget = target;
     262             :     } else {
     263             :         nsresult rv;
     264           0 :         mTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
     265           0 :         if (NS_FAILED(rv)) {
     266           0 :             return rv;
     267             :         }
     268             :     }
     269             : 
     270           0 :     return NS_OK;
     271             : }
     272             : 
     273             : //-----------------------------------------------------------------------------
     274             : // nsIAsyncStreamCopier
     275             : 
     276             : NS_IMETHODIMP
     277           0 : nsAsyncStreamCopier::Init(nsIInputStream *source,
     278             :                           nsIOutputStream *sink,
     279             :                           nsIEventTarget *target,
     280             :                           bool sourceBuffered,
     281             :                           bool sinkBuffered,
     282             :                           uint32_t chunkSize,
     283             :                           bool closeSource,
     284             :                           bool closeSink)
     285             : {
     286           0 :     NS_ASSERTION(sourceBuffered || sinkBuffered, "at least one stream must be buffered");
     287           0 :     mMode = sourceBuffered ? NS_ASYNCCOPY_VIA_READSEGMENTS
     288             :                            : NS_ASYNCCOPY_VIA_WRITESEGMENTS;
     289             : 
     290           0 :     return InitInternal(source, sink, target, chunkSize, closeSource, closeSink);
     291             : }
     292             : 
     293             : //-----------------------------------------------------------------------------
     294             : // nsIAsyncStreamCopier2
     295             : 
     296             : NS_IMETHODIMP
     297           0 : nsAsyncStreamCopier::Init(nsIInputStream *source,
     298             :                           nsIOutputStream *sink,
     299             :                           nsIEventTarget *target,
     300             :                           uint32_t chunkSize,
     301             :                           bool closeSource,
     302             :                           bool closeSink)
     303             : {
     304           0 :     mShouldSniffBuffering = true;
     305             : 
     306           0 :     return InitInternal(source, sink, target, chunkSize, closeSource, closeSink);
     307             : }
     308             : 
     309             : /**
     310             :  * Detect whether the input or the output stream is buffered,
     311             :  * bufferize one of them if neither is buffered.
     312             :  */
     313             : nsresult
     314           0 : nsAsyncStreamCopier::ApplyBufferingPolicy()
     315             : {
     316             :     // This function causes I/O, it must not be executed on the main
     317             :     // thread.
     318           0 :     MOZ_ASSERT(!NS_IsMainThread());
     319             : 
     320           0 :     if (NS_OutputStreamIsBuffered(mSink)) {
     321             :       // Sink is buffered, no need to perform additional buffering
     322           0 :       mMode = NS_ASYNCCOPY_VIA_WRITESEGMENTS;
     323           0 :       return NS_OK;
     324             :     }
     325           0 :     if (NS_InputStreamIsBuffered(mSource)) {
     326             :       // Source is buffered, no need to perform additional buffering
     327           0 :       mMode = NS_ASYNCCOPY_VIA_READSEGMENTS;
     328           0 :       return NS_OK;
     329             :     }
     330             : 
     331             :     // No buffering, let's buffer the sink
     332             :     nsresult rv;
     333             :     nsCOMPtr<nsIBufferedOutputStream> sink =
     334           0 :       do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
     335           0 :     if (NS_FAILED(rv)) {
     336           0 :       return rv;
     337             :     }
     338             : 
     339           0 :     rv = sink->Init(mSink, mChunkSize);
     340           0 :     if (NS_FAILED(rv)) {
     341           0 :       return rv;
     342             :     }
     343             : 
     344           0 :     mMode = NS_ASYNCCOPY_VIA_WRITESEGMENTS;
     345           0 :     mSink = sink;
     346           0 :     return NS_OK;
     347             : }
     348             : 
     349             : //-----------------------------------------------------------------------------
     350             : // Both nsIAsyncStreamCopier and nsIAsyncStreamCopier2
     351             : 
     352             : NS_IMETHODIMP
     353           0 : nsAsyncStreamCopier::AsyncCopy(nsIRequestObserver *observer, nsISupports *ctx)
     354             : {
     355           0 :     LOG(("nsAsyncStreamCopier::AsyncCopy [this=%p observer=%p]\n", this, observer));
     356             : 
     357           0 :     NS_ASSERTION(mSource && mSink, "not initialized");
     358             :     nsresult rv;
     359             : 
     360           0 :     if (observer) {
     361             :         // build proxy for observer events
     362           0 :         rv = NS_NewRequestObserverProxy(getter_AddRefs(mObserver), observer, ctx);
     363           0 :         if (NS_FAILED(rv)) return rv;
     364             :     }
     365             : 
     366             :     // from this point forward, AsyncCopy is going to return NS_OK.  any errors
     367             :     // will be reported via OnStopRequest.
     368           0 :     mIsPending = true;
     369             : 
     370           0 :     if (mObserver) {
     371           0 :         rv = mObserver->OnStartRequest(AsRequest(), nullptr);
     372           0 :         if (NS_FAILED(rv))
     373           0 :             Cancel(rv);
     374             :     }
     375             : 
     376           0 :     if (!mShouldSniffBuffering) {
     377             :         // No buffer sniffing required, let's proceed
     378           0 :         AsyncCopyInternal();
     379           0 :         return NS_OK;
     380             :     }
     381             : 
     382           0 :     if (NS_IsMainThread()) {
     383             :         // Don't perform buffer sniffing on the main thread
     384           0 :         nsCOMPtr<nsIRunnable> event = new AsyncApplyBufferingPolicyEvent(this);
     385           0 :         rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
     386           0 :         if (NS_FAILED(rv)) {
     387           0 :           Cancel(rv);
     388             :         }
     389           0 :         return NS_OK;
     390             :     }
     391             : 
     392             :     // We're not going to block the main thread, so let's sniff here
     393           0 :     rv = ApplyBufferingPolicy();
     394           0 :     if (NS_FAILED(rv)) {
     395           0 :         Cancel(rv);
     396             :     }
     397           0 :     AsyncCopyInternal();
     398           0 :     return NS_OK;
     399             : }
     400             : 
     401             : // Launch async copy.
     402             : // All errors are reported through the observer.
     403             : void
     404           0 : nsAsyncStreamCopier::AsyncCopyInternal()
     405             : {
     406           0 :   MOZ_ASSERT(mMode ==  NS_ASYNCCOPY_VIA_READSEGMENTS
     407             :              || mMode == NS_ASYNCCOPY_VIA_WRITESEGMENTS);
     408             : 
     409             :     nsresult rv;
     410             :     // we want to receive progress notifications; release happens in
     411             :     // OnAsyncCopyComplete.
     412           0 :     NS_ADDREF_THIS();
     413             :     {
     414           0 :       MutexAutoLock lock(mLock);
     415           0 :       rv = NS_AsyncCopy(mSource, mSink, mTarget, mMode, mChunkSize,
     416           0 :                         OnAsyncCopyComplete, this, mCloseSource, mCloseSink,
     417           0 :                         getter_AddRefs(mCopierCtx));
     418             :     }
     419           0 :     if (NS_FAILED(rv)) {
     420           0 :         NS_RELEASE_THIS();
     421           0 :         Cancel(rv);
     422             :     }
     423           0 : }
     424             : 
     425             : 

Generated by: LCOV version 1.13