/src/mozilla-central/uriloader/exthandler/nsExternalHelperAppService.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
5 | | |
6 | | #ifndef nsExternalHelperAppService_h__ |
7 | | #define nsExternalHelperAppService_h__ |
8 | | |
9 | | #include "mozilla/Logging.h" |
10 | | #include "prtime.h" |
11 | | |
12 | | #include "nsIExternalHelperAppService.h" |
13 | | #include "nsIExternalProtocolService.h" |
14 | | #include "nsIWebProgressListener2.h" |
15 | | #include "nsIHelperAppLauncherDialog.h" |
16 | | |
17 | | #include "nsIMIMEInfo.h" |
18 | | #include "nsIMIMEService.h" |
19 | | #include "nsINamed.h" |
20 | | #include "nsIStreamListener.h" |
21 | | #include "nsIFile.h" |
22 | | #include "nsIFileStreams.h" |
23 | | #include "nsIOutputStream.h" |
24 | | #include "nsString.h" |
25 | | #include "nsIInterfaceRequestor.h" |
26 | | #include "nsIInterfaceRequestorUtils.h" |
27 | | #include "nsIChannel.h" |
28 | | #include "nsIBackgroundFileSaver.h" |
29 | | |
30 | | #include "nsIHandlerService.h" |
31 | | #include "nsCOMPtr.h" |
32 | | #include "nsIObserver.h" |
33 | | #include "nsCOMArray.h" |
34 | | #include "nsWeakReference.h" |
35 | | #include "nsIPrompt.h" |
36 | | #include "nsAutoPtr.h" |
37 | | #include "mozilla/Attributes.h" |
38 | | |
39 | | class nsExternalAppHandler; |
40 | | class nsIMIMEInfo; |
41 | | class nsITransfer; |
42 | | class MaybeCloseWindowHelper; |
43 | | |
44 | | /** |
45 | | * The helper app service. Responsible for handling content that Mozilla |
46 | | * itself can not handle |
47 | | */ |
48 | | class nsExternalHelperAppService |
49 | | : public nsIExternalHelperAppService, |
50 | | public nsPIExternalAppLauncher, |
51 | | public nsIExternalProtocolService, |
52 | | public nsIMIMEService, |
53 | | public nsIObserver, |
54 | | public nsSupportsWeakReference |
55 | | { |
56 | | public: |
57 | | NS_DECL_ISUPPORTS |
58 | | NS_DECL_NSIEXTERNALHELPERAPPSERVICE |
59 | | NS_DECL_NSPIEXTERNALAPPLAUNCHER |
60 | | NS_DECL_NSIEXTERNALPROTOCOLSERVICE |
61 | | NS_DECL_NSIMIMESERVICE |
62 | | NS_DECL_NSIOBSERVER |
63 | | |
64 | | nsExternalHelperAppService(); |
65 | | |
66 | | /** |
67 | | * Initializes internal state. Will be called automatically when |
68 | | * this service is first instantiated. |
69 | | */ |
70 | | MOZ_MUST_USE nsresult Init(); |
71 | | |
72 | | /** |
73 | | * Given a mimetype and an extension, looks up a mime info from the OS. |
74 | | * The mime type is given preference. This function follows the same rules |
75 | | * as nsIMIMEService::GetFromTypeAndExtension. |
76 | | * This is supposed to be overridden by the platform-specific |
77 | | * nsOSHelperAppService! |
78 | | * @param aFileExt The file extension; may be empty. UTF-8 encoded. |
79 | | * @param [out] aFound |
80 | | * Should be set to true if the os has a mapping, to |
81 | | * false otherwise. Must not be null. |
82 | | * @return A MIMEInfo. This function must return a MIMEInfo object if it |
83 | | * can allocate one. The only justifiable reason for not |
84 | | * returning one is an out-of-memory error. |
85 | | * If null, the value of aFound is unspecified. |
86 | | */ |
87 | | virtual already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, |
88 | | const nsACString& aFileExt, |
89 | | bool * aFound) = 0; |
90 | | |
91 | | /** |
92 | | * Given a string identifying an application, create an nsIFile representing |
93 | | * it. This function should look in $PATH for the application. |
94 | | * The base class implementation will first try to interpret platformAppPath |
95 | | * as an absolute path, and if that fails it will look for a file next to the |
96 | | * mozilla executable. Subclasses can override this method if they want a |
97 | | * different behaviour. |
98 | | * @param platformAppPath A platform specific path to an application that we |
99 | | * got out of the rdf data source. This can be a mac |
100 | | * file spec, a unix path or a windows path depending |
101 | | * on the platform |
102 | | * @param aFile [out] An nsIFile representation of that platform |
103 | | * application path. |
104 | | */ |
105 | | virtual nsresult GetFileTokenForPath(const char16_t * platformAppPath, |
106 | | nsIFile ** aFile); |
107 | | |
108 | | virtual nsresult OSProtocolHandlerExists(const char *aScheme, |
109 | | bool *aExists) = 0; |
110 | | |
111 | | /** |
112 | | * Given an extension, get a MIME type string. If not overridden by |
113 | | * the OS-specific nsOSHelperAppService, will call into GetMIMEInfoFromOS |
114 | | * with an empty mimetype. |
115 | | * @return true if we successfully found a mimetype. |
116 | | */ |
117 | | virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension, |
118 | | nsACString& aMIMEType); |
119 | | |
120 | | protected: |
121 | | virtual ~nsExternalHelperAppService(); |
122 | | |
123 | | /** |
124 | | * Searches the "extra" array of MIMEInfo objects for an object |
125 | | * with a specific type. If found, it will modify the passed-in |
126 | | * MIMEInfo. Otherwise, it will return an error and the MIMEInfo |
127 | | * will be untouched. |
128 | | * @param aContentType The type to search for. |
129 | | * @param aMIMEInfo [inout] The mime info, if found |
130 | | */ |
131 | | nsresult FillMIMEInfoForMimeTypeFromExtras( |
132 | | const nsACString& aContentType, nsIMIMEInfo * aMIMEInfo); |
133 | | /** |
134 | | * Searches the "extra" array of MIMEInfo objects for an object |
135 | | * with a specific extension. |
136 | | * |
137 | | * Does not change the MIME Type of the MIME Info. |
138 | | * |
139 | | * @see FillMIMEInfoForMimeTypeFromExtras |
140 | | */ |
141 | | nsresult FillMIMEInfoForExtensionFromExtras( |
142 | | const nsACString& aExtension, nsIMIMEInfo * aMIMEInfo); |
143 | | |
144 | | /** |
145 | | * Searches the "extra" array for a MIME type, and gets its extension. |
146 | | * @param aExtension The extension to search for |
147 | | * @param aMIMEType [out] The found MIME type. |
148 | | * @return true if the extension was found, false otherwise. |
149 | | */ |
150 | | bool GetTypeFromExtras(const nsACString& aExtension, |
151 | | nsACString& aMIMEType); |
152 | | |
153 | | /** |
154 | | * Logging Module. Usage: set MOZ_LOG=HelperAppService:level, where level |
155 | | * should be 2 for errors, 3 for debug messages from the cross- platform |
156 | | * nsExternalHelperAppService, and 4 for os-specific debug messages. |
157 | | */ |
158 | | static mozilla::LazyLogModule mLog; |
159 | | |
160 | | // friend, so that it can access the nspr log module. |
161 | | friend class nsExternalAppHandler; |
162 | | |
163 | | /** |
164 | | * Helper function for ExpungeTemporaryFiles and ExpungeTemporaryPrivateFiles |
165 | | */ |
166 | | static void ExpungeTemporaryFilesHelper(nsCOMArray<nsIFile> &fileList); |
167 | | /** |
168 | | * Helper function for DeleteTemporaryFileOnExit and DeleteTemporaryPrivateFileWhenPossible |
169 | | */ |
170 | | static nsresult DeleteTemporaryFileHelper(nsIFile* aTemporaryFile, |
171 | | nsCOMArray<nsIFile> &aFileList); |
172 | | /** |
173 | | * Functions related to the tempory file cleanup service provided by |
174 | | * nsExternalHelperAppService |
175 | | */ |
176 | | void ExpungeTemporaryFiles(); |
177 | | /** |
178 | | * Functions related to the tempory file cleanup service provided by |
179 | | * nsExternalHelperAppService (for the temporary files added during |
180 | | * the private browsing mode) |
181 | | */ |
182 | | void ExpungeTemporaryPrivateFiles(); |
183 | | |
184 | | /** |
185 | | * Array for the files that should be deleted |
186 | | */ |
187 | | nsCOMArray<nsIFile> mTemporaryFilesList; |
188 | | /** |
189 | | * Array for the files that should be deleted (for the temporary files |
190 | | * added during the private browsing mode) |
191 | | */ |
192 | | nsCOMArray<nsIFile> mTemporaryPrivateFilesList; |
193 | | |
194 | | private: |
195 | | nsresult DoContentContentProcessHelper(const nsACString& aMimeContentType, |
196 | | nsIRequest *aRequest, |
197 | | nsIInterfaceRequestor *aContentContext, |
198 | | bool aForceSave, |
199 | | nsIInterfaceRequestor *aWindowContext, |
200 | | nsIStreamListener ** aStreamListener); |
201 | | }; |
202 | | |
203 | | /** |
204 | | * An external app handler is just a small little class that presents itself as |
205 | | * a nsIStreamListener. It saves the incoming data into a temp file. The handler |
206 | | * is bound to an application when it is created. When it receives an |
207 | | * OnStopRequest it launches the application using the temp file it has |
208 | | * stored the data into. We create a handler every time we have to process |
209 | | * data using a helper app. |
210 | | */ |
211 | | class nsExternalAppHandler final : public nsIStreamListener, |
212 | | public nsIHelperAppLauncher, |
213 | | public nsIBackgroundFileSaverObserver, |
214 | | public nsINamed |
215 | | { |
216 | | public: |
217 | | NS_DECL_THREADSAFE_ISUPPORTS |
218 | | NS_DECL_NSISTREAMLISTENER |
219 | | NS_DECL_NSIREQUESTOBSERVER |
220 | | NS_DECL_NSIHELPERAPPLAUNCHER |
221 | | NS_DECL_NSICANCELABLE |
222 | | NS_DECL_NSIBACKGROUNDFILESAVEROBSERVER |
223 | | NS_DECL_NSINAMED |
224 | | |
225 | | /** |
226 | | * @param aMIMEInfo MIMEInfo object, representing the type of the |
227 | | * content that should be handled |
228 | | * @param aFileExtension The extension we need to append to our temp file, |
229 | | * INCLUDING the ".". e.g. .mp3 |
230 | | * @param aContentContext dom Window context, as passed to DoContent. |
231 | | * @param aWindowContext Top level window context used in dialog parenting, |
232 | | * as passed to DoContent. This parameter may be null, |
233 | | * in which case dialogs will be parented to |
234 | | * aContentContext. |
235 | | * @param mExtProtSvc nsExternalHelperAppService on creation |
236 | | * @param aFileName The filename to use |
237 | | * @param aReason A constant from nsIHelperAppLauncherDialog indicating |
238 | | * why the request is handled by a helper app. |
239 | | */ |
240 | | nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo, const nsACString& aFileExtension, |
241 | | nsIInterfaceRequestor * aContentContext, |
242 | | nsIInterfaceRequestor * aWindowContext, |
243 | | nsExternalHelperAppService * aExtProtSvc, |
244 | | const nsAString& aFilename, |
245 | | uint32_t aReason, bool aForceSave); |
246 | | |
247 | | /** |
248 | | * Clean up after the request was diverted to the parent process. |
249 | | */ |
250 | | void DidDivertRequest(nsIRequest *request); |
251 | | |
252 | | /** |
253 | | * Apply content conversions if needed. |
254 | | */ |
255 | | void MaybeApplyDecodingForExtension(nsIRequest *request); |
256 | | |
257 | | /** |
258 | | * Get the dialog parent. Public for ExternalHelperAppChild::OnStartRequest. |
259 | | */ |
260 | 0 | nsIInterfaceRequestor* GetDialogParent() { |
261 | 0 | return mWindowContext ? mWindowContext : mContentContext; |
262 | 0 | } |
263 | | |
264 | 0 | void SetContentContext(nsIInterfaceRequestor* context) { |
265 | 0 | MOZ_ASSERT(!mWindowContext); |
266 | 0 | mContentContext = context; |
267 | 0 | } |
268 | | |
269 | | protected: |
270 | | ~nsExternalAppHandler(); |
271 | | |
272 | | nsCOMPtr<nsIFile> mTempFile; |
273 | | nsCOMPtr<nsIURI> mSourceUrl; |
274 | | nsString mTempFileExtension; |
275 | | nsString mTempLeafName; |
276 | | |
277 | | /** |
278 | | * The MIME Info for this load. Will never be null. |
279 | | */ |
280 | | nsCOMPtr<nsIMIMEInfo> mMimeInfo; |
281 | | |
282 | | /** |
283 | | * The dom window associated with this request to handle content. |
284 | | */ |
285 | | nsCOMPtr<nsIInterfaceRequestor> mContentContext; |
286 | | |
287 | | /** |
288 | | * If set, the parent window helper app dialogs and file pickers |
289 | | * should use in parenting. If null, we use mContentContext. |
290 | | */ |
291 | | nsCOMPtr<nsIInterfaceRequestor> mWindowContext; |
292 | | |
293 | | /** |
294 | | * Used to close the window on a timer, to avoid any exceptions that are |
295 | | * thrown if we try to close the window before it's fully loaded. |
296 | | */ |
297 | | RefPtr<MaybeCloseWindowHelper> mMaybeCloseWindowHelper; |
298 | | |
299 | | /** |
300 | | * The following field is set if we were processing an http channel that had |
301 | | * a content disposition header which specified the SUGGESTED file name we |
302 | | * should present to the user in the save to disk dialog. |
303 | | */ |
304 | | nsString mSuggestedFileName; |
305 | | |
306 | | /** |
307 | | * If set, this handler should forcibly save the file to disk regardless of |
308 | | * MIME info settings or anything else, without ever popping up the |
309 | | * unknown content type handling dialog. |
310 | | */ |
311 | | bool mForceSave; |
312 | | |
313 | | /** |
314 | | * The canceled flag is set if the user canceled the launching of this |
315 | | * application before we finished saving the data to a temp file. |
316 | | */ |
317 | | bool mCanceled; |
318 | | |
319 | | /** |
320 | | * True if a stop request has been issued. |
321 | | */ |
322 | | bool mStopRequestIssued; |
323 | | |
324 | | bool mIsFileChannel; |
325 | | |
326 | | /** |
327 | | * One of the REASON_ constants from nsIHelperAppLauncherDialog. Indicates the |
328 | | * reason the dialog was shown (unknown content type, server requested it, |
329 | | * etc). |
330 | | */ |
331 | | uint32_t mReason; |
332 | | |
333 | | /** |
334 | | * Track the executable-ness of the temporary file. |
335 | | */ |
336 | | bool mTempFileIsExecutable; |
337 | | |
338 | | PRTime mTimeDownloadStarted; |
339 | | int64_t mContentLength; |
340 | | int64_t mProgress; /**< Number of bytes received (for sending progress notifications). */ |
341 | | |
342 | | /** |
343 | | * When we are told to save the temp file to disk (in a more permament |
344 | | * location) before we are done writing the content to a temp file, then |
345 | | * we need to remember the final destination until we are ready to use it. |
346 | | */ |
347 | | nsCOMPtr<nsIFile> mFinalFileDestination; |
348 | | |
349 | | uint32_t mBufferSize; |
350 | | |
351 | | /** |
352 | | * This object handles saving the data received from the network to a |
353 | | * temporary location first, and then move the file to its final location, |
354 | | * doing all the input/output on a background thread. |
355 | | */ |
356 | | nsCOMPtr<nsIBackgroundFileSaver> mSaver; |
357 | | |
358 | | /** |
359 | | * Stores the SHA-256 hash associated with the file that we downloaded. |
360 | | */ |
361 | | nsAutoCString mHash; |
362 | | /** |
363 | | * Stores the signature information of the downloaded file in an nsIArray of |
364 | | * nsIX509CertList of nsIX509Cert. If the file is unsigned this will be |
365 | | * empty. |
366 | | */ |
367 | | nsCOMPtr<nsIArray> mSignatureInfo; |
368 | | /** |
369 | | * Stores the redirect information associated with the channel. |
370 | | */ |
371 | | nsCOMPtr<nsIArray> mRedirects; |
372 | | /** |
373 | | * Creates the temporary file for the download and an output stream for it. |
374 | | * Upon successful return, both mTempFile and mSaver will be valid. |
375 | | */ |
376 | | nsresult SetUpTempFile(nsIChannel * aChannel); |
377 | | /** |
378 | | * When we download a helper app, we are going to retarget all load |
379 | | * notifications into our own docloader and load group instead of |
380 | | * using the window which initiated the load....RetargetLoadNotifications |
381 | | * contains that information... |
382 | | */ |
383 | | void RetargetLoadNotifications(nsIRequest *request); |
384 | | /** |
385 | | * Once the user tells us how they want to dispose of the content |
386 | | * create an nsITransfer so they know what's going on. If this fails, the |
387 | | * caller MUST call Cancel. |
388 | | */ |
389 | | nsresult CreateTransfer(); |
390 | | |
391 | | /** |
392 | | * If we fail to create the necessary temporary file to initiate a transfer |
393 | | * we will report the failure by creating a failed nsITransfer. |
394 | | */ |
395 | | nsresult CreateFailedTransfer(bool aIsPrivateBrowsing); |
396 | | |
397 | | /* |
398 | | * The following two functions are part of the split of SaveToDisk |
399 | | * to make it async, and works as following: |
400 | | * |
401 | | * SaveToDisk -------> RequestSaveDestination |
402 | | * . |
403 | | * . |
404 | | * v |
405 | | * ContinueSave <------- SaveDestinationAvailable |
406 | | */ |
407 | | |
408 | | /** |
409 | | * This is called by SaveToDisk to decide what's the final |
410 | | * file destination chosen by the user or by auto-download settings. |
411 | | */ |
412 | | void RequestSaveDestination(const nsString& aDefaultFile, |
413 | | const nsString& aDefaultFileExt); |
414 | | |
415 | | /** |
416 | | * When SaveToDisk is called, it possibly delegates to RequestSaveDestination |
417 | | * to decide the file destination. ContinueSave must then be called when |
418 | | * the final destination is finally known. |
419 | | * @param aFile The file that was chosen as the final destination. |
420 | | * Must not be null. |
421 | | */ |
422 | | nsresult ContinueSave(nsIFile* aFile); |
423 | | |
424 | | /** |
425 | | * After we're done prompting the user for any information, if the original |
426 | | * channel had a refresh url associated with it (which might point to a |
427 | | * "thank you for downloading" kind of page, then process that....It is safe |
428 | | * to invoke this method multiple times. We'll clear mOriginalChannel after |
429 | | * it's called and this ensures we won't call it again.... |
430 | | */ |
431 | | void ProcessAnyRefreshTags(); |
432 | | |
433 | | /** |
434 | | * Notify our nsITransfer object that we are done with the download. This is |
435 | | * always called after the target file has been closed. |
436 | | * |
437 | | * @param aStatus |
438 | | * NS_OK for success, or a failure code if the download failed. |
439 | | * A partially downloaded file may still be available in this case. |
440 | | */ |
441 | | void NotifyTransfer(nsresult aStatus); |
442 | | |
443 | | /** |
444 | | * Helper routine that searches a pref string for a given mime type |
445 | | */ |
446 | | bool GetNeverAskFlagFromPref(const char * prefName, const char * aContentType); |
447 | | |
448 | | /** |
449 | | * Helper routine to ensure mSuggestedFileName is "correct"; |
450 | | * this ensures that mTempFileExtension only contains an extension when it |
451 | | * is different from mSuggestedFileName's extension. |
452 | | */ |
453 | | void EnsureSuggestedFileName(); |
454 | | |
455 | | typedef enum { kReadError, kWriteError, kLaunchError } ErrorType; |
456 | | /** |
457 | | * Utility function to send proper error notification to web progress listener |
458 | | */ |
459 | | void SendStatusChange(ErrorType type, nsresult aStatus, nsIRequest *aRequest, const nsString& path); |
460 | | |
461 | | /** |
462 | | * Set in nsHelperDlgApp.js. This is always null after the user has chosen an |
463 | | * action. |
464 | | */ |
465 | | nsCOMPtr<nsIWebProgressListener2> mDialogProgressListener; |
466 | | /** |
467 | | * Set once the user has chosen an action. This is null after the download |
468 | | * has been canceled or completes. |
469 | | */ |
470 | | nsCOMPtr<nsITransfer> mTransfer; |
471 | | |
472 | | nsCOMPtr<nsIChannel> mOriginalChannel; /**< in the case of a redirect, this will be the pre-redirect channel. */ |
473 | | nsCOMPtr<nsIHelperAppLauncherDialog> mDialog; |
474 | | |
475 | | /** |
476 | | |
477 | | * The request that's being loaded. Initialized in OnStartRequest. |
478 | | * Nulled out in OnStopRequest or once we know what we're doing |
479 | | * with the data, whichever happens later. |
480 | | */ |
481 | | nsCOMPtr<nsIRequest> mRequest; |
482 | | |
483 | | RefPtr<nsExternalHelperAppService> mExtProtSvc; |
484 | | }; |
485 | | |
486 | | #endif // nsExternalHelperAppService_h__ |