LCOV - code coverage report
Current view: top level - netwerk/base - BackgroundFileSaver.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 1 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 ts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /**
       8             :  * This file defines two implementations of the nsIBackgroundFileSaver
       9             :  * interface.  See the "test_backgroundfilesaver.js" file for usage examples.
      10             :  */
      11             : 
      12             : #ifndef BackgroundFileSaver_h__
      13             : #define BackgroundFileSaver_h__
      14             : 
      15             : #include "ScopedNSSTypes.h"
      16             : #include "mozilla/Mutex.h"
      17             : #include "nsCOMArray.h"
      18             : #include "nsCOMPtr.h"
      19             : #include "nsIAsyncOutputStream.h"
      20             : #include "nsIBackgroundFileSaver.h"
      21             : #include "nsIStreamListener.h"
      22             : #include "nsNSSShutDown.h"
      23             : #include "nsStreamUtils.h"
      24             : #include "nsString.h"
      25             : 
      26             : class nsIAsyncInputStream;
      27             : class nsIThread;
      28             : class nsIX509CertList;
      29             : 
      30             : namespace mozilla {
      31             : namespace net {
      32             : 
      33             : class DigestOutputStream;
      34             : 
      35             : ////////////////////////////////////////////////////////////////////////////////
      36             : //// BackgroundFileSaver
      37             : 
      38             : class BackgroundFileSaver : public nsIBackgroundFileSaver,
      39             :                             public nsNSSShutDownObject
      40             : {
      41             : public:
      42             :   NS_DECL_NSIBACKGROUNDFILESAVER
      43             : 
      44             :   BackgroundFileSaver();
      45             : 
      46             :   /**
      47             :    * Initializes the pipe and the worker thread on XPCOM construction.
      48             :    *
      49             :    * This is called automatically by the XPCOM infrastructure, and if this
      50             :    * fails, the factory will delete this object without returning a reference.
      51             :    */
      52             :   nsresult Init();
      53             : 
      54             :   /**
      55             :    * Used by nsNSSShutDownList to manage nsNSSShutDownObjects.
      56             :    */
      57             :   void virtualDestroyNSSReference() override;
      58             : 
      59             :   /**
      60             :    * Number of worker threads that are currently running.
      61             :    */
      62             :   static uint32_t sThreadCount;
      63             : 
      64             :   /**
      65             :    * Maximum number of worker threads reached during the current download session,
      66             :    * used for telemetry.
      67             :    *
      68             :    * When there are no more worker threads running, we consider the download
      69             :    * session finished, and this counter is reset.
      70             :    */
      71             :   static uint32_t sTelemetryMaxThreadCount;
      72             : 
      73             : 
      74             : protected:
      75             :   virtual ~BackgroundFileSaver();
      76             : 
      77             :   /**
      78             :    * Helper function for managing NSS objects (mDigestContext).
      79             :    */
      80             :   void destructorSafeDestroyNSSReference();
      81             : 
      82             :   /**
      83             :    * Thread that constructed this object.
      84             :    */
      85             :   nsCOMPtr<nsIEventTarget> mControlEventTarget;
      86             : 
      87             :   /**
      88             :    * Thread to which the actual input/output is delegated.
      89             :    */
      90             :   nsCOMPtr<nsIThread> mWorkerThread;
      91             : 
      92             :   /**
      93             :    * Stream that receives data from derived classes.  The received data will be
      94             :    * available to the worker thread through mPipeInputStream. This is an
      95             :    * instance of nsPipeOutputStream, not BackgroundFileSaverOutputStream.
      96             :    */
      97             :   nsCOMPtr<nsIAsyncOutputStream> mPipeOutputStream;
      98             : 
      99             :   /**
     100             :    * Used during initialization, determines if the pipe is created with an
     101             :    * infinite buffer.  An infinite buffer is required if the derived class
     102             :    * implements nsIStreamListener, because this interface requires all the
     103             :    * provided data to be consumed synchronously.
     104             :    */
     105             :   virtual bool HasInfiniteBuffer() = 0;
     106             : 
     107             :   /**
     108             :    * Used by derived classes if they need to be called back while copying.
     109             :    */
     110             :   virtual nsAsyncCopyProgressFun GetProgressCallback() = 0;
     111             : 
     112             :   /**
     113             :    * Stream used by the worker thread to read the data to be saved.
     114             :    */
     115             :   nsCOMPtr<nsIAsyncInputStream> mPipeInputStream;
     116             : 
     117             : private:
     118             :   friend class NotifyTargetChangeRunnable;
     119             : 
     120             :   /**
     121             :    * Matches the nsIBackgroundFileSaver::observer property.
     122             :    *
     123             :    * @remarks This is a strong reference so that JavaScript callers don't need
     124             :    *          to worry about keeping another reference to the observer.
     125             :    */
     126             :   nsCOMPtr<nsIBackgroundFileSaverObserver> mObserver;
     127             : 
     128             :   //////////////////////////////////////////////////////////////////////////////
     129             :   //// Shared state between control and worker threads
     130             : 
     131             :   /**
     132             :    * Protects the shared state between control and worker threads.  This mutex
     133             :    * is always locked for a very short time, never during input/output.
     134             :    */
     135             :   mozilla::Mutex mLock;
     136             : 
     137             :   /**
     138             :    * True if the worker thread is already waiting to process a change in state.
     139             :    */
     140             :   bool mWorkerThreadAttentionRequested;
     141             : 
     142             :   /**
     143             :    * True if the operation should finish as soon as possibile.
     144             :    */
     145             :   bool mFinishRequested;
     146             : 
     147             :   /**
     148             :    * True if the operation completed, with either success or failure.
     149             :    */
     150             :   bool mComplete;
     151             : 
     152             :   /**
     153             :    * Holds the current file saver status.  This is a success status while the
     154             :    * object is working correctly, and remains such if the operation completes
     155             :    * successfully.  This becomes an error status when an error occurs on the
     156             :    * worker thread, or when the operation is canceled.
     157             :    */
     158             :   nsresult mStatus;
     159             : 
     160             :   /**
     161             :    * True if we should append data to the initial target file, instead of
     162             :    * overwriting it.
     163             :    */
     164             :   bool mAppend;
     165             : 
     166             :   /**
     167             :    * This is set by the first SetTarget call on the control thread, and contains
     168             :    * the target file name that will be used by the worker thread, as soon as it
     169             :    * is possible to update mActualTarget and open the file.  This is null if no
     170             :    * target was ever assigned to this object.
     171             :    */
     172             :   nsCOMPtr<nsIFile> mInitialTarget;
     173             : 
     174             :   /**
     175             :    * This is set by the first SetTarget call on the control thread, and
     176             :    * indicates whether mInitialTarget should be kept as partially completed,
     177             :    * rather than deleted, if the operation fails or is canceled.
     178             :    */
     179             :   bool mInitialTargetKeepPartial;
     180             : 
     181             :   /**
     182             :    * This is set by subsequent SetTarget calls on the control thread, and
     183             :    * contains the new target file name to which the worker thread will move the
     184             :    * target file, as soon as it can be done.  This is null if SetTarget was
     185             :    * called only once, or no target was ever assigned to this object.
     186             :    *
     187             :    * The target file can be renamed multiple times, though only the most recent
     188             :    * rename is guaranteed to be processed by the worker thread.
     189             :    */
     190             :   nsCOMPtr<nsIFile> mRenamedTarget;
     191             : 
     192             :   /**
     193             :    * This is set by subsequent SetTarget calls on the control thread, and
     194             :    * indicates whether mRenamedTarget should be kept as partially completed,
     195             :    * rather than deleted, if the operation fails or is canceled.
     196             :    */
     197             :   bool mRenamedTargetKeepPartial;
     198             : 
     199             :   /**
     200             :    * While NS_AsyncCopy is in progress, allows canceling it.  Null otherwise.
     201             :    * This is read by both threads but only written by the worker thread.
     202             :    */
     203             :   nsCOMPtr<nsISupports> mAsyncCopyContext;
     204             : 
     205             :   /**
     206             :    * The SHA 256 hash in raw bytes of the downloaded file. This is written
     207             :    * by the worker thread but can be read on the main thread.
     208             :    */
     209             :   nsCString mSha256;
     210             : 
     211             :   /**
     212             :    * Whether or not to compute the hash. Must be set on the main thread before
     213             :    * setTarget is called.
     214             :    */
     215             :   bool mSha256Enabled;
     216             : 
     217             :   /**
     218             :    * Store the signature info.
     219             :    */
     220             :   nsCOMArray<nsIX509CertList> mSignatureInfo;
     221             : 
     222             :   /**
     223             :    * Whether or not to extract the signature. Must be set on the main thread
     224             :    * before setTarget is called.
     225             :    */
     226             :   bool mSignatureInfoEnabled;
     227             : 
     228             :   //////////////////////////////////////////////////////////////////////////////
     229             :   //// State handled exclusively by the worker thread
     230             : 
     231             :   /**
     232             :    * Current target file associated to the input and output streams.
     233             :    */
     234             :   nsCOMPtr<nsIFile> mActualTarget;
     235             : 
     236             :   /**
     237             :    * Indicates whether mActualTarget should be kept as partially completed,
     238             :    * rather than deleted, if the operation fails or is canceled.
     239             :    */
     240             :   bool mActualTargetKeepPartial;
     241             : 
     242             :   /**
     243             :    * Used to calculate the file hash. This keeps state across file renames and
     244             :    * is lazily initialized in ProcessStateChange.
     245             :    */
     246             :   UniquePK11Context mDigestContext;
     247             : 
     248             :   //////////////////////////////////////////////////////////////////////////////
     249             :   //// Private methods
     250             : 
     251             :   /**
     252             :    * Called when NS_AsyncCopy completes.
     253             :    *
     254             :    * @param aClosure
     255             :    *        Populated with a raw pointer to the BackgroundFileSaver object.
     256             :    * @param aStatus
     257             :    *        Success or failure status specified when the copy was interrupted.
     258             :    */
     259             :   static void AsyncCopyCallback(void *aClosure, nsresult aStatus);
     260             : 
     261             :   /**
     262             :    * Called on the control thread after state changes, to ensure that the worker
     263             :    * thread will process the state change appropriately.
     264             :    *
     265             :    * @param aShouldInterruptCopy
     266             :    *        If true, the current NS_AsyncCopy, if any, is canceled.
     267             :    */
     268             :   nsresult GetWorkerThreadAttention(bool aShouldInterruptCopy);
     269             : 
     270             :   /**
     271             :    * Event called on the worker thread to begin processing a state change.
     272             :    */
     273             :   nsresult ProcessAttention();
     274             : 
     275             :   /**
     276             :    * Called by ProcessAttention to execute the operations corresponding to the
     277             :    * state change.  If this results in an error, ProcessAttention will force the
     278             :    * entire operation to be aborted.
     279             :    */
     280             :   nsresult ProcessStateChange();
     281             : 
     282             :   /**
     283             :    * Returns true if completion conditions are met on the worker thread.  The
     284             :    * first time this happens, posts the completion event to the control thread.
     285             :    */
     286             :   bool CheckCompletion();
     287             : 
     288             :   /**
     289             :    * Event called on the control thread to indicate that file contents will now
     290             :    * be saved to the specified file.
     291             :    */
     292             :   nsresult NotifyTargetChange(nsIFile *aTarget);
     293             : 
     294             :   /**
     295             :    * Event called on the control thread to send the final notification.
     296             :    */
     297             :   nsresult NotifySaveComplete();
     298             : 
     299             :   /**
     300             :    * Verifies the signature of the binary at the specified file path and stores
     301             :    * the signature data in mSignatureInfo. We extract only X.509 certificates,
     302             :    * since that is what Google's Safebrowsing protocol specifies.
     303             :    */
     304             :   nsresult ExtractSignatureInfo(const nsAString& filePath);
     305             : };
     306             : 
     307             : ////////////////////////////////////////////////////////////////////////////////
     308             : //// BackgroundFileSaverOutputStream
     309             : 
     310             : class BackgroundFileSaverOutputStream : public BackgroundFileSaver
     311             :                                       , public nsIAsyncOutputStream
     312             :                                       , public nsIOutputStreamCallback
     313             : {
     314             : public:
     315             :   NS_DECL_THREADSAFE_ISUPPORTS
     316             :   NS_DECL_NSIOUTPUTSTREAM
     317             :   NS_DECL_NSIASYNCOUTPUTSTREAM
     318             :   NS_DECL_NSIOUTPUTSTREAMCALLBACK
     319             : 
     320             :   BackgroundFileSaverOutputStream();
     321             : 
     322             : protected:
     323             :   virtual bool HasInfiniteBuffer() override;
     324             :   virtual nsAsyncCopyProgressFun GetProgressCallback() override;
     325             : 
     326             : private:
     327             :   ~BackgroundFileSaverOutputStream();
     328             : 
     329             :   /**
     330             :    * Original callback provided to our AsyncWait wrapper.
     331             :    */
     332             :   nsCOMPtr<nsIOutputStreamCallback> mAsyncWaitCallback;
     333             : };
     334             : 
     335             : ////////////////////////////////////////////////////////////////////////////////
     336             : //// BackgroundFileSaverStreamListener. This class is instantiated by
     337             : // nsExternalHelperAppService, DownloadCore.jsm, and possibly others.
     338             : 
     339             : class BackgroundFileSaverStreamListener final : public BackgroundFileSaver
     340             :                                               , public nsIStreamListener
     341             : {
     342             : public:
     343             :   NS_DECL_THREADSAFE_ISUPPORTS
     344             :   NS_DECL_NSIREQUESTOBSERVER
     345             :   NS_DECL_NSISTREAMLISTENER
     346             : 
     347             :   BackgroundFileSaverStreamListener();
     348             : 
     349             : protected:
     350             :   virtual bool HasInfiniteBuffer() override;
     351             :   virtual nsAsyncCopyProgressFun GetProgressCallback() override;
     352             : 
     353             : private:
     354             :   ~BackgroundFileSaverStreamListener();
     355             : 
     356             :   /**
     357             :    * Protects the state related to whether the request should be suspended.
     358             :    */
     359             :   mozilla::Mutex mSuspensionLock;
     360             : 
     361             :   /**
     362             :    * Whether we should suspend the request because we received too much data.
     363             :    */
     364             :   bool mReceivedTooMuchData;
     365             : 
     366             :   /**
     367             :    * Request for which we received too much data.  This is populated when
     368             :    * mReceivedTooMuchData becomes true for the first time.
     369             :    */
     370             :   nsCOMPtr<nsIRequest> mRequest;
     371             : 
     372             :   /**
     373             :    * Whether mRequest is currently suspended.
     374             :    */
     375             :   bool mRequestSuspended;
     376             : 
     377             :   /**
     378             :    * Called while NS_AsyncCopy is copying data.
     379             :    */
     380             :   static void AsyncCopyProgressCallback(void *aClosure, uint32_t aCount);
     381             : 
     382             :   /**
     383             :    * Called on the control thread to suspend or resume the request.
     384             :    */
     385             :   nsresult NotifySuspendOrResume();
     386             : };
     387             : 
     388             : // A wrapper around nsIOutputStream, so that we can compute hashes on the
     389             : // stream without copying and without polluting pristine NSS code with XPCOM
     390             : // interfaces.
     391             : class DigestOutputStream : public nsNSSShutDownObject,
     392             :                            public nsIOutputStream
     393             : {
     394             : public:
     395             :   NS_DECL_THREADSAFE_ISUPPORTS
     396             :   NS_DECL_NSIOUTPUTSTREAM
     397             :   // Constructor. Neither parameter may be null. The caller owns both.
     398             :   DigestOutputStream(nsIOutputStream* outputStream, PK11Context* aContext);
     399             : 
     400             :   // We don't own any NSS objects here, so no need to clean up
     401           0 :   void virtualDestroyNSSReference() override { }
     402             : 
     403             : private:
     404             :   ~DigestOutputStream();
     405             : 
     406             :   // Calls to write are passed to this stream.
     407             :   nsCOMPtr<nsIOutputStream> mOutputStream;
     408             :   // Digest context used to compute the hash, owned by the caller.
     409             :   PK11Context* mDigestContext;
     410             : 
     411             :   // Don't accidentally copy construct.
     412             :   DigestOutputStream(const DigestOutputStream& d);
     413             : };
     414             : 
     415             : } // namespace net
     416             : } // namespace mozilla
     417             : 
     418             : #endif

Generated by: LCOV version 1.13