uriloader/exthandler/nsExternalHelperAppService.h

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

mercurial