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__