blob: 04411fffb19229c36bc29d527069f5435ae3cb80 [file] [log] [blame]
kalman30a92f962015-09-03 18:08:201// Copyright 2015 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/files/file_path.h"
6#include "base/strings/stringprintf.h"
7#include "chrome/browser/extensions/extension_apitest.h"
8#include "chrome/browser/extensions/test_extension_dir.h"
thestige80821242015-09-30 23:46:089#include "chrome/browser/ui/browser_navigator_params.h"
kalman30a92f962015-09-03 18:08:2010#include "chrome/browser/ui/tabs/tab_strip_model.h"
11#include "chrome/test/base/ui_test_utils.h"
12#include "content/public/browser/web_contents.h"
13#include "content/public/test/browser_test_utils.h"
14#include "extensions/common/extension.h"
15#include "net/dns/mock_host_resolver.h"
16#include "net/test/embedded_test_server/embedded_test_server.h"
17
18namespace extensions {
19
20namespace {
21
22// JavaScript snippet which performs a fetch given a URL expression to be
23// substituted as %s, then sends back the fetched content using the
24// domAutomationController.
25const char* kFetchScript =
26 "fetch(%s).then(function(result) {\n"
27 " return result.text();\n"
28 "}).then(function(text) {\n"
29 " window.domAutomationController.send(text);\n"
30 "}).catch(function(err) {\n"
31 " window.domAutomationController.send(String(err));\n"
32 "});\n";
33
34class ExtensionFetchTest : public ExtensionApiTest {
35 protected:
36 // Writes an empty background page and a text file called "text" with content
37 // "text content", then loads and returns the extension. |dir| must already
38 // have a manifest.
39 const Extension* WriteFilesAndLoadTestExtension(TestExtensionDir* dir) {
40 dir->WriteFile(FILE_PATH_LITERAL("text"), "text content");
41 dir->WriteFile(FILE_PATH_LITERAL("bg.js"), "");
vabr9142fe22016-09-08 13:19:2242 return LoadExtension(dir->UnpackedPath());
kalman30a92f962015-09-03 18:08:2043 }
44
45 // Returns |kFetchScript| with |url_expression| substituted as its test URL.
46 std::string GetFetchScript(const std::string& url_expression) {
47 return base::StringPrintf(kFetchScript, url_expression.c_str());
48 }
49
50 // Returns |url| as a string surrounded by single quotes, for passing to
51 // JavaScript as a string literal.
52 std::string GetQuotedURL(const GURL& url) {
53 return base::StringPrintf("'%s'", url.spec().c_str());
54 }
55
56 // Like GetQuotedURL(), but fetching the URL from the test server's |host|
57 // and |path|.
58 std::string GetQuotedTestServerURL(const std::string& host,
59 const std::string& path) {
60 return GetQuotedURL(embedded_test_server()->GetURL(host, path));
61 }
62
63 // Opens a tab, puts it in the foreground, navigates it to |url| then returns
64 // its WebContents.
65 content::WebContents* CreateAndNavigateTab(const GURL& url) {
cm.sanchi2522bc92017-12-04 08:04:1366 NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK);
nick3b04f322016-08-31 19:29:1967 params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
kalman30a92f962015-09-03 18:08:2068 ui_test_utils::NavigateToURL(&params);
69 return browser()->tab_strip_model()->GetActiveWebContents();
70 }
71
72 private:
73 void SetUpOnMainThread() override {
74 ExtensionApiTest::SetUpOnMainThread();
75 host_resolver()->AddRule("*", "127.0.0.1");
76 ASSERT_TRUE(StartEmbeddedTestServer());
77 }
78};
79
80IN_PROC_BROWSER_TEST_F(ExtensionFetchTest, ExtensionCanFetchExtensionResource) {
81 TestExtensionDir dir;
82 dir.WriteManifestWithSingleQuotes(
83 "{"
84 "'background': {'scripts': ['bg.js']},"
85 "'manifest_version': 2,"
86 "'name': 'ExtensionCanFetchExtensionResource',"
87 "'version': '1'"
88 "}");
89 const Extension* extension = WriteFilesAndLoadTestExtension(&dir);
90 ASSERT_TRUE(extension);
91
92 EXPECT_EQ(
93 "text content",
94 ExecuteScriptInBackgroundPage(
95 extension->id(), GetFetchScript("chrome.runtime.getURL('text')")));
96}
97
98IN_PROC_BROWSER_TEST_F(ExtensionFetchTest,
99 ExtensionCanFetchHostedResourceWithHostPermissions) {
100 TestExtensionDir dir;
101 dir.WriteManifestWithSingleQuotes(
102 "{"
103 "'background': {'scripts': ['bg.js']},"
104 "'manifest_version': 2,"
105 "'name': 'ExtensionCanFetchHostedResourceWithHostPermissions',"
106 "'permissions': ['http://example.com/*'],"
107 "'version': '1'"
108 "}");
109 const Extension* extension = WriteFilesAndLoadTestExtension(&dir);
110 ASSERT_TRUE(extension);
111
112 EXPECT_EQ("Hello!", ExecuteScriptInBackgroundPage(
113 extension->id(),
114 GetFetchScript(GetQuotedTestServerURL(
115 "example.com", "/extensions/test_file.txt"))));
116}
117
118IN_PROC_BROWSER_TEST_F(
119 ExtensionFetchTest,
120 ExtensionCannotFetchHostedResourceWithoutHostPermissions) {
121 TestExtensionDir dir;
122 dir.WriteManifestWithSingleQuotes(
123 "{"
124 "'background': {'scripts': ['bg.js']},"
125 "'manifest_version': 2,"
126 "'name': 'ExtensionCannotFetchHostedResourceWithoutHostPermissions',"
127 "'version': '1'"
128 "}");
129 const Extension* extension = WriteFilesAndLoadTestExtension(&dir);
130 ASSERT_TRUE(extension);
131
132 // TODO(kalman): Another test would be to configure the test server to work
133 // with CORS, and test that the fetch succeeds.
134 EXPECT_EQ(
135 "TypeError: Failed to fetch",
136 ExecuteScriptInBackgroundPage(
137 extension->id(), GetFetchScript(GetQuotedTestServerURL(
138 "example.com", "/extensions/test_file.txt"))));
139}
140
141IN_PROC_BROWSER_TEST_F(ExtensionFetchTest,
142 HostCanFetchWebAccessibleExtensionResource) {
143 TestExtensionDir dir;
144 dir.WriteManifestWithSingleQuotes(
145 "{"
146 "'background': {'scripts': ['bg.js']},"
147 "'manifest_version': 2,"
148 "'name': 'HostCanFetchWebAccessibleExtensionResource',"
149 "'version': '1',"
150 "'web_accessible_resources': ['text']"
151 "}");
152 const Extension* extension = WriteFilesAndLoadTestExtension(&dir);
153 ASSERT_TRUE(extension);
154
155 content::WebContents* empty_tab = CreateAndNavigateTab(
156 embedded_test_server()->GetURL("example.com", "/empty.html"));
157
158 // TODO(kalman): Test this from a content script too.
159 std::string fetch_result;
160 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
161 empty_tab,
162 GetFetchScript(GetQuotedURL(extension->GetResourceURL("text"))),
163 &fetch_result));
164 EXPECT_EQ("text content", fetch_result);
165}
166
167IN_PROC_BROWSER_TEST_F(ExtensionFetchTest,
168 HostCannotFetchNonWebAccessibleExtensionResource) {
169 TestExtensionDir dir;
170 dir.WriteManifestWithSingleQuotes(
171 "{"
172 "'background': {'scripts': ['bg.js']},"
173 "'manifest_version': 2,"
174 "'name': 'HostCannotFetchNonWebAccessibleExtensionResource',"
175 "'version': '1'"
176 "}");
177 const Extension* extension = WriteFilesAndLoadTestExtension(&dir);
178 ASSERT_TRUE(extension);
179
180 content::WebContents* empty_tab = CreateAndNavigateTab(
181 embedded_test_server()->GetURL("example.com", "/empty.html"));
182
183 // TODO(kalman): Test this from a content script too.
184 std::string fetch_result;
185 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
186 empty_tab,
187 GetFetchScript(GetQuotedURL(extension->GetResourceURL("text"))),
188 &fetch_result));
189 EXPECT_EQ("TypeError: Failed to fetch", fetch_result);
190}
191
192} // namespace
193
194} // namespace extensions