diff options
author | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-14 19:35:10 +0000 |
---|---|---|
committer | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-14 19:35:10 +0000 |
commit | e7f009da9894df2b8e48aa21578aa4e5ecd7a765 (patch) | |
tree | 0ca8f38fa2a3531d6f6ef373faac0b1f84eb7369 | |
parent | 286d5d1b43741c2a4b18d4dde38430e5d06097fa (diff) | |
download | chromium_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
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); |