DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (dcc6d7a0dc00)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
/* -*- 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 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 "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
{
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