зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1364050 - Part 3 - Remove obsolete code from the nsIDownloadManager implementation. r=mak
A missing dependency in "nsTypeAheadFind.h" is also fixed to allow the removal of the include files from "nsToolkitCompsModule.cpp". MozReview-Commit-ID: EefZA9bEUW0 --HG-- extra : rebase_source : 8ddfaf72f2b89c6e906561710045ec677e46da79
This commit is contained in:
Родитель
f85ca5d424
Коммит
93316227a7
|
@ -61,6 +61,9 @@ var whitelist = new Set([
|
|||
{file: "chrome://devtools/content/inspector/markup/markup.xhtml",
|
||||
isFromDevTools: true},
|
||||
|
||||
// Kept for add-on compatibility, should be removed in bug 851471.
|
||||
{file: "chrome://mozapps/skin/downloads/downloadIcon.png"},
|
||||
|
||||
// extensions/pref/autoconfig/src/nsReadConfig.cpp
|
||||
{file: "resource://gre/defaults/autoconfig/prefcalls.js"},
|
||||
|
||||
|
@ -111,7 +114,6 @@ var whitelist = new Set([
|
|||
// browser/extensions/pdfjs/content/web/viewer.js#7450
|
||||
{file: "resource://pdf.js/web/debugger.js"},
|
||||
|
||||
|
||||
// Starting from here, files in the whitelist are bugs that need fixing.
|
||||
// Bug 1339420
|
||||
{file: "chrome://branding/content/icon128.png"},
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "nsDownloadManager.h"
|
||||
#include "DownloadPlatform.h"
|
||||
#include "nsDownloadProxy.h"
|
||||
#include "rdf.h"
|
||||
|
||||
#include "nsTypeAheadFind.h"
|
||||
|
@ -88,7 +87,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAlertsService)
|
|||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDownloadManager,
|
||||
nsDownloadManager::GetSingleton)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(DownloadPlatform)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadProxy)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTypeAheadFind)
|
||||
|
||||
|
@ -147,7 +145,6 @@ NS_DEFINE_NAMED_CID(NS_PARENTALCONTROLSSERVICE_CID);
|
|||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_DOWNLOADMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DOWNLOADPLATFORM_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DOWNLOAD_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FIND_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_TYPEAHEADFIND_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_APPLICATION_REPUTATION_SERVICE_CID);
|
||||
|
@ -183,7 +180,6 @@ static const Module::CIDEntry kToolkitCIDs[] = {
|
|||
#endif
|
||||
{ &kNS_DOWNLOADMANAGER_CID, false, nullptr, nsDownloadManagerConstructor },
|
||||
{ &kNS_DOWNLOADPLATFORM_CID, false, nullptr, DownloadPlatformConstructor },
|
||||
{ &kNS_DOWNLOAD_CID, false, nullptr, nsDownloadProxyConstructor },
|
||||
{ &kNS_FIND_SERVICE_CID, false, nullptr, nsFindServiceConstructor },
|
||||
{ &kNS_TYPEAHEADFIND_CID, false, nullptr, nsTypeAheadFindConstructor },
|
||||
{ &kNS_APPLICATION_REPUTATION_SERVICE_CID, false, nullptr, ApplicationReputationServiceConstructor },
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
/* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* 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/. */
|
||||
|
||||
#include "mozilla/storage.h"
|
||||
#include "mozilla/storage/Variant.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsString.h"
|
||||
#include "SQLFunctions.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
#include "plbase64.h"
|
||||
#include "prio.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
// The length of guids that are used by the download manager
|
||||
#define GUID_LENGTH 12
|
||||
|
||||
namespace mozilla {
|
||||
namespace downloads {
|
||||
|
||||
// Keep this file in sync with the GUID-related code in toolkit/places/SQLFunctions.cpp
|
||||
// and toolkit/places/Helpers.cpp!
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// GUID Creation Function
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// GenerateGUIDFunction
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
GenerateGUIDFunction::create(mozIStorageConnection *aDBConn)
|
||||
{
|
||||
RefPtr<GenerateGUIDFunction> function = new GenerateGUIDFunction();
|
||||
nsresult rv = aDBConn->CreateFunction(
|
||||
NS_LITERAL_CSTRING("generate_guid"), 0, function
|
||||
);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(
|
||||
GenerateGUIDFunction,
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
static
|
||||
nsresult
|
||||
Base64urlEncode(const uint8_t* aBytes,
|
||||
uint32_t aNumBytes,
|
||||
nsCString& _result)
|
||||
{
|
||||
// SetLength does not set aside space for null termination. PL_Base64Encode
|
||||
// will not null terminate, however, nsCStrings must be null terminated. As a
|
||||
// result, we set the capacity to be one greater than what we need, and the
|
||||
// length to our desired length.
|
||||
uint32_t length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math.
|
||||
NS_ENSURE_TRUE(_result.SetCapacity(length + 1, mozilla::fallible),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
_result.SetLength(length);
|
||||
(void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes,
|
||||
_result.BeginWriting());
|
||||
|
||||
// base64url encoding is defined in RFC 4648. It replaces the last two
|
||||
// alphabet characters of base64 encoding with '-' and '_' respectively.
|
||||
_result.ReplaceChar('+', '-');
|
||||
_result.ReplaceChar('/', '_');
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
nsresult
|
||||
GenerateRandomBytes(uint32_t aSize,
|
||||
uint8_t* _buffer)
|
||||
{
|
||||
// On Windows, we'll use its built-in cryptographic API.
|
||||
#if defined(XP_WIN)
|
||||
HCRYPTPROV cryptoProvider;
|
||||
BOOL rc = CryptAcquireContext(&cryptoProvider, 0, 0, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
|
||||
if (rc) {
|
||||
rc = CryptGenRandom(cryptoProvider, aSize, _buffer);
|
||||
(void)CryptReleaseContext(cryptoProvider, 0);
|
||||
}
|
||||
return rc ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
||||
// On Unix, we'll just read in from /dev/urandom.
|
||||
#elif defined(XP_UNIX)
|
||||
NS_ENSURE_ARG_MAX(aSize, INT32_MAX);
|
||||
PRFileDesc* urandom = PR_Open("/dev/urandom", PR_RDONLY, 0);
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (urandom) {
|
||||
int32_t bytesRead = PR_Read(urandom, _buffer, aSize);
|
||||
if (bytesRead == static_cast<int32_t>(aSize)) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
(void)PR_Close(urandom);
|
||||
}
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
GenerateGUID(nsCString& _guid)
|
||||
{
|
||||
_guid.Truncate();
|
||||
|
||||
// Request raw random bytes and base64url encode them. For each set of three
|
||||
// bytes, we get one character.
|
||||
const uint32_t kRequiredBytesLength =
|
||||
static_cast<uint32_t>(GUID_LENGTH / 4 * 3);
|
||||
|
||||
uint8_t buffer[kRequiredBytesLength];
|
||||
nsresult rv = GenerateRandomBytes(kRequiredBytesLength, buffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = Base64urlEncode(buffer, kRequiredBytesLength, _guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
GenerateGUIDFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
{
|
||||
nsAutoCString guid;
|
||||
nsresult rv = GenerateGUID(guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_result = new mozilla::storage::UTF8TextVariant(guid));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace downloads
|
||||
} // namespace mozilla
|
|
@ -1,46 +0,0 @@
|
|||
/* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_downloads_SQLFunctions_h
|
||||
#define mozilla_downloads_SQLFunctions_h
|
||||
|
||||
#include "mozIStorageFunction.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsCString;
|
||||
class mozIStorageConnection;
|
||||
|
||||
namespace mozilla {
|
||||
namespace downloads {
|
||||
|
||||
/**
|
||||
* SQL function to generate a GUID for a place or bookmark item. This is just
|
||||
* a wrapper around GenerateGUID in SQLFunctions.cpp.
|
||||
*
|
||||
* @return a guid for the item.
|
||||
* @see toolkit/components/places/SQLFunctions.h - keep this in sync
|
||||
*/
|
||||
class GenerateGUIDFunction final : public mozIStorageFunction
|
||||
{
|
||||
~GenerateGUIDFunction() {}
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
|
||||
/**
|
||||
* Registers the function with the specified database connection.
|
||||
*
|
||||
* @param aDBConn
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
};
|
||||
|
||||
nsresult GenerateGUID(nsCString& _guid);
|
||||
|
||||
} // namespace downloads
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -19,7 +19,7 @@ if [ ! -e $PROTOC_PATH ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f nsDownloadManager.cpp ]; then
|
||||
if [ ! -f nsIApplicationReputation.idl ]; then
|
||||
echo "You must run this script in the toolkit/components/downloads" >&2
|
||||
echo "directory of the source tree." >&2
|
||||
exit 1
|
||||
|
|
|
@ -37,18 +37,6 @@ UNIFIED_SOURCES += [
|
|||
'nsDownloadManager.cpp'
|
||||
]
|
||||
|
||||
# SQLFunctions.cpp cannot be built in unified mode because of Windows headers.
|
||||
SOURCES += [
|
||||
'SQLFunctions.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
# Can't build unified because we need CreateEvent which some IPC code
|
||||
# included in LoadContext ends up undefining.
|
||||
SOURCES += [
|
||||
'nsDownloadScanner.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,449 +6,34 @@
|
|||
#ifndef downloadmanager___h___
|
||||
#define downloadmanager___h___
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#define DOWNLOAD_SCANNER
|
||||
#endif
|
||||
|
||||
#include "nsIDownload.h"
|
||||
#include "nsIDownloadManager.h"
|
||||
#include "nsIDownloadProgressListener.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsINavHistoryService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozIDOMWindow.h"
|
||||
#include "mozStorageHelper.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
typedef int16_t DownloadState;
|
||||
typedef int16_t DownloadType;
|
||||
|
||||
class nsIArray;
|
||||
class nsDownload;
|
||||
|
||||
#ifdef DOWNLOAD_SCANNER
|
||||
#include "nsDownloadScanner.h"
|
||||
#endif
|
||||
|
||||
class nsDownloadManager final : public nsIDownloadManager,
|
||||
public nsINavHistoryObserver,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
class nsDownloadManager final : public nsIDownloadManager
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOADMANAGER
|
||||
NS_DECL_NSINAVHISTORYOBSERVER
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsresult Init();
|
||||
|
||||
static nsDownloadManager *GetSingleton();
|
||||
|
||||
nsDownloadManager()
|
||||
#ifdef DOWNLOAD_SCANNER
|
||||
: mScanner(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsDownloadManager();
|
||||
|
||||
nsresult InitDB();
|
||||
nsresult InitFileDB();
|
||||
void CloseAllDBs();
|
||||
void CloseDB(mozIStorageConnection* aDBConn,
|
||||
mozIStorageStatement* aUpdateStmt,
|
||||
mozIStorageStatement* aGetIdsStmt);
|
||||
nsresult InitPrivateDB();
|
||||
already_AddRefed<mozIStorageConnection> GetFileDBConnection(nsIFile *dbFile) const;
|
||||
already_AddRefed<mozIStorageConnection> GetPrivateDBConnection() const;
|
||||
nsresult CreateTable(mozIStorageConnection* aDBConn);
|
||||
|
||||
/**
|
||||
* Fix up the database after a crash such as dealing with previously-active
|
||||
* downloads. Call this before RestoreActiveDownloads to get the downloads
|
||||
* fixed here to be auto-resumed.
|
||||
*/
|
||||
nsresult RestoreDatabaseState();
|
||||
|
||||
/**
|
||||
* Paused downloads that survive across sessions are considered active, so
|
||||
* rebuild the list of these downloads.
|
||||
*/
|
||||
nsresult RestoreActiveDownloads();
|
||||
|
||||
nsresult GetDownloadFromDB(const nsACString& aGUID, nsDownload **retVal);
|
||||
nsresult GetDownloadFromDB(uint32_t aID, nsDownload **retVal);
|
||||
nsresult GetDownloadFromDB(mozIStorageConnection* aDBConn,
|
||||
mozIStorageStatement* stmt,
|
||||
nsDownload **retVal);
|
||||
|
||||
/**
|
||||
* Specially track the active downloads so that we don't need to check
|
||||
* every download to see if they're in progress.
|
||||
*/
|
||||
nsresult AddToCurrentDownloads(nsDownload *aDl);
|
||||
|
||||
void SendEvent(nsDownload *aDownload, const char *aTopic);
|
||||
|
||||
/**
|
||||
* Adds a download with the specified information to the DB.
|
||||
*
|
||||
* @return The id of the download, or 0 if there was an error.
|
||||
*/
|
||||
int64_t AddDownloadToDB(const nsAString &aName,
|
||||
const nsACString &aSource,
|
||||
const nsACString &aTarget,
|
||||
const nsAString &aTempPath,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
const nsACString &aMimeType,
|
||||
const nsACString &aPreferredApp,
|
||||
nsHandlerInfoAction aPreferredAction,
|
||||
bool aPrivate,
|
||||
nsACString &aNewGUID);
|
||||
|
||||
void NotifyListenersOnDownloadStateChange(int16_t aOldState,
|
||||
nsDownload *aDownload);
|
||||
void NotifyListenersOnProgressChange(nsIWebProgress *aProgress,
|
||||
nsIRequest *aRequest,
|
||||
int64_t aCurSelfProgress,
|
||||
int64_t aMaxSelfProgress,
|
||||
int64_t aCurTotalProgress,
|
||||
int64_t aMaxTotalProgress,
|
||||
nsDownload *aDownload);
|
||||
void NotifyListenersOnStateChange(nsIWebProgress *aProgress,
|
||||
nsIRequest *aRequest,
|
||||
uint32_t aStateFlags,
|
||||
nsresult aStatus,
|
||||
nsDownload *aDownload);
|
||||
|
||||
nsDownload *FindDownload(const nsACString& aGUID);
|
||||
nsDownload *FindDownload(uint32_t aID);
|
||||
|
||||
/**
|
||||
* First try to resume the download, and if that fails, retry it.
|
||||
*
|
||||
* @param aDl The download to resume and/or retry.
|
||||
*/
|
||||
nsresult ResumeRetry(nsDownload *aDl);
|
||||
|
||||
/**
|
||||
* Pause all active downloads and remember if they should try to auto-resume
|
||||
* when the download manager starts again.
|
||||
*
|
||||
* @param aSetResume Indicate if the downloads that get paused should be set
|
||||
* as auto-resume.
|
||||
*/
|
||||
nsresult PauseAllDownloads(bool aSetResume);
|
||||
|
||||
/**
|
||||
* Resume all paused downloads unless we're only supposed to do the automatic
|
||||
* ones; in that case, try to retry them as well if resuming doesn't work.
|
||||
*
|
||||
* @param aResumeAll If true, all downloads will be resumed; otherwise, only
|
||||
* those that are marked as auto-resume will resume.
|
||||
*/
|
||||
nsresult ResumeAllDownloads(bool aResumeAll);
|
||||
|
||||
/**
|
||||
* Stop tracking the active downloads. Only use this when we're about to quit
|
||||
* the download manager because we destroy our list of active downloads to
|
||||
* break the dlmgr<->dl cycle. Active downloads that aren't real-paused will
|
||||
* be canceled.
|
||||
*/
|
||||
nsresult RemoveAllDownloads();
|
||||
|
||||
/**
|
||||
* Find all downloads from a source URI and delete them.
|
||||
*
|
||||
* @param aURI
|
||||
* The source URI to remove downloads
|
||||
*/
|
||||
nsresult RemoveDownloadsForURI(nsIURI *aURI);
|
||||
|
||||
/**
|
||||
* Callback used for resuming downloads after getting a wake notification.
|
||||
*
|
||||
* @param aTimer
|
||||
* Timer object fired after some delay after a wake notification
|
||||
* @param aClosure
|
||||
* nsDownloadManager object used to resume downloads
|
||||
*/
|
||||
static void ResumeOnWakeCallback(nsITimer *aTimer, void *aClosure);
|
||||
nsCOMPtr<nsITimer> mResumeOnWakeTimer;
|
||||
|
||||
void ConfirmCancelDownloads(int32_t aCount,
|
||||
nsISupportsPRBool *aCancelDownloads,
|
||||
const char16_t *aTitle,
|
||||
const char16_t *aCancelMessageMultiple,
|
||||
const char16_t *aCancelMessageSingle,
|
||||
const char16_t *aDontCancelButton);
|
||||
|
||||
int32_t GetRetentionBehavior();
|
||||
|
||||
/**
|
||||
* Type to indicate possible behaviors for active downloads across sessions.
|
||||
*
|
||||
* Possible values are:
|
||||
* QUIT_AND_RESUME - downloads should be auto-resumed
|
||||
* QUIT_AND_PAUSE - downloads should be paused
|
||||
* QUIT_AND_CANCEL - downloads should be cancelled
|
||||
*/
|
||||
enum QuitBehavior {
|
||||
QUIT_AND_RESUME = 0,
|
||||
QUIT_AND_PAUSE = 1,
|
||||
QUIT_AND_CANCEL = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates user-set behavior for active downloads across sessions,
|
||||
*
|
||||
* @return value of user-set pref for active download behavior
|
||||
*/
|
||||
enum QuitBehavior GetQuitBehavior();
|
||||
|
||||
void OnEnterPrivateBrowsingMode();
|
||||
void OnLeavePrivateBrowsingMode();
|
||||
|
||||
nsresult RetryDownload(const nsACString& aGUID);
|
||||
nsresult RetryDownload(nsDownload* dl);
|
||||
|
||||
nsresult RemoveDownload(const nsACString& aGUID);
|
||||
|
||||
nsresult NotifyDownloadRemoval(nsDownload* aRemoved);
|
||||
|
||||
// Virus scanner for windows
|
||||
#ifdef DOWNLOAD_SCANNER
|
||||
private:
|
||||
nsDownloadScanner* mScanner;
|
||||
#endif
|
||||
|
||||
private:
|
||||
nsresult CleanUp(mozIStorageConnection* aDBConn);
|
||||
nsresult InitStatements(mozIStorageConnection* aDBConn,
|
||||
mozIStorageStatement** aUpdateStatement,
|
||||
mozIStorageStatement** aGetIdsStatement);
|
||||
nsresult RemoveAllDownloads(nsCOMArray<nsDownload>& aDownloads);
|
||||
nsresult PauseAllDownloads(nsCOMArray<nsDownload>& aDownloads, bool aSetResume);
|
||||
nsresult ResumeAllDownloads(nsCOMArray<nsDownload>& aDownloads, bool aResumeAll);
|
||||
nsresult RemoveDownloadsForURI(mozIStorageStatement* aStatement, nsIURI *aURI);
|
||||
|
||||
bool mUseJSTransfer;
|
||||
nsCOMArray<nsIDownloadProgressListener> mListeners;
|
||||
nsCOMArray<nsIDownloadProgressListener> mPrivacyAwareListeners;
|
||||
nsCOMPtr<nsIStringBundle> mBundle;
|
||||
nsCOMPtr<mozIStorageConnection> mDBConn;
|
||||
nsCOMPtr<mozIStorageConnection> mPrivateDBConn;
|
||||
nsCOMArray<nsDownload> mCurrentDownloads;
|
||||
nsCOMArray<nsDownload> mCurrentPrivateDownloads;
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
nsCOMPtr<mozIStorageStatement> mUpdateDownloadStatement;
|
||||
nsCOMPtr<mozIStorageStatement> mUpdatePrivateDownloadStatement;
|
||||
nsCOMPtr<mozIStorageStatement> mGetIdsForURIStatement;
|
||||
nsCOMPtr<mozIStorageStatement> mGetPrivateIdsForURIStatement;
|
||||
nsAutoPtr<mozStorageTransaction> mHistoryTransaction;
|
||||
|
||||
static nsDownloadManager *gDownloadManagerService;
|
||||
|
||||
friend class nsDownload;
|
||||
};
|
||||
|
||||
class nsDownload final : public nsIDownload
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER2
|
||||
NS_DECL_NSITRANSFER
|
||||
NS_DECL_NSIDOWNLOAD
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDownload();
|
||||
|
||||
/**
|
||||
* This method MUST be called when changing states on a download. It will
|
||||
* notify the download listener when a change happens. This also updates the
|
||||
* database, by calling UpdateDB().
|
||||
*/
|
||||
nsresult SetState(DownloadState aState);
|
||||
|
||||
protected:
|
||||
virtual ~nsDownload();
|
||||
|
||||
/**
|
||||
* Finish up the download by breaking reference cycles and clearing unneeded
|
||||
* data. Additionally, the download removes itself from the download
|
||||
* manager's list of current downloads.
|
||||
*
|
||||
* NOTE: This method removes the cycle created when starting the download, so
|
||||
* make sure to use kungFuDeathGrip if you want to access member variables.
|
||||
*/
|
||||
void Finalize();
|
||||
|
||||
/**
|
||||
* For finished resumed downloads that came in from exthandler, perform the
|
||||
* action that would have been done if the download wasn't resumed.
|
||||
*/
|
||||
nsresult ExecuteDesiredAction();
|
||||
|
||||
/**
|
||||
* Move the temporary file to the final destination by removing the existing
|
||||
* dummy target and renaming the temporary.
|
||||
*/
|
||||
nsresult MoveTempToTarget();
|
||||
|
||||
/**
|
||||
* Set the target file permissions to be appropriate.
|
||||
*/
|
||||
nsresult FixTargetPermissions();
|
||||
|
||||
/**
|
||||
* Update the start time which also implies the last update time is the same.
|
||||
*/
|
||||
void SetStartTime(int64_t aStartTime);
|
||||
|
||||
/**
|
||||
* Update the amount of bytes transferred and max bytes; and recalculate the
|
||||
* download percent.
|
||||
*/
|
||||
void SetProgressBytes(int64_t aCurrBytes, int64_t aMaxBytes);
|
||||
|
||||
/**
|
||||
* All this does is cancel the connection that the download is using. It does
|
||||
* not remove it from the download manager.
|
||||
*/
|
||||
nsresult CancelTransfer();
|
||||
|
||||
/**
|
||||
* Download is not transferring?
|
||||
*/
|
||||
bool IsPaused();
|
||||
|
||||
/**
|
||||
* Download can continue from the middle of a transfer?
|
||||
*/
|
||||
bool IsResumable();
|
||||
|
||||
/**
|
||||
* Download was resumed?
|
||||
*/
|
||||
bool WasResumed();
|
||||
|
||||
/**
|
||||
* Indicates if the download should try to automatically resume or not.
|
||||
*/
|
||||
bool ShouldAutoResume();
|
||||
|
||||
/**
|
||||
* Download is in a state to stop and complete the download?
|
||||
*/
|
||||
bool IsFinishable();
|
||||
|
||||
/**
|
||||
* Download is totally done transferring and all?
|
||||
*/
|
||||
bool IsFinished();
|
||||
|
||||
/**
|
||||
* Update the DB with the current state of the download including time,
|
||||
* download state and other values not known when first creating the
|
||||
* download DB entry.
|
||||
*/
|
||||
nsresult UpdateDB();
|
||||
|
||||
/**
|
||||
* Fail a download because of a failure status and prompt the provided
|
||||
* message or use a generic download failure message if nullptr.
|
||||
*/
|
||||
nsresult FailDownload(nsresult aStatus, const char16_t *aMessage);
|
||||
|
||||
/**
|
||||
* Opens the downloaded file with the appropriate application, which is
|
||||
* either the OS default, MIME type default, or the one selected by the user.
|
||||
*
|
||||
* This also adds the temporary file to the "To be deleted on Exit" list, if
|
||||
* the corresponding user preference is set (except on OS X).
|
||||
*
|
||||
* This function was adopted from nsExternalAppHandler::OpenWithApplication
|
||||
* (uriloader/exthandler/nsExternalHelperAppService.cpp).
|
||||
*/
|
||||
nsresult OpenWithApplication();
|
||||
|
||||
nsDownloadManager *mDownloadManager;
|
||||
nsCOMPtr<nsIURI> mTarget;
|
||||
|
||||
private:
|
||||
nsString mDisplayName;
|
||||
nsCString mEntityID;
|
||||
nsCString mGUID;
|
||||
|
||||
nsCOMPtr<nsIURI> mSource;
|
||||
nsCOMPtr<nsIURI> mReferrer;
|
||||
nsCOMPtr<nsICancelable> mCancelable;
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
nsCOMPtr<nsIFile> mTempFile;
|
||||
nsCOMPtr<nsIMIMEInfo> mMIMEInfo;
|
||||
|
||||
DownloadState mDownloadState;
|
||||
|
||||
uint32_t mID;
|
||||
int32_t mPercentComplete;
|
||||
|
||||
/**
|
||||
* These bytes are based on the position of where the request started, so 0
|
||||
* doesn't necessarily mean we have nothing. Use GetAmountTransferred and
|
||||
* GetSize for the real transferred amount and size.
|
||||
*/
|
||||
int64_t mCurrBytes;
|
||||
int64_t mMaxBytes;
|
||||
|
||||
PRTime mStartTime;
|
||||
PRTime mLastUpdate;
|
||||
int64_t mResumedAt;
|
||||
double mSpeed;
|
||||
|
||||
bool mHasMultipleFiles;
|
||||
bool mPrivate;
|
||||
|
||||
/**
|
||||
* Track various states of the download trying to auto-resume when starting
|
||||
* the download manager or restoring from a crash.
|
||||
*
|
||||
* DONT_RESUME: Don't automatically resume the download
|
||||
* AUTO_RESUME: Automaically resume the download
|
||||
*/
|
||||
enum AutoResume { DONT_RESUME, AUTO_RESUME };
|
||||
AutoResume mAutoResume;
|
||||
|
||||
/**
|
||||
* Stores the SHA-256 hash associated with the downloaded file.
|
||||
*/
|
||||
nsCString mHash;
|
||||
|
||||
/**
|
||||
* Stores the certificate chains in an nsIArray of nsIX509CertList of
|
||||
* nsIX509Cert, if this binary is signed.
|
||||
*/
|
||||
nsCOMPtr<nsIArray> mSignatureInfo;
|
||||
|
||||
/**
|
||||
* Stores the redirects that led to this download in an nsIArray of
|
||||
* nsIPrincipal.
|
||||
*/
|
||||
nsCOMPtr<nsIArray> mRedirects;
|
||||
|
||||
friend class nsDownloadManager;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef downloadproxy___h___
|
||||
#define downloadproxy___h___
|
||||
|
||||
#include "nsIDownloadManager.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsIDownloadManagerUI.h"
|
||||
|
||||
#define PREF_BDM_SHOWWHENSTARTING "browser.download.manager.showWhenStarting"
|
||||
#define PREF_BDM_FOCUSWHENSTARTING "browser.download.manager.focusWhenStarting"
|
||||
|
||||
// This class only exists because nsDownload cannot inherit from nsITransfer
|
||||
// directly. The reason for this is that nsDownloadManager (incorrectly) keeps
|
||||
// an nsCOMArray of nsDownloads, and nsCOMArray is only intended for use with
|
||||
// abstract classes. Using a concrete class that multiply inherits from classes
|
||||
// deriving from nsISupports will throw ambiguous base class errors.
|
||||
class nsDownloadProxy : public nsITransfer
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual ~nsDownloadProxy() { }
|
||||
|
||||
public:
|
||||
|
||||
nsDownloadProxy() { }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(nsIURI* aSource,
|
||||
nsIURI* aTarget,
|
||||
const nsAString& aDisplayName,
|
||||
nsIMIMEInfo *aMIMEInfo,
|
||||
PRTime aStartTime,
|
||||
nsIFile* aTempFile,
|
||||
nsICancelable* aCancelable,
|
||||
bool aIsPrivate) override {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDownloadManager> dm = do_GetService("@mozilla.org/download-manager;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = dm->AddDownload(nsIDownloadManager::DOWNLOAD_TYPE_DOWNLOAD, aSource,
|
||||
aTarget, aDisplayName, aMIMEInfo, aStartTime,
|
||||
aTempFile, aCancelable, aIsPrivate,
|
||||
getter_AddRefs(mInner));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
|
||||
|
||||
bool showDM = true;
|
||||
if (branch)
|
||||
branch->GetBoolPref(PREF_BDM_SHOWWHENSTARTING, &showDM);
|
||||
|
||||
if (showDM) {
|
||||
nsCOMPtr<nsIDownloadManagerUI> dmui =
|
||||
do_GetService("@mozilla.org/download-manager-ui;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool visible;
|
||||
rv = dmui->GetVisible(&visible);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool focusWhenStarting = true;
|
||||
if (branch)
|
||||
(void)branch->GetBoolPref(PREF_BDM_FOCUSWHENSTARTING, &focusWhenStarting);
|
||||
|
||||
if (visible && !focusWhenStarting)
|
||||
return NS_OK;
|
||||
|
||||
return dmui->Show(nullptr, mInner, nsIDownloadManagerUI::REASON_NEW_DOWNLOAD, aIsPrivate);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStateChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest, uint32_t aStateFlags,
|
||||
nsresult aStatus) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStatusChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, nsresult aStatus,
|
||||
const char16_t *aMessage) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnLocationChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, nsIURI *aLocation,
|
||||
uint32_t aFlags) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnLocationChange(aWebProgress, aRequest, aLocation, aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnProgressChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest,
|
||||
int32_t aCurSelfProgress,
|
||||
int32_t aMaxSelfProgress,
|
||||
int32_t aCurTotalProgress,
|
||||
int32_t aMaxTotalProgress) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnProgressChange(aWebProgress, aRequest,
|
||||
aCurSelfProgress,
|
||||
aMaxSelfProgress,
|
||||
aCurTotalProgress,
|
||||
aMaxTotalProgress);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnProgressChange64(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest,
|
||||
int64_t aCurSelfProgress,
|
||||
int64_t aMaxSelfProgress,
|
||||
int64_t aCurTotalProgress,
|
||||
int64_t aMaxTotalProgress) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnProgressChange64(aWebProgress, aRequest,
|
||||
aCurSelfProgress,
|
||||
aMaxSelfProgress,
|
||||
aCurTotalProgress,
|
||||
aMaxTotalProgress);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnRefreshAttempted(nsIWebProgress *aWebProgress,
|
||||
nsIURI *aUri,
|
||||
int32_t aDelay,
|
||||
bool aSameUri,
|
||||
bool *allowRefresh) override
|
||||
{
|
||||
*allowRefresh = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnSecurityChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, uint32_t aState) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnSecurityChange(aWebProgress, aRequest, aState);
|
||||
}
|
||||
|
||||
NS_IMETHOD SetSha256Hash(const nsACString& aHash) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->SetSha256Hash(aHash);
|
||||
}
|
||||
|
||||
NS_IMETHOD SetSignatureInfo(nsIArray* aSignatureInfo) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->SetSignatureInfo(aSignatureInfo);
|
||||
}
|
||||
|
||||
NS_IMETHOD SetRedirects(nsIArray* aRedirects) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->SetRedirects(aRedirects);
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDownload> mInner;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDownloadProxy, nsITransfer,
|
||||
nsIWebProgressListener, nsIWebProgressListener2)
|
||||
|
||||
#endif
|
|
@ -1,728 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: se cin sw=2 ts=2 et : */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsDownloadScanner.h"
|
||||
#include <comcat.h>
|
||||
#include <process.h>
|
||||
#include "nsDownloadManager.h"
|
||||
#include "nsIXULAppInfo.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "prtime.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
|
||||
/**
|
||||
* Code overview
|
||||
*
|
||||
* Download scanner attempts to make use of one of two different virus
|
||||
* scanning interfaces available on Windows - IOfficeAntiVirus (Windows
|
||||
* 95/NT 4 and IE 5) and IAttachmentExecute (XPSP2 and up). The latter
|
||||
* interface supports calling IOfficeAntiVirus internally, while also
|
||||
* adding support for XPSP2+ ADS forks which define security related
|
||||
* prompting on downloaded content.
|
||||
*
|
||||
* Both interfaces are synchronous and can take a while, so it is not a
|
||||
* good idea to call either from the main thread. Some antivirus scanners can
|
||||
* take a long time to scan or the call might block while the scanner shows
|
||||
* its UI so if the user were to download many files that finished around the
|
||||
* same time, they would have to wait a while if the scanning were done on
|
||||
* exactly one other thread. Since the overhead of creating a thread is
|
||||
* relatively small compared to the time it takes to download a file and scan
|
||||
* it, a new thread is spawned for each download that is to be scanned. Since
|
||||
* most of the mozilla codebase is not threadsafe, all the information needed
|
||||
* for the scanner is gathered in the main thread in nsDownloadScanner::Scan::Start.
|
||||
* The only function of nsDownloadScanner::Scan which is invoked on another
|
||||
* thread is DoScan.
|
||||
*
|
||||
* Watchdog overview
|
||||
*
|
||||
* The watchdog is used internally by the scanner. It maintains a queue of
|
||||
* current download scans. In a separate thread, it dequeues the oldest scan
|
||||
* and waits on that scan's thread with a timeout given by WATCHDOG_TIMEOUT
|
||||
* (default is 30 seconds). If the wait times out, then the watchdog notifies
|
||||
* the Scan that it has timed out. If the scan really has timed out, then the
|
||||
* Scan object will dispatch its run method to the main thread; this will
|
||||
* release the watchdog thread's addref on the Scan. If it has not timed out
|
||||
* (i.e. the Scan just finished in time), then the watchdog dispatches a
|
||||
* ReleaseDispatcher to release its ref of the Scan on the main thread.
|
||||
*
|
||||
* In order to minimize execution time, there are two events used to notify the
|
||||
* watchdog thread of a non-empty queue and a quit event. Every blocking wait
|
||||
* that the watchdog thread does waits on the quit event; this lets the thread
|
||||
* quickly exit when shutting down. Also, the download scan queue will be empty
|
||||
* most of the time; rather than use a spin loop, a simple event is triggered
|
||||
* by the main thread when a new scan is added to an empty queue. When the
|
||||
* watchdog thread knows that it has run out of elements in the queue, it will
|
||||
* wait on the new item event.
|
||||
*
|
||||
* Memory/resource leaks due to timeout:
|
||||
* In the event of a timeout, the thread must remain alive; terminating it may
|
||||
* very well cause the antivirus scanner to crash or be put into an
|
||||
* inconsistent state; COM resources may also not be cleaned up. The downside
|
||||
* is that we need to leave the thread running; suspending it may lead to a
|
||||
* deadlock. Because the scan call may be ongoing, it may be dependent on the
|
||||
* memory referenced by the MSOAVINFO structure, so we cannot free mName, mPath
|
||||
* or mOrigin; this means that we cannot free the Scan object since doing so
|
||||
* will deallocate that memory. Note that mDownload is set to null upon timeout
|
||||
* or completion, so the download itself is never leaked. If the scan does
|
||||
* eventually complete, then the all the memory and resources will be freed.
|
||||
* It is possible, however extremely rare, that in the event of a timeout, the
|
||||
* mStateSync critical section will leak its event; this will happen only if
|
||||
* the scanning thread, watchdog thread or main thread try to enter the
|
||||
* critical section when one of the others is already in it.
|
||||
*
|
||||
* Reasoning for CheckAndSetState - there exists a race condition between the time when
|
||||
* either the timeout or normal scan sets the state and when Scan::Run is
|
||||
* executed on the main thread. Ex: mStatus could be set by Scan::DoScan* which
|
||||
* then queues a dispatch on the main thread. Before that dispatch is executed,
|
||||
* the timeout code fires and sets mStatus to AVSCAN_TIMEDOUT which then queues
|
||||
* its dispatch to the main thread (the same function as DoScan*). Both
|
||||
* dispatches run and both try to set the download state to AVSCAN_TIMEDOUT
|
||||
* which is incorrect.
|
||||
*
|
||||
* There are 5 possible outcomes of the virus scan:
|
||||
* AVSCAN_GOOD => the file is clean
|
||||
* AVSCAN_BAD => the file has a virus
|
||||
* AVSCAN_UGLY => the file had a virus, but it was cleaned
|
||||
* AVSCAN_FAILED => something else went wrong with the virus scanner.
|
||||
* AVSCAN_TIMEDOUT => the scan (thread setup + execution) took too long
|
||||
*
|
||||
* Both the good and ugly states leave the user with a benign file, so they
|
||||
* transition to the finished state. Bad files are sent to the blocked state.
|
||||
* The failed and timedout states transition to finished downloads.
|
||||
*
|
||||
* Possible Future enhancements:
|
||||
* * Create an interface for scanning files in general
|
||||
* * Make this a service
|
||||
* * Get antivirus scanner status via WMI/registry
|
||||
*/
|
||||
|
||||
// IAttachementExecute supports user definable settings for certain
|
||||
// security related prompts. This defines a general GUID for use in
|
||||
// all projects. Individual projects can define an individual guid
|
||||
// if they want to.
|
||||
#ifndef MOZ_VIRUS_SCANNER_PROMPT_GUID
|
||||
#define MOZ_VIRUS_SCANNER_PROMPT_GUID \
|
||||
{ 0xb50563d1, 0x16b6, 0x43c2, { 0xa6, 0x6a, 0xfa, 0xe6, 0xd2, 0x11, 0xf2, \
|
||||
0xea } }
|
||||
#endif
|
||||
static const GUID GUID_MozillaVirusScannerPromptGeneric =
|
||||
MOZ_VIRUS_SCANNER_PROMPT_GUID;
|
||||
|
||||
// Initial timeout is 30 seconds
|
||||
#define WATCHDOG_TIMEOUT (30*PR_USEC_PER_SEC)
|
||||
|
||||
// Maximum length for URI's passed into IAE
|
||||
#define MAX_IAEURILENGTH 1683
|
||||
|
||||
class nsDownloadScannerWatchdog
|
||||
{
|
||||
typedef nsDownloadScanner::Scan Scan;
|
||||
public:
|
||||
nsDownloadScannerWatchdog();
|
||||
~nsDownloadScannerWatchdog();
|
||||
|
||||
nsresult Init();
|
||||
nsresult Shutdown();
|
||||
|
||||
void Watch(Scan *scan);
|
||||
private:
|
||||
static unsigned int __stdcall WatchdogThread(void *p);
|
||||
CRITICAL_SECTION mQueueSync;
|
||||
nsDeque mScanQueue;
|
||||
HANDLE mThread;
|
||||
HANDLE mNewItemEvent;
|
||||
HANDLE mQuitEvent;
|
||||
};
|
||||
|
||||
nsDownloadScanner::nsDownloadScanner() :
|
||||
mAESExists(false)
|
||||
{
|
||||
}
|
||||
|
||||
// This destructor appeases the compiler; it would otherwise complain about an
|
||||
// incomplete type for nsDownloadWatchdog in the instantiation of
|
||||
// nsAutoPtr::~nsAutoPtr
|
||||
// Plus, it's a handy location to call nsDownloadScannerWatchdog::Shutdown from
|
||||
nsDownloadScanner::~nsDownloadScanner() {
|
||||
if (mWatchdog)
|
||||
(void)mWatchdog->Shutdown();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::Init()
|
||||
{
|
||||
// This CoInitialize/CoUninitialize pattern seems to be common in the Mozilla
|
||||
// codebase. All other COM calls/objects are made on different threads.
|
||||
nsresult rv = NS_OK;
|
||||
CoInitialize(nullptr);
|
||||
|
||||
if (!IsAESAvailable()) {
|
||||
CoUninitialize();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mAESExists = true;
|
||||
|
||||
// Initialize scanning
|
||||
mWatchdog = new nsDownloadScannerWatchdog();
|
||||
if (mWatchdog) {
|
||||
rv = mWatchdog->Init();
|
||||
if (FAILED(rv))
|
||||
mWatchdog = nullptr;
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::IsAESAvailable()
|
||||
{
|
||||
// Try to instantiate IAE to see if it's available.
|
||||
RefPtr<IAttachmentExecute> ae;
|
||||
HRESULT hr;
|
||||
hr = CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_INPROC,
|
||||
IID_IAttachmentExecute, getter_AddRefs(ae));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Could not instantiate attachment execution service\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If IAttachementExecute is available, use the CheckPolicy call to find out
|
||||
// if this download should be prevented due to Security Zone Policy settings.
|
||||
AVCheckPolicyState
|
||||
nsDownloadScanner::CheckPolicy(nsIURI *aSource, nsIURI *aTarget)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mAESExists || !aSource || !aTarget)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
nsAutoCString source;
|
||||
rv = aSource->GetSpec(source);
|
||||
if (NS_FAILED(rv))
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
nsCOMPtr<nsIFileURL> fileUrl(do_QueryInterface(aTarget));
|
||||
if (!fileUrl)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
nsCOMPtr<nsIFile> theFile;
|
||||
nsAutoString aFileName;
|
||||
if (NS_FAILED(fileUrl->GetFile(getter_AddRefs(theFile))) ||
|
||||
NS_FAILED(theFile->GetLeafName(aFileName)))
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
// IAttachementExecute prohibits src data: schemes by default but we
|
||||
// support them. If this is a data src, skip off doing a policy check.
|
||||
// (The file will still be scanned once it lands on the local system.)
|
||||
bool isDataScheme(false);
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aSource);
|
||||
if (innerURI)
|
||||
(void)innerURI->SchemeIs("data", &isDataScheme);
|
||||
if (isDataScheme)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
RefPtr<IAttachmentExecute> ae;
|
||||
HRESULT hr;
|
||||
hr = CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_INPROC,
|
||||
IID_IAttachmentExecute, getter_AddRefs(ae));
|
||||
if (FAILED(hr))
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
(void)ae->SetClientGuid(GUID_MozillaVirusScannerPromptGeneric);
|
||||
(void)ae->SetSource(NS_ConvertUTF8toUTF16(source).get());
|
||||
(void)ae->SetFileName(aFileName.get());
|
||||
|
||||
// Any failure means the file download/exec will be blocked by the system.
|
||||
// S_OK or S_FALSE imply it's ok.
|
||||
hr = ae->CheckPolicy();
|
||||
|
||||
if (hr == S_OK)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
if (hr == S_FALSE)
|
||||
return AVPOLICY_PROMPT;
|
||||
|
||||
if (hr == E_INVALIDARG)
|
||||
return AVPOLICY_PROMPT;
|
||||
|
||||
return AVPOLICY_BLOCKED;
|
||||
}
|
||||
|
||||
#ifndef THREAD_MODE_BACKGROUND_BEGIN
|
||||
#define THREAD_MODE_BACKGROUND_BEGIN 0x00010000
|
||||
#endif
|
||||
|
||||
#ifndef THREAD_MODE_BACKGROUND_END
|
||||
#define THREAD_MODE_BACKGROUND_END 0x00020000
|
||||
#endif
|
||||
|
||||
unsigned int __stdcall
|
||||
nsDownloadScanner::ScannerThreadFunction(void *p)
|
||||
{
|
||||
HANDLE currentThread = GetCurrentThread();
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Antivirus scan should not be run on the main thread");
|
||||
nsDownloadScanner::Scan *scan = static_cast<nsDownloadScanner::Scan*>(p);
|
||||
if (!SetThreadPriority(currentThread, THREAD_MODE_BACKGROUND_BEGIN))
|
||||
(void)SetThreadPriority(currentThread, THREAD_PRIORITY_IDLE);
|
||||
scan->DoScan();
|
||||
(void)SetThreadPriority(currentThread, THREAD_MODE_BACKGROUND_END);
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The sole purpose of this class is to release an object on the main thread
|
||||
// It assumes that its creator will addref it and it will release itself on
|
||||
// the main thread too
|
||||
class ReleaseDispatcher : public mozilla::Runnable {
|
||||
public:
|
||||
explicit ReleaseDispatcher(nsISupports *ptr)
|
||||
: mPtr(ptr) {}
|
||||
NS_IMETHOD Run();
|
||||
private:
|
||||
nsISupports *mPtr;
|
||||
};
|
||||
|
||||
nsresult ReleaseDispatcher::Run() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Antivirus scan release dispatch should be run on the main thread");
|
||||
NS_RELEASE(mPtr);
|
||||
NS_RELEASE_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDownloadScanner::Scan::Scan(nsDownloadScanner *scanner, nsDownload *download)
|
||||
: mDLScanner(scanner), mThread(nullptr),
|
||||
mDownload(download), mStatus(AVSCAN_NOTSTARTED),
|
||||
mSkipSource(false)
|
||||
{
|
||||
InitializeCriticalSection(&mStateSync);
|
||||
}
|
||||
|
||||
nsDownloadScanner::Scan::~Scan() {
|
||||
DeleteCriticalSection(&mStateSync);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::Scan::Start()
|
||||
{
|
||||
mStartTime = PR_Now();
|
||||
|
||||
mThread = (HANDLE)_beginthreadex(nullptr, 0, ScannerThreadFunction,
|
||||
this, CREATE_SUSPENDED, nullptr);
|
||||
if (!mThread)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Get the path to the file on disk
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = mDownload->GetTargetFile(getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = file->GetPath(mPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Grab the app name
|
||||
nsCOMPtr<nsIXULAppInfo> appinfo =
|
||||
do_GetService(XULAPPINFO_SERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString name;
|
||||
rv = appinfo->GetName(name);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
CopyUTF8toUTF16(name, mName);
|
||||
|
||||
// Get the origin
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = mDownload->GetSource(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString origin;
|
||||
rv = uri->GetSpec(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Certain virus interfaces do not like extremely long uris.
|
||||
// Chop off the path and cgi data and just pass the base domain.
|
||||
if (origin.Length() > MAX_IAEURILENGTH) {
|
||||
rv = uri->GetPrePath(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
CopyUTF8toUTF16(origin, mOrigin);
|
||||
|
||||
// We count https/ftp/http as an http download
|
||||
bool isHttp(false), isFtp(false), isHttps(false);
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
|
||||
if (!innerURI) innerURI = uri;
|
||||
(void)innerURI->SchemeIs("http", &isHttp);
|
||||
(void)innerURI->SchemeIs("ftp", &isFtp);
|
||||
(void)innerURI->SchemeIs("https", &isHttps);
|
||||
mIsHttpDownload = isHttp || isFtp || isHttps;
|
||||
|
||||
// IAttachementExecute prohibits src data: schemes by default but we
|
||||
// support them. Mark the download if it's a data scheme, so we
|
||||
// can skip off supplying the src to IAttachementExecute when we scan
|
||||
// the resulting file.
|
||||
(void)innerURI->SchemeIs("data", &mSkipSource);
|
||||
|
||||
// ResumeThread returns the previous suspend count
|
||||
if (1 != ::ResumeThread(mThread)) {
|
||||
CloseHandle(mThread);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::Scan::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Antivirus scan dispatch should be run on the main thread");
|
||||
|
||||
// Cleanup our thread
|
||||
if (mStatus != AVSCAN_TIMEDOUT)
|
||||
WaitForSingleObject(mThread, INFINITE);
|
||||
CloseHandle(mThread);
|
||||
|
||||
DownloadState downloadState = 0;
|
||||
EnterCriticalSection(&mStateSync);
|
||||
switch (mStatus) {
|
||||
case AVSCAN_BAD:
|
||||
downloadState = nsIDownloadManager::DOWNLOAD_DIRTY;
|
||||
break;
|
||||
default:
|
||||
case AVSCAN_FAILED:
|
||||
case AVSCAN_GOOD:
|
||||
case AVSCAN_UGLY:
|
||||
case AVSCAN_TIMEDOUT:
|
||||
downloadState = nsIDownloadManager::DOWNLOAD_FINISHED;
|
||||
break;
|
||||
}
|
||||
LeaveCriticalSection(&mStateSync);
|
||||
// Download will be null if we already timed out
|
||||
if (mDownload)
|
||||
(void)mDownload->SetState(downloadState);
|
||||
|
||||
// Clean up some other variables
|
||||
// In the event of a timeout, our destructor won't be called
|
||||
mDownload = nullptr;
|
||||
|
||||
NS_RELEASE_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static DWORD
|
||||
ExceptionFilterFunction(DWORD exceptionCode) {
|
||||
switch(exceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::Scan::DoScanAES()
|
||||
{
|
||||
// This warning is for the destructor of ae which will not be invoked in the
|
||||
// event of a win32 exception
|
||||
#pragma warning(disable: 4509)
|
||||
HRESULT hr;
|
||||
RefPtr<IAttachmentExecute> ae;
|
||||
MOZ_SEH_TRY {
|
||||
hr = CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_ALL,
|
||||
IID_IAttachmentExecute, getter_AddRefs(ae));
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
return CheckAndSetState(AVSCAN_NOTSTARTED,AVSCAN_FAILED);
|
||||
}
|
||||
|
||||
// If we (somehow) already timed out, then don't bother scanning
|
||||
if (CheckAndSetState(AVSCAN_SCANNING, AVSCAN_NOTSTARTED)) {
|
||||
AVScanState newState;
|
||||
if (SUCCEEDED(hr)) {
|
||||
bool gotException = false;
|
||||
MOZ_SEH_TRY {
|
||||
(void)ae->SetClientGuid(GUID_MozillaVirusScannerPromptGeneric);
|
||||
(void)ae->SetLocalPath(mPath.get());
|
||||
// Provide the src for everything but data: schemes.
|
||||
if (!mSkipSource)
|
||||
(void)ae->SetSource(mOrigin.get());
|
||||
|
||||
// Save() will invoke the scanner
|
||||
hr = ae->Save();
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
ae = nullptr;
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
if(gotException) {
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
else if (SUCCEEDED(hr)) { // Passed the scan
|
||||
newState = AVSCAN_GOOD;
|
||||
}
|
||||
else if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND) {
|
||||
NS_WARNING("Downloaded file disappeared before it could be scanned");
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
else if (hr == E_INVALIDARG) {
|
||||
NS_WARNING("IAttachementExecute returned invalid argument error");
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
else {
|
||||
newState = AVSCAN_UGLY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
return CheckAndSetState(newState, AVSCAN_SCANNING);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#pragma warning(default: 4509)
|
||||
|
||||
void
|
||||
nsDownloadScanner::Scan::DoScan()
|
||||
{
|
||||
CoInitialize(nullptr);
|
||||
|
||||
if (DoScanAES()) {
|
||||
// We need to do a few more things on the main thread
|
||||
NS_DispatchToMainThread(this);
|
||||
} else {
|
||||
// We timed out, so just release
|
||||
ReleaseDispatcher* releaser = new ReleaseDispatcher(ToSupports(this));
|
||||
if(releaser) {
|
||||
NS_ADDREF(releaser);
|
||||
NS_DispatchToMainThread(releaser);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
CoUninitialize();
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
// Not much we can do at this point...
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE
|
||||
nsDownloadScanner::Scan::GetWaitableThreadHandle() const
|
||||
{
|
||||
HANDLE targetHandle = INVALID_HANDLE_VALUE;
|
||||
(void)DuplicateHandle(GetCurrentProcess(), mThread,
|
||||
GetCurrentProcess(), &targetHandle,
|
||||
SYNCHRONIZE, // Only allow clients to wait on this handle
|
||||
FALSE, // cannot be inherited by child processes
|
||||
0);
|
||||
return targetHandle;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::Scan::NotifyTimeout()
|
||||
{
|
||||
bool didTimeout = CheckAndSetState(AVSCAN_TIMEDOUT, AVSCAN_SCANNING) ||
|
||||
CheckAndSetState(AVSCAN_TIMEDOUT, AVSCAN_NOTSTARTED);
|
||||
if (didTimeout) {
|
||||
// We need to do a few more things on the main thread
|
||||
NS_DispatchToMainThread(this);
|
||||
}
|
||||
return didTimeout;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::Scan::CheckAndSetState(AVScanState newState, AVScanState expectedState) {
|
||||
bool gotExpectedState = false;
|
||||
EnterCriticalSection(&mStateSync);
|
||||
if((gotExpectedState = (mStatus == expectedState)))
|
||||
mStatus = newState;
|
||||
LeaveCriticalSection(&mStateSync);
|
||||
return gotExpectedState;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::ScanDownload(nsDownload *download)
|
||||
{
|
||||
if (!mAESExists)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// No ref ptr, see comment below
|
||||
Scan *scan = new Scan(this, download);
|
||||
if (!scan)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(scan);
|
||||
|
||||
nsresult rv = scan->Start();
|
||||
|
||||
// Note that we only release upon error. On success, the scan is passed off
|
||||
// to a new thread. It is eventually released in Scan::Run on the main thread.
|
||||
if (NS_FAILED(rv))
|
||||
NS_RELEASE(scan);
|
||||
else
|
||||
// Notify the watchdog
|
||||
mWatchdog->Watch(scan);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsDownloadScannerWatchdog::nsDownloadScannerWatchdog()
|
||||
: mNewItemEvent(nullptr), mQuitEvent(nullptr) {
|
||||
InitializeCriticalSection(&mQueueSync);
|
||||
}
|
||||
nsDownloadScannerWatchdog::~nsDownloadScannerWatchdog() {
|
||||
DeleteCriticalSection(&mQueueSync);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScannerWatchdog::Init() {
|
||||
// Both events are auto-reset
|
||||
mNewItemEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (INVALID_HANDLE_VALUE == mNewItemEvent)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mQuitEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (INVALID_HANDLE_VALUE == mQuitEvent) {
|
||||
(void)CloseHandle(mNewItemEvent);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// This thread is always running, however it will be asleep
|
||||
// for most of the dlmgr's lifetime
|
||||
mThread = (HANDLE)_beginthreadex(nullptr, 0, WatchdogThread,
|
||||
this, 0, nullptr);
|
||||
if (!mThread) {
|
||||
(void)CloseHandle(mNewItemEvent);
|
||||
(void)CloseHandle(mQuitEvent);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScannerWatchdog::Shutdown() {
|
||||
// Tell the watchdog thread to quite
|
||||
(void)SetEvent(mQuitEvent);
|
||||
(void)WaitForSingleObject(mThread, INFINITE);
|
||||
(void)CloseHandle(mThread);
|
||||
// Manually clear and release the queued scans
|
||||
while (mScanQueue.GetSize() != 0) {
|
||||
Scan *scan = reinterpret_cast<Scan*>(mScanQueue.Pop());
|
||||
NS_RELEASE(scan);
|
||||
}
|
||||
(void)CloseHandle(mNewItemEvent);
|
||||
(void)CloseHandle(mQuitEvent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDownloadScannerWatchdog::Watch(Scan *scan) {
|
||||
bool wasEmpty;
|
||||
// Note that there is no release in this method
|
||||
// The scan will be released by the watchdog ALWAYS on the main thread
|
||||
// when either the watchdog thread processes the scan or the watchdog
|
||||
// is shut down
|
||||
NS_ADDREF(scan);
|
||||
EnterCriticalSection(&mQueueSync);
|
||||
wasEmpty = mScanQueue.GetSize()==0;
|
||||
mScanQueue.Push(scan);
|
||||
LeaveCriticalSection(&mQueueSync);
|
||||
// If the queue was empty, then the watchdog thread is/will be asleep
|
||||
if (wasEmpty)
|
||||
(void)SetEvent(mNewItemEvent);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
__stdcall
|
||||
nsDownloadScannerWatchdog::WatchdogThread(void *p) {
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Antivirus scan watchdog should not be run on the main thread");
|
||||
nsDownloadScannerWatchdog *watchdog = (nsDownloadScannerWatchdog*)p;
|
||||
HANDLE waitHandles[3] = {watchdog->mNewItemEvent, watchdog->mQuitEvent, INVALID_HANDLE_VALUE};
|
||||
DWORD waitStatus;
|
||||
DWORD queueItemsLeft = 0;
|
||||
// Loop until quit event or error
|
||||
while (0 != queueItemsLeft ||
|
||||
((WAIT_OBJECT_0 + 1) !=
|
||||
(waitStatus =
|
||||
WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE)) &&
|
||||
waitStatus != WAIT_FAILED)) {
|
||||
Scan *scan = nullptr;
|
||||
PRTime startTime, expectedEndTime, now;
|
||||
DWORD waitTime;
|
||||
|
||||
// Pop scan from queue
|
||||
EnterCriticalSection(&watchdog->mQueueSync);
|
||||
scan = reinterpret_cast<Scan*>(watchdog->mScanQueue.Pop());
|
||||
queueItemsLeft = watchdog->mScanQueue.GetSize();
|
||||
LeaveCriticalSection(&watchdog->mQueueSync);
|
||||
|
||||
// Calculate expected end time
|
||||
startTime = scan->GetStartTime();
|
||||
expectedEndTime = WATCHDOG_TIMEOUT + startTime;
|
||||
now = PR_Now();
|
||||
// PRTime is not guaranteed to be a signed integral type (afaik), but
|
||||
// currently it is
|
||||
if (now > expectedEndTime) {
|
||||
waitTime = 0;
|
||||
} else {
|
||||
// This is a positive value, and we know that it will not overflow
|
||||
// (bounded by WATCHDOG_TIMEOUT)
|
||||
// waitTime is in milliseconds, nspr uses microseconds
|
||||
waitTime = static_cast<DWORD>((expectedEndTime - now)/PR_USEC_PER_MSEC);
|
||||
}
|
||||
HANDLE hThread = waitHandles[2] = scan->GetWaitableThreadHandle();
|
||||
|
||||
// Wait for the thread (obj 1) or quit event (obj 0)
|
||||
waitStatus = WaitForMultipleObjects(2, (waitHandles+1), FALSE, waitTime);
|
||||
CloseHandle(hThread);
|
||||
|
||||
ReleaseDispatcher* releaser = new ReleaseDispatcher(ToSupports(scan));
|
||||
if(!releaser)
|
||||
continue;
|
||||
NS_ADDREF(releaser);
|
||||
// Got quit event or error
|
||||
if (waitStatus == WAIT_FAILED || waitStatus == WAIT_OBJECT_0) {
|
||||
NS_DispatchToMainThread(releaser);
|
||||
break;
|
||||
// Thread exited normally
|
||||
} else if (waitStatus == (WAIT_OBJECT_0+1)) {
|
||||
NS_DispatchToMainThread(releaser);
|
||||
continue;
|
||||
// Timeout case
|
||||
} else {
|
||||
NS_ASSERTION(waitStatus == WAIT_TIMEOUT, "Unexpected wait status in dlmgr watchdog thread");
|
||||
if (!scan->NotifyTimeout()) {
|
||||
// If we didn't time out, then release the thread
|
||||
NS_DispatchToMainThread(releaser);
|
||||
} else {
|
||||
// NotifyTimeout did a dispatch which will release the scan, so we
|
||||
// don't need to release the scan
|
||||
NS_RELEASE(releaser);
|
||||
}
|
||||
}
|
||||
}
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
/* vim: se cin sw=2 ts=2 et : */
|
||||
|
||||
#ifndef nsDownloadScanner_h_
|
||||
#define nsDownloadScanner_h_
|
||||
|
||||
#ifdef WIN32_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#define AVVENDOR
|
||||
#include <objidl.h>
|
||||
#include <msoav.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
enum AVScanState
|
||||
{
|
||||
AVSCAN_NOTSTARTED = 0,
|
||||
AVSCAN_SCANNING,
|
||||
AVSCAN_GOOD,
|
||||
AVSCAN_BAD,
|
||||
AVSCAN_UGLY,
|
||||
AVSCAN_FAILED,
|
||||
AVSCAN_TIMEDOUT
|
||||
};
|
||||
|
||||
enum AVCheckPolicyState
|
||||
{
|
||||
AVPOLICY_DOWNLOAD,
|
||||
AVPOLICY_PROMPT,
|
||||
AVPOLICY_BLOCKED
|
||||
};
|
||||
|
||||
// See nsDownloadScanner.cpp for declaration and definition
|
||||
class nsDownloadScannerWatchdog;
|
||||
class nsDownload;
|
||||
|
||||
class nsDownloadScanner
|
||||
{
|
||||
public:
|
||||
nsDownloadScanner();
|
||||
~nsDownloadScanner();
|
||||
nsresult Init();
|
||||
nsresult ScanDownload(nsDownload *download);
|
||||
AVCheckPolicyState CheckPolicy(nsIURI *aSource, nsIURI *aTarget);
|
||||
|
||||
private:
|
||||
bool mAESExists;
|
||||
nsTArray<CLSID> mScanCLSID;
|
||||
bool IsAESAvailable();
|
||||
bool EnumerateOAVProviders();
|
||||
|
||||
nsAutoPtr<nsDownloadScannerWatchdog> mWatchdog;
|
||||
|
||||
static unsigned int __stdcall ScannerThreadFunction(void *p);
|
||||
class Scan : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
Scan(nsDownloadScanner *scanner, nsDownload *download);
|
||||
~Scan();
|
||||
nsresult Start();
|
||||
|
||||
// Returns the time that Start was called
|
||||
PRTime GetStartTime() const { return mStartTime; }
|
||||
// Returns a copy of the thread handle that can be waited on, but not
|
||||
// terminated
|
||||
// The caller is responsible for closing the handle
|
||||
// If the thread has terminated, then this will return the pseudo-handle
|
||||
// INVALID_HANDLE_VALUE
|
||||
HANDLE GetWaitableThreadHandle() const;
|
||||
|
||||
// Called on a secondary thread to notify the scan that it has timed out
|
||||
// this is used only by the watchdog thread
|
||||
bool NotifyTimeout();
|
||||
|
||||
private:
|
||||
nsDownloadScanner *mDLScanner;
|
||||
PRTime mStartTime;
|
||||
HANDLE mThread;
|
||||
RefPtr<nsDownload> mDownload;
|
||||
// Guards mStatus
|
||||
CRITICAL_SECTION mStateSync;
|
||||
AVScanState mStatus;
|
||||
nsString mPath;
|
||||
nsString mName;
|
||||
nsString mOrigin;
|
||||
// Also true if it is an ftp download
|
||||
bool mIsHttpDownload;
|
||||
bool mSkipSource;
|
||||
|
||||
/* @summary Sets the Scan's state to newState if the current state is
|
||||
expectedState
|
||||
* @param newState The new state of the scan
|
||||
* @param expectedState The state that the caller expects the scan to be in
|
||||
* @return If the old state matched expectedState
|
||||
*/
|
||||
bool CheckAndSetState(AVScanState newState, AVScanState expectedState);
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
void DoScan();
|
||||
bool DoScanAES();
|
||||
bool DoScanOAV();
|
||||
|
||||
friend unsigned int __stdcall nsDownloadScanner::ScannerThreadFunction(void *);
|
||||
};
|
||||
// Used to give access to Scan
|
||||
friend class nsDownloadScannerWatchdog;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
* 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/. */
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsIController.h"
|
||||
|
|
Загрузка…
Ссылка в новой задаче