| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/renderer_context_menu/render_view_context_menu.h" | 5 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
| 18 #include "base/run_loop.h" |
| 18 #include "base/strings/string16.h" | 19 #include "base/strings/string16.h" |
| 19 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 21 #include "build/build_config.h" | 22 #include "build/build_config.h" |
| 22 #include "chrome/app/chrome_command_ids.h" | 23 #include "chrome/app/chrome_command_ids.h" |
| 23 #include "chrome/browser/browser_process.h" | 24 #include "chrome/browser/browser_process.h" |
| 24 #include "chrome/browser/chrome_notification_types.h" | 25 #include "chrome/browser/chrome_notification_types.h" |
| 25 #include "chrome/browser/profiles/profile_attributes_entry.h" | 26 #include "chrome/browser/profiles/profile_attributes_entry.h" |
| 26 #include "chrome/browser/profiles/profile_attributes_storage.h" | 27 #include "chrome/browser/profiles/profile_attributes_storage.h" |
| 27 #include "chrome/browser/profiles/profile_window.h" | 28 #include "chrome/browser/profiles/profile_window.h" |
| 28 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsert
est_util.h" | 29 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsert
est_util.h" |
| 29 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_uti
l.h" | 30 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_uti
l.h" |
| 30 #include "chrome/browser/search_engines/template_url_service_factory.h" | 31 #include "chrome/browser/search_engines/template_url_service_factory.h" |
| 31 #include "chrome/browser/ui/browser.h" | 32 #include "chrome/browser/ui/browser.h" |
| 32 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 33 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 33 #include "chrome/common/render_messages.h" | 34 #include "chrome/common/render_messages.h" |
| 35 #include "chrome/common/thumbnail_capturer.mojom.h" |
| 34 #include "chrome/test/base/in_process_browser_test.h" | 36 #include "chrome/test/base/in_process_browser_test.h" |
| 35 #include "chrome/test/base/search_test_utils.h" | 37 #include "chrome/test/base/search_test_utils.h" |
| 36 #include "chrome/test/base/ui_test_utils.h" | 38 #include "chrome/test/base/ui_test_utils.h" |
| 37 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switc
hes.h" | 39 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switc
hes.h" |
| 38 #include "components/search_engines/template_url_data.h" | 40 #include "components/search_engines/template_url_data.h" |
| 39 #include "components/search_engines/template_url_service.h" | 41 #include "components/search_engines/template_url_service.h" |
| 40 #include "content/public/browser/browser_message_filter.h" | 42 #include "content/public/browser/browser_message_filter.h" |
| 41 #include "content/public/browser/browser_thread.h" | 43 #include "content/public/browser/browser_thread.h" |
| 42 #include "content/public/browser/navigation_controller.h" | 44 #include "content/public/browser/navigation_controller.h" |
| 43 #include "content/public/browser/navigation_entry.h" | 45 #include "content/public/browser/navigation_entry.h" |
| 44 #include "content/public/browser/notification_service.h" | 46 #include "content/public/browser/notification_service.h" |
| 47 #include "content/public/browser/render_frame_host.h" |
| 45 #include "content/public/browser/render_process_host.h" | 48 #include "content/public/browser/render_process_host.h" |
| 46 #include "content/public/browser/render_view_host.h" | 49 #include "content/public/browser/render_view_host.h" |
| 47 #include "content/public/browser/render_widget_host.h" | 50 #include "content/public/browser/render_widget_host.h" |
| 48 #include "content/public/browser/web_contents.h" | 51 #include "content/public/browser/web_contents.h" |
| 49 #include "content/public/test/browser_test_utils.h" | 52 #include "content/public/test/browser_test_utils.h" |
| 50 #include "content/public/test/test_utils.h" | 53 #include "content/public/test/test_utils.h" |
| 51 #include "net/base/load_flags.h" | 54 #include "net/base/load_flags.h" |
| 52 #include "net/test/embedded_test_server/embedded_test_server.h" | 55 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 53 #include "net/url_request/url_request.h" | 56 #include "net/url_request/url_request.h" |
| 54 #include "net/url_request/url_request_filter.h" | 57 #include "net/url_request/url_request_filter.h" |
| 55 #include "net/url_request/url_request_interceptor.h" | 58 #include "net/url_request/url_request_interceptor.h" |
| 59 #include "services/service_manager/public/cpp/interface_provider.h" |
| 56 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 60 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
| 57 #include "third_party/WebKit/public/web/WebContextMenuData.h" | 61 #include "third_party/WebKit/public/web/WebContextMenuData.h" |
| 58 #include "ui/base/models/menu_model.h" | 62 #include "ui/base/models/menu_model.h" |
| 59 | 63 |
| 60 using content::WebContents; | 64 using content::WebContents; |
| 61 | 65 |
| 62 namespace { | 66 namespace { |
| 63 | 67 |
| 64 class ContextMenuBrowserTest : public InProcessBrowserTest { | 68 class ContextMenuBrowserTest : public InProcessBrowserTest { |
| 65 public: | 69 public: |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 541 content::WebContents* tab = tab_observer.GetTab(); | 545 content::WebContents* tab = tab_observer.GetTab(); |
| 542 content::WaitForLoadStop(tab); | 546 content::WaitForLoadStop(tab); |
| 543 | 547 |
| 544 // Verify that it's the correct tab and profile. | 548 // Verify that it's the correct tab and profile. |
| 545 EXPECT_EQ(url, tab->GetURL()); | 549 EXPECT_EQ(url, tab->GetURL()); |
| 546 EXPECT_EQ(profile, Profile::FromBrowserContext(tab->GetBrowserContext())); | 550 EXPECT_EQ(profile, Profile::FromBrowserContext(tab->GetBrowserContext())); |
| 547 } | 551 } |
| 548 } | 552 } |
| 549 #endif // !defined(OS_CHROMEOS) | 553 #endif // !defined(OS_CHROMEOS) |
| 550 | 554 |
| 551 class ThumbnailResponseWatcher : public content::NotificationObserver { | |
| 552 public: | |
| 553 enum QuitReason { | |
| 554 STILL_RUNNING = 0, | |
| 555 THUMBNAIL_RECEIVED, | |
| 556 RENDER_PROCESS_GONE, | |
| 557 }; | |
| 558 | |
| 559 class MessageFilter : public content::BrowserMessageFilter { | |
| 560 public: | |
| 561 explicit MessageFilter(ThumbnailResponseWatcher* owner) | |
| 562 : content::BrowserMessageFilter(ChromeMsgStart), owner_(owner) {} | |
| 563 | |
| 564 bool OnMessageReceived(const IPC::Message& message) override { | |
| 565 if (message.type() == | |
| 566 ChromeViewHostMsg_RequestThumbnailForContextNode_ACK::ID) { | |
| 567 content::BrowserThread::PostTask( | |
| 568 content::BrowserThread::UI, FROM_HERE, | |
| 569 base::Bind(&MessageFilter::OnRequestThumbnailForContextNodeACK, | |
| 570 this)); | |
| 571 } | |
| 572 return false; | |
| 573 } | |
| 574 | |
| 575 void OnRequestThumbnailForContextNodeACK() { | |
| 576 if (owner_) | |
| 577 owner_->OnRequestThumbnailForContextNodeACK(); | |
| 578 } | |
| 579 | |
| 580 void Disown() { owner_ = nullptr; } | |
| 581 | |
| 582 private: | |
| 583 ~MessageFilter() override {} | |
| 584 | |
| 585 ThumbnailResponseWatcher* owner_; | |
| 586 | |
| 587 DISALLOW_COPY_AND_ASSIGN(MessageFilter); | |
| 588 }; | |
| 589 | |
| 590 explicit ThumbnailResponseWatcher( | |
| 591 content::RenderProcessHost* render_process_host) | |
| 592 : message_loop_runner_(new content::MessageLoopRunner), | |
| 593 filter_(new MessageFilter(this)), | |
| 594 quit_reason_(STILL_RUNNING) { | |
| 595 notification_registrar_.Add( | |
| 596 this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 597 content::Source<content::RenderProcessHost>(render_process_host)); | |
| 598 notification_registrar_.Add( | |
| 599 this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | |
| 600 content::Source<content::RenderProcessHost>(render_process_host)); | |
| 601 render_process_host->AddFilter(filter_.get()); | |
| 602 } | |
| 603 | |
| 604 ~ThumbnailResponseWatcher() override { filter_->Disown(); } | |
| 605 | |
| 606 QuitReason Wait() WARN_UNUSED_RESULT { | |
| 607 message_loop_runner_->Run(); | |
| 608 DCHECK_NE(STILL_RUNNING, quit_reason_); | |
| 609 return quit_reason_; | |
| 610 } | |
| 611 | |
| 612 void Observe(int type, | |
| 613 const content::NotificationSource& source, | |
| 614 const content::NotificationDetails& details) override { | |
| 615 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED || | |
| 616 type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED); | |
| 617 quit_reason_ = RENDER_PROCESS_GONE; | |
| 618 message_loop_runner_->Quit(); | |
| 619 } | |
| 620 | |
| 621 void OnRequestThumbnailForContextNodeACK() { | |
| 622 quit_reason_ = THUMBNAIL_RECEIVED; | |
| 623 message_loop_runner_->Quit(); | |
| 624 } | |
| 625 | |
| 626 private: | |
| 627 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
| 628 scoped_refptr<MessageFilter> filter_; | |
| 629 content::NotificationRegistrar notification_registrar_; | |
| 630 QuitReason quit_reason_; | |
| 631 | |
| 632 DISALLOW_COPY_AND_ASSIGN(ThumbnailResponseWatcher); | |
| 633 }; | |
| 634 | |
| 635 // Maintains image search test state. In particular, note that |menu_observer_| | 555 // Maintains image search test state. In particular, note that |menu_observer_| |
| 636 // must live until the right-click completes asynchronously. | 556 // must live until the right-click completes asynchronously. |
| 637 class SearchByImageBrowserTest : public InProcessBrowserTest { | 557 class SearchByImageBrowserTest : public InProcessBrowserTest { |
| 638 protected: | 558 protected: |
| 639 void SetupAndLoadImagePage(const std::string& image_path) { | 559 void SetupAndLoadImagePage(const std::string& image_path) { |
| 640 // The test server must start first, so that we know the port that the test | 560 // The test server must start first, so that we know the port that the test |
| 641 // server is using. | 561 // server is using. |
| 642 ASSERT_TRUE(embedded_test_server()->Start()); | 562 ASSERT_TRUE(embedded_test_server()->Start()); |
| 643 SetupImageSearchEngine(); | 563 SetupImageSearchEngine(); |
| 644 | 564 |
| 645 // Go to a page with an image in it. The test server doesn't serve the image | 565 // Go to a page with an image in it. The test server doesn't serve the image |
| 646 // with the right MIME type, so use a data URL to make a page containing it. | 566 // with the right MIME type, so use a data URL to make a page containing it. |
| 647 GURL image_url(embedded_test_server()->GetURL(image_path)); | 567 GURL image_url(embedded_test_server()->GetURL(image_path)); |
| 648 GURL page("data:text/html,<img src='" + image_url.spec() + "'>"); | 568 GURL page("data:text/html,<img src='" + image_url.spec() + "'>"); |
| 649 ui_test_utils::NavigateToURL(browser(), page); | 569 ui_test_utils::NavigateToURL(browser(), page); |
| 650 } | 570 } |
| 651 | 571 |
| 652 void AttemptImageSearch() { | 572 void AttemptImageSearch() { |
| 653 // Right-click where the image should be. | |
| 654 // |menu_observer_| will cause the search-by-image menu item to be clicked. | 573 // |menu_observer_| will cause the search-by-image menu item to be clicked. |
| 655 menu_observer_.reset(new ContextMenuNotificationObserver( | 574 menu_observer_.reset(new ContextMenuNotificationObserver( |
| 656 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE)); | 575 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE)); |
| 576 RightClickImage(); |
| 577 } |
| 578 |
| 579 // Right-click where the image should be. |
| 580 void RightClickImage() { |
| 657 content::WebContents* tab = | 581 content::WebContents* tab = |
| 658 browser()->tab_strip_model()->GetActiveWebContents(); | 582 browser()->tab_strip_model()->GetActiveWebContents(); |
| 659 content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::Button::Right, | 583 content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::Button::Right, |
| 660 gfx::Point(15, 15)); | 584 gfx::Point(15, 15)); |
| 661 } | 585 } |
| 662 | 586 |
| 663 GURL GetImageSearchURL() { | 587 GURL GetImageSearchURL() { |
| 664 static const char kImageSearchURL[] = "/imagesearch"; | 588 static const char kImageSearchURL[] = "/imagesearch"; |
| 665 return embedded_test_server()->GetURL(kImageSearchURL); | 589 return embedded_test_server()->GetURL(kImageSearchURL); |
| 666 } | 590 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 tab_observer.Wait(); | 633 tab_observer.Wait(); |
| 710 content::WebContents* new_tab = tab_observer.GetTab(); | 634 content::WebContents* new_tab = tab_observer.GetTab(); |
| 711 content::WaitForLoadStop(new_tab); | 635 content::WaitForLoadStop(new_tab); |
| 712 EXPECT_EQ(GetImageSearchURL(), new_tab->GetURL()); | 636 EXPECT_EQ(GetImageSearchURL(), new_tab->GetURL()); |
| 713 } | 637 } |
| 714 | 638 |
| 715 IN_PROC_BROWSER_TEST_F(SearchByImageBrowserTest, ImageSearchWithCorruptImage) { | 639 IN_PROC_BROWSER_TEST_F(SearchByImageBrowserTest, ImageSearchWithCorruptImage) { |
| 716 static const char kCorruptImage[] = "/image_search/corrupt.png"; | 640 static const char kCorruptImage[] = "/image_search/corrupt.png"; |
| 717 SetupAndLoadImagePage(kCorruptImage); | 641 SetupAndLoadImagePage(kCorruptImage); |
| 718 | 642 |
| 719 content::WebContents* tab = | 643 // Open and close a context menu. |
| 720 browser()->tab_strip_model()->GetActiveWebContents(); | 644 ContextMenuWaiter waiter(content::NotificationService::AllSources()); |
| 721 ThumbnailResponseWatcher watcher(tab->GetRenderProcessHost()); | 645 RightClickImage(); |
| 722 AttemptImageSearch(); | 646 waiter.WaitForMenuOpenAndClose(); |
| 647 |
| 648 chrome::mojom::ThumbnailCapturerPtr thumbnail_capturer; |
| 649 browser() |
| 650 ->tab_strip_model() |
| 651 ->GetActiveWebContents() |
| 652 ->GetMainFrame() |
| 653 ->GetRemoteInterfaces() |
| 654 ->GetInterface(&thumbnail_capturer); |
| 655 |
| 656 auto callback = [](bool* response_received, const base::Closure& quit, |
| 657 const std::vector<uint8_t>& thumbnail_data, |
| 658 const gfx::Size& original_size) { |
| 659 *response_received = true; |
| 660 quit.Run(); |
| 661 }; |
| 662 |
| 663 base::RunLoop run_loop; |
| 664 bool response_received = false; |
| 665 thumbnail_capturer->RequestThumbnailForContextNode( |
| 666 0, gfx::Size(2048, 2048), |
| 667 base::Bind(callback, &response_received, run_loop.QuitClosure())); |
| 668 run_loop.Run(); |
| 723 | 669 |
| 724 // The browser should receive a response from the renderer, because the | 670 // The browser should receive a response from the renderer, because the |
| 725 // renderer should not crash. | 671 // renderer should not crash. |
| 726 EXPECT_EQ(ThumbnailResponseWatcher::THUMBNAIL_RECEIVED, watcher.Wait()); | 672 ASSERT_TRUE(response_received); |
| 727 } | 673 } |
| 728 | 674 |
| 729 class LoadImageRequestInterceptor : public net::URLRequestInterceptor { | 675 class LoadImageRequestInterceptor : public net::URLRequestInterceptor { |
| 730 public: | 676 public: |
| 731 LoadImageRequestInterceptor() : num_requests_(0), | 677 LoadImageRequestInterceptor() : num_requests_(0), |
| 732 requests_to_wait_for_(-1), | 678 requests_to_wait_for_(-1), |
| 733 weak_factory_(this) { | 679 weak_factory_(this) { |
| 734 } | 680 } |
| 735 | 681 |
| 736 ~LoadImageRequestInterceptor() override {} | 682 ~LoadImageRequestInterceptor() override {} |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImage) { | 789 IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImage) { |
| 844 static const char kValidImage[] = "/load_image/image.png"; | 790 static const char kValidImage[] = "/load_image/image.png"; |
| 845 SetupAndLoadImagePage(kValidImage); | 791 SetupAndLoadImagePage(kValidImage); |
| 846 AddLoadImageInterceptor(kValidImage); | 792 AddLoadImageInterceptor(kValidImage); |
| 847 AttemptLoadImage(); | 793 AttemptLoadImage(); |
| 848 interceptor_->WaitForRequests(1); | 794 interceptor_->WaitForRequests(1); |
| 849 EXPECT_EQ(1, interceptor_->num_requests()); | 795 EXPECT_EQ(1, interceptor_->num_requests()); |
| 850 } | 796 } |
| 851 | 797 |
| 852 } // namespace | 798 } // namespace |
| OLD | NEW |