Backed out changeset 019382e24635 (bug 858234) for Linux mochitest-5 leaks.

This commit is contained in:
Ryan VanderMeulen 2013-05-31 16:06:10 -04:00
Родитель f69515d8d9
Коммит b5aaf55a6a
9 изменённых файлов: 310 добавлений и 198 удалений

Просмотреть файл

@ -2525,13 +2525,6 @@ nsDownload::~nsDownload()
{
}
NS_IMETHODIMP nsDownload::SetSha256Hash(const nsACString& aHash) {
MOZ_ASSERT(NS_IsMainThread(), "Must call SetSha256Hash on main thread");
// This will be used later to query the application reputation service.
mHash = aHash;
return NS_OK;
}
#ifdef MOZ_ENABLE_GIO
static void gio_set_metadata_done(GObject *source_obj, GAsyncResult *res, gpointer user_data)
{
@ -2594,6 +2587,7 @@ nsDownload::SetState(DownloadState aState)
#endif
case nsIDownloadManager::DOWNLOAD_FINISHED:
{
// Do what exthandler would have done if necessary
nsresult rv = ExecuteDesiredAction();
if (NS_FAILED(rv)) {
// We've failed to execute the desired action. As a result, we should
@ -2935,8 +2929,6 @@ nsDownload::OnStateChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, uint32_t aStateFlags,
nsresult aStatus)
{
MOZ_ASSERT(NS_IsMainThread(), "Must call OnStateChange in main thread");
// We don't want to lose access to our member variables
nsRefPtr<nsDownload> kungFuDeathGrip = this;
@ -3196,12 +3188,10 @@ nsDownload::Finalize()
nsresult
nsDownload::ExecuteDesiredAction()
{
// nsExternalHelperAppHandler is the only caller of AddDownload that sets a
// tempfile parameter. In this case, execute the desired action according to
// the saved mime info.
if (!mTempFile) {
// If we have a temp file and we have resumed, we have to do what the
// external helper app service would have done.
if (!mTempFile || !WasResumed())
return NS_OK;
}
// We need to bail if for some reason the temp file got removed
bool fileExists;

Просмотреть файл

@ -421,11 +421,6 @@ private:
enum AutoResume { DONT_RESUME, AUTO_RESUME };
AutoResume mAutoResume;
/**
* Stores the SHA-256 hash associated with the downloaded file.
*/
nsAutoCString mHash;
friend class nsDownloadManager;
};

Просмотреть файл

@ -16,11 +16,6 @@
#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
{
public:
@ -148,12 +143,6 @@ public:
return mInner->OnSecurityChange(aWebProgress, aRequest, aState);
}
NS_IMETHODIMP SetSha256Hash(const nsACString& aHash)
{
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
return mInner->SetSha256Hash(aHash);
}
private:
nsCOMPtr<nsIDownload> mInner;
};

Просмотреть файл

@ -114,12 +114,8 @@ interface nsIDownloadManager : nsISupports {
* @param aTempFile The location of a temporary file; i.e. a file in which
* the received data will be stored, but which is not
* equal to the target file. (will be moved to the real
* target by the DownloadManager, when the download is
* finished). This will be null for all callers except for
* nsExternalHelperAppHandler. Addons should generally pass
* null for aTempFile. This will be moved to the real target
* by the download manager when the download is finished,
* and the action indicated by aMIMEInfo will be executed.
* target by the caller, when the download is finished)
* May be null.
*
* @param aCancelable An object that can be used to abort the download.
* Must not be null.

Просмотреть файл

@ -52,8 +52,7 @@ MockTransfer.prototype = {
onRefreshAttempted: function () {},
/* nsITransfer */
init: function() {},
setSha256Hash: function() {}
init: function () {}
};
// Create an instance of a MockObjectRegisterer whose methods can be used to

Просмотреть файл

@ -10,7 +10,7 @@ interface nsICancelable;
interface nsIMIMEInfo;
interface nsIFile;
[scriptable, uuid(b1c81100-9d66-11e2-9e96-0800200c9a66)]
[scriptable, uuid(08b0b78c-6d7d-4d97-86c9-be5a695813c9)]
interface nsITransfer : nsIWebProgressListener2 {
/**
@ -57,14 +57,6 @@ interface nsITransfer : nsIWebProgressListener2 {
in nsIFile aTempFile,
in nsICancelable aCancelable,
in boolean aIsPrivate);
/*
* Used to notify the transfer object of the hash of the downloaded file.
* Must be called on the main thread, only after the download has finished
* successfully.
* @param aHash The SHA-256 hash in raw bytes of the downloaded file.
*/
void setSha256Hash(in ACString aHash);
};
%{C++

Просмотреть файл

@ -141,8 +141,8 @@ PRLogModuleInfo* nsExternalHelperAppService::mLog = nullptr;
// of PR_LOG_DEBUG (4), and we want less detailed output here
// Using 3 instead of PR_LOG_WARN because we don't output warnings
#undef LOG
#define LOG(args) PR_LOG(nsExternalHelperAppService::mLog, 3, args)
#define LOG_ENABLED() PR_LOG_TEST(nsExternalHelperAppService::mLog, 3)
#define LOG(args) PR_LOG(mLog, 3, args)
#define LOG_ENABLED() PR_LOG_TEST(mLog, 3)
static const char NEVER_ASK_FOR_SAVE_TO_DISK_PREF[] =
"browser.helperApps.neverAsk.saveToDisk";
@ -1111,13 +1111,14 @@ nsExternalAppHandler::nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo,
, mForceSave(aForceSave)
, mCanceled(false)
, mShouldCloseWindow(false)
, mReceivedDispositionInfo(false)
, mStopRequestIssued(false)
, mProgressListenerInitialized(false)
, mReason(aReason)
, mContentLength(-1)
, mProgress(0)
, mSaver(nullptr)
, mDialogProgressListener(nullptr)
, mTransfer(nullptr)
, mKeepRequestAlive(false)
, mRequest(nullptr)
, mExtProtSvc(aExtProtSvc)
{
@ -1157,9 +1158,24 @@ nsExternalAppHandler::~nsExternalAppHandler()
NS_IMETHODIMP nsExternalAppHandler::SetWebProgressListener(nsIWebProgressListener2 * aWebProgressListener)
{
// This is always called by nsHelperDlg.js. Go ahead and register the
// progress listener. At this point, we don't have mTransfer.
mDialogProgressListener = aWebProgressListener;
// this call back means we've successfully brought up the
// progress window so set the appropriate flag, even though
// aWebProgressListener might be null
if (mReceivedDispositionInfo)
mProgressListenerInitialized = true;
// Go ahead and register the progress listener....
mWebProgressListener = aWebProgressListener;
// while we were bringing up the progress dialog, we actually finished processing the
// url. If that's the case then mStopRequestIssued will be true. We need to execute the
// operation since we are actually done now.
if (mStopRequestIssued && aWebProgressListener)
{
return ExecuteDesiredAction();
}
return NS_OK;
}
@ -1197,6 +1213,13 @@ NS_IMETHODIMP nsExternalAppHandler::GetContentLength(int64_t *aContentLength)
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::CloseProgressWindow()
{
// release extra state...
mWebProgressListener = nullptr;
return NS_OK;
}
void nsExternalAppHandler::RetargetLoadNotifications(nsIRequest *request)
{
// we are going to run the downloading of the helper app in our own little docloader / load group context.
@ -1377,10 +1400,6 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel)
return rv;
}
rv = mSaver->EnableSha256();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Enabled hashing"));
rv = mSaver->SetTarget(mTempFile, false);
NS_ENSURE_SUCCESS(rv, rv);
@ -1575,18 +1594,25 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
if (alwaysAsk)
{
// do this first! make sure we don't try to take an action until the user tells us what they want to do
// with it...
mReceivedDispositionInfo = false;
mKeepRequestAlive = true;
// invoke the dialog!!!!! use mWindowContext as the window context parameter for the dialog request
mDialog = do_CreateInstance( NS_HELPERAPPLAUNCHERDLG_CONTRACTID, &rv );
NS_ENSURE_SUCCESS(rv, rv);
// this will create a reference cycle (the dialog holds a reference to us as
// nsIHelperAppLauncher), which will be broken in Cancel or CreateTransfer.
// nsIHelperAppLauncher), which will be broken in Cancel or
// CreateProgressListener.
rv = mDialog->Show( this, mWindowContext, mReason );
// what do we do if the dialog failed? I guess we should call Cancel and abort the load....
}
else
{
mReceivedDispositionInfo = true; // no need to wait for a response from the user
// We need to do the save/open immediately, then.
#ifdef XP_WIN
@ -1631,8 +1657,8 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
return NS_OK;
}
// Convert error info into proper message text and send OnStatusChange
// notification to the dialog progress listener or nsITransfer implementation.
// Convert error info into proper message text and send OnStatusChange notification
// to the web progress listener.
void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, nsIRequest *aRequest, const nsAFlatString &path)
{
nsAutoString msgId;
@ -1698,7 +1724,7 @@ void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, nsIRequ
}
PR_LOG(nsExternalHelperAppService::mLog, PR_LOG_ERROR,
("Error: %s, type=%i, listener=0x%p, rv=0x%08X\n",
NS_LossyConvertUTF16toASCII(msgId).get(), type, mDialogProgressListener.get(), rv));
NS_LossyConvertUTF16toASCII(msgId).get(), type, mWebProgressListener.get(), rv));
PR_LOG(nsExternalHelperAppService::mLog, PR_LOG_ERROR,
(" path='%s'\n", NS_ConvertUTF16toUTF8(path).get()));
@ -1714,12 +1740,10 @@ void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, nsIRequ
const PRUnichar *strings[] = { path.get() };
if(NS_SUCCEEDED(bundle->FormatStringFromName(msgId.get(), strings, 1, getter_Copies(msgText))))
{
if (mDialogProgressListener)
if (mWebProgressListener)
{
// We have a listener, let it handle the error.
mDialogProgressListener->OnStatusChange(nullptr, (type == kReadError) ? aRequest : nullptr, rv, msgText);
} else if (mTransfer) {
mTransfer->OnStatusChange(nullptr, (type == kReadError) ? aRequest : nullptr, rv, msgText);
mWebProgressListener->OnStatusChange(nullptr, (type == kReadError) ? aRequest : nullptr, rv, msgText);
}
else
if (XRE_GetProcessType() == GeckoProcessType_Default) {
@ -1760,10 +1784,11 @@ nsExternalAppHandler::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
if (NS_SUCCEEDED(rv))
{
// Send progress notification.
if (mTransfer) {
mTransfer->OnProgressChange64(nullptr, request, mProgress,
mContentLength, mProgress,
mContentLength);
if (mWebProgressListener)
{
mWebProgressListener->OnProgressChange64(nullptr, request, mProgress,
mContentLength, mProgress,
mContentLength);
}
}
else
@ -1786,6 +1811,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStopRequest(nsIRequest *request, nsISuppor
{
mStopRequestIssued = true;
if (!mKeepRequestAlive)
mRequest = nullptr;
// Cancel if the request did not complete successfully.
if (!mCanceled && NS_FAILED(aStatus))
{
@ -1816,10 +1844,6 @@ NS_IMETHODIMP
nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver *aSaver,
nsresult aStatus)
{
// Save the hash
nsresult rv = mSaver->GetSha256Hash(mHash);
NS_ENSURE_SUCCESS(rv, rv);
// Free the reference that the saver keeps on us.
mSaver = nullptr;
@ -1835,48 +1859,57 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver *aSaver,
return NS_OK;
}
// Notify the transfer object that we are done if the user has chosen an
// action. If the user hasn't chosen an action and InitializeDownload hasn't
// been called, the progress listener (nsITransfer) will be notified in
// CreateTransfer.
if (mTransfer) {
rv = NotifyTransfer();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult nsExternalAppHandler::NotifyTransfer()
{
MOZ_ASSERT(NS_IsMainThread(), "Must notify on main thread");
MOZ_ASSERT(!mCanceled, "Can't notify if canceled or action "
"hasn't been chosen");
MOZ_ASSERT(mTransfer, "We must have an nsITransfer");
LOG(("Notifying progress listener"));
nsresult rv = mTransfer->SetSha256Hash(mHash);
NS_ENSURE_SUCCESS(rv, rv);
rv = mTransfer->OnProgressChange64(nullptr, nullptr, mProgress,
mContentLength, mProgress, mContentLength);
NS_ENSURE_SUCCESS(rv, rv);
rv = mTransfer->OnStateChange(nullptr, nullptr,
nsIWebProgressListener::STATE_STOP |
nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_NETWORK, NS_OK);
NS_ENSURE_SUCCESS(rv, rv);
// Do what the user asked for
ExecuteDesiredAction();
// This nsITransfer object holds a reference to us (we are its observer), so
// we need to release the reference to break a reference cycle (and therefore
// to prevent leaking)
mTransfer = nullptr;
mWebProgressListener = nullptr;
return NS_OK;
}
nsresult nsExternalAppHandler::ExecuteDesiredAction()
{
nsresult rv = NS_OK;
if (mProgressListenerInitialized && !mCanceled)
{
rv = MoveFile(mFinalFileDestination);
if (NS_SUCCEEDED(rv))
{
nsHandlerInfoAction action = nsIMIMEInfo::saveToDisk;
mMimeInfo->GetPreferredAction(&action);
if (action == nsIMIMEInfo::useHelperApp ||
action == nsIMIMEInfo::useSystemDefault)
{
rv = OpenWithApplication();
}
else if(action == nsIMIMEInfo::saveToDisk)
{
mExtProtSvc->FixFilePermissions(mFinalFileDestination);
}
}
// Notify dialog that download is complete.
// By waiting till this point, it ensures that the progress dialog doesn't indicate
// success until we're really done.
if(mWebProgressListener)
{
if (!mCanceled)
{
mWebProgressListener->OnProgressChange64(nullptr, nullptr, mProgress, mContentLength, mProgress, mContentLength);
}
mWebProgressListener->OnStateChange(nullptr, nullptr,
nsIWebProgressListener::STATE_STOP |
nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_NETWORK, NS_OK);
}
}
return rv;
}
NS_IMETHODIMP nsExternalAppHandler::GetMIMEInfo(nsIMIMEInfo ** aMIMEInfo)
{
*aMIMEInfo = mMimeInfo;
@ -1904,14 +1937,14 @@ nsresult nsExternalAppHandler::InitializeDownload(nsITransfer* aTransfer)
nsCOMPtr<nsIURI> target;
rv = NS_NewFileURI(getter_AddRefs(target), mFinalFileDestination);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
rv = aTransfer->Init(mSourceUrl, target, EmptyString(),
mMimeInfo, mTimeDownloadStarted, mTempFile, this,
channel && NS_UsePrivateBrowsing(channel));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) return rv;
// Now let's add the download to history
nsCOMPtr<nsIDownloadHistory> dh(do_GetService(NS_DOWNLOADHISTORY_CONTRACTID));
@ -1930,38 +1963,31 @@ nsresult nsExternalAppHandler::InitializeDownload(nsITransfer* aTransfer)
return rv;
}
nsresult nsExternalAppHandler::CreateTransfer()
nsresult nsExternalAppHandler::CreateProgressListener()
{
// We are back from the helper app dialog (where the user chooses to save or
// open), but we aren't done processing the load. in this case, throw up a
// progress dialog so the user can see what's going on.
// we are back from the helper app dialog (where the user chooses to save or open), but we aren't
// done processing the load. in this case, throw up a progress dialog so the user can see what's going on...
// Also, release our reference to mDialog. We don't need it anymore, and we
// need to break the reference cycle.
mDialog = nullptr;
if (!mDialogProgressListener) {
NS_WARNING("The dialog should nullify the dialog progress listener");
}
nsresult rv;
// We must be able to create an nsITransfer object. If not, it doesn't matter
// much that we can't launch the helper application or save to disk.
mTransfer = do_CreateInstance(NS_TRANSFER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = InitializeDownload(mTransfer);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsITransfer> tr = do_CreateInstance(NS_TRANSFER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
InitializeDownload(tr);
rv = mTransfer->OnStateChange(nullptr, mRequest,
nsIWebProgressListener::STATE_START |
nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_NETWORK, NS_OK);
NS_ENSURE_SUCCESS(rv, rv);
if (tr)
tr->OnStateChange(nullptr, mRequest, nsIWebProgressListener::STATE_START |
nsIWebProgressListener::STATE_IS_REQUEST |
nsIWebProgressListener::STATE_IS_NETWORK, NS_OK);
// While we were bringing up the progress dialog, we actually finished
// processing the url. If that's the case then mStopRequestIssued will be
// true and OnSaveComplete has been called.
if (mStopRequestIssued && !mSaver) {
return NotifyTransfer();
}
// note we might not have a listener here if the QI() failed, or if
// there is no nsITransfer object, but we still call
// SetWebProgressListener() to make sure our progress state is sane
// NOTE: This will set up a reference cycle (this nsITransfer has us set up as
// its observer). This cycle will be broken in Cancel, CloseProgressWindow or
// OnStopRequest.
SetWebProgressListener(tr);
mRequest = nullptr;
@ -2023,9 +2049,68 @@ void nsExternalAppHandler::RequestSaveDestination(const nsAFlatString &aDefaultF
}
}
nsresult nsExternalAppHandler::MoveFile(nsIFile * aNewFileLocation)
{
nsresult rv = NS_OK;
NS_ASSERTION(mStopRequestIssued, "uhoh, how did we get here if we aren't done getting data?");
// if the on stop request was actually issued then it's now time to actually perform the file move....
if (mStopRequestIssued && aNewFileLocation)
{
// Unfortunately, MoveTo will fail if a file already exists at the user specified location....
// but the user has told us, this is where they want the file! (when we threw up the save to file dialog,
// it told them the file already exists and do they wish to over write it. So it should be okay to delete
// fileToUse if it already exists.
bool equalToTempFile = false;
bool filetoUseAlreadyExists = false;
aNewFileLocation->Equals(mTempFile, &equalToTempFile);
aNewFileLocation->Exists(&filetoUseAlreadyExists);
if (filetoUseAlreadyExists && !equalToTempFile)
aNewFileLocation->Remove(false);
// extract the new leaf name from the file location
nsAutoString fileName;
aNewFileLocation->GetLeafName(fileName);
nsCOMPtr<nsIFile> directoryLocation;
rv = aNewFileLocation->GetParent(getter_AddRefs(directoryLocation));
if (directoryLocation)
{
rv = mTempFile->MoveTo(directoryLocation, fileName);
}
if (NS_FAILED(rv))
{
// Send error notification.
nsAutoString path;
aNewFileLocation->GetPath(path);
SendStatusChange(kWriteError, rv, nullptr, path);
Cancel(rv); // Cancel (and clean up temp file).
}
#if defined(XP_OS2)
else
{
// tag the file with its source URI
nsCOMPtr<nsILocalFileOS2> localFileOS2 = do_QueryInterface(aNewFileLocation);
if (localFileOS2)
{
nsAutoCString url;
mSourceUrl->GetSpec(url);
localFileOS2->SetFileSource(url);
}
}
#endif
}
return rv;
}
// SaveToDisk should only be called by the helper app dialog which allows
// the user to say launch with application or save to disk. It doesn't actually
// perform the save, it just prompts for the destination file name.
// perform the save, it just prompts for the destination file name. The actual save
// won't happen until we are done downloading the content and are sure we've
// shown a progress dialog. This was done to simplify the
// logic that was showing up in this method. Internal callers who actually want
// to preform the save should call ::MoveFile
NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, bool aRememberThisPreference)
{
if (mCanceled)
@ -2033,6 +2118,9 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, bool
mMimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
// The helper app dialog has told us what to do.
mReceivedDispositionInfo = true;
if (!aNewFileLocation) {
if (mSuggestedFileName.IsEmpty())
RequestSaveDestination(mTempLeafName, mTempFileExtension);
@ -2055,9 +2143,6 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, bool
}
nsresult nsExternalAppHandler::ContinueSave(nsIFile * aNewFileLocation)
{
if (mCanceled)
return NS_OK;
NS_PRECONDITION(aNewFileLocation, "Must be called with a non-null file");
nsresult rv = NS_OK;
@ -2065,10 +2150,9 @@ nsresult nsExternalAppHandler::ContinueSave(nsIFile * aNewFileLocation)
mFinalFileDestination = do_QueryInterface(fileToUse);
// Move what we have in the final directory, but append .part
// to it, to indicate that it's unfinished. Do not call SetTarget on the
// saver if we are done (Finish has been called) but OnSaverComplete has not
// been called.
if (mFinalFileDestination && mSaver && !mStopRequestIssued)
// to it, to indicate that it's unfinished.
// do not do that if we're already done
if (mFinalFileDestination && !mStopRequestIssued)
{
nsCOMPtr<nsIFile> movedFile;
mFinalFileDestination->Clone(getter_AddRefs(movedFile));
@ -2079,22 +2163,24 @@ nsresult nsExternalAppHandler::ContinueSave(nsIFile * aNewFileLocation)
name.AppendLiteral(".part");
movedFile->SetLeafName(name);
rv = mSaver->SetTarget(movedFile, true);
if (NS_FAILED(rv)) {
nsAutoString path;
mTempFile->GetPath(path);
SendStatusChange(kWriteError, rv, nullptr, path);
Cancel(rv);
return NS_OK;
if (mSaver)
{
rv = mSaver->SetTarget(movedFile, true);
if (NS_FAILED(rv)) {
nsAutoString path;
mTempFile->GetPath(path);
SendStatusChange(kWriteError, rv, nullptr, path);
Cancel(rv);
return NS_OK;
}
}
mTempFile = movedFile;
}
}
// The helper app dialog has told us what to do and we have a final file
// destination.
CreateTransfer();
if (!mProgressListenerInitialized)
CreateProgressListener();
// now that the user has chosen the file location to save to, it's okay to fire the refresh tag
// if there is one. We don't want to do this before the save as dialog goes away because this dialog
@ -2106,9 +2192,68 @@ nsresult nsExternalAppHandler::ContinueSave(nsIFile * aNewFileLocation)
}
// LaunchWithApplication should only be called by the helper app dialog which
// allows the user to say launch with application or save to disk. It doesn't
// actually perform launch with application.
nsresult nsExternalAppHandler::OpenWithApplication()
{
nsresult rv = NS_OK;
if (mCanceled)
return NS_OK;
// we only should have gotten here if the on stop request had been fired already.
NS_ASSERTION(mStopRequestIssued, "uhoh, how did we get here if we aren't done getting data?");
// if a stop request was already issued then proceed with launching the application.
if (mStopRequestIssued)
{
// Note for the default value:
// Mac users have been very verbal about temp files being deleted on
// app exit - they don't like it - but we'll continue to do this on
// other platforms for now.
bool deleteTempFileOnExit =
Preferences::GetBool("browser.helperApps.deleteTempFileOnExit",
#if !defined(XP_MACOSX)
true);
#else
false);
#endif
// See whether the channel has been opened in private browsing mode
NS_ASSERTION(mRequest, "This should never be called with a null request");
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
bool inPrivateBrowsing = channel && NS_UsePrivateBrowsing(channel);
// make the tmp file readonly so users won't edit it and lose the changes
// only if we're going to delete the file
if (deleteTempFileOnExit || inPrivateBrowsing)
mFinalFileDestination->SetPermissions(0400);
rv = mMimeInfo->LaunchWithFile(mFinalFileDestination);
if (NS_FAILED(rv))
{
// Send error notification.
nsAutoString path;
mFinalFileDestination->GetPath(path);
SendStatusChange(kLaunchError, rv, nullptr, path);
Cancel(rv); // Cancel, and clean up temp file.
}
// Always schedule files to be deleted at the end of the private browsing
// mode, regardless of the value of the pref.
else if (deleteTempFileOnExit) {
mExtProtSvc->DeleteTemporaryFileOnExit(mFinalFileDestination);
}
else if (inPrivateBrowsing) {
mExtProtSvc->DeleteTemporaryPrivateFileWhenPossible(mFinalFileDestination);
}
}
return rv;
}
// LaunchWithApplication should only be called by the helper app dialog which allows
// the user to say launch with application or save to disk. It doesn't actually
// perform launch with application. That won't happen until we are done downloading
// the content and are sure we've shown a progress dialog. This was done to simplify the
// logic that was showing up in this method.
NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication, bool aRememberThisPreference)
{
if (mCanceled)
@ -2117,6 +2262,7 @@ NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication
// user has chosen to launch using an application, fire any refresh tags now...
ProcessAnyRefreshTags();
mReceivedDispositionInfo = true;
if (mMimeInfo && aApplication) {
PlatformLocalHandlerApp_t *handlerApp =
new PlatformLocalHandlerApp_t(EmptyString(), aApplication);
@ -2146,13 +2292,12 @@ NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication
return rv;
}
// Now that the user has elected to launch the downloaded file with a helper
// app, we're justified in removing the 'salted' name. We'll rename to what
// was specified in mSuggestedFileName after the download is done prior to
// launching the helper app. So that any existing file of that name won't be
// overwritten we call CreateUnique(). Also note that we use the same
// directory as originally downloaded so nsDownload can rename in place
// later.
// Now that the user has elected to launch the downloaded file with a helper app, we're justified in
// removing the 'salted' name. We'll rename to what was specified in mSuggestedFileName after the
// download is done prior to launching the helper app. So that any existing file of that name won't
// be overwritten we call CreateUnique() before calling MoveFile(). Also note that we use the same
// directory as originally downloaded to so that MoveFile() just does an in place rename.
nsCOMPtr<nsIFile> fileToUse;
(void) GetDownloadDirectory(getter_AddRefs(fileToUse));
@ -2173,7 +2318,8 @@ NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication
{
mFinalFileDestination = do_QueryInterface(fileToUse);
// launch the progress window now that the user has picked the desired action.
CreateTransfer();
if (!mProgressListenerInitialized)
CreateProgressListener();
}
else
{
@ -2205,8 +2351,7 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason)
// Release the listener, to break the reference cycle with it (we are the
// observer of the listener).
mDialogProgressListener = nullptr;
mTransfer = nullptr;
mWebProgressListener = nullptr;
return NS_OK;
}

Просмотреть файл

@ -282,9 +282,12 @@ protected:
bool mShouldCloseWindow;
/**
* True if a stop request has been issued.
* have we received information from the user about how they want to
* dispose of this content
*/
bool mReceivedDispositionInfo;
bool mStopRequestIssued;
bool mProgressListenerInitialized;
bool mIsFileChannel;
@ -320,11 +323,6 @@ protected:
*/
nsCOMPtr<nsIBackgroundFileSaver> mSaver;
/**
* Stores the SHA-256 hash associated with the file that we downloaded.
*/
nsAutoCString mHash;
/**
* Creates the temporary file for the download and an output stream for it.
* Upon successful return, both mTempFile and mSaver will be valid.
@ -338,10 +336,12 @@ protected:
*/
void RetargetLoadNotifications(nsIRequest *request);
/**
* Once the user tells us how they want to dispose of the content
* create an nsITransfer so they know what's going on...
* If the user tells us how they want to dispose of the content and
* we still haven't finished downloading while they were deciding,
* then create a progress listener of some kind so they know
* what's going on...
*/
nsresult CreateTransfer();
nsresult CreateProgressListener();
/*
@ -381,10 +381,22 @@ protected:
void ProcessAnyRefreshTags();
/**
* Notify our nsITransfer object that we are done with the download.
* An internal method used to actually move the temp file to the final
* destination once we done receiving data AND have showed the progress dialog
*/
nsresult NotifyTransfer();
nsresult MoveFile(nsIFile * aNewFileLocation);
/**
* An internal method used to actually launch a helper app given the temp file
* once we are done receiving data AND have showed the progress dialog.
* Uses the application specified in the mime info.
*/
nsresult OpenWithApplication();
/**
* Helper routine which peaks at the mime action specified by mMimeInfo
* and calls either MoveFile or OpenWithApplication
*/
nsresult ExecuteDesiredAction();
/**
* Helper routine that searches a pref string for a given mime type
*/
@ -415,17 +427,7 @@ protected:
*/
nsresult MaybeCloseWindow();
/**
* Set in nsHelperDlgApp.js. This is always null after the user has chosen an
* action.
*/
nsCOMPtr<nsIWebProgressListener2> mDialogProgressListener;
/**
* Set once the user has chosen an action. This is null after the download
* has been canceled or completes.
*/
nsCOMPtr<nsITransfer> mTransfer;
nsCOMPtr<nsIWebProgressListener2> mWebProgressListener;
nsCOMPtr<nsIChannel> mOriginalChannel; /**< in the case of a redirect, this will be the pre-redirect channel. */
nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;

Просмотреть файл

@ -96,16 +96,14 @@ interface nsIHelperAppLauncher : nsICancelable
readonly attribute AString suggestedFileName;
/**
* Saves the final destination of the file. Does not actually perform the
* save.
* NOTE: This will release the reference to the
* nsIHelperAppLauncherDialog.
* Called when we want to just save the content to a particular file.
* NOTE: This will release the reference to the nsIHelperAppLauncherDialog.
* @param aNewFileLocation Location where the content should be saved
*/
void saveToDisk(in nsIFile aNewFileLocation, in boolean aRememberThisPreference);
/**
* Remembers that aApplication should be used to launch this content. Does
* not actually launch the application.
* Use aApplication to launch with this content.
* NOTE: This will release the reference to the nsIHelperAppLauncherDialog.
* @param aApplication nsIFile corresponding to the location of the application to use.
* @param aRememberThisPreference TRUE if we should remember this choice.
@ -127,6 +125,12 @@ interface nsIHelperAppLauncher : nsICancelable
*/
void setWebProgressListener(in nsIWebProgressListener2 aWebProgressListener);
/**
* when the stand alone progress window actually closes, it calls this method
* so we can release any local state...
*/
void closeProgressWindow();
/**
* The file we are saving to
*/