Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1043)

Unified Diff: content/browser/download/mhtml_generation_browsertest.cc

Issue 2163073002: Avoid crashing if MHTMLGenerationManager::JobFinished is called twice. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Posting the injection ->UI->FILE->UI. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/download/docs/save-page-as.md ('k') | content/browser/download/mhtml_generation_manager.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/download/mhtml_generation_browsertest.cc
diff --git a/content/browser/download/mhtml_generation_browsertest.cc b/content/browser/download/mhtml_generation_browsertest.cc
index 0605115bccf62a4075a60d3dd2ceeeabe5cf8a0d..8a8052efd3d4cba81795b59e0ef338543d48779f 100644
--- a/content/browser/download/mhtml_generation_browsertest.cc
+++ b/content/browser/download/mhtml_generation_browsertest.cc
@@ -12,6 +12,9 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/common/frame_messages.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/mhtml_generation_params.h"
#include "content/public/test/browser_test_utils.h"
@@ -102,7 +105,10 @@ class MHTMLGenerationTest : public ContentBrowserTest {
void GenerateMHTML(const MHTMLGenerationParams& params, const GURL& url) {
NavigateToURL(shell(), url);
+ GenerateMHTMLForCurrentPage(params);
+ }
+ void GenerateMHTMLForCurrentPage(const MHTMLGenerationParams& params) {
base::RunLoop run_loop;
shell()->web_contents()->GenerateMHTML(
@@ -220,6 +226,121 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) {
HasSubstr("Content-Transfer-Encoding: quoted-printable"));
}
+class GenerateMHTMLAndExitRendererMessageFilter : public BrowserMessageFilter {
+ public:
+ GenerateMHTMLAndExitRendererMessageFilter(
+ RenderProcessHostImpl* render_process_host)
+ : BrowserMessageFilter(FrameMsgStart),
+ render_process_host_(render_process_host) {}
+
+ protected:
+ ~GenerateMHTMLAndExitRendererMessageFilter() override {}
+
+ private:
+ bool OnMessageReceived(const IPC::Message& message) override {
+ if (message.type() == FrameHostMsg_SerializeAsMHTMLResponse::ID) {
+ // After |return false| below, this IPC message will be handled by the
+ // product code as illustrated below. (1), (2), (3) depict points in time
+ // when product code runs on UI and FILE threads. (X), (Y), (Z) depict
+ // when we want test-injected tasks to run - for the repro, (Z) has to
+ // happen between (1) and (3). (Y?) and (Z?) depict when test tasks can
+ // theoretically happen and ruin the repro.
+ //
+ // IO thread UI thread FILE thread
+ // --------- --------- -----------
+ // | | |
+ // WE ARE HERE | |
+ // | | |
+ // after |return false| | |
+ // +--------------->+ |
+ // | | |
+ // | (X) |
+ // | | |
+ // | | (Y?)
+ // | (Z?) |
+ // | | |
+ // (1) | MHTMLGenerationManager |
+ // | ::OnSerializeAsMHTMLResponse |
+ // | +-------------------->+
+ // | | |
+ // | | (Y)
+ // | | |
+ // (2) | | MHTMLGenerationManager::Job
+ // | | ::CloseFileOnFileThread
+ // | | |
+ // | (Z) |
+ // | test needs to inject |
+ // | fast renderer shutdown |
+ // | HERE - between (1) and (3) |
+ // | | |
+ // | | |
+ // | +<--------------------+
+ // | | |
+ // (3) | MHTMLGenerationManager |
+ // | ::OnFileClosed |
+ // | | |
+ //
+ // We hope that (Z) happens between (1) and (3) by doing the following:
+ // - From here post TaskX to UI thread. (X) is guaranteed to happen
+ // before timepoint (1) (because posting of (1) happens after
+ // |return false| / before we post TaskX below).
+ // - From (X) post TaskY to FILE thread. Because this posting is done
+ // before (1), we can guarantee that (Y) will happen before (2).
+ // - From (Y) post TaskZ to UI thread. Because this posting is done
+ // before (2), we can guarantee that (Z) will happen before (3).
+ // - We cannot really guarantee that (Y) and (Z) happen *after* (1) - i.e.
+ // execution at (Y?) and (Z?) instead is possible. In practice,
+ // bouncing off of UI and FILE thread does mean (Z) happens after (1).
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, base::Bind(
+ &GenerateMHTMLAndExitRendererMessageFilter::TaskX,
+ base::Unretained(this)));
+ }
+
+ return false;
+ };
+
+ void TaskX() {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE, base::Bind(
+ &GenerateMHTMLAndExitRendererMessageFilter::TaskY,
+ base::Unretained(this)));
+ }
+
+ void TaskY() {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, base::Bind(
+ &GenerateMHTMLAndExitRendererMessageFilter::TaskZ,
+ base::Unretained(this)));
+ }
+
+ void TaskZ() {
+ render_process_host_->FastShutdownIfPossible();
+ }
+
+ RenderProcessHostImpl* render_process_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(GenerateMHTMLAndExitRendererMessageFilter);
+};
+
+// Regression test for the crash/race from https://crbug.com/612098.
+IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTMLAndExitRenderer) {
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/simple_page.html"));
+
+ RenderProcessHostImpl* render_process_host =
+ static_cast<RenderProcessHostImpl*>(
+ shell()->web_contents()->GetRenderProcessHost());
+ scoped_refptr<BrowserMessageFilter> filter =
+ new GenerateMHTMLAndExitRendererMessageFilter(render_process_host);
+ render_process_host->AddFilter(filter.get());
+
+ base::FilePath path(temp_dir_.path());
+ path = path.Append(FILE_PATH_LITERAL("test.mht"));
+ GenerateMHTMLForCurrentPage(MHTMLGenerationParams(path));
+
+ EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
+}
+
IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, InvalidPath) {
base::FilePath path(FILE_PATH_LITERAL("/invalid/file/path"));
« no previous file with comments | « content/browser/download/docs/save-page-as.md ('k') | content/browser/download/mhtml_generation_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698