summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-14 19:35:10 +0000
committerjcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-14 19:35:10 +0000
commite7f009da9894df2b8e48aa21578aa4e5ecd7a765 (patch)
tree0ca8f38fa2a3531d6f6ef373faac0b1f84eb7369
parent286d5d1b43741c2a4b18d4dde38430e5d06097fa (diff)
downloadchromium_src-e7f009da9894df2b8e48aa21578aa4e5ecd7a765.zip
chromium_src-e7f009da9894df2b8e48aa21578aa4e5ecd7a765.tar.gz
chromium_src-e7f009da9894df2b8e48aa21578aa4e5ecd7a765.tar.bz2
Hooking MHTML generation to the browser.
This CL adds a class that can be used to generate MHTML for the current page of a tab. It is not yet surfaced in the UI. BUG=None TEST=Run the browser tests. Review URL: http://codereview.chromium.org/7044095 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@89047 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_process.h3
-rw-r--r--chrome/browser/browser_process_impl.cc8
-rw-r--r--chrome/browser/browser_process_impl.h4
-rw-r--r--chrome/browser/download/mhtml_generation_browsertest.cc66
-rw-r--r--chrome/browser/download/mhtml_generation_manager.cc136
-rw-r--r--chrome/browser/download/mhtml_generation_manager.h81
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.cc13
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.h1
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/render_messages.h11
-rw-r--r--chrome/renderer/chrome_content_renderer_client.cc2
-rw-r--r--chrome/renderer/mhtml_generator.cc65
-rw-r--r--chrome/renderer/mhtml_generator.h32
-rw-r--r--chrome/test/testing_browser_process.cc4
-rw-r--r--chrome/test/testing_browser_process.h2
-rw-r--r--content/browser/renderer_host/database_message_filter.cc21
-rw-r--r--content/common/notification_type.h5
-rw-r--r--ipc/ipc.gypi1
-rw-r--r--ipc/ipc_platform_file.cc43
-rw-r--r--ipc/ipc_platform_file.h8
-rw-r--r--ppapi/proxy/proxy_channel.cc25
-rw-r--r--webkit/database/vfs_backend.cc26
-rw-r--r--webkit/database/vfs_backend.h7
25 files changed, 500 insertions, 69 deletions
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 3351d0b..82e7970 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -30,6 +30,7 @@ class IconManager;
class IntranetRedirectDetector;
class IOThread;
class MetricsService;
+class MHTMLGenerationManager;
class NotificationUIManager;
class PrefService;
class ProfileManager;
@@ -239,6 +240,8 @@ class BrowserProcess {
plugin_data_remover_mime_type_ = mime_type;
}
+ virtual MHTMLGenerationManager* mhtml_generation_manager() = 0;
+
private:
// User-data-dir based profiles.
std::vector<std::wstring> user_data_dir_profiles_;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 771f67e..41c846c 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -26,6 +26,7 @@
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_protocol_handler.h"
#include "chrome/browser/download/download_file_manager.h"
+#include "chrome/browser/download/mhtml_generation_manager.h"
#include "chrome/browser/download/save_file_manager.h"
#include "chrome/browser/extensions/extension_event_router_forwarder.h"
#include "chrome/browser/extensions/extension_tab_id_map.h"
@@ -691,6 +692,13 @@ prerender::PrerenderTracker* BrowserProcessImpl::prerender_tracker() {
return prerender_tracker_.get();
}
+MHTMLGenerationManager* BrowserProcessImpl::mhtml_generation_manager() {
+ if (!mhtml_generation_manager_.get())
+ mhtml_generation_manager_ = new MHTMLGenerationManager();
+
+ return mhtml_generation_manager_.get();
+}
+
void BrowserProcessImpl::ClearLocalState(const FilePath& profile_path) {
webkit_database::DatabaseTracker::ClearLocalState(profile_path);
BrowsingDataRemover::ClearGearsData(profile_path);
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 0d32964..adb5a1f 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -116,6 +116,8 @@ class BrowserProcessImpl : public BrowserProcess,
virtual void SetIPCLoggingEnabled(bool enable);
#endif
+ virtual MHTMLGenerationManager* mhtml_generation_manager();
+
private:
void ClearLocalState(const FilePath& profile_path);
bool ShouldClearLocalState(FilePath* profile_path);
@@ -292,6 +294,8 @@ class BrowserProcessImpl : public BrowserProcess,
NotificationRegistrar notification_registrar_;
scoped_refptr<PluginDataRemover> plugin_data_remover_;
+ scoped_refptr<MHTMLGenerationManager> mhtml_generation_manager_;
+
// Monitors the state of the 'DisablePluginFinder' policy.
BooleanPrefMember plugin_finder_disabled_pref_;
diff --git a/chrome/browser/download/mhtml_generation_browsertest.cc b/chrome/browser/download/mhtml_generation_browsertest.cc
new file mode 100644
index 0000000..6077b02
--- /dev/null
+++ b/chrome/browser/download/mhtml_generation_browsertest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_path.h"
+#include "base/scoped_temp_dir.h"
+#include "chrome/browser/download/mhtml_generation_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/testing_browser_process.h"
+#include "chrome/test/ui_test_utils.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "net/test/test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MHTMLGenerationTest : public InProcessBrowserTest {
+ public:
+ MHTMLGenerationTest() {}
+
+ protected:
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ InProcessBrowserTest::SetUp();
+ }
+
+ ScopedTempDir temp_dir_;
+};
+
+// Tests that generating a MHTML does create contents.
+// Note that the actual content of the file is not tested, the purpose of this
+// test is to ensure we were successfull in creating the MHTML data from the
+// renderer.
+IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) {
+ ASSERT_TRUE(test_server()->Start());
+
+ FilePath path(temp_dir_.path());
+ path = path.Append(FILE_PATH_LITERAL("test.mht"));
+
+ ui_test_utils::NavigateToURL(browser(),
+ test_server()->GetURL("files/google/google.html"));
+
+ TabContents* tab = browser()->GetSelectedTabContentsWrapper()->tab_contents();
+ MHTMLGenerationManager* mhtml_generation_manager =
+ g_browser_process->mhtml_generation_manager();
+
+ Source<RenderViewHost> source(tab->render_view_host());
+ ui_test_utils::WindowedNotificationObserverWithDetails<
+ MHTMLGenerationManager::NotificationDetails> signal(
+ NotificationType::MHTML_GENERATED, source);
+ mhtml_generation_manager->GenerateMHTML(tab, path);
+ signal.Wait();
+
+ MHTMLGenerationManager::NotificationDetails details;
+ ASSERT_TRUE(signal.GetDetailsFor(source.map_key(), &details));
+ ASSERT_TRUE(details.success);
+
+ // Make sure the generated file has some contents.
+ int64 file_size;
+ ASSERT_TRUE(file_util::GetFileSize(path, &file_size));
+ EXPECT_GT(file_size, 100);
+}
+
+} // namespace
diff --git a/chrome/browser/download/mhtml_generation_manager.cc b/chrome/browser/download/mhtml_generation_manager.cc
new file mode 100644
index 0000000..ea98155
--- /dev/null
+++ b/chrome/browser/download/mhtml_generation_manager.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/mhtml_generation_manager.h"
+
+#include "base/platform_file.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/common/render_messages.h"
+#include "content/browser/renderer_host/render_process_host.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/notification_service.h"
+#include "content/common/page_transition_types.h"
+
+MHTMLGenerationManager::Job::Job()
+ : browser_file(base::kInvalidPlatformFileValue),
+ renderer_file(IPC::InvalidPlatformFileForTransit()),
+ process_id(-1),
+ routing_id(-1) {
+}
+
+MHTMLGenerationManager::MHTMLGenerationManager() {
+}
+
+MHTMLGenerationManager::~MHTMLGenerationManager() {
+}
+
+void MHTMLGenerationManager::GenerateMHTML(TabContents* tab_contents,
+ const FilePath& file) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ static int id_counter = 0;
+
+ int job_id = id_counter++;
+ Job job;
+ job.file_path = file;
+ job.process_id = tab_contents->GetRenderProcessHost()->id();
+ job.routing_id = tab_contents->render_view_host()->routing_id();
+ id_to_job_[job_id] = job;
+
+ base::ProcessHandle renderer_process =
+ tab_contents->GetRenderProcessHost()->GetHandle();
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &MHTMLGenerationManager::CreateFile,
+ job_id, file, renderer_process));
+}
+
+void MHTMLGenerationManager::MHTMLGenerated(int job_id, bool success) {
+ JobFinished(job_id, success);
+}
+
+void MHTMLGenerationManager::CreateFile(int job_id, const FilePath& file_path,
+ base::ProcessHandle renderer_process) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ base::PlatformFile browser_file = base::CreatePlatformFile(file_path,
+ base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE,
+ NULL, NULL);
+ if (browser_file == base::kInvalidPlatformFileValue) {
+ LOG(ERROR) << "Failed to create file to save MHTML at: " <<
+ file_path.value();
+ }
+
+ IPC::PlatformFileForTransit renderer_file =
+ IPC::GetFileHandleForProcess(browser_file, renderer_process, false);
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &MHTMLGenerationManager::FileCreated,
+ job_id, browser_file, renderer_file));
+}
+
+void MHTMLGenerationManager::FileCreated(int job_id,
+ base::PlatformFile browser_file,
+ IPC::PlatformFileForTransit renderer_file) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (browser_file == base::kInvalidPlatformFileValue) {
+ LOG(ERROR) << "Failed to create file";
+ JobFinished(job_id, false);
+ return;
+ }
+
+ IDToJobMap::iterator iter = id_to_job_.find(job_id);
+ if (iter == id_to_job_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ Job& job = iter->second;
+ job.browser_file = browser_file;
+ job.renderer_file = renderer_file;
+
+ TabContents* tab_contents =
+ tab_util::GetTabContentsByID(job.process_id, job.routing_id);
+ if (!tab_contents) {
+ // The tab went away.
+ JobFinished(job_id, false);
+ return;
+ }
+
+ RenderViewHost* host = tab_contents->render_view_host();
+ host->Send(new ViewMsg_SavePageAsMHTML(host->routing_id(), job_id,
+ renderer_file));
+}
+
+void MHTMLGenerationManager::JobFinished(int job_id, bool success) {
+ IDToJobMap::iterator iter = id_to_job_.find(job_id);
+ if (iter == id_to_job_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ Job& job = iter->second;
+
+ TabContents* tab_contents =
+ tab_util::GetTabContentsByID(job.process_id, job.routing_id);
+ if (tab_contents) {
+ NotificationDetails details;
+ details.file_path = job.file_path;
+ details.success = success;
+
+ NotificationService::current()->Notify(
+ NotificationType::MHTML_GENERATED,
+ Source<RenderViewHost>(tab_contents->render_view_host()),
+ Details<NotificationDetails>(&details));
+ }
+
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &MHTMLGenerationManager::CloseFile,
+ job.browser_file));
+
+ id_to_job_.erase(job_id);
+}
+
+void MHTMLGenerationManager::CloseFile(base::PlatformFile file) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ base::ClosePlatformFile(file);
+}
diff --git a/chrome/browser/download/mhtml_generation_manager.h b/chrome/browser/download/mhtml_generation_manager.h
new file mode 100644
index 0000000..8e8557f
--- /dev/null
+++ b/chrome/browser/download/mhtml_generation_manager.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DOWNLOAD_MHTML_GENERATION_MANAGER_H_
+#define CHROME_BROWSER_DOWNLOAD_MHTML_GENERATION_MANAGER_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "base/platform_file.h"
+#include "base/process.h"
+#include "content/browser/browser_thread.h"
+#include "ipc/ipc_platform_file.h"
+
+class FilePath;
+class TabContents;
+
+class MHTMLGenerationManager
+ : public base::RefCountedThreadSafe<MHTMLGenerationManager,
+ BrowserThread::DeleteOnUIThread> {
+ public:
+ MHTMLGenerationManager();
+ ~MHTMLGenerationManager();
+
+ // Instructs the render view to generate a MHTML representation of the current
+ // page for |tab_contents|.
+ void GenerateMHTML(TabContents* tab_contents, const FilePath& file);
+
+ // Notification from the renderer that the MHTML generation succeeded/failed.
+ void MHTMLGenerated(int job_id, bool success);
+
+ // The details sent along with the MHTML_GENERATED notification.
+ struct NotificationDetails {
+ FilePath file_path;
+ bool success;
+ };
+
+ private:
+ struct Job{
+ Job();
+
+ FilePath file_path;
+
+ // The handles to file the MHTML is saved to, for the browser and renderer
+ // processes.
+ base::PlatformFile browser_file;
+ IPC::PlatformFileForTransit renderer_file;
+
+ // The IDs mapping to a specific tab.
+ int process_id;
+ int routing_id;
+ };
+
+ // Called on the file thread to create |file|.
+ void CreateFile(int job_id,
+ const FilePath& file,
+ base::ProcessHandle renderer_process);
+
+ // Called on the UI thread when the file that should hold the MHTML data has
+ // been created. This returns a handle to that file for the browser process
+ // and one for the renderer process. These handles are
+ // kInvalidPlatformFileValue if the file could not be opened.
+ void FileCreated(int job_id,
+ base::PlatformFile browser_file,
+ IPC::PlatformFileForTransit renderer_file);
+
+ // Called on the file thread to close the file the MHTML was saved to.
+ void CloseFile(base::PlatformFile file);
+
+ // Called on the UI thread when a job has been processed (successfully or
+ // not). Closes the file and removes the job from the job map.
+ void JobFinished(int job_id, bool success);
+
+ typedef std::map<int, Job> IDToJobMap;
+ IDToJobMap id_to_job_;
+
+ DISALLOW_COPY_AND_ASSIGN(MHTMLGenerationManager);
+};
+
+#endif // CHROME_BROWSER_DOWNLOAD_MHTML_GENERATION_MANAGER_H_
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index d7393aa..15852e2 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
+#include "chrome/browser/download/mhtml_generation_manager.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_message_service.h"
@@ -98,6 +99,7 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(ViewHostMsg_CanTriggerClipboardWrite,
OnCanTriggerClipboardWrite)
IPC_MESSAGE_HANDLER(ViewHostMsg_ClearPredictorCache, OnClearPredictorCache)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SavedPageAsMHTML, OnSavedPageAsMHTML)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -137,10 +139,10 @@ void ChromeRenderMessageFilter::OverrideThreadForMessage(
case ExtensionHostMsg_AddListener::ID:
case ExtensionHostMsg_RemoveListener::ID:
case ExtensionHostMsg_CloseChannel::ID:
- *thread = BrowserThread::UI;
- break;
case ViewHostMsg_UpdatedCacheStats::ID:
+ case ViewHostMsg_SavedPageAsMHTML::ID:
*thread = BrowserThread::UI;
+ break;
default:
break;
}
@@ -500,3 +502,10 @@ void ChromeRenderMessageFilter::OnSetCookie(const IPC::Message& message,
AutomationResourceMessageFilter::SetCookiesForUrl(
render_process_id_, message.routing_id(), url, cookie);
}
+
+
+void ChromeRenderMessageFilter::OnSavedPageAsMHTML(int job_id, bool success) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ g_browser_process->mhtml_generation_manager()->
+ MHTMLGenerated(job_id, success);
+}
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h
index 867b824..55590d2 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.h
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.h
@@ -124,6 +124,7 @@ class ChromeRenderMessageFilter : public BrowserMessageFilter {
const GURL& url,
const GURL& first_party_for_cookies,
const std::string& cookie);
+ void OnSavedPageAsMHTML(int job_id, bool success);
int render_process_id_;
ProfileId profile_id_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 93f036e..c9ad4f0 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -857,6 +857,8 @@
'browser/download/drag_download_file.h',
'browser/download/drag_download_util.cc',
'browser/download/drag_download_util.h',
+ 'browser/download/mhtml_generation_manager.cc',
+ 'browser/download/mhtml_generation_manager.h',
'browser/download/save_file.cc',
'browser/download/save_file.h',
'browser/download/save_file_manager.cc',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 85eefc5..8f17d6b 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -120,6 +120,8 @@
'renderer/external_extension.h',
'renderer/localized_error.cc',
'renderer/localized_error.h',
+ 'renderer/mhtml_generator.cc',
+ 'renderer/mhtml_generator.h',
'renderer/page_click_listener.h',
'renderer/page_click_tracker.cc',
'renderer/page_click_tracker.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index c239a79..bfaf920 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2360,6 +2360,7 @@
'browser/content_settings/content_settings_browsertest.cc',
'browser/crash_recovery_browsertest.cc',
'browser/download/download_browsertest.cc',
+ 'browser/download/mhtml_generation_browsertest.cc',
'browser/download/save_page_browsertest.cc',
'browser/extensions/alert_apitest.cc',
'browser/extensions/all_urls_apitest.cc',
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 6b6fe9f..65f07433 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -26,6 +26,7 @@
#include "chrome/common/translate_errors.h"
#include "content/common/common_param_traits.h"
#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h"
#include "ui/gfx/rect.h"
@@ -269,6 +270,11 @@ IPC_MESSAGE_ROUTED1(ViewMsg_SetAllowDisplayingInsecureContent,
IPC_MESSAGE_ROUTED1(ViewMsg_SetAllowRunningInsecureContent,
bool /* allowed */)
+// Instructs the renderer to save the current page to MHTML.
+IPC_MESSAGE_ROUTED2(ViewMsg_SavePageAsMHTML,
+ int /* job_id */,
+ IPC::PlatformFileForTransit /* file handle */)
+
//-----------------------------------------------------------------------------
// TabContents messages
// These are messages sent from the renderer to the browser process.
@@ -497,6 +503,11 @@ IPC_MESSAGE_ROUTED0(ViewHostMsg_DidBlockDisplayingInsecureContent)
// a secure origin by a security policy. The page may appear incomplete.
IPC_MESSAGE_ROUTED0(ViewHostMsg_DidBlockRunningInsecureContent)
+// Notifies the browser that the page was or was not saved as MHTML.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_SavedPageAsMHTML,
+ int /* job_id*/,
+ bool /* success */)
+
// Suggest results -----------------------------------------------------------
IPC_MESSAGE_ROUTED3(ViewHostMsg_SetSuggestions,
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 78148d3..bd71656 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -44,6 +44,7 @@
#include "chrome/renderer/external_extension.h"
#include "chrome/renderer/loadtimes_extension_bindings.h"
#include "chrome/renderer/localized_error.h"
+#include "chrome/renderer/mhtml_generator.h"
#include "chrome/renderer/net/renderer_net_predictor.h"
#include "chrome/renderer/page_click_tracker.h"
#include "chrome/renderer/page_load_histograms.h"
@@ -197,6 +198,7 @@ void ChromeContentRendererClient::RenderViewCreated(RenderView* render_view) {
new ContentSettingsObserver(render_view);
new DevToolsAgent(render_view);
new ExtensionHelper(render_view, extension_dispatcher_.get());
+ new MHTMLGenerator(render_view);
new PageLoadHistograms(render_view, histogram_snapshots_.get());
new PrintWebViewHelper(render_view);
new SearchBox(render_view);
diff --git a/chrome/renderer/mhtml_generator.cc b/chrome/renderer/mhtml_generator.cc
new file mode 100644
index 0000000..8dfe79a3
--- /dev/null
+++ b/chrome/renderer/mhtml_generator.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/mhtml_generator.h"
+
+#include "base/platform_file.h"
+#include "chrome/common/render_messages.h"
+#include "content/renderer/render_view.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPageSerializer.h"
+
+MHTMLGenerator::MHTMLGenerator(RenderView* render_view)
+ : RenderViewObserver(render_view),
+ file_(base::kInvalidPlatformFileValue) {
+}
+
+MHTMLGenerator::~MHTMLGenerator() {
+}
+
+// RenderViewObserver implementation:
+bool MHTMLGenerator::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(MHTMLGenerator, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_SavePageAsMHTML, OnSavePageAsMHTML)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void MHTMLGenerator::OnSavePageAsMHTML(
+ int job_id, IPC::PlatformFileForTransit file_for_transit) {
+ base::PlatformFile file =
+ IPC::PlatformFileForTransitToPlatformFile(file_for_transit);
+ file_ = file;
+ bool success = GenerateMHTML();
+ NotifyBrowser(job_id, success);
+}
+
+void MHTMLGenerator::NotifyBrowser(int job_id, bool success) {
+ render_view()->Send(new ViewHostMsg_SavedPageAsMHTML(
+ render_view()->routing_id(), job_id, success));
+ file_ = base::kInvalidPlatformFileValue;
+}
+
+// TODO(jcivelli): write the chunks in deferred tasks to give a chance to the
+// message loop to process other events.
+bool MHTMLGenerator::GenerateMHTML() {
+ WebKit::WebCString mhtml =
+ WebKit::WebPageSerializer::serializeToMHTML(render_view()->webview());
+ const size_t chunk_size = 1024;
+ const char* data = mhtml.data();
+ size_t total_bytes_written = 0;
+ while (total_bytes_written < mhtml.length()) {
+ size_t copy_size =
+ std::min(mhtml.length() - total_bytes_written, chunk_size);
+ int bytes_written = base::WritePlatformFile(file_, total_bytes_written,
+ data + total_bytes_written,
+ copy_size);
+ if (bytes_written == -1)
+ return false;
+ total_bytes_written += bytes_written;
+ }
+ return true;
+}
diff --git a/chrome/renderer/mhtml_generator.h b/chrome/renderer/mhtml_generator.h
new file mode 100644
index 0000000..3520657
--- /dev/null
+++ b/chrome/renderer/mhtml_generator.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_MHTML_GENERATOR_H_
+#define CHROME_RENDERER_MHTML_GENERATOR_H_
+
+#include "content/renderer/render_view_observer.h"
+
+#include "ipc/ipc_platform_file.h"
+
+class MHTMLGenerator : public RenderViewObserver {
+ public:
+ explicit MHTMLGenerator(RenderView* render_view);
+ virtual ~MHTMLGenerator();
+
+ private:
+ // RenderViewObserver implementation:
+ virtual bool OnMessageReceived(const IPC::Message& message);
+
+ void OnSavePageAsMHTML(int job_id,
+ IPC::PlatformFileForTransit file_for_transit);
+
+ void NotifyBrowser(int job_id, bool success);
+ bool GenerateMHTML();
+
+ base::PlatformFile file_;
+
+ DISALLOW_COPY_AND_ASSIGN(MHTMLGenerator);
+};
+
+#endif // CHROME_RENDERER_MHTML_GENERATOR_H_
diff --git a/chrome/test/testing_browser_process.cc b/chrome/test/testing_browser_process.cc
index 386ffa0..86332ae 100644
--- a/chrome/test/testing_browser_process.cc
+++ b/chrome/test/testing_browser_process.cc
@@ -230,6 +230,10 @@ prerender::PrerenderTracker* TestingBrowserProcess::prerender_tracker() {
return prerender_tracker_.get();
}
+MHTMLGenerationManager* TestingBrowserProcess::mhtml_generation_manager() {
+ return NULL;
+}
+
void TestingBrowserProcess::SetLocalState(PrefService* local_state) {
if (!local_state && notification_ui_manager_.get())
notification_ui_manager_.reset(); // Used local_state_.
diff --git a/chrome/test/testing_browser_process.h b/chrome/test/testing_browser_process.h
index f2ea1ee..030fea4 100644
--- a/chrome/test/testing_browser_process.h
+++ b/chrome/test/testing_browser_process.h
@@ -21,6 +21,7 @@
class BackgroundModeManager;
class IOThread;
class GoogleURLTracker;
+class MHTMLGenerationManager;
class NotificationUIManager;
class PrefService;
class WatchDogThread;
@@ -113,6 +114,7 @@ class TestingBrowserProcess : public BrowserProcess {
#if defined(IPC_MESSAGE_LOG_ENABLED)
virtual void SetIPCLoggingEnabled(bool enable) {}
#endif
+ virtual MHTMLGenerationManager* mhtml_generation_manager();
// Set the local state for tests. Consumer is responsible for cleaning it up
// afterwards (using ScopedTestingLocalState, for example).
diff --git a/content/browser/renderer_host/database_message_filter.cc b/content/browser/renderer_host/database_message_filter.cc
index 262276a..63afbfa2 100644
--- a/content/browser/renderer_host/database_message_filter.cc
+++ b/content/browser/renderer_host/database_message_filter.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include <string>
+#include "base/platform_file.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
@@ -143,7 +144,8 @@ void DatabaseMessageFilter::OnDatabaseOpenFile(const string16& vfs_file_name,
IPC::Message* reply_msg) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::PlatformFile file_handle = base::kInvalidPlatformFileValue;
- base::PlatformFile target_handle = base::kInvalidPlatformFileValue;
+ IPC::PlatformFileForTransit target_handle =
+ IPC::InvalidPlatformFileForTransit();
string16 origin_identifier;
string16 database_name;
@@ -182,17 +184,10 @@ void DatabaseMessageFilter::OnDatabaseOpenFile(const string16& vfs_file_name,
// process. The original handle is closed, unless we saved it in the
// database tracker.
bool auto_close = !db_tracker_->HasSavedIncognitoFileHandle(vfs_file_name);
- VfsBackend::GetFileHandleForProcess(peer_handle(), file_handle,
- &target_handle, auto_close);
-
- DatabaseHostMsg_OpenFile::WriteReplyParams(
- reply_msg,
-#if defined(OS_WIN)
- target_handle
-#elif defined(OS_POSIX)
- base::FileDescriptor(target_handle, auto_close)
-#endif
- );
+ target_handle =
+ IPC::GetFileHandleForProcess(file_handle, peer_handle(), auto_close);
+
+ DatabaseHostMsg_OpenFile::WriteReplyParams(reply_msg, target_handle);
Send(reply_msg);
}
diff --git a/content/common/notification_type.h b/content/common/notification_type.h
index 2f36869..8e0c076 100644
--- a/content/common/notification_type.h
+++ b/content/common/notification_type.h
@@ -1192,6 +1192,11 @@ class NotificationType {
// The source is the corresponding RenderViewHost. There are no details.
DOWNLOAD_INITIATED,
+ // Sent when a page generation to MHTML has finished.
+ // The source is the corresponding RenderViewHost. The details is a
+ // MHTMLGenerationManager::NotificationDetails.
+ MHTML_GENERATED,
+
// Misc --------------------------------------------------------------------
#if defined(OS_CHROMEOS)
diff --git a/ipc/ipc.gypi b/ipc/ipc.gypi
index 4ccf993..1ef4074 100644
--- a/ipc/ipc.gypi
+++ b/ipc/ipc.gypi
@@ -30,6 +30,7 @@
'ipc_message_utils.cc',
'ipc_message_utils.h',
'ipc_param_traits.h',
+ 'ipc_platform_file.cc',
'ipc_platform_file.h',
'ipc_switches.cc',
'ipc_switches.h',
diff --git a/ipc/ipc_platform_file.cc b/ipc/ipc_platform_file.cc
new file mode 100644
index 0000000..2b15ceb
--- /dev/null
+++ b/ipc/ipc_platform_file.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/ipc_platform_file.h"
+
+namespace IPC {
+
+PlatformFileForTransit GetFileHandleForProcess(base::PlatformFile handle,
+ base::ProcessHandle process,
+ bool close_source_handle) {
+ IPC::PlatformFileForTransit out_handle;
+#if defined(OS_WIN)
+ DWORD options = DUPLICATE_SAME_ACCESS;
+ if (close_source_handle)
+ options |= DUPLICATE_CLOSE_SOURCE;
+ if (!::DuplicateHandle(::GetCurrentProcess(),
+ handle,
+ process,
+ &out_handle,
+ 0,
+ FALSE,
+ options)) {
+ out_handle = IPC::InvalidPlatformFileForTransit();
+ }
+#elif defined(OS_POSIX)
+ // If asked to close the source, we can simply re-use the source fd instead of
+ // dup()ing and close()ing.
+ // When we're not closing the source, we need to duplicate the handle and take
+ // ownership of that. The reason is that this function is often used to
+ // generate IPC messages, and the handle must remain valid until it's sent to
+ // the other process from the I/O thread. Without the dup, calling code might
+ // close the source handle before the message is sent, creating a race
+ // condition.
+ int fd = close_source_handle ? handle : ::dup(handle);
+ out_handle = base::FileDescriptor(fd, true);
+#else
+ #error Not implemented.
+#endif
+ return out_handle;
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_platform_file.h b/ipc/ipc_platform_file.h
index e08b8a5..a99ed9d 100644
--- a/ipc/ipc_platform_file.h
+++ b/ipc/ipc_platform_file.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/platform_file.h"
+#include "base/process.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -39,6 +40,11 @@ inline base::PlatformFile PlatformFileForTransitToPlatformFile(
#endif
}
+// Returns a file handle equivalent to |file| that can be used in |process|.
+PlatformFileForTransit GetFileHandleForProcess(base::PlatformFile file,
+ base::ProcessHandle process,
+ bool close_source_handle);
+
} // namespace IPC
#endif // IPC_IPC_PLATFORM_FILE_H_
diff --git a/ppapi/proxy/proxy_channel.cc b/ppapi/proxy/proxy_channel.cc
index 0bce041..d304dca 100644
--- a/ppapi/proxy/proxy_channel.cc
+++ b/ppapi/proxy/proxy_channel.cc
@@ -4,6 +4,7 @@
#include "ppapi/proxy/proxy_channel.h"
+#include "ipc/ipc_platform_file.h"
#include "ipc/ipc_test_sink.h"
namespace pp {
@@ -49,28 +50,8 @@ int ProxyChannel::GetRendererFD() {
IPC::PlatformFileForTransit ProxyChannel::ShareHandleWithRemote(
base::PlatformFile handle,
bool should_close_source) {
- IPC::PlatformFileForTransit out_handle;
-#if defined(OS_WIN)
- DWORD options = DUPLICATE_SAME_ACCESS;
- if (should_close_source)
- options |= DUPLICATE_CLOSE_SOURCE;
- if (!::DuplicateHandle(::GetCurrentProcess(),
- handle,
- remote_process_handle_,
- &out_handle,
- 0,
- FALSE,
- options))
- out_handle = IPC::InvalidPlatformFileForTransit();
-#elif defined(OS_POSIX)
- // If asked to close the source, we can simply re-use the source fd instead of
- // dup()ing and close()ing.
- int fd = should_close_source ? handle : ::dup(handle);
- out_handle = base::FileDescriptor(fd, true);
-#else
- #error Not implemented.
-#endif
- return out_handle;
+ return IPC::GetFileHandleForProcess(handle, remote_process_handle_,
+ should_close_source);
}
bool ProxyChannel::Send(IPC::Message* msg) {
diff --git a/webkit/database/vfs_backend.cc b/webkit/database/vfs_backend.cc
index e734a7e..b3879ce 100644
--- a/webkit/database/vfs_backend.cc
+++ b/webkit/database/vfs_backend.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,30 +14,6 @@ namespace webkit_database {
static const int kFileTypeMask = 0x00007F00;
// static
-void VfsBackend::GetFileHandleForProcess(base::ProcessHandle process_handle,
- const base::PlatformFile& file_handle,
- base::PlatformFile* target_handle,
- bool close_source_handle) {
- if (file_handle == base::kInvalidPlatformFileValue) {
- *target_handle = base::kInvalidPlatformFileValue;
- return;
- }
-
-#if defined(OS_WIN)
- // Duplicate the file handle.
- if (!DuplicateHandle(GetCurrentProcess(), file_handle,
- process_handle, target_handle, 0, false,
- DUPLICATE_SAME_ACCESS |
- (close_source_handle ? DUPLICATE_CLOSE_SOURCE : 0))) {
- // file_handle is closed whether or not DuplicateHandle succeeds.
- *target_handle = INVALID_HANDLE_VALUE;
- }
-#elif defined(OS_POSIX)
- *target_handle = file_handle;
-#endif
-}
-
-// static
bool VfsBackend::FileTypeIsMainDB(int desired_flags) {
return (desired_flags & kFileTypeMask) == SQLITE_OPEN_MAIN_DB;
}
diff --git a/webkit/database/vfs_backend.h b/webkit/database/vfs_backend.h
index 99effc8..7e5d338 100644
--- a/webkit/database/vfs_backend.h
+++ b/webkit/database/vfs_backend.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,11 +15,6 @@ namespace webkit_database {
class VfsBackend {
public:
- static void GetFileHandleForProcess(base::ProcessHandle process_handle,
- const base::PlatformFile& file_handle,
- base::PlatformFile* target_handle,
- bool close_source_handle);
-
static void OpenFile(const FilePath& file_path,
int desired_flags,
base::PlatformFile* file_handle);