Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / streams_private / streams_private_apitest.cc
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
3 // found in the LICENSE file.
4
5 #include "base/command_line.h"
6 #include "base/message_loop/message_loop.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/download/download_prefs.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "chrome/common/extensions/api/streams_private.h"
14 #include "chrome/common/extensions/manifest_handlers/mime_types_handler.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/test/base/test_switches.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "content/public/browser/download_item.h"
19 #include "content/public/browser/download_manager.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/resource_controller.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/test/download_test_observer.h"
24 #include "extensions/browser/event_router.h"
25 #include "extensions/browser/extension_system.h"
26 #include "extensions/test/result_catcher.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
29 #include "net/test/embedded_test_server/http_request.h"
30 #include "net/test/embedded_test_server/http_response.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32
33 using content::BrowserContext;
34 using content::BrowserThread;
35 using content::DownloadItem;
36 using content::DownloadManager;
37 using content::DownloadUrlParameters;
38 using content::ResourceController;
39 using content::WebContents;
40 using extensions::Event;
41 using extensions::ExtensionSystem;
42 using extensions::ResultCatcher;
43 using net::test_server::BasicHttpResponse;
44 using net::test_server::HttpRequest;
45 using net::test_server::HttpResponse;
46 using net::test_server::EmbeddedTestServer;
47 using testing::_;
48
49 namespace streams_private = extensions::api::streams_private;
50
51 namespace {
52
53 // Test server's request handler.
54 // Returns response that should be sent by the test server.
55 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
56   scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse());
57
58   // For relative path "/doc_path.doc", return success response with MIME type
59   // "application/msword".
60   if (request.relative_url == "/doc_path.doc") {
61     response->set_code(net::HTTP_OK);
62     response->set_content_type("application/msword");
63     return response.Pass();
64   }
65
66   // For relative path "/spreadsheet_path.xls", return success response with
67   // MIME type "application/xls".
68   if (request.relative_url == "/spreadsheet_path.xls") {
69     response->set_code(net::HTTP_OK);
70     response->set_content_type("application/msexcel");
71     // Test that multiple headers with the same name are merged.
72     response->AddCustomHeader("Test-Header", "part1");
73     response->AddCustomHeader("Test-Header", "part2");
74     return response.Pass();
75   }
76
77   // For relative path "/text_path_attch.txt", return success response with
78   // MIME type "text/plain" and content "txt content". Also, set content
79   // disposition to be attachment.
80   if (request.relative_url == "/text_path_attch.txt") {
81     response->set_code(net::HTTP_OK);
82     response->set_content("txt content");
83     response->set_content_type("text/plain");
84     response->AddCustomHeader("Content-Disposition",
85                               "attachment; filename=test_path.txt");
86     return response.Pass();
87   }
88
89   // For relative path "/test_path_attch.txt", return success response with
90   // MIME type "text/plain" and content "txt content".
91   if (request.relative_url == "/text_path.txt") {
92     response->set_code(net::HTTP_OK);
93     response->set_content("txt content");
94     response->set_content_type("text/plain");
95     return response.Pass();
96   }
97
98   // A random HTML file to navigate to.
99   if (request.relative_url == "/index.html") {
100     response->set_code(net::HTTP_OK);
101     response->set_content("html content");
102     response->set_content_type("text/html");
103     return response.Pass();
104   }
105
106   // RTF files for testing chrome.streamsPrivate.abort().
107   if (request.relative_url == "/abort.rtf" ||
108       request.relative_url == "/no_abort.rtf") {
109     response->set_code(net::HTTP_OK);
110     response->set_content_type("application/rtf");
111     return response.Pass();
112   }
113
114   // Respond to /favicon.ico for navigating to the page.
115   if (request.relative_url == "/favicon.ico") {
116     response->set_code(net::HTTP_NOT_FOUND);
117     return response.Pass();
118   }
119
120   // No other requests should be handled in the tests.
121   EXPECT_TRUE(false) << "NOTREACHED!";
122   response->set_code(net::HTTP_NOT_FOUND);
123   return response.Pass();
124 }
125
126 // Tests to verify that resources are correctly intercepted by
127 // StreamsResourceThrottle.
128 // The test extension expects the resources that should be handed to the
129 // extension to have MIME type 'application/msword' and the resources that
130 // should be downloaded by the browser to have MIME type 'text/plain'.
131 class StreamsPrivateApiTest : public ExtensionApiTest {
132  public:
133   StreamsPrivateApiTest() {}
134
135   ~StreamsPrivateApiTest() override {}
136
137   void SetUpOnMainThread() override {
138     // Init test server.
139     test_server_.reset(new EmbeddedTestServer);
140     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
141     test_server_->RegisterRequestHandler(base::Bind(&HandleRequest));
142
143     ExtensionApiTest::SetUpOnMainThread();
144   }
145
146   void TearDownOnMainThread() override {
147     // Tear down the test server.
148     EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
149     test_server_.reset();
150     ExtensionApiTest::TearDownOnMainThread();
151   }
152
153   void InitializeDownloadSettings() {
154     ASSERT_TRUE(browser());
155     ASSERT_TRUE(downloads_dir_.CreateUniqueTempDir());
156
157     // Setup default downloads directory to the scoped tmp directory created for
158     // the test.
159     browser()->profile()->GetPrefs()->SetFilePath(
160         prefs::kDownloadDefaultDirectory, downloads_dir_.path());
161     // Ensure there are no prompts for download during the test.
162     browser()->profile()->GetPrefs()->SetBoolean(
163         prefs::kPromptForDownload, false);
164
165     DownloadManager* manager = GetDownloadManager();
166     DownloadPrefs::FromDownloadManager(manager)->ResetAutoOpen();
167     manager->RemoveAllDownloads();
168   }
169
170   // Sends onExecuteContentHandler event with the MIME type "test/done" to the
171   // test extension.
172   // The test extension calls 'chrome.test.notifySuccess' when it receives the
173   // event with the "test/done" MIME type (unless the 'chrome.test.notifyFail'
174   // has already been called).
175   void SendDoneEvent() {
176     streams_private::StreamInfo info;
177     info.mime_type = "test/done";
178     info.original_url = "http://foo";
179     info.stream_url = "blob://bar";
180     info.tab_id = 10;
181     info.expected_content_size = 20;
182
183     scoped_ptr<Event> event(
184         new Event(streams_private::OnExecuteMimeTypeHandler::kEventName,
185                   streams_private::OnExecuteMimeTypeHandler::Create(info)));
186
187     extensions::EventRouter::Get(browser()->profile())
188         ->DispatchEventToExtension(test_extension_id_, event.Pass());
189   }
190
191   // Loads the test extension and set's up its file_browser_handler to handle
192   // 'application/msword' and 'text/plain' MIME types.
193   // The extension will notify success when it detects an event with the MIME
194   // type 'application/msword' and notify fail when it detects an event with the
195   // MIME type 'text/plain'.
196   const extensions::Extension* LoadTestExtension() {
197     // The test extension id is set by the key value in the manifest.
198     test_extension_id_ = "oickdpebdnfbgkcaoklfcdhjniefkcji";
199
200     const extensions::Extension* extension = LoadExtension(
201         test_data_dir_.AppendASCII("streams_private/handle_mime_type"));
202     if (!extension)
203       return NULL;
204
205     MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
206     if (!handler) {
207       message_ = "No mime type handlers defined.";
208       return NULL;
209     }
210
211     DCHECK_EQ(test_extension_id_, extension->id());
212
213     return extension;
214   }
215
216   // Returns the download manager for the current browser.
217   DownloadManager* GetDownloadManager() const {
218     DownloadManager* download_manager =
219         BrowserContext::GetDownloadManager(browser()->profile());
220     EXPECT_TRUE(download_manager);
221     return download_manager;
222   }
223
224   // Deletes the download and waits until it's flushed.
225   // The |manager| should have |download| in its list of downloads.
226   void DeleteDownloadAndWaitForFlush(DownloadItem* download,
227                                      DownloadManager* manager) {
228     scoped_refptr<content::DownloadTestFlushObserver> flush_observer(
229         new content::DownloadTestFlushObserver(manager));
230     download->Remove();
231     flush_observer->WaitForFlush();
232   }
233
234  protected:
235   std::string test_extension_id_;
236   // The HTTP server used in the tests.
237   scoped_ptr<EmbeddedTestServer> test_server_;
238   base::ScopedTempDir downloads_dir_;
239 };
240
241 // Tests that navigating to a resource with a MIME type handleable by an
242 // installed, white-listed extension invokes the extension's
243 // onExecuteContentHandler event (and does not start a download).
244 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Navigate) {
245 #if defined(OS_WIN) && defined(USE_ASH)
246   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
247   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
248     return;
249 #endif
250
251   ASSERT_TRUE(LoadTestExtension()) << message_;
252
253   ResultCatcher catcher;
254
255   ui_test_utils::NavigateToURL(browser(),
256                                test_server_->GetURL("/doc_path.doc"));
257
258   // Wait for the response from the test server.
259   base::MessageLoop::current()->RunUntilIdle();
260
261   // There should be no downloads started by the navigation.
262   DownloadManager* download_manager = GetDownloadManager();
263   std::vector<DownloadItem*> downloads;
264   download_manager->GetAllDownloads(&downloads);
265   ASSERT_EQ(0u, downloads.size());
266
267   // The test extension should receive onExecuteContentHandler event with MIME
268   // type 'application/msword' (and call chrome.test.notifySuccess).
269   EXPECT_TRUE(catcher.GetNextResult());
270 }
271
272 // Tests that navigating to a file URL also intercepts despite there being no
273 // HTTP headers. This is a regression test for https://crbug.com/416433.
274 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, FileURL) {
275 #if defined(OS_WIN) && defined(USE_ASH)
276   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
277   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
278     return;
279 #endif
280
281   ASSERT_TRUE(LoadTestExtension()) << message_;
282
283   ResultCatcher catcher;
284
285   ui_test_utils::NavigateToURL(browser(), ui_test_utils::GetTestUrl(
286       base::FilePath(FILE_PATH_LITERAL("downloads")),
287       base::FilePath(FILE_PATH_LITERAL("Picture_1.doc"))));
288
289   // There should be no downloads started by the navigation.
290   DownloadManager* download_manager = GetDownloadManager();
291   std::vector<DownloadItem*> downloads;
292   download_manager->GetAllDownloads(&downloads);
293   ASSERT_EQ(0u, downloads.size());
294
295   // The test extension should receive onExecuteContentHandler event with MIME
296   // type 'application/msword' (and call chrome.test.notifySuccess).
297   EXPECT_TRUE(catcher.GetNextResult());
298 }
299
300 // Tests that navigating cross-site to a resource with a MIME type handleable by
301 // an installed, white-listed extension invokes the extension's
302 // onExecuteContentHandler event (and does not start a download).
303 // Regression test for http://crbug.com/342999.
304 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, NavigateCrossSite) {
305 #if defined(OS_WIN) && defined(USE_ASH)
306   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
307   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
308     return;
309 #endif
310
311   ASSERT_TRUE(LoadTestExtension()) << message_;
312
313   ResultCatcher catcher;
314
315   // Navigate to a URL on a different hostname.
316   std::string initial_host = "www.example.com";
317   host_resolver()->AddRule(initial_host, "127.0.0.1");
318   GURL::Replacements replacements;
319   replacements.SetHostStr(initial_host);
320   GURL initial_url =
321       test_server_->GetURL("/index.html").ReplaceComponents(replacements);
322   ui_test_utils::NavigateToURL(browser(), initial_url);
323
324   // Now navigate to the doc file; the extension should pick it up normally.
325   ui_test_utils::NavigateToURL(browser(),
326                                test_server_->GetURL("/doc_path.doc"));
327
328   // Wait for the response from the test server.
329   base::MessageLoop::current()->RunUntilIdle();
330
331   // There should be no downloads started by the navigation.
332   DownloadManager* download_manager = GetDownloadManager();
333   std::vector<DownloadItem*> downloads;
334   download_manager->GetAllDownloads(&downloads);
335   ASSERT_EQ(0u, downloads.size());
336
337   // The test extension should receive onExecuteContentHandler event with MIME
338   // type 'application/msword' (and call chrome.test.notifySuccess).
339   EXPECT_TRUE(catcher.GetNextResult());
340 }
341
342 // Tests that navigation to an attachment starts a download, even if there is an
343 // extension with a file browser handler that can handle the attachment's MIME
344 // type.
345 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, NavigateToAnAttachment) {
346   InitializeDownloadSettings();
347
348   ASSERT_TRUE(LoadTestExtension()) << message_;
349
350   ResultCatcher catcher;
351
352   // The test should start a download.
353   DownloadManager* download_manager = GetDownloadManager();
354   scoped_ptr<content::DownloadTestObserver> download_observer(
355       new content::DownloadTestObserverInProgress(download_manager, 1));
356
357   ui_test_utils::NavigateToURL(browser(),
358                                test_server_->GetURL("/text_path_attch.txt"));
359
360   // Wait for the download to start.
361   download_observer->WaitForFinished();
362
363   // There should be one download started by the navigation.
364   DownloadManager::DownloadVector downloads;
365   download_manager->GetAllDownloads(&downloads);
366   ASSERT_EQ(1u, downloads.size());
367
368   // Cancel and delete the download started in the test.
369   DeleteDownloadAndWaitForFlush(downloads[0], download_manager);
370
371   // The test extension should not receive any events by now. Send it an event
372   // with MIME type "test/done", so it stops waiting for the events. (If there
373   // was an event with MIME type 'text/plain', |catcher.GetNextResult()| will
374   // fail regardless of the sent event; chrome.test.notifySuccess will not be
375   // called by the extension).
376   SendDoneEvent();
377   EXPECT_TRUE(catcher.GetNextResult());
378 }
379
380 // Tests that direct download requests don't get intercepted by
381 // StreamsResourceThrottle, even if there is an extension with a file
382 // browser handler that can handle the download's MIME type.
383 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, DirectDownload) {
384   InitializeDownloadSettings();
385
386   ASSERT_TRUE(LoadTestExtension()) << message_;
387
388   ResultCatcher catcher;
389
390   DownloadManager* download_manager = GetDownloadManager();
391   scoped_ptr<content::DownloadTestObserver> download_observer(
392       new content::DownloadTestObserverInProgress(download_manager, 1));
393
394   // The resource's URL on the test server.
395   GURL url = test_server_->GetURL("/text_path.txt");
396
397   // The download's target file path.
398   base::FilePath target_path =
399       downloads_dir_.path().Append(FILE_PATH_LITERAL("download_target.txt"));
400
401   // Set the downloads parameters.
402   content::WebContents* web_contents =
403       browser()->tab_strip_model()->GetActiveWebContents();
404   ASSERT_TRUE(web_contents);
405   scoped_ptr<DownloadUrlParameters> params(
406       DownloadUrlParameters::FromWebContents(web_contents, url));
407   params->set_file_path(target_path);
408
409   // Start download of the URL with a path "/text_path.txt" on the test server.
410   download_manager->DownloadUrl(params.Pass());
411
412   // Wait for the download to start.
413   download_observer->WaitForFinished();
414
415   // There should have been one download.
416   std::vector<DownloadItem*> downloads;
417   download_manager->GetAllDownloads(&downloads);
418   ASSERT_EQ(1u, downloads.size());
419
420   // Cancel and delete the download statred in the test.
421   DeleteDownloadAndWaitForFlush(downloads[0], download_manager);
422
423   // The test extension should not receive any events by now. Send it an event
424   // with MIME type "test/done", so it stops waiting for the events. (If there
425   // was an event with MIME type 'text/plain', |catcher.GetNextResult()| will
426   // fail regardless of the sent event; chrome.test.notifySuccess will not be
427   // called by the extension).
428   SendDoneEvent();
429   EXPECT_TRUE(catcher.GetNextResult());
430 }
431
432 // Tests that response headers are correctly passed to the API and that multiple
433 // repsonse headers with the same name are merged correctly.
434 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Headers) {
435 #if defined(OS_WIN) && defined(USE_ASH)
436   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
437   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
438     return;
439 #endif
440
441   ASSERT_TRUE(LoadTestExtension()) << message_;
442
443   ResultCatcher catcher;
444
445   ui_test_utils::NavigateToURL(browser(),
446                                test_server_->GetURL("/spreadsheet_path.xls"));
447
448   // Wait for the response from the test server.
449   base::MessageLoop::current()->RunUntilIdle();
450
451   // There should be no downloads started by the navigation.
452   DownloadManager* download_manager = GetDownloadManager();
453   std::vector<DownloadItem*> downloads;
454   download_manager->GetAllDownloads(&downloads);
455   ASSERT_EQ(0u, downloads.size());
456
457   // The test extension should receive onExecuteContentHandler event with MIME
458   // type 'application/msexcel' (and call chrome.test.notifySuccess).
459   EXPECT_TRUE(catcher.GetNextResult());
460 }
461
462 // Tests that chrome.streamsPrivate.abort() works correctly.
463 IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Abort) {
464 #if defined(OS_WIN) && defined(USE_ASH)
465   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
466   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
467     return;
468 #endif
469
470   ASSERT_TRUE(LoadTestExtension()) << message_;
471
472   ResultCatcher catcher;
473   ui_test_utils::NavigateToURL(browser(),
474                                test_server_->GetURL("/no_abort.rtf"));
475   base::MessageLoop::current()->RunUntilIdle();
476   EXPECT_TRUE(catcher.GetNextResult());
477
478   ui_test_utils::NavigateToURL(browser(),
479                                test_server_->GetURL("/abort.rtf"));
480   base::MessageLoop::current()->RunUntilIdle();
481   EXPECT_TRUE(catcher.GetNextResult());
482 }
483
484 }  // namespace