Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 #include <memory> | 6 #include <memory> |
| 7 | 7 |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/test/histogram_tester.h" | 16 #include "base/test/histogram_tester.h" |
| 17 #include "base/threading/thread_restrictions.h" | 17 #include "base/threading/thread_restrictions.h" |
| 18 #include "content/browser/frame_host/frame_tree_node.h" | |
| 18 #include "content/browser/renderer_host/render_process_host_impl.h" | 19 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 20 #include "content/browser/web_contents/web_contents_impl.h" | |
| 19 #include "content/common/frame_messages.h" | 21 #include "content/common/frame_messages.h" |
| 20 #include "content/public/browser/render_process_host.h" | 22 #include "content/public/browser/render_process_host.h" |
| 21 #include "content/public/browser/web_contents.h" | |
| 22 #include "content/public/common/mhtml_generation_params.h" | 23 #include "content/public/common/mhtml_generation_params.h" |
| 23 #include "content/public/test/browser_test_utils.h" | 24 #include "content/public/test/browser_test_utils.h" |
| 24 #include "content/public/test/content_browser_test.h" | 25 #include "content/public/test/content_browser_test.h" |
| 25 #include "content/public/test/content_browser_test_utils.h" | 26 #include "content/public/test/content_browser_test_utils.h" |
| 26 #include "content/public/test/test_utils.h" | 27 #include "content/public/test/test_utils.h" |
| 27 #include "content/shell/browser/shell.h" | 28 #include "content/shell/browser/shell.h" |
| 28 #include "net/base/filename_util.h" | 29 #include "net/base/filename_util.h" |
| 29 #include "net/dns/mock_host_resolver.h" | 30 #include "net/dns/mock_host_resolver.h" |
| 30 #include "net/test/embedded_test_server/embedded_test_server.h" | 31 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 31 #include "testing/gmock/include/gmock/gmock.h" | 32 #include "testing/gmock/include/gmock/gmock.h" |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 215 | 216 |
| 216 // Tests that generating a MHTML does create contents. | 217 // Tests that generating a MHTML does create contents. |
| 217 // Note that the actual content of the file is not tested, the purpose of this | 218 // Note that the actual content of the file is not tested, the purpose of this |
| 218 // test is to ensure we were successful in creating the MHTML data from the | 219 // test is to ensure we were successful in creating the MHTML data from the |
| 219 // renderer. | 220 // renderer. |
| 220 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) { | 221 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) { |
| 221 base::FilePath path(temp_dir_.GetPath()); | 222 base::FilePath path(temp_dir_.GetPath()); |
| 222 path = path.Append(FILE_PATH_LITERAL("test.mht")); | 223 path = path.Append(FILE_PATH_LITERAL("test.mht")); |
| 223 | 224 |
| 224 GenerateMHTML(path, embedded_test_server()->GetURL("/simple_page.html")); | 225 GenerateMHTML(path, embedded_test_server()->GetURL("/simple_page.html")); |
| 226 | |
| 227 // Checks that no other test failure was detected so far. | |
| 225 ASSERT_FALSE(HasFailure()); | 228 ASSERT_FALSE(HasFailure()); |
| 226 | 229 |
| 227 // Make sure the actual generated file has some contents. | 230 // Make sure the actual generated file has some contents. |
| 228 EXPECT_GT(file_size(), 0); // Verify the size reported by the callback. | 231 EXPECT_GT(file_size(), 0); // Verify the size reported by the callback. |
| 229 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size. | 232 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size. |
| 230 | 233 |
| 231 { | 234 { |
| 232 base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification; | 235 base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification; |
| 233 std::string mhtml; | 236 std::string mhtml; |
| 234 ASSERT_TRUE(base::ReadFileToString(path, &mhtml)); | 237 ASSERT_TRUE(base::ReadFileToString(path, &mhtml)); |
| 235 EXPECT_THAT(mhtml, | 238 EXPECT_THAT(mhtml, |
| 236 HasSubstr("Content-Transfer-Encoding: quoted-printable")); | 239 HasSubstr("Content-Transfer-Encoding: quoted-printable")); |
| 237 } | 240 } |
| 238 | 241 |
| 239 // Checks that the final status reported to UMA is correct. | 242 // Checks that the final status reported to UMA is correct. |
| 240 histogram_tester()->ExpectUniqueSample( | 243 histogram_tester()->ExpectUniqueSample( |
| 241 "PageSerialization.MhtmlGeneration.FinalSaveStatus", | 244 "PageSerialization.MhtmlGeneration.FinalSaveStatus", |
| 242 static_cast<int>(MhtmlSaveStatus::SUCCESS), 1); | 245 static_cast<int>(MhtmlSaveStatus::SUCCESS), 1); |
| 243 } | 246 } |
| 244 | 247 |
| 248 // Removes all children of the root tree node once the first MHTML serialization | |
| 249 // response (regarding the main frame) is received from the renderer but before | |
| 250 // that message is actually handled by the browser UI thread. | |
| 251 class ChildFrameRemoverFilter : public BrowserMessageFilter { | |
| 252 public: | |
| 253 ChildFrameRemoverFilter(WebContentsImpl* web_contents) | |
| 254 : BrowserMessageFilter(FrameMsgStart), web_contents_(web_contents) {} | |
|
Łukasz Anforowicz
2016/11/28 22:15:37
nit: DCHECK(web_contents_) ?
carlosk
2016/11/29 02:11:20
Done.
| |
| 255 | |
| 256 protected: | |
| 257 ~ChildFrameRemoverFilter() override {} | |
| 258 | |
| 259 private: | |
| 260 bool OnMessageReceived(const IPC::Message& message) override { | |
|
Łukasz Anforowicz
2016/11/28 22:15:37
nit: DCHECK_CURRENTLY_ON(BrowserThread::IO) ?
carlosk
2016/11/29 02:11:20
Done.
| |
| 261 if (message.type() == FrameHostMsg_SerializeAsMHTMLResponse::ID) { | |
| 262 if (!already_received_response_) { | |
| 263 already_received_response_ = true; | |
| 264 BrowserThread::PostTask( | |
| 265 BrowserThread::UI, FROM_HERE, | |
| 266 base::Bind(&ChildFrameRemoverFilter::RemoveAllChildFrames, | |
| 267 base::Unretained(this))); | |
| 268 } else { | |
| 269 ADD_FAILURE() | |
| 270 << "Should not receive another MHTML serialization response"; | |
| 271 } | |
| 272 } | |
| 273 return false; | |
| 274 } | |
| 275 | |
| 276 void RemoveAllChildFrames() { | |
|
Łukasz Anforowicz
2016/11/28 22:15:37
nit: DCHECK_CURRENTLY_ON(BrowserThread::UI) ?
(th
carlosk
2016/11/29 02:11:20
Agreed and done. Also added these checks to the ot
| |
| 277 int tree_node_count = 1; | |
| 278 for (auto tree_node : web_contents_->GetFrameTree()->Nodes()) | |
| 279 tree_node_count += tree_node->child_count(); | |
| 280 // Note: at least 2 children nodes are needed to test all code paths. | |
| 281 ASSERT_GE(tree_node_count, 3); | |
| 282 FrameTreeNode* root = web_contents_->GetFrameTree()->root(); | |
| 283 while (root->child_count()) | |
| 284 root->RemoveChild(root->child_at(root->child_count() - 1)); | |
|
Łukasz Anforowicz
2016/11/28 22:15:37
Is it okay to instead call root->RemoveChild(0)?
carlosk
2016/11/29 02:11:20
This was just my ODD of always removing vector ele
Łukasz Anforowicz
2016/11/29 19:18:13
Thanks.
I see now that the simpler code might be
| |
| 285 ASSERT_EQ(0u, root->child_count()); | |
| 286 } | |
| 287 | |
| 288 WebContentsImpl* web_contents_; | |
| 289 bool already_received_response_ = false; | |
| 290 | |
| 291 DISALLOW_COPY_AND_ASSIGN(ChildFrameRemoverFilter); | |
| 292 }; | |
| 293 | |
| 294 // Tests that if child frames are removed while saving a MHTML page the | |
| 295 // operation fails by default. | |
| 296 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, FailDueToMissingIframe) { | |
| 297 NavigateToURL(shell(), | |
|
Łukasz Anforowicz
2016/11/28 22:15:37
nit: ASSERT_TRUE(NavigateToURL(...)
(this will al
carlosk
2016/11/29 02:11:20
Done for all calls of this function.
| |
| 298 embedded_test_server()->GetURL("/site_per_process_main.html")); | |
| 299 | |
| 300 scoped_refptr<BrowserMessageFilter> filter = new ChildFrameRemoverFilter( | |
| 301 static_cast<WebContentsImpl*>(shell()->web_contents())); | |
| 302 shell()->web_contents()->GetRenderProcessHost()->AddFilter(filter.get()); | |
| 303 | |
| 304 base::FilePath path(temp_dir_.GetPath()); | |
| 305 path = path.Append(FILE_PATH_LITERAL("test.mht")); | |
| 306 | |
| 307 MHTMLGenerationParams params(path); | |
| 308 | |
| 309 // Verifies the default is to not ignore missing iframes. | |
| 310 ASSERT_FALSE(params.ignore_missing_frames); | |
| 311 | |
| 312 GenerateMHTMLForCurrentPage(params); | |
| 313 | |
| 314 // Checks that no other test failure was detected so far. | |
| 315 ASSERT_FALSE(HasFailure()); | |
| 316 | |
| 317 // Verify the size reported by the callback is negative (an error happened). | |
| 318 EXPECT_LT(file_size(), 0); | |
| 319 | |
| 320 // Checks that the final status reported to UMA is correct. | |
| 321 histogram_tester()->ExpectUniqueSample( | |
| 322 "PageSerialization.MhtmlGeneration.FinalSaveStatus", | |
| 323 static_cast<int>(MhtmlSaveStatus::FRAME_NO_LONGER_EXISTS), 1); | |
| 324 } | |
| 325 | |
| 326 // Tests that a MHTML save operation does not fail when frames are removed if | |
| 327 // the caller configures it to ignore missing frames. | |
| 328 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, SucceedIgnoringMissingIframe) { | |
| 329 NavigateToURL(shell(), | |
|
Łukasz Anforowicz
2016/11/28 22:15:37
nit: ASSERT_TRUE(NavigateToURL(...)
carlosk
2016/11/29 02:11:20
Done.
| |
| 330 embedded_test_server()->GetURL("/site_per_process_main.html")); | |
| 331 | |
| 332 scoped_refptr<BrowserMessageFilter> filter = new ChildFrameRemoverFilter( | |
| 333 static_cast<WebContentsImpl*>(shell()->web_contents())); | |
| 334 shell()->web_contents()->GetRenderProcessHost()->AddFilter(filter.get()); | |
| 335 | |
| 336 base::FilePath path(temp_dir_.GetPath()); | |
| 337 path = path.Append(FILE_PATH_LITERAL("test.mht")); | |
| 338 | |
| 339 MHTMLGenerationParams params(path); | |
| 340 | |
| 341 // Enables the ignoring of missing iframes. | |
| 342 params.ignore_missing_frames = true; | |
| 343 | |
| 344 GenerateMHTMLForCurrentPage(params); | |
| 345 | |
| 346 // Checks that no other test failure was detected so far. | |
| 347 ASSERT_FALSE(HasFailure()); | |
| 348 | |
| 349 // Verify the size reported by the callback is positive. | |
| 350 EXPECT_GT(file_size(), 0); | |
| 351 | |
| 352 // Checks that the final status reported to UMA is correct. | |
| 353 histogram_tester()->ExpectUniqueSample( | |
| 354 "PageSerialization.MhtmlGeneration.FinalSaveStatus", | |
| 355 static_cast<int>(MhtmlSaveStatus::SUCCESS), 1); | |
| 356 } | |
| 357 | |
| 245 class GenerateMHTMLAndExitRendererMessageFilter : public BrowserMessageFilter { | 358 class GenerateMHTMLAndExitRendererMessageFilter : public BrowserMessageFilter { |
| 246 public: | 359 public: |
| 247 GenerateMHTMLAndExitRendererMessageFilter( | 360 GenerateMHTMLAndExitRendererMessageFilter( |
| 248 RenderProcessHostImpl* render_process_host) | 361 RenderProcessHostImpl* render_process_host) |
| 249 : BrowserMessageFilter(FrameMsgStart), | 362 : BrowserMessageFilter(FrameMsgStart), |
| 250 render_process_host_(render_process_host) {} | 363 render_process_host_(render_process_host) {} |
| 251 | 364 |
| 252 protected: | 365 protected: |
| 253 ~GenerateMHTMLAndExitRendererMessageFilter() override {} | 366 ~GenerateMHTMLAndExitRendererMessageFilter() override {} |
| 254 | 367 |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 644 | 757 |
| 645 // Make sure that URLs of both frames are present | 758 // Make sure that URLs of both frames are present |
| 646 // (note that these are single-line regexes). | 759 // (note that these are single-line regexes). |
| 647 EXPECT_THAT( | 760 EXPECT_THAT( |
| 648 mhtml, | 761 mhtml, |
| 649 ContainsRegex("Content-Location:.*/frame_tree/page_with_one_frame.html")); | 762 ContainsRegex("Content-Location:.*/frame_tree/page_with_one_frame.html")); |
| 650 EXPECT_THAT(mhtml, ContainsRegex("Content-Location:.*/title1.html")); | 763 EXPECT_THAT(mhtml, ContainsRegex("Content-Location:.*/title1.html")); |
| 651 } | 764 } |
| 652 | 765 |
| 653 } // namespace content | 766 } // namespace content |
| OLD | NEW |