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