uriloader/exthandler/nsExternalHelperAppService.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/uriloader/exthandler/nsExternalHelperAppService.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,466 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef nsExternalHelperAppService_h__
    1.10 +#define nsExternalHelperAppService_h__
    1.11 +
    1.12 +#ifdef MOZ_LOGGING
    1.13 +#define FORCE_PR_LOG
    1.14 +#endif
    1.15 +#include "prlog.h"
    1.16 +#include "prtime.h"
    1.17 +
    1.18 +#include "nsIExternalHelperAppService.h"
    1.19 +#include "nsIExternalProtocolService.h"
    1.20 +#include "nsIWebProgressListener2.h"
    1.21 +#include "nsIHelperAppLauncherDialog.h"
    1.22 +
    1.23 +#include "nsIMIMEInfo.h"
    1.24 +#include "nsIMIMEService.h"
    1.25 +#include "nsIStreamListener.h"
    1.26 +#include "nsIFile.h"
    1.27 +#include "nsIFileStreams.h"
    1.28 +#include "nsIOutputStream.h"
    1.29 +#include "nsString.h"
    1.30 +#include "nsIInterfaceRequestor.h"
    1.31 +#include "nsIInterfaceRequestorUtils.h"
    1.32 +#include "nsIChannel.h"
    1.33 +#include "nsITimer.h"
    1.34 +#include "nsIBackgroundFileSaver.h"
    1.35 +
    1.36 +#include "nsIHandlerService.h"
    1.37 +#include "nsCOMPtr.h"
    1.38 +#include "nsIObserver.h"
    1.39 +#include "nsCOMArray.h"
    1.40 +#include "nsWeakReference.h"
    1.41 +#include "nsIPrompt.h"
    1.42 +#include "nsAutoPtr.h"
    1.43 +#include "mozilla/Attributes.h"
    1.44 +#include "necko-config.h"
    1.45 +
    1.46 +class nsExternalAppHandler;
    1.47 +class nsIMIMEInfo;
    1.48 +class nsITransfer;
    1.49 +class nsIDOMWindow;
    1.50 +
    1.51 +/**
    1.52 + * The helper app service. Responsible for handling content that Mozilla
    1.53 + * itself can not handle
    1.54 + */
    1.55 +class nsExternalHelperAppService
    1.56 +: public nsIExternalHelperAppService,
    1.57 +  public nsPIExternalAppLauncher,
    1.58 +  public nsIExternalProtocolService,
    1.59 +  public nsIMIMEService,
    1.60 +  public nsIObserver,
    1.61 +  public nsSupportsWeakReference
    1.62 +{
    1.63 +public:
    1.64 +  NS_DECL_ISUPPORTS
    1.65 +  NS_DECL_NSIEXTERNALHELPERAPPSERVICE
    1.66 +  NS_DECL_NSPIEXTERNALAPPLAUNCHER
    1.67 +  NS_DECL_NSIEXTERNALPROTOCOLSERVICE
    1.68 +  NS_DECL_NSIMIMESERVICE
    1.69 +  NS_DECL_NSIOBSERVER
    1.70 +
    1.71 +  nsExternalHelperAppService();
    1.72 +  virtual ~nsExternalHelperAppService();
    1.73 +
    1.74 +  /**
    1.75 +   * Initializes internal state. Will be called automatically when
    1.76 +   * this service is first instantiated.
    1.77 +   */
    1.78 +  NS_HIDDEN_(nsresult) Init();
    1.79 + 
    1.80 +  /**
    1.81 +   * Given a mimetype and an extension, looks up a mime info from the OS.
    1.82 +   * The mime type is given preference. This function follows the same rules
    1.83 +   * as nsIMIMEService::GetFromTypeAndExtension.
    1.84 +   * This is supposed to be overridden by the platform-specific
    1.85 +   * nsOSHelperAppService!
    1.86 +   * @param aFileExt The file extension; may be empty. UTF-8 encoded.
    1.87 +   * @param [out] aFound
    1.88 +   *        Should be set to true if the os has a mapping, to
    1.89 +   *        false otherwise. Must not be null.
    1.90 +   * @return A MIMEInfo. This function must return a MIMEInfo object if it
    1.91 +   *         can allocate one.  The only justifiable reason for not
    1.92 +   *         returning one is an out-of-memory error.
    1.93 +   *         If null, the value of aFound is unspecified.
    1.94 +   */
    1.95 +  virtual already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType,
    1.96 +                                                          const nsACString& aFileExt,
    1.97 +                                                          bool       * aFound) = 0;
    1.98 +
    1.99 +  /**
   1.100 +   * Given a string identifying an application, create an nsIFile representing
   1.101 +   * it. This function should look in $PATH for the application.
   1.102 +   * The base class implementation will first try to interpret platformAppPath
   1.103 +   * as an absolute path, and if that fails it will look for a file next to the
   1.104 +   * mozilla executable. Subclasses can override this method if they want a
   1.105 +   * different behaviour.
   1.106 +   * @param platformAppPath A platform specific path to an application that we
   1.107 +   *                        got out of the rdf data source. This can be a mac
   1.108 +   *                        file spec, a unix path or a windows path depending
   1.109 +   *                        on the platform
   1.110 +   * @param aFile           [out] An nsIFile representation of that platform
   1.111 +   *                        application path.
   1.112 +   */
   1.113 +  virtual nsresult GetFileTokenForPath(const char16_t * platformAppPath,
   1.114 +                                       nsIFile ** aFile);
   1.115 +
   1.116 +  virtual NS_HIDDEN_(nsresult) OSProtocolHandlerExists(const char *aScheme,
   1.117 +                                                       bool *aExists) = 0;
   1.118 +
   1.119 +protected:
   1.120 +  /**
   1.121 +   * Searches the "extra" array of MIMEInfo objects for an object
   1.122 +   * with a specific type. If found, it will modify the passed-in
   1.123 +   * MIMEInfo. Otherwise, it will return an error and the MIMEInfo
   1.124 +   * will be untouched.
   1.125 +   * @param aContentType The type to search for.
   1.126 +   * @param aMIMEInfo    [inout] The mime info, if found
   1.127 +   */
   1.128 +  NS_HIDDEN_(nsresult) FillMIMEInfoForMimeTypeFromExtras(
   1.129 +    const nsACString& aContentType, nsIMIMEInfo * aMIMEInfo);
   1.130 +  /**
   1.131 +   * Searches the "extra" array of MIMEInfo objects for an object
   1.132 +   * with a specific extension.
   1.133 +   *
   1.134 +   * Does not change the MIME Type of the MIME Info.
   1.135 +   *
   1.136 +   * @see FillMIMEInfoForMimeTypeFromExtras
   1.137 +   */
   1.138 +  NS_HIDDEN_(nsresult) FillMIMEInfoForExtensionFromExtras(
   1.139 +    const nsACString& aExtension, nsIMIMEInfo * aMIMEInfo);
   1.140 +
   1.141 +  /**
   1.142 +   * Searches the "extra" array for a MIME type, and gets its extension.
   1.143 +   * @param aExtension The extension to search for
   1.144 +   * @param aMIMEType [out] The found MIME type.
   1.145 +   * @return true if the extension was found, false otherwise.
   1.146 +   */
   1.147 +  NS_HIDDEN_(bool) GetTypeFromExtras(const nsACString& aExtension,
   1.148 +                                       nsACString& aMIMEType);
   1.149 +
   1.150 +#ifdef PR_LOGGING
   1.151 +  /**
   1.152 +   * NSPR Logging Module. Usage: set NSPR_LOG_MODULES=HelperAppService:level,
   1.153 +   * where level should be 2 for errors, 3 for debug messages from the cross-
   1.154 +   * platform nsExternalHelperAppService, and 4 for os-specific debug messages.
   1.155 +   */
   1.156 +  static PRLogModuleInfo* mLog;
   1.157 +
   1.158 +#endif
   1.159 +  // friend, so that it can access the nspr log module.
   1.160 +  friend class nsExternalAppHandler;
   1.161 +
   1.162 +  /**
   1.163 +   * Helper function for ExpungeTemporaryFiles and ExpungeTemporaryPrivateFiles
   1.164 +   */
   1.165 +  static void ExpungeTemporaryFilesHelper(nsCOMArray<nsIFile> &fileList);
   1.166 +  /**
   1.167 +   * Helper function for DeleteTemporaryFileOnExit and DeleteTemporaryPrivateFileWhenPossible
   1.168 +   */
   1.169 +  static nsresult DeleteTemporaryFileHelper(nsIFile* aTemporaryFile,
   1.170 +                                            nsCOMArray<nsIFile> &aFileList);
   1.171 +  /**
   1.172 +   * Functions related to the tempory file cleanup service provided by
   1.173 +   * nsExternalHelperAppService
   1.174 +   */
   1.175 +  void ExpungeTemporaryFiles();
   1.176 +  /**
   1.177 +   * Functions related to the tempory file cleanup service provided by
   1.178 +   * nsExternalHelperAppService (for the temporary files added during
   1.179 +   * the private browsing mode)
   1.180 +   */
   1.181 +  void ExpungeTemporaryPrivateFiles();
   1.182 +
   1.183 +#ifdef NECKO_PROTOCOL_rtsp
   1.184 +  /**
   1.185 +   * Launch video app for rtsp protocol. This function is supported only on Gonk
   1.186 +   * for now.
   1.187 +   */
   1.188 +  static void LaunchVideoAppForRtsp(nsIURI* aURI);
   1.189 +#endif
   1.190 +
   1.191 +  /**
   1.192 +   * Array for the files that should be deleted
   1.193 +   */
   1.194 +  nsCOMArray<nsIFile> mTemporaryFilesList;
   1.195 +  /**
   1.196 +   * Array for the files that should be deleted (for the temporary files
   1.197 +   * added during the private browsing mode)
   1.198 +   */
   1.199 +  nsCOMArray<nsIFile> mTemporaryPrivateFilesList;
   1.200 +};
   1.201 +
   1.202 +/**
   1.203 + * An external app handler is just a small little class that presents itself as
   1.204 + * a nsIStreamListener. It saves the incoming data into a temp file. The handler
   1.205 + * is bound to an application when it is created. When it receives an
   1.206 + * OnStopRequest it launches the application using the temp file it has
   1.207 + * stored the data into.  We create a handler every time we have to process
   1.208 + * data using a helper app.
   1.209 + */
   1.210 +class nsExternalAppHandler MOZ_FINAL : public nsIStreamListener,
   1.211 +                                       public nsIHelperAppLauncher,
   1.212 +                                       public nsITimerCallback,
   1.213 +                                       public nsIBackgroundFileSaverObserver
   1.214 +{
   1.215 +public:
   1.216 +  NS_DECL_THREADSAFE_ISUPPORTS
   1.217 +  NS_DECL_NSISTREAMLISTENER
   1.218 +  NS_DECL_NSIREQUESTOBSERVER
   1.219 +  NS_DECL_NSIHELPERAPPLAUNCHER
   1.220 +  NS_DECL_NSICANCELABLE
   1.221 +  NS_DECL_NSITIMERCALLBACK
   1.222 +  NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER
   1.223 +
   1.224 +  /**
   1.225 +   * @param aMIMEInfo      MIMEInfo object, representing the type of the
   1.226 +   *                       content that should be handled
   1.227 +   * @param aFileExtension The extension we need to append to our temp file,
   1.228 +   *                       INCLUDING the ".". e.g. .mp3
   1.229 +   * @param aWindowContext Window context, as passed to DoContent
   1.230 +   * @param mExtProtSvc    nsExternalHelperAppService on creation
   1.231 +   * @param aFileName      The filename to use
   1.232 +   * @param aReason        A constant from nsIHelperAppLauncherDialog indicating
   1.233 +   *                       why the request is handled by a helper app.
   1.234 +   */
   1.235 +  nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo, const nsCSubstring& aFileExtension,
   1.236 +                       nsIInterfaceRequestor * aWindowContext,
   1.237 +                       nsExternalHelperAppService * aExtProtSvc,
   1.238 +                       const nsAString& aFilename,
   1.239 +                       uint32_t aReason, bool aForceSave);
   1.240 +
   1.241 +  ~nsExternalAppHandler();
   1.242 +
   1.243 +  /**
   1.244 +   * Clean up after the request was diverted to the parent process.
   1.245 +   */
   1.246 +  void DidDivertRequest(nsIRequest *request);
   1.247 +
   1.248 +protected:
   1.249 +  nsCOMPtr<nsIFile> mTempFile;
   1.250 +  nsCOMPtr<nsIURI> mSourceUrl;
   1.251 +  nsString mTempFileExtension;
   1.252 +  nsString mTempLeafName;
   1.253 +
   1.254 +  /**
   1.255 +   * The MIME Info for this load. Will never be null.
   1.256 +   */
   1.257 +  nsCOMPtr<nsIMIMEInfo> mMimeInfo;
   1.258 +  nsCOMPtr<nsIInterfaceRequestor> mWindowContext;
   1.259 +
   1.260 +  /**
   1.261 +   * Used to close the window on a timer, to avoid any exceptions that are
   1.262 +   * thrown if we try to close the window before it's fully loaded.
   1.263 +   */
   1.264 +  nsCOMPtr<nsIDOMWindow> mWindowToClose;
   1.265 +  nsCOMPtr<nsITimer> mTimer;
   1.266 +
   1.267 +  /**
   1.268 +   * The following field is set if we were processing an http channel that had
   1.269 +   * a content disposition header which specified the SUGGESTED file name we
   1.270 +   * should present to the user in the save to disk dialog. 
   1.271 +   */
   1.272 +  nsString mSuggestedFileName;
   1.273 +
   1.274 +  /**
   1.275 +   * If set, this handler should forcibly save the file to disk regardless of
   1.276 +   * MIME info settings or anything else, without ever popping up the 
   1.277 +   * unknown content type handling dialog.
   1.278 +   */
   1.279 +  bool mForceSave;
   1.280 +  
   1.281 +  /**
   1.282 +   * The canceled flag is set if the user canceled the launching of this
   1.283 +   * application before we finished saving the data to a temp file.
   1.284 +   */
   1.285 +  bool mCanceled;
   1.286 +
   1.287 +  /**
   1.288 +   * This is set based on whether the channel indicates that a new window
   1.289 +   * was opened specifically for this download.  If so, then we
   1.290 +   * close it.
   1.291 +   */
   1.292 +  bool mShouldCloseWindow;
   1.293 +
   1.294 +  /**
   1.295 +   * True if a stop request has been issued.
   1.296 +   */
   1.297 +  bool mStopRequestIssued; 
   1.298 +
   1.299 +  bool mIsFileChannel;
   1.300 +
   1.301 +  /**
   1.302 +   * One of the REASON_ constants from nsIHelperAppLauncherDialog. Indicates the
   1.303 +   * reason the dialog was shown (unknown content type, server requested it,
   1.304 +   * etc).
   1.305 +   */
   1.306 +  uint32_t mReason;
   1.307 +
   1.308 +  /**
   1.309 +   * Track the executable-ness of the temporary file.
   1.310 +   */
   1.311 +  bool mTempFileIsExecutable;
   1.312 +
   1.313 +  PRTime mTimeDownloadStarted;
   1.314 +  int64_t mContentLength;
   1.315 +  int64_t mProgress; /**< Number of bytes received (for sending progress notifications). */
   1.316 +
   1.317 +  /**
   1.318 +   * When we are told to save the temp file to disk (in a more permament
   1.319 +   * location) before we are done writing the content to a temp file, then
   1.320 +   * we need to remember the final destination until we are ready to use it.
   1.321 +   */
   1.322 +  nsCOMPtr<nsIFile> mFinalFileDestination;
   1.323 +
   1.324 +  uint32_t mBufferSize;
   1.325 +
   1.326 +  /**
   1.327 +   * This object handles saving the data received from the network to a
   1.328 +   * temporary location first, and then move the file to its final location,
   1.329 +   * doing all the input/output on a background thread.
   1.330 +   */
   1.331 +  nsCOMPtr<nsIBackgroundFileSaver> mSaver;
   1.332 +
   1.333 +  /**
   1.334 +   * Stores the SHA-256 hash associated with the file that we downloaded.
   1.335 +   */
   1.336 +  nsAutoCString mHash;
   1.337 +  /**
   1.338 +   * Stores the signature information of the downloaded file in an nsIArray of
   1.339 +   * nsIX509CertList of nsIX509Cert. If the file is unsigned this will be
   1.340 +   * empty.
   1.341 +   */
   1.342 +  nsCOMPtr<nsIArray> mSignatureInfo;
   1.343 +  /**
   1.344 +   * Creates the temporary file for the download and an output stream for it.
   1.345 +   * Upon successful return, both mTempFile and mSaver will be valid.
   1.346 +   */
   1.347 +  nsresult SetUpTempFile(nsIChannel * aChannel);
   1.348 +  /**
   1.349 +   * When we download a helper app, we are going to retarget all load
   1.350 +   * notifications into our own docloader and load group instead of
   1.351 +   * using the window which initiated the load....RetargetLoadNotifications
   1.352 +   * contains that information...
   1.353 +   */
   1.354 +  void RetargetLoadNotifications(nsIRequest *request);
   1.355 +  /**
   1.356 +   * Once the user tells us how they want to dispose of the content
   1.357 +   * create an nsITransfer so they know what's going on. If this fails, the
   1.358 +   * caller MUST call Cancel.
   1.359 +   */
   1.360 +  nsresult CreateTransfer();
   1.361 +
   1.362 +  /**
   1.363 +   * If we fail to create the necessary temporary file to initiate a transfer
   1.364 +   * we will report the failure by creating a failed nsITransfer.
   1.365 +   */
   1.366 +  nsresult CreateFailedTransfer(bool aIsPrivateBrowsing);
   1.367 +
   1.368 +  /*
   1.369 +   * The following two functions are part of the split of SaveToDisk
   1.370 +   * to make it async, and works as following:
   1.371 +   *
   1.372 +   *    SaveToDisk    ------->   RequestSaveDestination
   1.373 +   *                                     .
   1.374 +   *                                     .
   1.375 +   *                                     v
   1.376 +   *    ContinueSave  <-------   SaveDestinationAvailable
   1.377 +   */
   1.378 +
   1.379 +  /**
   1.380 +   * This is called by SaveToDisk to decide what's the final
   1.381 +   * file destination chosen by the user or by auto-download settings.
   1.382 +   */
   1.383 +  void RequestSaveDestination(const nsAFlatString &aDefaultFile,
   1.384 +                              const nsAFlatString &aDefaultFileExt);
   1.385 +
   1.386 +  /**
   1.387 +   * When SaveToDisk is called, it possibly delegates to RequestSaveDestination
   1.388 +   * to decide the file destination. ContinueSave must then be called when
   1.389 +   * the final destination is finally known.
   1.390 +   * @param  aFile  The file that was chosen as the final destination.
   1.391 +   *                Must not be null.
   1.392 +   */
   1.393 +  nsresult ContinueSave(nsIFile* aFile);
   1.394 +
   1.395 +  /**
   1.396 +   * After we're done prompting the user for any information, if the original
   1.397 +   * channel had a refresh url associated with it (which might point to a
   1.398 +   * "thank you for downloading" kind of page, then process that....It is safe
   1.399 +   * to invoke this method multiple times. We'll clear mOriginalChannel after
   1.400 +   * it's called and this ensures we won't call it again....
   1.401 +   */
   1.402 +  void ProcessAnyRefreshTags();
   1.403 +
   1.404 +  /**
   1.405 +   * Notify our nsITransfer object that we are done with the download.  This is
   1.406 +   * always called after the target file has been closed.
   1.407 +   *
   1.408 +   * @param aStatus
   1.409 +   *        NS_OK for success, or a failure code if the download failed.
   1.410 +   *        A partially downloaded file may still be available in this case.
   1.411 +   */
   1.412 +  void NotifyTransfer(nsresult aStatus);
   1.413 +
   1.414 +  /**
   1.415 +   * Helper routine that searches a pref string for a given mime type
   1.416 +   */
   1.417 +  bool GetNeverAskFlagFromPref(const char * prefName, const char * aContentType);
   1.418 +
   1.419 +  /**
   1.420 +   * Helper routine to ensure mSuggestedFileName is "correct";
   1.421 +   * this ensures that mTempFileExtension only contains an extension when it
   1.422 +   * is different from mSuggestedFileName's extension.
   1.423 +   */
   1.424 +  void EnsureSuggestedFileName();
   1.425 +
   1.426 +  typedef enum { kReadError, kWriteError, kLaunchError } ErrorType;
   1.427 +  /**
   1.428 +   * Utility function to send proper error notification to web progress listener
   1.429 +   */
   1.430 +  void SendStatusChange(ErrorType type, nsresult aStatus, nsIRequest *aRequest, const nsAFlatString &path);
   1.431 +
   1.432 +  /**
   1.433 +   * Closes the window context if it does not have a refresh header
   1.434 +   * and it never displayed content before the external helper app
   1.435 +   * service was invoked.
   1.436 +   */
   1.437 +  nsresult MaybeCloseWindow();
   1.438 +
   1.439 +  /**
   1.440 +   * Set in nsHelperDlgApp.js. This is always null after the user has chosen an
   1.441 +   * action.
   1.442 +   */
   1.443 +  nsCOMPtr<nsIWebProgressListener2> mDialogProgressListener;
   1.444 +  /**
   1.445 +   * Set once the user has chosen an action. This is null after the download
   1.446 +   * has been canceled or completes.
   1.447 +   */
   1.448 +  nsCOMPtr<nsITransfer> mTransfer;
   1.449 +
   1.450 +  nsCOMPtr<nsIChannel> mOriginalChannel; /**< in the case of a redirect, this will be the pre-redirect channel. */
   1.451 +  nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;
   1.452 +
   1.453 +  /**
   1.454 +   * Keep request alive in case when helper non-modal dialog shown.
   1.455 +   * Thus in OnStopRequest the mRequest will not be set to null (it will be set to null further).
   1.456 +   */
   1.457 +  bool mKeepRequestAlive;
   1.458 +
   1.459 +  /**
   1.460 +   * The request that's being loaded. Initialized in OnStartRequest.
   1.461 +   * Nulled out in OnStopRequest or once we know what we're doing
   1.462 +   * with the data, whichever happens later.
   1.463 +   */
   1.464 +  nsCOMPtr<nsIRequest> mRequest;
   1.465 +
   1.466 +  nsRefPtr<nsExternalHelperAppService> mExtProtSvc;
   1.467 +};
   1.468 +
   1.469 +#endif // nsExternalHelperAppService_h__

mercurial