no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / uriloader / exthandler / nsExternalHelperAppService.h
blob1f77e095dbfa3acc046779114007d83fc1cfa087
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsExternalHelperAppService_h__
7 #define nsExternalHelperAppService_h__
9 #include "mozilla/Logging.h"
10 #include "prtime.h"
12 #include "nsIExternalHelperAppService.h"
13 #include "nsIExternalProtocolService.h"
14 #include "nsIWebProgressListener2.h"
15 #include "nsIHelperAppLauncherDialog.h"
17 #include "nsILoadInfo.h"
18 #include "nsIMIMEInfo.h"
19 #include "nsIMIMEService.h"
20 #include "nsINamed.h"
21 #include "nsIStreamListener.h"
22 #include "nsIFile.h"
23 #include "nsIPermission.h"
24 #include "nsString.h"
25 #include "nsIInterfaceRequestor.h"
26 #include "nsIInterfaceRequestorUtils.h"
27 #include "nsIChannel.h"
28 #include "nsIBackgroundFileSaver.h"
30 #include "nsCOMPtr.h"
31 #include "nsIObserver.h"
32 #include "nsCOMArray.h"
33 #include "nsWeakReference.h"
34 #include "mozilla/Attributes.h"
36 class nsExternalAppHandler;
37 class nsIMIMEInfo;
38 class nsITransfer;
39 class nsIPrincipal;
40 class MaybeCloseWindowHelper;
42 #define EXTERNAL_APP_HANDLER_IID \
43 { \
44 0x50eb7479, 0x71ff, 0x4ef8, { \
45 0xb3, 0x1e, 0x3b, 0x59, 0xc8, 0xab, 0xb9, 0x24 \
46 } \
49 /**
50 * The helper app service. Responsible for handling content that Mozilla
51 * itself can not handle
52 * Note that this is an abstract class - we depend on appropriate subclassing
53 * on a per-OS basis to implement some methods.
55 class nsExternalHelperAppService : public nsIExternalHelperAppService,
56 public nsPIExternalAppLauncher,
57 public nsIExternalProtocolService,
58 public nsIMIMEService,
59 public nsIObserver,
60 public nsSupportsWeakReference {
61 public:
62 NS_DECL_ISUPPORTS
63 NS_DECL_NSIEXTERNALHELPERAPPSERVICE
64 NS_DECL_NSPIEXTERNALAPPLAUNCHER
65 NS_DECL_NSIMIMESERVICE
66 NS_DECL_NSIOBSERVER
68 nsExternalHelperAppService();
70 /**
71 * Initializes internal state. Will be called automatically when
72 * this service is first instantiated.
74 [[nodiscard]] nsresult Init();
76 /**
77 * nsIExternalProtocolService methods that we provide in this class. Other
78 * methods should be implemented by per-OS subclasses.
80 NS_IMETHOD ExternalProtocolHandlerExists(const char* aProtocolScheme,
81 bool* aHandlerExists) override;
82 NS_IMETHOD IsExposedProtocol(const char* aProtocolScheme,
83 bool* aResult) override;
84 NS_IMETHOD GetProtocolHandlerInfo(const nsACString& aScheme,
85 nsIHandlerInfo** aHandlerInfo) override;
87 NS_IMETHOD LoadURI(nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
88 nsIPrincipal* aRedirectPrincipal,
89 mozilla::dom::BrowsingContext* aBrowsingContext,
90 bool aWasTriggeredExternally,
91 bool aHasValidUserGestureActivation) override;
92 NS_IMETHOD SetProtocolHandlerDefaults(nsIHandlerInfo* aHandlerInfo,
93 bool aOSHandlerExists) override;
95 /**
96 * Given a string identifying an application, create an nsIFile representing
97 * it. This function should look in $PATH for the application.
98 * The base class implementation will first try to interpret platformAppPath
99 * as an absolute path, and if that fails it will look for a file next to the
100 * mozilla executable. Subclasses can override this method if they want a
101 * different behaviour.
102 * @param platformAppPath A platform specific path to an application that we
103 * got out of the rdf data source. This can be a mac
104 * file spec, a unix path or a windows path depending
105 * on the platform
106 * @param aFile [out] An nsIFile representation of that platform
107 * application path.
109 virtual nsresult GetFileTokenForPath(const char16_t* platformAppPath,
110 nsIFile** aFile);
112 NS_IMETHOD OSProtocolHandlerExists(const char* aScheme, bool* aExists) = 0;
115 * Given an extension, get a MIME type string from the builtin list of
116 * mime types.
117 * @return true if we successfully found a mimetype.
119 virtual bool GetMIMETypeFromDefaultForExtension(const nsACString& aExtension,
120 nsACString& aMIMEType);
123 * Given an extension, get a MIME type string. If not overridden by
124 * the OS-specific nsOSHelperAppService, will call into GetMIMEInfoFromOS
125 * with an empty mimetype.
126 * @return true if we successfully found a mimetype.
128 virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension,
129 nsACString& aMIMEType);
131 static already_AddRefed<nsExternalHelperAppService> GetSingleton();
133 // Internal method. Only called directly from tests.
134 static nsresult EscapeURI(nsIURI* aURI, nsIURI** aResult);
137 * Logging Module. Usage: set MOZ_LOG=HelperAppService:level, where level
138 * should be 2 for errors, 3 for debug messages from the cross- platform
139 * nsExternalHelperAppService, and 4 for os-specific debug messages.
141 static mozilla::LazyLogModule sLog;
143 protected:
144 virtual ~nsExternalHelperAppService();
147 * Searches the "extra" array of MIMEInfo objects for an object
148 * with a specific type. If found, it will modify the passed-in
149 * MIMEInfo. Otherwise, it will return an error and the MIMEInfo
150 * will be untouched.
151 * @param aContentType The type to search for.
152 * @param aOverwriteDescription Whether to overwrite the description
153 * @param aMIMEInfo [inout] The mime info, if found
155 nsresult FillMIMEInfoForMimeTypeFromExtras(const nsACString& aContentType,
156 bool aOverwriteDescription,
157 nsIMIMEInfo* aMIMEInfo);
159 * Searches the "extra" array of MIMEInfo objects for an object
160 * with a specific extension.
162 * Does not change the MIME Type of the MIME Info.
164 * @see FillMIMEInfoForMimeTypeFromExtras
166 nsresult FillMIMEInfoForExtensionFromExtras(const nsACString& aExtension,
167 nsIMIMEInfo* aMIMEInfo);
170 * Replace the primary extension of the mimeinfo object if it's in our
171 * list of forbidden extensions. This fixes up broken information
172 * provided to us by the OS.
174 bool MaybeReplacePrimaryExtension(const nsACString& aPrimaryExtension,
175 nsIMIMEInfo* aMIMEInfo);
178 * Searches the "extra" array for a MIME type, and gets its extension.
179 * @param aExtension The extension to search for
180 * @param aMIMEType [out] The found MIME type.
181 * @return true if the extension was found, false otherwise.
183 bool GetTypeFromExtras(const nsACString& aExtension, nsACString& aMIMEType);
185 // friend, so that it can access the nspr log module.
186 friend class nsExternalAppHandler;
189 * Helper function for ExpungeTemporaryFiles and ExpungeTemporaryPrivateFiles
191 static void ExpungeTemporaryFilesHelper(nsCOMArray<nsIFile>& fileList);
193 * Helper function for DeleteTemporaryFileOnExit and
194 * DeleteTemporaryPrivateFileWhenPossible
196 static nsresult DeleteTemporaryFileHelper(nsIFile* aTemporaryFile,
197 nsCOMArray<nsIFile>& aFileList);
199 * Functions related to the tempory file cleanup service provided by
200 * nsExternalHelperAppService
202 void ExpungeTemporaryFiles();
204 * Functions related to the tempory file cleanup service provided by
205 * nsExternalHelperAppService (for the temporary files added during
206 * the private browsing mode)
208 void ExpungeTemporaryPrivateFiles();
210 bool GetFileNameFromChannel(nsIChannel* aChannel, nsAString& aFileName,
211 nsIURI** aURI);
213 // Internal version of the method from nsIMIMEService.
214 already_AddRefed<nsIMIMEInfo> ValidateFileNameForSaving(
215 nsAString& aFileName, const nsACString& aMimeType, nsIURI* aURI,
216 nsIURI* aOriginalURI, uint32_t aFlags, bool aAllowURLExtension);
218 // If aFileName is blank or just an extension, set aFileName to the
219 // default filename.
220 void CheckDefaultFileName(nsAString& aFileName, uint32_t aFlags);
222 // Ensure that the filename is safe for the file system. This will remove or
223 // replace any invalid characters and trim extra whitespace as needed. If the
224 // filename is too long, it will be truncated but the existing period and
225 // extension, if any, will be preserved.
226 void SanitizeFileName(nsAString& aFileName, uint32_t aFlags);
229 * Helper routine that checks how we should modify an extension
230 * for this file.
232 enum ModifyExtensionType {
233 // Replace an invalid extension with the preferred one.
234 ModifyExtension_Replace = 0,
235 // Append the preferred extension after any existing one.
236 ModifyExtension_Append = 1,
237 // Don't modify the extension.
238 ModifyExtension_Ignore = 2
240 ModifyExtensionType ShouldModifyExtension(nsIMIMEInfo* aMimeInfo,
241 bool aForceAppend,
242 const nsCString& aFileExt);
245 * Array for the files that should be deleted
247 nsCOMArray<nsIFile> mTemporaryFilesList;
249 * Array for the files that should be deleted (for the temporary files
250 * added during the private browsing mode)
252 nsCOMArray<nsIFile> mTemporaryPrivateFilesList;
254 private:
255 nsresult DoContentContentProcessHelper(
256 const nsACString& aMimeContentType, nsIChannel* aChannel,
257 mozilla::dom::BrowsingContext* aContentContext, bool aForceSave,
258 nsIInterfaceRequestor* aWindowContext,
259 nsIStreamListener** aStreamListener);
263 * An external app handler is just a small little class that presents itself as
264 * a nsIStreamListener. It saves the incoming data into a temp file. The handler
265 * is bound to an application when it is created. When it receives an
266 * OnStopRequest it launches the application using the temp file it has
267 * stored the data into. We create a handler every time we have to process
268 * data using a helper app.
270 class nsExternalAppHandler final : public nsIStreamListener,
271 public nsIHelperAppLauncher,
272 public nsIBackgroundFileSaverObserver,
273 public nsINamed {
274 public:
275 NS_DECL_THREADSAFE_ISUPPORTS
276 NS_DECL_NSISTREAMLISTENER
277 NS_DECL_NSIREQUESTOBSERVER
278 NS_DECL_NSIHELPERAPPLAUNCHER
279 NS_DECL_NSICANCELABLE
280 NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER
281 NS_DECL_NSINAMED
283 NS_DECLARE_STATIC_IID_ACCESSOR(EXTERNAL_APP_HANDLER_IID)
286 * @param aMIMEInfo MIMEInfo object, representing the type of the
287 * content that should be handled
288 * @param aFileExtension The extension we need to append to our temp file,
289 * INCLUDING the ".". e.g. .mp3
290 * @param aContentContext dom Window context, as passed to DoContent.
291 * @param aWindowContext Top level window context used in dialog parenting,
292 * as passed to DoContent. This parameter may be null,
293 * in which case dialogs will be parented to
294 * aContentContext.
295 * @param mExtProtSvc nsExternalHelperAppService on creation
296 * @param aSuggestedFileName The filename to use
297 * @param aReason A constant from nsIHelperAppLauncherDialog
298 * indicating why the request is handled by a helper app.
300 nsExternalAppHandler(nsIMIMEInfo* aMIMEInfo, const nsAString& aFileExtension,
301 mozilla::dom::BrowsingContext* aBrowsingContext,
302 nsIInterfaceRequestor* aWindowContext,
303 nsExternalHelperAppService* aExtProtSvc,
304 const nsAString& aSuggestedFileName, uint32_t aReason,
305 bool aForceSave);
308 * Clean up after the request was diverted to the parent process.
310 void DidDivertRequest(nsIRequest* request);
313 * Apply content conversions if needed.
315 void MaybeApplyDecodingForExtension(nsIRequest* request);
317 void SetShouldCloseWindow() { mShouldCloseWindow = true; }
319 protected:
320 bool IsDownloadSpam(nsIChannel* aChannel);
322 ~nsExternalAppHandler();
324 nsCOMPtr<nsIFile> mTempFile;
325 nsCOMPtr<nsIURI> mSourceUrl;
326 nsString mFileExtension;
327 nsString mTempLeafName;
330 * The MIME Info for this load. Will never be null.
332 nsCOMPtr<nsIMIMEInfo> mMimeInfo;
335 * The BrowsingContext associated with this request to handle content.
337 RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext;
340 * If set, the parent window helper app dialogs and file pickers
341 * should use in parenting. If null, we use mContentContext.
343 nsCOMPtr<nsIInterfaceRequestor> mWindowContext;
346 * Used to close the window on a timer, to avoid any exceptions that are
347 * thrown if we try to close the window before it's fully loaded.
349 RefPtr<MaybeCloseWindowHelper> mMaybeCloseWindowHelper;
352 * The following field is set if we were processing an http channel that had
353 * a content disposition header which specified the SUGGESTED file name we
354 * should present to the user in the save to disk dialog.
356 nsString mSuggestedFileName;
359 * If set, this handler should forcibly save the file to disk regardless of
360 * MIME info settings or anything else, without ever popping up the
361 * unknown content type handling dialog.
363 bool mForceSave;
366 * If set, any internally handled type that has a disposition of
367 nsIChannel::DISPOSITION_ATTACHMENT will be saved to disk.
369 bool mForceSaveInternallyHandled;
372 * The canceled flag is set if the user canceled the launching of this
373 * application before we finished saving the data to a temp file.
375 bool mCanceled;
378 * True if a stop request has been issued.
380 bool mStopRequestIssued;
382 bool mIsFileChannel;
385 * True if the ExternalHelperAppChild told us that we should close the window
386 * if we handle the content as a download.
388 bool mShouldCloseWindow;
391 * True if the file should be handled internally.
393 bool mHandleInternally;
396 * True if any dialog (e.g. unknown content type or file picker) is shown —
397 * can stop downloads panel from opening, to avoid redundant interruptions.
399 bool mDialogShowing;
402 * One of the REASON_ constants from nsIHelperAppLauncherDialog. Indicates the
403 * reason the dialog was shown (unknown content type, server requested it,
404 * etc).
406 uint32_t mReason;
409 * Indicates if the nsContentSecurityUtils rate this download as
410 * acceptable, potentialy unwanted or illigal request.
413 int32_t mDownloadClassification;
416 * Track the executable-ness of the temporary file.
418 bool mTempFileIsExecutable;
420 PRTime mTimeDownloadStarted;
421 int64_t mContentLength;
422 int64_t mProgress; /**< Number of bytes received (for sending progress
423 notifications). */
426 * When we are told to save the temp file to disk (in a more permament
427 * location) before we are done writing the content to a temp file, then
428 * we need to remember the final destination until we are ready to use it.
430 nsCOMPtr<nsIFile> mFinalFileDestination;
432 uint32_t mBufferSize;
435 * This object handles saving the data received from the network to a
436 * temporary location first, and then move the file to its final location,
437 * doing all the input/output on a background thread.
439 nsCOMPtr<nsIBackgroundFileSaver> mSaver;
442 * Stores the SHA-256 hash associated with the file that we downloaded.
444 nsAutoCString mHash;
446 * Stores the signature information of the downloaded file in an nsTArray of
447 * nsTArray of Array of bytes. If the file is unsigned this will be
448 * empty.
450 nsTArray<nsTArray<nsTArray<uint8_t>>> mSignatureInfo;
452 * Stores the redirect information associated with the channel.
454 nsCOMPtr<nsIArray> mRedirects;
456 * Get the dialog parent: the parent window that we can attach
457 * a dialog to when prompting the user for a download.
459 already_AddRefed<nsIInterfaceRequestor> GetDialogParent();
461 * Creates the temporary file for the download and an output stream for it.
462 * Upon successful return, both mTempFile and mSaver will be valid.
464 nsresult SetUpTempFile(nsIChannel* aChannel);
466 * When we download a helper app, we are going to retarget all load
467 * notifications into our own docloader and load group instead of
468 * using the window which initiated the load....RetargetLoadNotifications
469 * contains that information...
471 void RetargetLoadNotifications(nsIRequest* request);
473 * Once the user tells us how they want to dispose of the content
474 * create an nsITransfer so they know what's going on. If this fails, the
475 * caller MUST call Cancel.
477 nsresult CreateTransfer();
480 * If we fail to create the necessary temporary file to initiate a transfer
481 * we will report the failure by creating a failed nsITransfer.
483 nsresult CreateFailedTransfer();
486 * The following two functions are part of the split of SaveToDisk
487 * to make it async, and works as following:
489 * SaveToDisk -------> RequestSaveDestination
493 * ContinueSave <------- SaveDestinationAvailable
497 * This is called by SaveToDisk to decide what's the final
498 * file destination chosen by the user or by auto-download settings.
500 void RequestSaveDestination(const nsString& aDefaultFile,
501 const nsString& aDefaultFileExt);
504 * When SaveToDisk is called, it possibly delegates to RequestSaveDestination
505 * to decide the file destination. ContinueSave must then be called when
506 * the final destination is finally known.
507 * @param aFile The file that was chosen as the final destination.
508 * Must not be null.
510 nsresult ContinueSave(nsIFile* aFile);
513 * Notify our nsITransfer object that we are done with the download. This is
514 * always called after the target file has been closed.
516 * @param aStatus
517 * NS_OK for success, or a failure code if the download failed.
518 * A partially downloaded file may still be available in this case.
520 void NotifyTransfer(nsresult aStatus);
523 * Helper routine that searches a pref string for a given mime type
525 bool GetNeverAskFlagFromPref(const char* prefName, const char* aContentType);
528 * Helper routine to ensure that mSuggestedFileName ends in the correct
529 * extension, in case the original extension contains invalid characters
530 * or if this download is for a mimetype where we enforce using a specific
531 * extension (image/, video/, and audio/ based mimetypes, and a few specific
532 * document types).
534 * It also ensure that mFileExtension only contains an extension
535 * when it is different from mSuggestedFileName's extension.
537 void EnsureCorrectExtension(const nsString& aFileExt);
539 typedef enum { kReadError, kWriteError, kLaunchError } ErrorType;
541 * Utility function to send proper error notification to web progress listener
543 void SendStatusChange(ErrorType type, nsresult aStatus, nsIRequest* aRequest,
544 const nsString& path);
547 * Set in HelperAppDlg.sys.mjs. This is always null after the user has chosen
548 * an action.
550 nsCOMPtr<nsIWebProgressListener2> mDialogProgressListener;
552 * Set once the user has chosen an action. This is null after the download
553 * has been canceled or completes.
555 nsCOMPtr<nsITransfer> mTransfer;
557 nsCOMPtr<nsIHelperAppLauncherDialog> mDialog;
561 * The request that's being loaded. Initialized in OnStartRequest.
562 * Nulled out in OnStopRequest or once we know what we're doing
563 * with the data, whichever happens later.
565 nsCOMPtr<nsIRequest> mRequest;
567 RefPtr<nsExternalHelperAppService> mExtProtSvc;
569 NS_DEFINE_STATIC_IID_ACCESSOR(nsExternalAppHandler, EXTERNAL_APP_HANDLER_IID)
571 #endif // nsExternalHelperAppService_h__