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/files/file_path.h"
7#include "base/path_service.h"
8#include "base/prefs/pref_service.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/extensions/crx_installer.h"
11#include "chrome/browser/extensions/extension_browsertest.h"
12#include "chrome/browser/extensions/extension_service.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/ui/browser.h"
15#include "chrome/browser/ui/tabs/tab_strip_model.h"
16#include "chrome/common/chrome_paths.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/test/base/ui_test_utils.h"
20#include "content/public/browser/plugin_service.h"
21#include "content/public/browser/web_contents.h"
22#include "content/public/common/webplugininfo.h"
23#include "content/public/test/browser_test_utils.h"
24#include "extensions/browser/extension_system.h"
25#include "net/dns/mock_host_resolver.h"
26
27using content::PluginService;
28using content::WebContents;
29using extensions::Extension;
30using extensions::Manifest;
31
32namespace {
33
34const char* kExtensionId = "bjjcibdiodkkeanflmiijlcfieiemced";
35
36// This class tests that the Native Client plugin is blocked unless the
37// .nexe is part of an extension from the Chrome Webstore.
38class NaClExtensionTest : public ExtensionBrowserTest {
39 public:
40  NaClExtensionTest() {}
41
42 protected:
43  enum InstallType {
44    INSTALL_TYPE_COMPONENT,
45    INSTALL_TYPE_UNPACKED,
46    INSTALL_TYPE_FROM_WEBSTORE,
47    INSTALL_TYPE_NON_WEBSTORE,
48  };
49  enum PluginType {
50    PLUGIN_TYPE_NONE = 0,
51    PLUGIN_TYPE_EMBED = 1,
52    PLUGIN_TYPE_CONTENT_HANDLER = 2,
53    PLUGIN_TYPE_ALL = PLUGIN_TYPE_EMBED |
54                      PLUGIN_TYPE_CONTENT_HANDLER,
55  };
56
57
58  const Extension* InstallExtension(const base::FilePath& file_path,
59                                    InstallType install_type) {
60    ExtensionService* service = extensions::ExtensionSystem::Get(
61        browser()->profile())->extension_service();
62    const Extension* extension = NULL;
63    switch (install_type) {
64      case INSTALL_TYPE_COMPONENT:
65        if (LoadExtensionAsComponent(file_path)) {
66          extension = service->GetExtensionById(kExtensionId, false);
67        }
68        break;
69
70      case INSTALL_TYPE_UNPACKED:
71        // Install the extension from a folder so it's unpacked.
72        if (LoadExtension(file_path)) {
73          extension = service->GetExtensionById(kExtensionId, false);
74        }
75        break;
76
77      case INSTALL_TYPE_FROM_WEBSTORE:
78        // Install native_client.crx from the webstore.
79        if (InstallExtensionFromWebstore(file_path, 1)) {
80          extension = service->GetExtensionById(last_loaded_extension_id(),
81                                                false);
82        }
83        break;
84
85      case INSTALL_TYPE_NON_WEBSTORE:
86        // Install native_client.crx but not from the webstore.
87        if (ExtensionBrowserTest::InstallExtension(file_path, 1)) {
88          extension = service->GetExtensionById(last_loaded_extension_id(),
89                                                false);
90        }
91        break;
92    }
93    return extension;
94  }
95
96  const Extension* InstallExtension(InstallType install_type) {
97    base::FilePath file_path = test_data_dir_.AppendASCII("native_client");
98    return InstallExtension(file_path, install_type);
99  }
100
101  const Extension* InstallHostedApp() {
102    base::FilePath file_path = test_data_dir_.AppendASCII(
103        "native_client_hosted_app");
104    return InstallExtension(file_path, INSTALL_TYPE_FROM_WEBSTORE);
105  }
106
107  bool IsNaClPluginLoaded() {
108    base::FilePath path;
109    if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) {
110      content::WebPluginInfo info;
111      return PluginService::GetInstance()->GetPluginInfoByPath(path, &info);
112    }
113    return false;
114  }
115
116  void CheckPluginsCreated(const GURL& url, PluginType expected_to_succeed) {
117    ui_test_utils::NavigateToURL(browser(), url);
118    // Don't run tests if the NaCl plugin isn't loaded.
119    if (!IsNaClPluginLoaded())
120      return;
121
122    bool embedded_plugin_created = false;
123    bool content_handler_plugin_created = false;
124    WebContents* web_contents =
125        browser()->tab_strip_model()->GetActiveWebContents();
126    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
127        web_contents,
128        "window.domAutomationController.send(EmbeddedPluginCreated());",
129        &embedded_plugin_created));
130    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
131        web_contents,
132        "window.domAutomationController.send(ContentHandlerPluginCreated());",
133        &content_handler_plugin_created));
134
135    EXPECT_EQ(embedded_plugin_created,
136              (expected_to_succeed & PLUGIN_TYPE_EMBED) != 0);
137    EXPECT_EQ(content_handler_plugin_created,
138              (expected_to_succeed & PLUGIN_TYPE_CONTENT_HANDLER) != 0);
139  }
140
141  void CheckPluginsCreated(const Extension* extension,
142                           PluginType expected_to_succeed) {
143    CheckPluginsCreated(extension->GetResourceURL("test.html"),
144                        expected_to_succeed);
145  }
146
147};
148
149// Test that the NaCl plugin isn't blocked for Webstore extensions.
150// Disabled: http://crbug.com/319892
151IN_PROC_BROWSER_TEST_F(NaClExtensionTest, DISABLED_WebStoreExtension) {
152  ASSERT_TRUE(test_server()->Start());
153
154  const Extension* extension = InstallExtension(INSTALL_TYPE_FROM_WEBSTORE);
155  ASSERT_TRUE(extension);
156  CheckPluginsCreated(extension, PLUGIN_TYPE_ALL);
157}
158
159// Test that the NaCl plugin is blocked for non-Webstore extensions.
160// Disabled: http://crbug.com/319892
161IN_PROC_BROWSER_TEST_F(NaClExtensionTest, DISABLED_NonWebStoreExtension) {
162  ASSERT_TRUE(test_server()->Start());
163
164  const Extension* extension = InstallExtension(INSTALL_TYPE_NON_WEBSTORE);
165  ASSERT_TRUE(extension);
166  CheckPluginsCreated(extension, PLUGIN_TYPE_NONE);
167}
168
169// Test that the NaCl plugin isn't blocked for component extensions.
170// Disabled: http://crbug.com/319892
171IN_PROC_BROWSER_TEST_F(NaClExtensionTest, DISABLED_ComponentExtension) {
172  ASSERT_TRUE(test_server()->Start());
173
174  const Extension* extension = InstallExtension(INSTALL_TYPE_COMPONENT);
175  ASSERT_TRUE(extension);
176  ASSERT_EQ(extension->location(), Manifest::COMPONENT);
177  CheckPluginsCreated(extension, PLUGIN_TYPE_ALL);
178}
179
180// Test that the NaCl plugin isn't blocked for unpacked extensions.
181// Disabled: http://crbug.com/319892
182IN_PROC_BROWSER_TEST_F(NaClExtensionTest, DISABLED_UnpackedExtension) {
183  ASSERT_TRUE(test_server()->Start());
184
185  const Extension* extension = InstallExtension(INSTALL_TYPE_UNPACKED);
186  ASSERT_TRUE(extension);
187  ASSERT_EQ(extension->location(), Manifest::UNPACKED);
188  CheckPluginsCreated(extension, PLUGIN_TYPE_ALL);
189}
190
191// Test that the NaCl plugin is blocked for non chrome-extension urls, except
192// if it's a content (MIME type) handler.
193// Disabled: http://crbug.com/319892
194IN_PROC_BROWSER_TEST_F(NaClExtensionTest, DISABLED_NonExtensionScheme) {
195  ASSERT_TRUE(test_server()->Start());
196
197  const Extension* extension = InstallExtension(INSTALL_TYPE_FROM_WEBSTORE);
198  ASSERT_TRUE(extension);
199  CheckPluginsCreated(
200      test_server()->GetURL("files/extensions/native_client/test.html"),
201      PLUGIN_TYPE_CONTENT_HANDLER);
202}
203
204// Test that NaCl plugin isn't blocked for hosted app URLs.
205IN_PROC_BROWSER_TEST_F(NaClExtensionTest, HostedApp) {
206  host_resolver()->AddRule("*", "127.0.0.1");
207  ASSERT_TRUE(test_server()->Start());
208
209  GURL url = test_server()->GetURL("files/extensions/native_client/test.html");
210  GURL::Replacements replace_host;
211  std::string host_str("localhost");
212  replace_host.SetHostStr(host_str);
213  replace_host.ClearPort();
214  url = url.ReplaceComponents(replace_host);
215
216  const Extension* extension = InstallHostedApp();
217  ASSERT_TRUE(extension);
218  CheckPluginsCreated(url, PLUGIN_TYPE_ALL);
219}
220
221}  // namespace
222