Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu_browsertest.cc
blobee2f6f73babd416298dc9af00fcb789f525f206f
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
3 // found in the LICENSE file.
5 #include <string>
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/macros.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/app/chrome_command_ids.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
17 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
18 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
19 #include "chrome/browser/search_engines/template_url_service_factory.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/render_messages.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
26 #include "components/search_engines/template_url_data.h"
27 #include "components/search_engines/template_url_service.h"
28 #include "content/public/browser/browser_message_filter.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/navigation_controller.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/render_process_host.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/test/browser_test_utils.h"
37 #include "content/public/test/test_utils.h"
38 #include "net/base/load_flags.h"
39 #include "net/url_request/url_request.h"
40 #include "net/url_request/url_request_filter.h"
41 #include "net/url_request/url_request_interceptor.h"
42 #include "third_party/WebKit/public/web/WebContextMenuData.h"
43 #include "third_party/WebKit/public/web/WebInputEvent.h"
45 using content::WebContents;
47 namespace {
49 class ContextMenuBrowserTest : public InProcessBrowserTest {
50 public:
51 ContextMenuBrowserTest() {}
53 TestRenderViewContextMenu* CreateContextMenu(
54 const GURL& unfiltered_url,
55 const GURL& url,
56 blink::WebContextMenuData::MediaType media_type) {
57 content::ContextMenuParams params;
58 params.media_type = media_type;
59 params.unfiltered_link_url = unfiltered_url;
60 params.link_url = url;
61 params.src_url = url;
62 WebContents* web_contents =
63 browser()->tab_strip_model()->GetActiveWebContents();
64 params.page_url = web_contents->GetController().GetActiveEntry()->GetURL();
65 #if defined(OS_MACOSX)
66 params.writing_direction_default = 0;
67 params.writing_direction_left_to_right = 0;
68 params.writing_direction_right_to_left = 0;
69 #endif // OS_MACOSX
70 TestRenderViewContextMenu* menu = new TestRenderViewContextMenu(
71 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
72 params);
73 menu->Init();
74 return menu;
77 TestRenderViewContextMenu* CreateContextMenuMediaTypeNone(
78 const GURL& unfiltered_url,
79 const GURL& url) {
80 return CreateContextMenu(unfiltered_url, url,
81 blink::WebContextMenuData::MediaTypeNone);
85 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
86 OpenEntryPresentForNormalURLs) {
87 scoped_ptr<TestRenderViewContextMenu> menu(CreateContextMenuMediaTypeNone(
88 GURL("http://www.google.com/"), GURL("http://www.google.com/")));
90 ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
91 ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
92 ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
95 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
96 OpenEntryAbsentForFilteredURLs) {
97 scoped_ptr<TestRenderViewContextMenu> menu(
98 CreateContextMenuMediaTypeNone(GURL("chrome://history"), GURL()));
100 ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
101 ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
102 ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
105 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
106 ContextMenuForCanvas) {
107 content::ContextMenuParams params;
108 params.media_type = blink::WebContextMenuData::MediaTypeCanvas;
110 TestRenderViewContextMenu menu(
111 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
112 params);
113 menu.Init();
115 ASSERT_TRUE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_SAVEIMAGEAS));
116 ASSERT_TRUE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_COPYIMAGE));
119 // Opens a link in a new tab via a "real" context menu.
120 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, RealMenu) {
121 ContextMenuNotificationObserver menu_observer(
122 IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
123 ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
124 content::NotificationService::AllSources());
126 // Go to a page with a link
127 ui_test_utils::NavigateToURL(
128 browser(), GURL("data:text/html,<a href='about:blank'>link</a>"));
130 // Open a context menu.
131 blink::WebMouseEvent mouse_event;
132 mouse_event.type = blink::WebInputEvent::MouseDown;
133 mouse_event.button = blink::WebMouseEvent::ButtonRight;
134 mouse_event.x = 15;
135 mouse_event.y = 15;
136 content::WebContents* tab =
137 browser()->tab_strip_model()->GetActiveWebContents();
138 gfx::Rect offset = tab->GetContainerBounds();
139 mouse_event.globalX = 15 + offset.x();
140 mouse_event.globalY = 15 + offset.y();
141 mouse_event.clickCount = 1;
142 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
143 mouse_event.type = blink::WebInputEvent::MouseUp;
144 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
146 // The menu_observer will select "Open in new tab", wait for the new tab to
147 // be added.
148 tab_observer.Wait();
149 tab = tab_observer.GetTab();
150 content::WaitForLoadStop(tab);
152 // Verify that it's the correct tab.
153 EXPECT_EQ(GURL("about:blank"), tab->GetURL());
156 // Verify that "Open Link in New Tab" doesn't send URL fragment as referrer.
157 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenInNewTabReferrer) {
158 ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
159 content::NotificationService::AllSources());
161 ASSERT_TRUE(test_server()->Start());
162 GURL echoheader(test_server()->GetURL("echoheader?Referer"));
164 // Go to a |page| with a link to echoheader URL.
165 GURL page("data:text/html,<a href='" + echoheader.spec() + "'>link</a>");
166 ui_test_utils::NavigateToURL(browser(), page);
168 // Set up referrer URL with fragment.
169 const GURL kReferrerWithFragment("http://foo.com/test#fragment");
170 const std::string kCorrectReferrer("http://foo.com/test");
172 // Set up menu with link URL.
173 content::ContextMenuParams context_menu_params;
174 context_menu_params.page_url = kReferrerWithFragment;
175 context_menu_params.link_url = echoheader;
177 // Select "Open Link in New Tab" and wait for the new tab to be added.
178 TestRenderViewContextMenu menu(
179 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
180 context_menu_params);
181 menu.Init();
182 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB, 0);
184 tab_observer.Wait();
185 content::WebContents* tab = tab_observer.GetTab();
186 content::WaitForLoadStop(tab);
188 // Verify that it's the correct tab.
189 ASSERT_EQ(echoheader, tab->GetURL());
190 // Verify that the text on the page matches |kCorrectReferrer|.
191 std::string actual_referrer;
192 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
193 tab,
194 "window.domAutomationController.send(window.document.body.textContent);",
195 &actual_referrer));
196 ASSERT_EQ(kCorrectReferrer, actual_referrer);
198 // Verify that the referrer on the page matches |kCorrectReferrer|.
199 std::string page_referrer;
200 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
201 tab,
202 "window.domAutomationController.send(window.document.referrer);",
203 &page_referrer));
204 ASSERT_EQ(kCorrectReferrer, page_referrer);
207 // Verify that "Open Link in Incognito Window " doesn't send referrer URL.
208 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenIncognitoNoneReferrer) {
209 ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
210 content::NotificationService::AllSources());
212 ASSERT_TRUE(test_server()->Start());
213 GURL echoheader(test_server()->GetURL("echoheader?Referer"));
215 // Go to a |page| with a link to echoheader URL.
216 GURL page("data:text/html,<a href='" + echoheader.spec() + "'>link</a>");
217 ui_test_utils::NavigateToURL(browser(), page);
219 // Set up referrer URL with fragment.
220 const GURL kReferrerWithFragment("http://foo.com/test#fragment");
221 const std::string kNoneReferrer("None");
222 const std::string kEmptyReferrer("");
224 // Set up menu with link URL.
225 content::ContextMenuParams context_menu_params;
226 context_menu_params.page_url = kReferrerWithFragment;
227 context_menu_params.link_url = echoheader;
229 // Select "Open Link in Incognito Window" and wait for window to be added.
230 TestRenderViewContextMenu menu(
231 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
232 context_menu_params);
233 menu.Init();
234 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD, 0);
236 tab_observer.Wait();
237 content::WebContents* tab = tab_observer.GetTab();
238 content::WaitForLoadStop(tab);
240 // Verify that it's the correct tab.
241 ASSERT_EQ(echoheader, tab->GetURL());
242 // Verify that the text on the page matches |kNoneReferrer|.
243 std::string actual_referrer;
244 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
245 tab,
246 "window.domAutomationController.send(window.document.body.textContent);",
247 &actual_referrer));
248 ASSERT_EQ(kNoneReferrer, actual_referrer);
250 // Verify that the referrer on the page matches |kEmptyReferrer|.
251 std::string page_referrer;
252 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
253 tab,
254 "window.domAutomationController.send(window.document.referrer);",
255 &page_referrer));
256 ASSERT_EQ(kEmptyReferrer, page_referrer);
259 // Check filename on clicking "Save Link As" via a "real" context menu.
260 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, SuggestedFileName) {
261 // Register observer.
262 ContextMenuWaiter menu_observer(content::NotificationService::AllSources());
264 // Go to a page with a link having download attribute.
265 const std::string kSuggestedFilename("test_filename.png");
266 ui_test_utils::NavigateToURL(
267 browser(),
268 GURL("data:text/html,<a href='about:blank' download='" +
269 kSuggestedFilename + "'>link</a>"));
271 // Open a context menu.
272 blink::WebMouseEvent mouse_event;
273 mouse_event.type = blink::WebInputEvent::MouseDown;
274 mouse_event.button = blink::WebMouseEvent::ButtonRight;
275 mouse_event.x = 15;
276 mouse_event.y = 15;
277 content::WebContents* tab =
278 browser()->tab_strip_model()->GetActiveWebContents();
279 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
280 mouse_event.type = blink::WebInputEvent::MouseUp;
281 tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
283 // Wait for context menu to be visible.
284 menu_observer.WaitForMenuOpenAndClose();
286 // Compare filename.
287 base::string16 suggested_filename = menu_observer.params().suggested_filename;
288 ASSERT_EQ(kSuggestedFilename, base::UTF16ToUTF8(suggested_filename).c_str());
291 // Ensure that View Page Info won't crash if there is no visible entry.
292 // See http://crbug.com/370863.
293 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, ViewPageInfoWithNoEntry) {
294 // Create a new tab with no committed entry.
295 ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
296 content::NotificationService::AllSources());
297 ASSERT_TRUE(content::ExecuteScript(
298 browser()->tab_strip_model()->GetActiveWebContents(), "window.open();"));
299 tab_observer.Wait();
300 content::WebContents* tab = tab_observer.GetTab();
301 EXPECT_FALSE(tab->GetController().GetLastCommittedEntry());
302 EXPECT_FALSE(tab->GetController().GetVisibleEntry());
304 // Create a context menu.
305 content::ContextMenuParams context_menu_params;
306 TestRenderViewContextMenu menu(tab->GetMainFrame(), context_menu_params);
307 menu.Init();
309 // The item shouldn't be enabled in the menu.
310 EXPECT_FALSE(menu.IsCommandIdEnabled(IDC_CONTENT_CONTEXT_VIEWPAGEINFO));
312 // Ensure that viewing page info doesn't crash even if you can get to it.
313 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_VIEWPAGEINFO, 0);
316 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, DataSaverOpenOrigImageInNewTab) {
317 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
318 command_line->AppendSwitch(
319 data_reduction_proxy::switches::kEnableDataReductionProxy);
321 scoped_ptr<TestRenderViewContextMenu> menu(
322 CreateContextMenu(GURL(), GURL("http://url.com/image.png"),
323 blink::WebContextMenuData::MediaTypeImage));
325 ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
326 ASSERT_TRUE(menu->IsItemPresent(
327 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB));
330 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
331 DataSaverHttpsOpenImageInNewTab) {
332 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
333 command_line->AppendSwitch(
334 data_reduction_proxy::switches::kEnableDataReductionProxy);
336 scoped_ptr<TestRenderViewContextMenu> menu(
337 CreateContextMenu(GURL(), GURL("https://url.com/image.png"),
338 blink::WebContextMenuData::MediaTypeImage));
340 ASSERT_FALSE(
341 menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB));
342 ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
345 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenImageInNewTab) {
346 scoped_ptr<TestRenderViewContextMenu> menu(
347 CreateContextMenu(GURL(), GURL("http://url.com/image.png"),
348 blink::WebContextMenuData::MediaTypeImage));
349 ASSERT_FALSE(
350 menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB));
351 ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
354 class ThumbnailResponseWatcher : public content::NotificationObserver {
355 public:
356 enum QuitReason {
357 STILL_RUNNING = 0,
358 THUMBNAIL_RECEIVED,
359 RENDER_PROCESS_GONE,
362 class MessageFilter : public content::BrowserMessageFilter {
363 public:
364 explicit MessageFilter(ThumbnailResponseWatcher* owner)
365 : content::BrowserMessageFilter(ChromeMsgStart), owner_(owner) {}
367 bool OnMessageReceived(const IPC::Message& message) override {
368 if (message.type() ==
369 ChromeViewHostMsg_RequestThumbnailForContextNode_ACK::ID) {
370 content::BrowserThread::PostTask(
371 content::BrowserThread::UI, FROM_HERE,
372 base::Bind(&MessageFilter::OnRequestThumbnailForContextNodeACK,
373 this));
375 return false;
378 void OnRequestThumbnailForContextNodeACK() {
379 if (owner_)
380 owner_->OnRequestThumbnailForContextNodeACK();
383 void Disown() { owner_ = nullptr; }
385 private:
386 ~MessageFilter() override {}
388 ThumbnailResponseWatcher* owner_;
390 DISALLOW_COPY_AND_ASSIGN(MessageFilter);
393 explicit ThumbnailResponseWatcher(
394 content::RenderProcessHost* render_process_host)
395 : message_loop_runner_(new content::MessageLoopRunner),
396 filter_(new MessageFilter(this)),
397 quit_reason_(STILL_RUNNING) {
398 notification_registrar_.Add(
399 this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
400 content::Source<content::RenderProcessHost>(render_process_host));
401 notification_registrar_.Add(
402 this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
403 content::Source<content::RenderProcessHost>(render_process_host));
404 render_process_host->AddFilter(filter_.get());
407 ~ThumbnailResponseWatcher() override { filter_->Disown(); }
409 QuitReason Wait() WARN_UNUSED_RESULT {
410 message_loop_runner_->Run();
411 DCHECK_NE(STILL_RUNNING, quit_reason_);
412 return quit_reason_;
415 void Observe(int type,
416 const content::NotificationSource& source,
417 const content::NotificationDetails& details) override {
418 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED ||
419 type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED);
420 quit_reason_ = RENDER_PROCESS_GONE;
421 message_loop_runner_->Quit();
424 void OnRequestThumbnailForContextNodeACK() {
425 quit_reason_ = THUMBNAIL_RECEIVED;
426 message_loop_runner_->Quit();
429 private:
430 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
431 scoped_refptr<MessageFilter> filter_;
432 content::NotificationRegistrar notification_registrar_;
433 QuitReason quit_reason_;
435 DISALLOW_COPY_AND_ASSIGN(ThumbnailResponseWatcher);
438 // Maintains image search test state. In particular, note that |menu_observer_|
439 // must live until the right-click completes asynchronously.
440 class SearchByImageBrowserTest : public InProcessBrowserTest {
441 protected:
442 void SetupAndLoadImagePage(const std::string& image_path) {
443 // The test server must start first, so that we know the port that the test
444 // server is using.
445 ASSERT_TRUE(test_server()->Start());
446 SetupImageSearchEngine();
448 // Go to a page with an image in it. The test server doesn't serve the image
449 // with the right MIME type, so use a data URL to make a page containing it.
450 GURL image_url(test_server()->GetURL(image_path));
451 GURL page("data:text/html,<img src='" + image_url.spec() + "'>");
452 ui_test_utils::NavigateToURL(browser(), page);
455 void AttemptImageSearch() {
456 // Right-click where the image should be.
457 // |menu_observer_| will cause the search-by-image menu item to be clicked.
458 menu_observer_.reset(new ContextMenuNotificationObserver(
459 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE));
460 content::WebContents* tab =
461 browser()->tab_strip_model()->GetActiveWebContents();
462 content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::ButtonRight,
463 gfx::Point(15, 15));
466 GURL GetImageSearchURL() {
467 static const char kImageSearchURL[] = "imagesearch";
468 return test_server()->GetURL(kImageSearchURL);
471 private:
472 void SetupImageSearchEngine() {
473 static const char kShortName[] = "test";
474 static const char kSearchURL[] = "search?q={searchTerms}";
475 static const char kImageSearchPostParams[] =
476 "thumb={google:imageThumbnail}";
478 TemplateURLService* model =
479 TemplateURLServiceFactory::GetForProfile(browser()->profile());
480 ASSERT_TRUE(model);
481 ui_test_utils::WaitForTemplateURLServiceToLoad(model);
482 ASSERT_TRUE(model->loaded());
484 TemplateURLData data;
485 data.SetShortName(base::ASCIIToUTF16(kShortName));
486 data.SetKeyword(data.short_name());
487 data.SetURL(test_server()->GetURL(kSearchURL).spec());
488 data.image_url = GetImageSearchURL().spec();
489 data.image_url_post_params = kImageSearchPostParams;
491 // The model takes ownership of |template_url|.
492 TemplateURL* template_url = new TemplateURL(data);
493 ASSERT_TRUE(model->Add(template_url));
494 model->SetUserSelectedDefaultSearchProvider(template_url);
497 void TearDownInProcessBrowserTestFixture() override {
498 menu_observer_.reset();
501 scoped_ptr<ContextMenuNotificationObserver> menu_observer_;
504 IN_PROC_BROWSER_TEST_F(SearchByImageBrowserTest, ImageSearchWithValidImage) {
505 static const char kValidImage[] = "files/image_search/valid.png";
506 SetupAndLoadImagePage(kValidImage);
508 ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
509 content::NotificationService::AllSources());
510 AttemptImageSearch();
512 // The browser should open a new tab for an image search.
513 tab_observer.Wait();
514 content::WebContents* new_tab = tab_observer.GetTab();
515 content::WaitForLoadStop(new_tab);
516 EXPECT_EQ(GetImageSearchURL(), new_tab->GetURL());
519 IN_PROC_BROWSER_TEST_F(SearchByImageBrowserTest, ImageSearchWithCorruptImage) {
520 static const char kCorruptImage[] = "files/image_search/corrupt.png";
521 SetupAndLoadImagePage(kCorruptImage);
523 content::WebContents* tab =
524 browser()->tab_strip_model()->GetActiveWebContents();
525 ThumbnailResponseWatcher watcher(tab->GetRenderProcessHost());
526 AttemptImageSearch();
528 // The browser should receive a response from the renderer, because the
529 // renderer should not crash.
530 EXPECT_EQ(ThumbnailResponseWatcher::THUMBNAIL_RECEIVED, watcher.Wait());
533 class LoadImageRequestInterceptor : public net::URLRequestInterceptor {
534 public:
535 LoadImageRequestInterceptor() : num_requests_(0),
536 requests_to_wait_for_(-1),
537 weak_factory_(this) {
540 ~LoadImageRequestInterceptor() override {}
542 // net::URLRequestInterceptor implementation
543 net::URLRequestJob* MaybeInterceptRequest(
544 net::URLRequest* request,
545 net::NetworkDelegate* network_delegate) const override {
546 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
547 EXPECT_TRUE(request->load_flags() & net::LOAD_BYPASS_CACHE);
548 content::BrowserThread::PostTask(
549 content::BrowserThread::UI, FROM_HERE,
550 base::Bind(&LoadImageRequestInterceptor::RequestCreated,
551 weak_factory_.GetWeakPtr()));
552 return nullptr;
555 void WaitForRequests(int requests_to_wait_for) {
556 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
557 DCHECK_EQ(-1, requests_to_wait_for_);
558 DCHECK(!run_loop_);
560 if (num_requests_ >= requests_to_wait_for)
561 return;
563 requests_to_wait_for_ = requests_to_wait_for;
564 run_loop_.reset(new base::RunLoop());
565 run_loop_->Run();
566 run_loop_.reset();
567 requests_to_wait_for_ = -1;
568 EXPECT_EQ(num_requests_, requests_to_wait_for);
571 // It is up to the caller to wait until all relevant requests has been
572 // created, either through calling WaitForRequests or some other manner,
573 // before calling this method.
574 int num_requests() const {
575 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
576 return num_requests_;
579 private:
580 void RequestCreated() {
581 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
583 num_requests_++;
584 if (num_requests_ == requests_to_wait_for_)
585 run_loop_->Quit();
588 // These are only used on the UI thread.
589 int num_requests_;
590 int requests_to_wait_for_;
591 scoped_ptr<base::RunLoop> run_loop_;
593 // This prevents any risk of flake if any test doesn't wait for a request
594 // it sent. Mutable so it can be accessed from a const function.
595 mutable base::WeakPtrFactory<LoadImageRequestInterceptor> weak_factory_;
597 DISALLOW_COPY_AND_ASSIGN(LoadImageRequestInterceptor);
600 class LoadImageBrowserTest : public InProcessBrowserTest {
601 protected:
602 void SetupAndLoadImagePage(const std::string& image_path) {
603 // Go to a page with an image in it. The test server doesn't serve the image
604 // with the right MIME type, so use a data URL to make a page containing it.
605 GURL image_url(test_server()->GetURL(image_path));
606 GURL page("data:text/html,<img src='" + image_url.spec() + "'>");
607 ui_test_utils::NavigateToURL(browser(), page);
610 void AddLoadImageInterceptor(const std::string& image_path) {
611 interceptor_ = new LoadImageRequestInterceptor();
612 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_);
613 content::BrowserThread::PostTask(
614 content::BrowserThread::IO, FROM_HERE,
615 base::Bind(&LoadImageBrowserTest::AddInterceptorForURL,
616 base::Unretained(this),
617 GURL(test_server()->GetURL(image_path).spec()),
618 base::Passed(&owned_interceptor)));
621 void AttemptLoadImage() {
622 // Right-click where the image should be.
623 // |menu_observer_| will cause the "Load image" menu item to be clicked.
624 menu_observer_.reset(new ContextMenuNotificationObserver(
625 IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE));
626 content::WebContents* tab =
627 browser()->tab_strip_model()->GetActiveWebContents();
628 content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::ButtonRight,
629 gfx::Point(15, 15));
632 void AddInterceptorForURL(
633 const GURL& url, scoped_ptr<net::URLRequestInterceptor> handler) {
634 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
635 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
636 url, handler.Pass());
639 LoadImageRequestInterceptor* interceptor_;
641 private:
642 scoped_ptr<ContextMenuNotificationObserver> menu_observer_;
645 IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImage) {
646 static const char kValidImage[] = "files/load_image/image.png";
647 SetupAndLoadImagePage(kValidImage);
648 AddLoadImageInterceptor(kValidImage);
649 AttemptLoadImage();
650 interceptor_->WaitForRequests(1);
651 EXPECT_EQ(1, interceptor_->num_requests());
654 } // namespace