1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is Chimera code.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright © 2002
19 * the Initial Developer. All Rights Reserved.
22 * David Hyatt <hyatt@netscape.com>
23 * Simon Fraser <sfraser@netscape.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK *****
39 * $Id: EphyHeaderSniffer.cpp 6588 2006-09-13 11:34:25Z chpe $
42 #include "mozilla-config.h"
45 #include <glib/gi18n.h>
46 #include <libgnomevfs/gnome-vfs-utils.h>
48 #include <nsStringAPI.h>
50 #include <nsComponentManagerUtils.h>
51 #include <nsIChannel.h>
52 #include <nsIDOMDocument.h>
53 #include <nsIDOMHTMLDocument.h>
54 #include <nsIDownload.h>
55 #include <nsIHttpChannel.h>
56 #include <nsIInputStream.h>
57 #include <nsILocalFile.h>
58 #include <nsIMIMEHeaderParam.h>
59 #include <nsIMIMEInfo.h>
60 #include <nsIMIMEService.h>
61 #include <nsIPrefService.h>
62 #include <nsIPromptService.h>
65 #include <nsIWebBrowserPersist.h>
66 #include <nsIWindowWatcher.h>
67 #include <nsServiceManagerUtils.h>
68 #include <nsXPCOMCID.h>
70 #include "eel-gconf-extensions.h"
71 #include "ephy-debug.h"
72 #include "ephy-file-chooser.h"
74 #include "ephy-prefs.h"
76 #include "EphyBadCertRejector.h"
77 #include "MozDownload.h"
79 #include "EphyHeaderSniffer.h"
81 EphyHeaderSniffer::EphyHeaderSniffer (nsIWebBrowserPersist
* aPersist
, MozillaEmbedPersist
*aEmbedPersist
,
82 nsIFile
* aFile
, nsIURI
* aURL
, nsIDOMDocument
* aDocument
, nsIInputStream
* aPostData
,
83 EphyEmbedSingle
*single
)
85 , mEmbedPersist(aEmbedPersist
)
88 , mOriginalURI(nsnull
)
89 , mDocument(aDocument
)
90 , mPostData(aPostData
)
92 LOG ("EphyHeaderSniffer ctor (%p)", this);
94 nsCOMPtr
<nsIWindowWatcher
> watcher
95 (do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
98 watcher
->GetNewAuthPrompter (nsnull
, getter_AddRefs (mAuthPrompt
));
101 g_object_add_weak_pointer (G_OBJECT (mSingle
),
102 (gpointer
*)&mSingle
);
105 EphyHeaderSniffer::~EphyHeaderSniffer()
107 LOG ("EphyHeaderSniffer dtor (%p)", this);
111 g_object_remove_weak_pointer (G_OBJECT (mSingle
),
112 (gpointer
*)&mSingle
);
116 NS_IMPL_ISUPPORTS3 (EphyHeaderSniffer
,
117 nsIWebProgressListener
,
118 nsIInterfaceRequestor
,
122 EphyHeaderSniffer::HandleContent ()
124 gboolean handled
= FALSE
;
127 if (mPostData
|| !mSingle
) return NS_ERROR_FAILURE
;
129 mURL
->GetSpec (uriSpec
);
131 g_signal_emit_by_name (mSingle
, "handle_content", mContentType
.get(),
132 uriSpec
.get(), &handled
);
134 return handled
? NS_OK
: NS_ERROR_FAILURE
;
138 EphyHeaderSniffer::OnStateChange (nsIWebProgress
*aWebProgress
, nsIRequest
*aRequest
, PRUint32 aStateFlags
,
141 if (aStateFlags
& nsIWebProgressListener::STATE_START
)
143 /* be sure to keep it alive while we save since it owns
144 us as a listener and keep ourselves alive */
145 nsCOMPtr
<nsIWebBrowserPersist
> kungFuDeathGrip(mPersist
);
146 nsCOMPtr
<nsIWebProgressListener
> kungFuSuicideGrip(this);
149 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(aRequest
, &rv
);
150 if (!channel
) return rv
;
151 channel
->GetContentType(mContentType
);
153 nsCOMPtr
<nsIURI
> origURI
;
154 channel
->GetOriginalURI(getter_AddRefs(origURI
));
156 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
159 httpChannel
->GetResponseHeader(nsCString("content-disposition"),
160 mContentDisposition
);
163 mPersist
->CancelSave();
166 mTmpFile
->Exists(&exists
);
169 mTmpFile
->Remove(PR_FALSE
);
172 rv
= HandleContent ();
173 if (NS_SUCCEEDED (rv
)) return NS_OK
;
175 rv
= PerformSave(origURI
);
178 /* FIXME put up some UI */
187 EphyHeaderSniffer::OnProgressChange (nsIWebProgress
*aWebProgress
,
188 nsIRequest
*aRequest
,
189 PRInt32 aCurSelfProgress
,
190 PRInt32 aMaxSelfProgress
,
191 PRInt32 aCurTotalProgress
,
192 PRInt32 aMaxTotalProgress
)
198 EphyHeaderSniffer::OnLocationChange (nsIWebProgress
*aWebProgress
,
199 nsIRequest
*aRequest
,
206 EphyHeaderSniffer::OnStatusChange (nsIWebProgress
*aWebProgress
,
207 nsIRequest
*aRequest
,
209 const PRUnichar
*aMessage
)
215 EphyHeaderSniffer::OnSecurityChange (nsIWebProgress
*aWebProgress
, nsIRequest
*aRequest
, PRUint32 state
)
220 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
222 EphyHeaderSniffer::GetInterface(const nsIID
& uuid
, void * *result
)
224 if (uuid
.Equals (NS_GET_IID (nsIBadCertListener
)) &&
227 EphyEmbedPersistFlags flags
;
229 g_object_get (mEmbedPersist
, "flags", &flags
, (char *) NULL
);
231 if (flags
& EPHY_EMBED_PERSIST_NO_CERTDIALOGS
)
233 EphyBadCertRejector
*badCertRejector
= new EphyBadCertRejector ();
234 if (!badCertRejector
) return NS_ERROR_OUT_OF_MEMORY
;
236 *result
= NS_STATIC_CAST(nsIBadCertListener
*, badCertRejector
);
237 NS_ADDREF (badCertRejector
);
243 return NS_ERROR_NO_INTERFACE
;
247 filechooser_response_cb (GtkWidget
*dialog
,
249 EphyHeaderSniffer
* sniffer
)
251 if (response
== GTK_RESPONSE_ACCEPT
)
255 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
257 if (ephy_gui_check_location_writable (dialog
, filename
) == FALSE
)
263 nsCOMPtr
<nsILocalFile
> destFile
= do_CreateInstance (NS_LOCAL_FILE_CONTRACTID
);
266 destFile
->InitWithNativePath (nsCString (filename
));
268 sniffer
->InitiateDownload (destFile
);
274 // FIXME how to inform user of failed save ?
276 gtk_widget_destroy (GTK_WIDGET (dialog
));
279 nsresult
EphyHeaderSniffer::PerformSave (nsIURI
* inOriginalURI
)
282 EphyEmbedPersistFlags flags
;
283 PRBool askDownloadDest
;
285 mOriginalURI
= inOriginalURI
;
287 flags
= ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (mEmbedPersist
));
288 askDownloadDest
= flags
& EPHY_EMBED_PERSIST_ASK_DESTINATION
;
290 nsString defaultFileName
;
292 if (!defaultFileName
.Length() && mContentDisposition
.Length())
294 /* 1 Use the HTTP header suggestion. */
295 nsCOMPtr
<nsIMIMEHeaderParam
> mimehdrpar
=
296 do_GetService("@mozilla.org/network/mime-hdrparam;1");
300 nsCString fallbackCharset
;
303 mURL
->GetOriginCharset(fallbackCharset
);
308 rv
= mimehdrpar
->GetParameter (mContentDisposition
, "filename",
309 fallbackCharset
, PR_TRUE
, nsnull
,
311 if (NS_FAILED(rv
) || !fileName
.Length())
313 rv
= mimehdrpar
->GetParameter (mContentDisposition
, "name",
314 fallbackCharset
, PR_TRUE
, nsnull
,
318 if (NS_SUCCEEDED(rv
) && fileName
.Length())
320 defaultFileName
= fileName
;
325 if (!defaultFileName
.Length())
327 /* 2 For file URLs, use the file name. */
329 nsCOMPtr
<nsIURL
> url(do_QueryInterface(mURL
));
332 nsCString fileNameCString
;
333 url
->GetFileName(fileNameCString
);
334 NS_CStringToUTF16 (fileNameCString
, NS_CSTRING_ENCODING_UTF8
,
339 if (!defaultFileName
.Length() && mDocument
)
341 /* 3 Use the title of the document. */
343 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc(do_QueryInterface(mDocument
));
346 htmlDoc
->GetTitle(defaultFileName
);
350 if (!defaultFileName
.Length() && mURL
)
352 /* 4 Use the host. */
354 mURL
->GetHost(hostName
);
355 NS_CStringToUTF16 (hostName
, NS_CSTRING_ENCODING_UTF8
,
359 /* 5 One last case to handle about:blank and other untitled pages. */
360 if (!defaultFileName
.Length())
362 NS_CStringToUTF16 (nsCString(_("Untitled")),
363 NS_CSTRING_ENCODING_UTF8
, defaultFileName
);
366 /* Validate the file name to ensure legality. */
367 nsCString cDefaultFileName
;
368 NS_UTF16ToCString (defaultFileName
, NS_CSTRING_ENCODING_UTF8
,
370 char *default_name
= g_strdup (cDefaultFileName
.get());
371 default_name
= g_strdelimit (default_name
, "/\\:", ' ');
374 key
= ephy_embed_persist_get_persist_key (EPHY_EMBED_PERSIST (mEmbedPersist
));
376 /* FIXME: do better here by using nsITextToSubURI service, like in
377 * http://lxr.mozilla.org/seamonkey/source/xpfe/communicator/resources/content/contentAreaUtils.js#763
380 filename
= gnome_vfs_unescape_string (default_name
, NULL
);
382 if (!g_utf8_validate (filename
, -1, NULL
))
385 filename
= g_strdup (default_name
);
388 g_free (default_name
);
392 EphyFileChooser
*dialog
;
397 title
= ephy_embed_persist_get_fc_title (EPHY_EMBED_PERSIST (mEmbedPersist
));
398 window
= ephy_embed_persist_get_fc_parent (EPHY_EMBED_PERSIST (mEmbedPersist
));
400 user_time
= ephy_embed_persist_get_user_time (EPHY_EMBED_PERSIST (mEmbedPersist
));
403 g_warning ("EphyHeaderSniffer::PerformSave without valid user time!\n");
406 dialog
= ephy_file_chooser_new (title
? title
: _("Save"),
408 GTK_FILE_CHOOSER_ACTION_SAVE
,
409 key
? key
: CONF_STATE_SAVE_DIR
,
410 EPHY_FILE_FILTER_ALL_SUPPORTED
);
411 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
), TRUE
);
413 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
),
416 g_signal_connect (dialog
, "response",
417 G_CALLBACK (filechooser_response_cb
), this);
419 ephy_gui_window_update_user_time (GTK_WIDGET (dialog
), user_time
);
420 gtk_widget_show (GTK_WIDGET (dialog
));
425 /* FIXME: how to inform user of failed save ? */
427 nsCOMPtr
<nsILocalFile
> destFile
;
428 BuildDownloadPath (filename
, getter_AddRefs (destFile
));
430 NS_ENSURE_TRUE (destFile
, NS_ERROR_FAILURE
);
432 return InitiateDownload (destFile
);
435 nsresult
EphyHeaderSniffer::InitiateDownload (nsILocalFile
*aDestFile
)
437 LOG ("Initiating download");
439 return InitiateMozillaDownload (mDocument
, mURL
, aDestFile
,
440 mContentType
.get(), mOriginalURI
, mEmbedPersist
,
441 mPostData
, nsnull
, -1);