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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdint.h> 5 #include <stdint.h>
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h" 11 #include "base/files/scoped_temp_dir.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/run_loop.h" 13 #include "base/run_loop.h"
14 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
15 #include "content/browser/renderer_host/render_process_host_impl.h"
16 #include "content/common/frame_messages.h"
17 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/web_contents.h" 18 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/mhtml_generation_params.h" 19 #include "content/public/common/mhtml_generation_params.h"
17 #include "content/public/test/browser_test_utils.h" 20 #include "content/public/test/browser_test_utils.h"
18 #include "content/public/test/content_browser_test.h" 21 #include "content/public/test/content_browser_test.h"
19 #include "content/public/test/content_browser_test_utils.h" 22 #include "content/public/test/content_browser_test_utils.h"
20 #include "content/public/test/test_utils.h" 23 #include "content/public/test/test_utils.h"
21 #include "content/shell/browser/shell.h" 24 #include "content/shell/browser/shell.h"
22 #include "net/base/filename_util.h" 25 #include "net/base/filename_util.h"
23 #include "net/dns/mock_host_resolver.h" 26 #include "net/dns/mock_host_resolver.h"
24 #include "net/test/embedded_test_server/embedded_test_server.h" 27 #include "net/test/embedded_test_server/embedded_test_server.h"
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 ASSERT_TRUE(embedded_test_server()->Start()); 98 ASSERT_TRUE(embedded_test_server()->Start());
96 ContentBrowserTest::SetUp(); 99 ContentBrowserTest::SetUp();
97 } 100 }
98 101
99 void GenerateMHTML(const base::FilePath& path, const GURL& url) { 102 void GenerateMHTML(const base::FilePath& path, const GURL& url) {
100 GenerateMHTML(MHTMLGenerationParams(path), url); 103 GenerateMHTML(MHTMLGenerationParams(path), url);
101 } 104 }
102 105
103 void GenerateMHTML(const MHTMLGenerationParams& params, const GURL& url) { 106 void GenerateMHTML(const MHTMLGenerationParams& params, const GURL& url) {
104 NavigateToURL(shell(), url); 107 NavigateToURL(shell(), url);
108 GenerateMHTMLForCurrentPage(params);
109 }
105 110
111 void GenerateMHTMLForCurrentPage(const MHTMLGenerationParams& params) {
106 base::RunLoop run_loop; 112 base::RunLoop run_loop;
107 113
108 shell()->web_contents()->GenerateMHTML( 114 shell()->web_contents()->GenerateMHTML(
109 params, base::Bind(&MHTMLGenerationTest::MHTMLGenerated, this, 115 params, base::Bind(&MHTMLGenerationTest::MHTMLGenerated, this,
110 run_loop.QuitClosure())); 116 run_loop.QuitClosure()));
111 117
112 // Block until the MHTML is generated. 118 // Block until the MHTML is generated.
113 run_loop.Run(); 119 run_loop.Run();
114 120
115 EXPECT_TRUE(has_mhtml_callback_run()); 121 EXPECT_TRUE(has_mhtml_callback_run());
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 // Make sure the actual generated file has some contents. 219 // Make sure the actual generated file has some contents.
214 EXPECT_GT(file_size(), 0); // Verify the size reported by the callback. 220 EXPECT_GT(file_size(), 0); // Verify the size reported by the callback.
215 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size. 221 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
216 222
217 std::string mhtml; 223 std::string mhtml;
218 ASSERT_TRUE(base::ReadFileToString(path, &mhtml)); 224 ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
219 EXPECT_THAT(mhtml, 225 EXPECT_THAT(mhtml,
220 HasSubstr("Content-Transfer-Encoding: quoted-printable")); 226 HasSubstr("Content-Transfer-Encoding: quoted-printable"));
221 } 227 }
222 228
229 class GenerateMHTMLAndExitRendererMessageFilter : public BrowserMessageFilter {
230 public:
231 GenerateMHTMLAndExitRendererMessageFilter(
232 RenderProcessHostImpl* render_process_host)
233 : BrowserMessageFilter(FrameMsgStart),
234 render_process_host_(render_process_host) {}
235
236 protected:
237 ~GenerateMHTMLAndExitRendererMessageFilter() override {}
238
239 private:
240 bool OnMessageReceived(const IPC::Message& message) override {
241 if (message.type() == FrameHostMsg_SerializeAsMHTMLResponse::ID) {
242 // After |return false| below, this IPC message will be handled by the
243 // product code as illustrated below. (1), (2), (3) depict points in time
244 // when product code runs on UI and FILE threads. (X), (Y), (Z) depict
245 // when we want test-injected tasks to run - for the repro, (Z) has to
246 // happen between (1) and (3). (Y?) and (Z?) depict when test tasks can
247 // theoretically happen and ruin the repro.
248 //
249 // IO thread UI thread FILE thread
250 // --------- --------- -----------
251 // | | |
252 // WE ARE HERE | |
253 // | | |
254 // after |return false| | |
255 // +--------------->+ |
256 // | | |
257 // | (X) |
258 // | | |
259 // | | (Y?)
260 // | (Z?) |
261 // | | |
262 // (1) | MHTMLGenerationManager |
263 // | ::OnSerializeAsMHTMLResponse |
264 // | +-------------------->+
265 // | | |
266 // | | (Y)
267 // | | |
268 // (2) | | MHTMLGenerationManager::Job
269 // | | ::CloseFileOnFileThread
270 // | | |
271 // | (Z) |
272 // | test needs to inject |
273 // | fast renderer shutdown |
274 // | HERE - between (1) and (3) |
275 // | | |
276 // | | |
277 // | +<--------------------+
278 // | | |
279 // (3) | MHTMLGenerationManager |
280 // | ::OnFileClosed |
281 // | | |
282 //
283 // We hope that (Z) happens between (1) and (3) by doing the following:
284 // - From here post TaskX to UI thread. (X) is guaranteed to happen
285 // before timepoint (1) (because posting of (1) happens after
286 // |return false| / before we post TaskX below).
287 // - From (X) post TaskY to FILE thread. Because this posting is done
288 // before (1), we can guarantee that (Y) will happen before (2).
289 // - From (Y) post TaskZ to UI thread. Because this posting is done
290 // before (2), we can guarantee that (Z) will happen before (3).
291 // - We cannot really guarantee that (Y) and (Z) happen *after* (1) - i.e.
292 // execution at (Y?) and (Z?) instead is possible. In practice,
293 // bouncing off of UI and FILE thread does mean (Z) happens after (1).
294 BrowserThread::PostTask(
295 BrowserThread::UI, FROM_HERE, base::Bind(
296 &GenerateMHTMLAndExitRendererMessageFilter::TaskX,
297 base::Unretained(this)));
298 }
299
300 return false;
301 };
302
303 void TaskX() {
304 BrowserThread::PostTask(
305 BrowserThread::FILE, FROM_HERE, base::Bind(
306 &GenerateMHTMLAndExitRendererMessageFilter::TaskY,
307 base::Unretained(this)));
308 }
309
310 void TaskY() {
311 BrowserThread::PostTask(
312 BrowserThread::UI, FROM_HERE, base::Bind(
313 &GenerateMHTMLAndExitRendererMessageFilter::TaskZ,
314 base::Unretained(this)));
315 }
316
317 void TaskZ() {
318 render_process_host_->FastShutdownIfPossible();
319 }
320
321 RenderProcessHostImpl* render_process_host_;
322
323 DISALLOW_COPY_AND_ASSIGN(GenerateMHTMLAndExitRendererMessageFilter);
324 };
325
326 // Regression test for the crash/race from https://crbug.com/612098.
327 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTMLAndExitRenderer) {
328 NavigateToURL(shell(), embedded_test_server()->GetURL("/simple_page.html"));
329
330 RenderProcessHostImpl* render_process_host =
331 static_cast<RenderProcessHostImpl*>(
332 shell()->web_contents()->GetRenderProcessHost());
333 scoped_refptr<BrowserMessageFilter> filter =
334 new GenerateMHTMLAndExitRendererMessageFilter(render_process_host);
335 render_process_host->AddFilter(filter.get());
336
337 base::FilePath path(temp_dir_.path());
338 path = path.Append(FILE_PATH_LITERAL("test.mht"));
339 GenerateMHTMLForCurrentPage(MHTMLGenerationParams(path));
340
341 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
342 }
343
223 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, InvalidPath) { 344 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, InvalidPath) {
224 base::FilePath path(FILE_PATH_LITERAL("/invalid/file/path")); 345 base::FilePath path(FILE_PATH_LITERAL("/invalid/file/path"));
225 346
226 GenerateMHTML(path, embedded_test_server()->GetURL( 347 GenerateMHTML(path, embedded_test_server()->GetURL(
227 "/download/local-about-blank-subframes.html")); 348 "/download/local-about-blank-subframes.html"));
228 ASSERT_FALSE(HasFailure()); // No failures with the invocation itself? 349 ASSERT_FALSE(HasFailure()); // No failures with the invocation itself?
229 350
230 EXPECT_EQ(file_size(), -1); // Expecting that the callback reported failure. 351 EXPECT_EQ(file_size(), -1); // Expecting that the callback reported failure.
231 } 352 }
232 353
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 591
471 // Make sure that URLs of both frames are present 592 // Make sure that URLs of both frames are present
472 // (note that these are single-line regexes). 593 // (note that these are single-line regexes).
473 EXPECT_THAT( 594 EXPECT_THAT(
474 mhtml, 595 mhtml,
475 ContainsRegex("Content-Location:.*/frame_tree/page_with_one_frame.html")); 596 ContainsRegex("Content-Location:.*/frame_tree/page_with_one_frame.html"));
476 EXPECT_THAT(mhtml, ContainsRegex("Content-Location:.*/title1.html")); 597 EXPECT_THAT(mhtml, ContainsRegex("Content-Location:.*/title1.html"));
477 } 598 }
478 599
479 } // namespace content 600 } // namespace content
OLDNEW
« 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