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