/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * This file defines two implementations of the nsIBackgroundFileSaver * interface. See the "test_backgroundfilesaver.js" file for usage examples.
*/
class BackgroundFileSaver : public nsIBackgroundFileSaver { public:
NS_DECL_NSIBACKGROUNDFILESAVER
BackgroundFileSaver();
/** * Initializes the pipe and the worker thread on XPCOM construction. * * This is called automatically by the XPCOM infrastructure, and if this * fails, the factory will delete this object without returning a reference.
*/
nsresult Init();
/** * Number of worker threads that are currently running.
*/ static uint32_t sThreadCount;
/** * Maximum number of worker threads reached during the current download * session, used for telemetry. * * When there are no more worker threads running, we consider the download * session finished, and this counter is reset.
*/ static uint32_t sTelemetryMaxThreadCount;
protected: virtual ~BackgroundFileSaver();
/** * Thread that constructed this object.
*/
nsCOMPtr<nsIEventTarget> mControlEventTarget;
/** * Thread to which the actual input/output is delegated.
*/
nsCOMPtr<nsISerialEventTarget> mBackgroundET;
/** * Stream that receives data from derived classes. The received data will be * available to the worker thread through mPipeInputStream. This is an * instance of nsPipeOutputStream, not BackgroundFileSaverOutputStream.
*/
nsCOMPtr<nsIAsyncOutputStream> mPipeOutputStream;
/** * Used during initialization, determines if the pipe is created with an * infinite buffer. An infinite buffer is required if the derived class * implements nsIStreamListener, because this interface requires all the * provided data to be consumed synchronously.
*/ virtualbool HasInfiniteBuffer() = 0;
/** * Used by derived classes if they need to be called back while copying.
*/ virtual nsAsyncCopyProgressFun GetProgressCallback() = 0;
/** * Stream used by the worker thread to read the data to be saved.
*/
nsCOMPtr<nsIAsyncInputStream> mPipeInputStream;
private: friendclass NotifyTargetChangeRunnable;
/** * Matches the nsIBackgroundFileSaver::observer property. * * @remarks This is a strong reference so that JavaScript callers don't need * to worry about keeping another reference to the observer.
*/
nsCOMPtr<nsIBackgroundFileSaverObserver> mObserver;
////////////////////////////////////////////////////////////////////////////// //// Shared state between control and worker threads
/** * Protects the shared state between control and worker threads. This mutex * is always locked for a very short time, never during input/output.
*/
mozilla::Mutex mLock{"BackgroundFileSaver.mLock"};
/** * True if the worker thread is already waiting to process a change in state.
*/ bool mWorkerThreadAttentionRequested MOZ_GUARDED_BY(mLock){false};
/** * True if the operation should finish as soon as possibile.
*/ bool mFinishRequested MOZ_GUARDED_BY(mLock){false};
/** * True if the operation completed, with either success or failure.
*/ bool mComplete MOZ_GUARDED_BY(mLock){false};
/** * Holds the current file saver status. This is a success status while the * object is working correctly, and remains such if the operation completes * successfully. This becomes an error status when an error occurs on the * worker thread, or when the operation is canceled.
*/
nsresult mStatus MOZ_GUARDED_BY(mLock){NS_OK};
/** * True if we should append data to the initial target file, instead of * overwriting it.
*/ bool mAppend MOZ_GUARDED_BY(mLock){false};
/** * This is set by the first SetTarget call on the control thread, and contains * the target file name that will be used by the worker thread, as soon as it * is possible to update mActualTarget and open the file. This is null if no * target was ever assigned to this object.
*/
nsCOMPtr<nsIFile> mInitialTarget MOZ_GUARDED_BY(mLock);
/** * This is set by the first SetTarget call on the control thread, and * indicates whether mInitialTarget should be kept as partially completed, * rather than deleted, if the operation fails or is canceled.
*/ bool mInitialTargetKeepPartial MOZ_GUARDED_BY(mLock){false};
/** * This is set by subsequent SetTarget calls on the control thread, and * contains the new target file name to which the worker thread will move the * target file, as soon as it can be done. This is null if SetTarget was * called only once, or no target was ever assigned to this object. * * The target file can be renamed multiple times, though only the most recent * rename is guaranteed to be processed by the worker thread.
*/
nsCOMPtr<nsIFile> mRenamedTarget MOZ_GUARDED_BY(mLock);
/** * This is set by subsequent SetTarget calls on the control thread, and * indicates whether mRenamedTarget should be kept as partially completed, * rather than deleted, if the operation fails or is canceled.
*/ bool mRenamedTargetKeepPartial MOZ_GUARDED_BY(mLock){false};
/** * While NS_AsyncCopy is in progress, allows canceling it. Null otherwise. * This is read by both threads but only written by the worker thread.
*/
nsCOMPtr<nsISupports> mAsyncCopyContext MOZ_GUARDED_BY(mLock);
/** * The SHA 256 hash in raw bytes of the downloaded file. This is written * by the worker thread but can be read on the main thread.
*/
nsCString mSha256 MOZ_GUARDED_BY(mLock);
/** * Whether or not to compute the hash. Must be set on the main thread before * setTarget is called.
*/ bool mSha256Enabled MOZ_GUARDED_BY(mLock){false};
/** * Store the signature info.
*/
nsTArray<nsTArray<nsTArray<uint8_t>>> mSignatureInfo MOZ_GUARDED_BY(mLock);
/** * Whether or not to extract the signature. Must be set on the main thread * before setTarget is called.
*/ bool mSignatureInfoEnabled MOZ_GUARDED_BY(mLock){false};
////////////////////////////////////////////////////////////////////////////// //// State handled exclusively by the worker thread
/** * Current target file associated to the input and output streams.
*/
nsCOMPtr<nsIFile> mActualTarget;
/** * Indicates whether mActualTarget should be kept as partially completed, * rather than deleted, if the operation fails or is canceled.
*/ bool mActualTargetKeepPartial{false};
/** * Used to calculate the file hash. This keeps state across file renames and * is lazily initialized in ProcessStateChange.
*/
Maybe<Digest> mDigest;
/** * Called when NS_AsyncCopy completes. * * @param aClosure * Populated with a raw pointer to the BackgroundFileSaver object. * @param aStatus * Success or failure status specified when the copy was interrupted.
*/ staticvoid AsyncCopyCallback(void* aClosure, nsresult aStatus);
/** * Called on the control thread after state changes, to ensure that the worker * thread will process the state change appropriately. * * @param aShouldInterruptCopy * If true, the current NS_AsyncCopy, if any, is canceled.
*/
nsresult GetWorkerThreadAttention(bool aShouldInterruptCopy);
/** * Event called on the worker thread to begin processing a state change.
*/
nsresult ProcessAttention();
/** * Called by ProcessAttention to execute the operations corresponding to the * state change. If this results in an error, ProcessAttention will force the * entire operation to be aborted.
*/
nsresult ProcessStateChange();
/** * Returns true if completion conditions are met on the worker thread. The * first time this happens, posts the completion event to the control thread.
*/ bool CheckCompletion();
/** * Event called on the control thread to indicate that file contents will now * be saved to the specified file.
*/
nsresult NotifyTargetChange(nsIFile* aTarget);
/** * Event called on the control thread to send the final notification.
*/
nsresult NotifySaveComplete();
/** * Verifies the signature of the binary at the specified file path and stores * the signature data in mSignatureInfo. We extract only X.509 certificates, * since that is what Google's Safebrowsing protocol specifies.
*/
nsresult ExtractSignatureInfo(const nsAString& filePath);
};
class BackgroundFileSaverOutputStream : public BackgroundFileSaver, public nsIAsyncOutputStream, public nsIOutputStreamCallback { public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOUTPUTSTREAM
NS_DECL_NSIASYNCOUTPUTSTREAM
NS_DECL_NSIOUTPUTSTREAMCALLBACK
/** * Original callback provided to our AsyncWait wrapper.
*/
nsCOMPtr<nsIOutputStreamCallback> mAsyncWaitCallback;
};
//////////////////////////////////////////////////////////////////////////////// //// BackgroundFileSaverStreamListener. This class is instantiated by // nsExternalHelperAppService, DownloadCore.sys.mjs, and possibly others.
class BackgroundFileSaverStreamListener final : public BackgroundFileSaver, public nsIStreamListener { public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
/** * Protects the state related to whether the request should be suspended.
*/
mozilla::Mutex mSuspensionLock{ "BackgroundFileSaverStreamListener.mSuspensionLock"};
/** * Whether we should suspend the request because we received too much data.
*/ bool mReceivedTooMuchData MOZ_GUARDED_BY(mSuspensionLock){false};
/** * Request for which we received too much data. This is populated when * mReceivedTooMuchData becomes true for the first time.
*/
nsCOMPtr<nsIRequest> mRequest MOZ_GUARDED_BY(mSuspensionLock);
/** * Whether mRequest is currently suspended.
*/ bool mRequestSuspended MOZ_GUARDED_BY(mSuspensionLock){false};
/** * Called while NS_AsyncCopy is copying data.
*/ staticvoid AsyncCopyProgressCallback(void* aClosure, uint32_t aCount);
/** * Called on the control thread to suspend or resume the request.
*/
nsresult NotifySuspendOrResume();
};
// A wrapper around nsIOutputStream, so that we can compute hashes on the // stream without copying and without polluting pristine NSS code with XPCOM // interfaces. class DigestOutputStream : public nsIOutputStream { public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOUTPUTSTREAM // Constructor. Neither parameter may be null. The caller owns both.
DigestOutputStream(nsIOutputStream* aStream, Digest& aDigest);
private: virtual ~DigestOutputStream() = default;
// Calls to write are passed to this stream.
nsCOMPtr<nsIOutputStream> mOutputStream; // Digest used to compute the hash, owned by the caller.
Digest& mDigest;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.