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/base64.h"
6 #include "base/files/file_path.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/path_service.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
17 #include "chrome/browser/extensions/extension_apitest.h"
18 #include "chrome/browser/extensions/test_extension_dir.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "content/public/browser/notification_registrar.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "extensions/browser/event_router.h"
29 #include "extensions/browser/extension_prefs.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/common/api/runtime.h"
32 #include "extensions/common/extension_builder.h"
33 #include "extensions/common/value_builder.h"
34 #include "net/cert/asn1_util.h"
35 #include "net/cert/jwk_serializer.h"
36 #include "net/dns/mock_host_resolver.h"
37 #include "net/ssl/server_bound_cert_service.h"
38 #include "net/test/embedded_test_server/embedded_test_server.h"
39 #include "net/url_request/url_request_context.h"
40 #include "net/url_request/url_request_context_getter.h"
41 #include "url/gurl.h"
42
43 namespace extensions {
44 namespace {
45
46 class MessageSender : public content::NotificationObserver {
47 public:
MessageSender()48 MessageSender() {
49 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
50 content::NotificationService::AllSources());
51 }
52
53 private:
BuildEventArguments(const bool last_message,const std::string & data)54 static scoped_ptr<base::ListValue> BuildEventArguments(
55 const bool last_message,
56 const std::string& data) {
57 base::DictionaryValue* event = new base::DictionaryValue();
58 event->SetBoolean("lastMessage", last_message);
59 event->SetString("data", data);
60 scoped_ptr<base::ListValue> arguments(new base::ListValue());
61 arguments->Append(event);
62 return arguments.Pass();
63 }
64
BuildEvent(scoped_ptr<base::ListValue> event_args,Profile * profile,GURL event_url)65 static scoped_ptr<Event> BuildEvent(scoped_ptr<base::ListValue> event_args,
66 Profile* profile,
67 GURL event_url) {
68 scoped_ptr<Event> event(new Event("test.onMessage", event_args.Pass()));
69 event->restrict_to_browser_context = profile;
70 event->event_url = event_url;
71 return event.Pass();
72 }
73
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)74 virtual void Observe(int type,
75 const content::NotificationSource& source,
76 const content::NotificationDetails& details) OVERRIDE {
77 EventRouter* event_router =
78 EventRouter::Get(content::Source<Profile>(source).ptr());
79
80 // Sends four messages to the extension. All but the third message sent
81 // from the origin http://b.com/ are supposed to arrive.
82 event_router->BroadcastEvent(BuildEvent(
83 BuildEventArguments(false, "no restriction"),
84 content::Source<Profile>(source).ptr(),
85 GURL()));
86 event_router->BroadcastEvent(BuildEvent(
87 BuildEventArguments(false, "http://a.com/"),
88 content::Source<Profile>(source).ptr(),
89 GURL("http://a.com/")));
90 event_router->BroadcastEvent(BuildEvent(
91 BuildEventArguments(false, "http://b.com/"),
92 content::Source<Profile>(source).ptr(),
93 GURL("http://b.com/")));
94 event_router->BroadcastEvent(BuildEvent(
95 BuildEventArguments(true, "last message"),
96 content::Source<Profile>(source).ptr(),
97 GURL()));
98 }
99
100 content::NotificationRegistrar registrar_;
101 };
102
103 // Tests that message passing between extensions and content scripts works.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,Messaging)104 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) {
105 ASSERT_TRUE(StartEmbeddedTestServer());
106 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_;
107 }
108
109 // Tests that message passing from one extension to another works.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MessagingExternal)110 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) {
111 ASSERT_TRUE(LoadExtension(
112 test_data_dir_.AppendASCII("..").AppendASCII("good")
113 .AppendASCII("Extensions")
114 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
115 .AppendASCII("1.0")));
116
117 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_;
118 }
119
120 // Tests that messages with event_urls are only passed to extensions with
121 // appropriate permissions.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MessagingEventURL)122 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingEventURL) {
123 MessageSender sender;
124 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_;
125 }
126
127 // Tests connecting from a panel to its extension.
128 class PanelMessagingTest : public ExtensionApiTest {
SetUpCommandLine(CommandLine * command_line)129 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
130 ExtensionApiTest::SetUpCommandLine(command_line);
131 command_line->AppendSwitch(switches::kEnablePanels);
132 }
133 };
134
IN_PROC_BROWSER_TEST_F(PanelMessagingTest,MessagingPanel)135 IN_PROC_BROWSER_TEST_F(PanelMessagingTest, MessagingPanel) {
136 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_;
137 }
138
139 // XXX(kalman): All web messaging tests disabled on windows due to extreme
140 // flakiness. See http://crbug.com/350517.
141 #if !defined(OS_WIN)
142
143 // Tests externally_connectable between a web page and an extension.
144 //
145 // TODO(kalman): Test between extensions. This is already tested in this file,
146 // but not with externally_connectable set in the manifest.
147 //
148 // TODO(kalman): Test with host permissions.
149 class ExternallyConnectableMessagingTest : public ExtensionApiTest {
150 protected:
151 // Result codes from the test. These must match up with |results| in
152 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
153 enum Result {
154 OK = 0,
155 NAMESPACE_NOT_DEFINED = 1,
156 FUNCTION_NOT_DEFINED = 2,
157 COULD_NOT_ESTABLISH_CONNECTION_ERROR = 3,
158 OTHER_ERROR = 4,
159 INCORRECT_RESPONSE_SENDER = 5,
160 INCORRECT_RESPONSE_MESSAGE = 6,
161 };
162
AppendIframe(const GURL & src)163 bool AppendIframe(const GURL& src) {
164 bool result;
165 CHECK(content::ExecuteScriptAndExtractBool(
166 browser()->tab_strip_model()->GetActiveWebContents(),
167 "actions.appendIframe('" + src.spec() + "');", &result));
168 return result;
169 }
170
CanConnectAndSendMessagesToMainFrame(const Extension * extension,const char * message=NULL)171 Result CanConnectAndSendMessagesToMainFrame(const Extension* extension,
172 const char* message = NULL) {
173 return CanConnectAndSendMessagesToFrame(
174 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
175 extension,
176 message);
177 }
178
CanConnectAndSendMessagesToIFrame(const Extension * extension,const char * message=NULL)179 Result CanConnectAndSendMessagesToIFrame(const Extension* extension,
180 const char* message = NULL) {
181 content::RenderFrameHost* frame = content::FrameMatchingPredicate(
182 browser()->tab_strip_model()->GetActiveWebContents(),
183 base::Bind(&content::FrameIsChildOfMainFrame));
184 return CanConnectAndSendMessagesToFrame(frame, extension, message);
185 }
186
CanConnectAndSendMessagesToFrame(content::RenderFrameHost * frame,const Extension * extension,const char * message)187 Result CanConnectAndSendMessagesToFrame(content::RenderFrameHost* frame,
188 const Extension* extension,
189 const char* message) {
190 int result;
191 std::string command = base::StringPrintf(
192 "assertions.canConnectAndSendMessages('%s', %s, %s)",
193 extension->id().c_str(),
194 extension->is_platform_app() ? "true" : "false",
195 message ? base::StringPrintf("'%s'", message).c_str() : "undefined");
196 CHECK(content::ExecuteScriptAndExtractInt(frame, command, &result));
197 return static_cast<Result>(result);
198 }
199
AreAnyNonWebApisDefinedForMainFrame()200 testing::AssertionResult AreAnyNonWebApisDefinedForMainFrame() {
201 return AreAnyNonWebApisDefinedForFrame(
202 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
203 }
204
AreAnyNonWebApisDefinedForIFrame()205 testing::AssertionResult AreAnyNonWebApisDefinedForIFrame() {
206 content::RenderFrameHost* frame = content::FrameMatchingPredicate(
207 browser()->tab_strip_model()->GetActiveWebContents(),
208 base::Bind(&content::FrameIsChildOfMainFrame));
209 return AreAnyNonWebApisDefinedForFrame(frame);
210 }
211
AreAnyNonWebApisDefinedForFrame(content::RenderFrameHost * frame)212 testing::AssertionResult AreAnyNonWebApisDefinedForFrame(
213 content::RenderFrameHost* frame) {
214 // All runtime API methods are non-web except for sendRequest and connect.
215 const char* non_messaging_apis[] = {
216 "getBackgroundPage",
217 "getManifest",
218 "getURL",
219 "reload",
220 "requestUpdateCheck",
221 "restart",
222 "connectNative",
223 "sendNativeMessage",
224 "onStartup",
225 "onInstalled",
226 "onSuspend",
227 "onSuspendCanceled",
228 "onUpdateAvailable",
229 "onBrowserUpdateAvailable",
230 "onConnect",
231 "onConnectExternal",
232 "onMessage",
233 "onMessageExternal",
234 "onRestartRequired",
235 // Note: no "id" here because this test method is used for hosted apps,
236 // which do have access to runtime.id.
237 };
238
239 // Turn the array into a JS array, which effectively gets eval()ed.
240 std::string as_js_array;
241 for (size_t i = 0; i < arraysize(non_messaging_apis); ++i) {
242 as_js_array += as_js_array.empty() ? "[" : ",";
243 as_js_array += base::StringPrintf("'%s'", non_messaging_apis[i]);
244 }
245 as_js_array += "]";
246
247 bool any_defined;
248 CHECK(content::ExecuteScriptAndExtractBool(
249 frame,
250 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
251 &any_defined));
252 return any_defined ?
253 testing::AssertionSuccess() : testing::AssertionFailure();
254 }
255
GetTlsChannelIdFromPortConnect(const Extension * extension,bool include_tls_channel_id,const char * message=NULL)256 std::string GetTlsChannelIdFromPortConnect(const Extension* extension,
257 bool include_tls_channel_id,
258 const char* message = NULL) {
259 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
260 extension,
261 include_tls_channel_id,
262 message);
263 }
264
GetTlsChannelIdFromSendMessage(const Extension * extension,bool include_tls_channel_id,const char * message=NULL)265 std::string GetTlsChannelIdFromSendMessage(const Extension* extension,
266 bool include_tls_channel_id,
267 const char* message = NULL) {
268 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
269 extension,
270 include_tls_channel_id,
271 message);
272 }
273
GetURLForPath(const std::string & host,const std::string & path)274 GURL GetURLForPath(const std::string& host, const std::string& path) {
275 std::string port = base::IntToString(embedded_test_server()->port());
276 GURL::Replacements replacements;
277 replacements.SetHostStr(host);
278 replacements.SetPortStr(port);
279 return embedded_test_server()->GetURL(path).ReplaceComponents(replacements);
280 }
281
chromium_org_url()282 GURL chromium_org_url() {
283 return GetURLForPath("www.chromium.org", "/chromium.org.html");
284 }
285
google_com_url()286 GURL google_com_url() {
287 return GetURLForPath("www.google.com", "/google.com.html");
288 }
289
LoadChromiumConnectableExtension()290 scoped_refptr<const Extension> LoadChromiumConnectableExtension() {
291 scoped_refptr<const Extension> extension =
292 LoadExtensionIntoDir(&web_connectable_dir_,
293 base::StringPrintf(
294 "{"
295 " \"name\": \"chromium_connectable\","
296 " %s,"
297 " \"externally_connectable\": {"
298 " \"matches\": [\"*://*.chromium.org:*/*\"]"
299 " }"
300 "}",
301 common_manifest()));
302 CHECK(extension.get());
303 return extension;
304 }
305
LoadChromiumConnectableApp()306 scoped_refptr<const Extension> LoadChromiumConnectableApp() {
307 scoped_refptr<const Extension> extension =
308 LoadExtensionIntoDir(&web_connectable_dir_,
309 "{"
310 " \"app\": {"
311 " \"background\": {"
312 " \"scripts\": [\"background.js\"]"
313 " }"
314 " },"
315 " \"externally_connectable\": {"
316 " \"matches\": [\"*://*.chromium.org:*/*\"]"
317 " },"
318 " \"manifest_version\": 2,"
319 " \"name\": \"app_connectable\","
320 " \"version\": \"1.0\""
321 "}");
322 CHECK(extension.get());
323 return extension;
324 }
325
LoadNotConnectableExtension()326 scoped_refptr<const Extension> LoadNotConnectableExtension() {
327 scoped_refptr<const Extension> extension =
328 LoadExtensionIntoDir(¬_connectable_dir_,
329 base::StringPrintf(
330 "{"
331 " \"name\": \"not_connectable\","
332 " %s"
333 "}",
334 common_manifest()));
335 CHECK(extension.get());
336 return extension;
337 }
338
339 scoped_refptr<const Extension>
LoadChromiumConnectableExtensionWithTlsChannelId()340 LoadChromiumConnectableExtensionWithTlsChannelId() {
341 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_,
342 connectable_with_tls_channel_id_manifest());
343 }
344
LoadChromiumHostedApp()345 scoped_refptr<const Extension> LoadChromiumHostedApp() {
346 scoped_refptr<const Extension> hosted_app =
347 LoadExtensionIntoDir(&hosted_app_dir_,
348 base::StringPrintf(
349 "{"
350 " \"name\": \"chromium_hosted_app\","
351 " \"version\": \"1.0\","
352 " \"manifest_version\": 2,"
353 " \"app\": {"
354 " \"urls\": [\"%s\"],"
355 " \"launch\": {"
356 " \"web_url\": \"%s\""
357 " }\n"
358 " }\n"
359 "}",
360 chromium_org_url().spec().c_str(),
361 chromium_org_url().spec().c_str()));
362 CHECK(hosted_app.get());
363 return hosted_app;
364 }
365
InitializeTestServer()366 void InitializeTestServer() {
367 base::FilePath test_data;
368 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
369 embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII(
370 "extensions/api_test/messaging/externally_connectable/sites"));
371 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
372 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
373 }
374
close_background_message()375 const char* close_background_message() {
376 return "closeBackgroundPage";
377 }
378
379 private:
LoadExtensionIntoDir(TestExtensionDir * dir,const std::string & manifest)380 scoped_refptr<const Extension> LoadExtensionIntoDir(
381 TestExtensionDir* dir,
382 const std::string& manifest) {
383 dir->WriteManifest(manifest);
384 dir->WriteFile(FILE_PATH_LITERAL("background.js"),
385 base::StringPrintf(
386 "function maybeClose(message) {\n"
387 " if (message.indexOf('%s') >= 0)\n"
388 " window.setTimeout(function() { window.close() }, 0);\n"
389 "}\n"
390 "chrome.runtime.onMessageExternal.addListener(\n"
391 " function(message, sender, reply) {\n"
392 " reply({ message: message, sender: sender });\n"
393 " maybeClose(message);\n"
394 "});\n"
395 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
396 " port.onMessage.addListener(function(message) {\n"
397 " port.postMessage({ message: message, sender: port.sender });\n"
398 " maybeClose(message);\n"
399 " });\n"
400 "});\n",
401 close_background_message()));
402 return LoadExtension(dir->unpacked_path());
403 }
404
common_manifest()405 const char* common_manifest() {
406 return "\"version\": \"1.0\","
407 "\"background\": {"
408 " \"scripts\": [\"background.js\"],"
409 " \"persistent\": false"
410 "},"
411 "\"manifest_version\": 2";
412 }
413
connectable_with_tls_channel_id_manifest()414 std::string connectable_with_tls_channel_id_manifest() {
415 return base::StringPrintf(
416 "{"
417 " \"name\": \"chromium_connectable_with_tls_channel_id\","
418 " %s,"
419 " \"externally_connectable\": {"
420 " \"matches\": [\"*://*.chromium.org:*/*\"],"
421 " \"accepts_tls_channel_id\": true"
422 " }"
423 "}",
424 common_manifest());
425 }
426
GetTlsChannelIdFromAssertion(const char * method,const Extension * extension,bool include_tls_channel_id,const char * message)427 std::string GetTlsChannelIdFromAssertion(const char* method,
428 const Extension* extension,
429 bool include_tls_channel_id,
430 const char* message) {
431 std::string result;
432 std::string args = "'" + extension->id() + "', ";
433 args += include_tls_channel_id ? "true" : "false";
434 if (message)
435 args += std::string(", '") + message + "'";
436 CHECK(content::ExecuteScriptAndExtractString(
437 browser()->tab_strip_model()->GetActiveWebContents(),
438 base::StringPrintf("assertions.%s(%s)", method, args.c_str()),
439 &result));
440 return result;
441 }
442
443 TestExtensionDir web_connectable_dir_;
444 TestExtensionDir not_connectable_dir_;
445 TestExtensionDir tls_channel_id_connectable_dir_;
446 TestExtensionDir hosted_app_dir_;
447 };
448
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,NotInstalled)449 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, NotInstalled) {
450 InitializeTestServer();
451
452 scoped_refptr<const Extension> extension =
453 ExtensionBuilder()
454 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
455 .SetManifest(DictionaryBuilder()
456 .Set("name", "Fake extension")
457 .Set("version", "1")
458 .Set("manifest_version", 2))
459 .Build();
460
461 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
462 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
463 CanConnectAndSendMessagesToMainFrame(extension));
464 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
465
466 ui_test_utils::NavigateToURL(browser(), google_com_url());
467 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
468 CanConnectAndSendMessagesToMainFrame(extension));
469 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
470 }
471
472 // Tests two extensions on the same sites: one web connectable, one not.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableAndNotConnectable)473 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
474 WebConnectableAndNotConnectable) {
475 InitializeTestServer();
476
477 // Install the web connectable extension. chromium.org can connect to it,
478 // google.com can't.
479 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
480
481 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
482 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(chromium_connectable));
483 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
484
485 ui_test_utils::NavigateToURL(browser(), google_com_url());
486 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
487 CanConnectAndSendMessagesToMainFrame(chromium_connectable));
488 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
489
490 // Install the non-connectable extension. Nothing can connect to it.
491 const Extension* not_connectable = LoadNotConnectableExtension();
492
493 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
494 // Namespace will be defined here because |chromium_connectable| can connect
495 // to it - so this will be the "cannot establish connection" error.
496 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
497 CanConnectAndSendMessagesToMainFrame(not_connectable));
498 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
499
500 ui_test_utils::NavigateToURL(browser(), google_com_url());
501 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
502 CanConnectAndSendMessagesToMainFrame(not_connectable));
503 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
504 }
505
506 // See http://crbug.com/297866
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,DISABLED_BackgroundPageClosesOnMessageReceipt)507 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
508 DISABLED_BackgroundPageClosesOnMessageReceipt) {
509 InitializeTestServer();
510
511 // Install the web connectable extension.
512 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
513
514 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
515 // If the background page closes after receipt of the message, it will still
516 // reply to this message...
517 EXPECT_EQ(OK,
518 CanConnectAndSendMessagesToMainFrame(chromium_connectable,
519 close_background_message()));
520 // and be re-opened by receipt of a subsequent message.
521 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(chromium_connectable));
522 }
523
524 // Tests a web connectable extension that doesn't receive TLS channel id.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableWithoutTlsChannelId)525 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
526 WebConnectableWithoutTlsChannelId) {
527 InitializeTestServer();
528
529 // Install the web connectable extension. chromium.org can connect to it,
530 // google.com can't.
531 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
532 ASSERT_TRUE(chromium_connectable);
533
534 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
535 // The web connectable extension doesn't request the TLS channel ID, so it
536 // doesn't get it, whether or not the page asks for it.
537 EXPECT_EQ(std::string(),
538 GetTlsChannelIdFromPortConnect(chromium_connectable, false));
539 EXPECT_EQ(std::string(),
540 GetTlsChannelIdFromSendMessage(chromium_connectable, true));
541 EXPECT_EQ(std::string(),
542 GetTlsChannelIdFromPortConnect(chromium_connectable, false));
543 EXPECT_EQ(std::string(),
544 GetTlsChannelIdFromSendMessage(chromium_connectable, true));
545 }
546
547 // Tests a web connectable extension that receives TLS channel id with a site
548 // that can't connect to it.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableWithTlsChannelIdWithNonMatchingSite)549 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
550 WebConnectableWithTlsChannelIdWithNonMatchingSite) {
551 InitializeTestServer();
552
553 const Extension* chromium_connectable =
554 LoadChromiumConnectableExtensionWithTlsChannelId();
555 ASSERT_TRUE(chromium_connectable);
556
557 ui_test_utils::NavigateToURL(browser(), google_com_url());
558 // The extension requests the TLS channel ID, but it doesn't get it for a
559 // site that can't connect to it, regardless of whether the page asks for it.
560 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
561 GetTlsChannelIdFromPortConnect(chromium_connectable, false));
562 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
563 GetTlsChannelIdFromSendMessage(chromium_connectable, true));
564 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
565 GetTlsChannelIdFromPortConnect(chromium_connectable, false));
566 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
567 GetTlsChannelIdFromSendMessage(chromium_connectable, true));
568 }
569
570 // Tests a web connectable extension that receives TLS channel id on a site
571 // that can connect to it, but with no TLS channel ID having been generated.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableWithTlsChannelIdWithEmptyTlsChannelId)572 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
573 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId) {
574 InitializeTestServer();
575
576 const Extension* chromium_connectable =
577 LoadChromiumConnectableExtensionWithTlsChannelId();
578 ASSERT_TRUE(chromium_connectable);
579
580 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
581
582 // Since the extension requests the TLS channel ID, it gets it for a site that
583 // can connect to it, but only if the page also asks to include it.
584 EXPECT_EQ(std::string(),
585 GetTlsChannelIdFromPortConnect(chromium_connectable, false));
586 EXPECT_EQ(std::string(),
587 GetTlsChannelIdFromSendMessage(chromium_connectable, false));
588 // If the page does ask for it, it isn't empty.
589 std::string tls_channel_id =
590 GetTlsChannelIdFromPortConnect(chromium_connectable, true);
591 // Because the TLS channel ID has never been generated for this domain,
592 // no TLS channel ID is reported.
593 EXPECT_EQ(std::string(), tls_channel_id);
594 }
595
596 // Flaky on Linux and Windows. http://crbug.com/315264
597 // Tests a web connectable extension that receives TLS channel id, but
598 // immediately closes its background page upon receipt of a message.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage)599 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
600 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage) {
601 InitializeTestServer();
602
603 const Extension* chromium_connectable =
604 LoadChromiumConnectableExtensionWithTlsChannelId();
605
606 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
607 // If the page does ask for it, it isn't empty, even if the background page
608 // closes upon receipt of the connect.
609 std::string tls_channel_id = GetTlsChannelIdFromPortConnect(
610 chromium_connectable, true, close_background_message());
611 // Because the TLS channel ID has never been generated for this domain,
612 // no TLS channel ID is reported.
613 EXPECT_EQ(std::string(), tls_channel_id);
614 // A subsequent connect will still succeed, even if the background page was
615 // previously closed.
616 tls_channel_id = GetTlsChannelIdFromPortConnect(chromium_connectable, true);
617 // And the empty value is still retrieved.
618 EXPECT_EQ(std::string(), tls_channel_id);
619 }
620
621 // Tests that enabling and disabling an extension makes the runtime bindings
622 // appear and disappear.
623 //
624 // TODO(kalman): Test with multiple extensions that can be accessed by the same
625 // host.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,EnablingAndDisabling)626 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
627 EnablingAndDisabling) {
628 InitializeTestServer();
629
630 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
631 const Extension* not_connectable = LoadNotConnectableExtension();
632
633 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
634 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(chromium_connectable));
635 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
636 CanConnectAndSendMessagesToMainFrame(not_connectable));
637
638 DisableExtension(chromium_connectable->id());
639 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
640 CanConnectAndSendMessagesToMainFrame(chromium_connectable));
641
642 EnableExtension(chromium_connectable->id());
643 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(chromium_connectable));
644 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
645 CanConnectAndSendMessagesToMainFrame(not_connectable));
646 }
647
648 // Tests connection from incognito tabs when the user denies the connection
649 // request. Spanning mode only. A separate test for apps and extensions.
650 //
651 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
652 // somewhere. This is a test that should be shared with the content script logic
653 // so it's not really our specific concern for web connectable.
654 //
655 // TODO(kalman): test messages from incognito extensions too.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoDenyApp)656 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
657 FromIncognitoDenyApp) {
658 InitializeTestServer();
659
660 scoped_refptr<const Extension> app = LoadChromiumConnectableApp();
661 ASSERT_TRUE(app->is_platform_app());
662
663 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
664 profile()->GetOffTheRecordProfile(),
665 chromium_org_url());
666 content::RenderFrameHost* incognito_frame = incognito_browser->
667 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
668
669 {
670 IncognitoConnectability::ScopedAlertTracker alert_tracker(
671 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
672
673 // No connection because incognito-enabled hasn't been set for the app, and
674 // the user denied our interactive request.
675 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
676 CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
677 EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
678
679 // Try again. User has already denied so alert not shown.
680 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
681 CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
682 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
683 }
684
685 // It's not possible to allow an app in incognito.
686 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app->id(), true);
687 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
688 CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
689 }
690
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoDenyExtension)691 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
692 FromIncognitoDenyExtension) {
693 InitializeTestServer();
694
695 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
696
697 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
698 profile()->GetOffTheRecordProfile(), chromium_org_url());
699 content::RenderFrameHost* incognito_frame =
700 incognito_browser->tab_strip_model()
701 ->GetActiveWebContents()
702 ->GetMainFrame();
703
704 {
705 IncognitoConnectability::ScopedAlertTracker alert_tracker(
706 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
707
708 // The alert doesn't show for extensions.
709 EXPECT_EQ(
710 COULD_NOT_ESTABLISH_CONNECTION_ERROR,
711 CanConnectAndSendMessagesToFrame(incognito_frame, extension, NULL));
712 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
713 }
714
715 // Allowing the extension in incognito mode will bypass the deny.
716 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension->id(), true);
717 EXPECT_EQ(OK,
718 CanConnectAndSendMessagesToFrame(incognito_frame, extension, NULL));
719 }
720
721 // Tests connection from incognito tabs when the user accepts the connection
722 // request. Spanning mode only. Separate tests for apps and extensions.
723 //
724 // TODO(kalman): see comment above about split mode.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoAllowApp)725 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
726 FromIncognitoAllowApp) {
727 InitializeTestServer();
728
729 scoped_refptr<const Extension> app = LoadChromiumConnectableApp();
730 ASSERT_TRUE(app->is_platform_app());
731
732 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
733 profile()->GetOffTheRecordProfile(),
734 chromium_org_url());
735 content::RenderFrameHost* incognito_frame = incognito_browser->
736 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
737
738 {
739 IncognitoConnectability::ScopedAlertTracker alert_tracker(
740 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
741
742 // Connection allowed even with incognito disabled, because the user
743 // accepted the interactive request.
744 EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
745 EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
746
747 // Try again. User has already allowed.
748 EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
749 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
750 }
751
752 // Apps can't be allowed in incognito mode, but it's moot because it's
753 // already allowed.
754 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app->id(), true);
755 EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
756 }
757
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoAllowExtension)758 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
759 FromIncognitoAllowExtension) {
760 InitializeTestServer();
761
762 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
763
764 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
765 profile()->GetOffTheRecordProfile(), chromium_org_url());
766 content::RenderFrameHost* incognito_frame =
767 incognito_browser->tab_strip_model()
768 ->GetActiveWebContents()
769 ->GetMainFrame();
770
771 {
772 IncognitoConnectability::ScopedAlertTracker alert_tracker(
773 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
774
775 // No alert is shown.
776 EXPECT_EQ(
777 COULD_NOT_ESTABLISH_CONNECTION_ERROR,
778 CanConnectAndSendMessagesToFrame(incognito_frame, extension, NULL));
779 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
780 }
781
782 // Allowing the extension in incognito mode is what allows connections.
783 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension->id(), true);
784 EXPECT_EQ(OK,
785 CanConnectAndSendMessagesToFrame(incognito_frame, extension, NULL));
786 }
787
788 // Tests a connection from an iframe within a tab which doesn't have
789 // permission. Iframe should work.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIframeWithPermission)790 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
791 FromIframeWithPermission) {
792 InitializeTestServer();
793
794 const Extension* extension = LoadChromiumConnectableExtension();
795
796 ui_test_utils::NavigateToURL(browser(), google_com_url());
797 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
798 CanConnectAndSendMessagesToMainFrame(extension));
799 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
800
801 ASSERT_TRUE(AppendIframe(chromium_org_url()));
802
803 EXPECT_EQ(OK, CanConnectAndSendMessagesToIFrame(extension));
804 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
805 }
806
807 // Tests connection from an iframe without permission within a tab that does.
808 // Iframe shouldn't work.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIframeWithoutPermission)809 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
810 FromIframeWithoutPermission) {
811 InitializeTestServer();
812
813 const Extension* extension = LoadChromiumConnectableExtension();
814
815 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
816 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(extension));
817 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
818
819 ASSERT_TRUE(AppendIframe(google_com_url()));
820
821 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
822 CanConnectAndSendMessagesToIFrame(extension));
823 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
824 }
825
826 // Tests externally_connectable between a web page and an extension with a
827 // TLS channel ID created for the origin.
828 class ExternallyConnectableMessagingWithTlsChannelIdTest :
829 public ExternallyConnectableMessagingTest {
830 public:
ExternallyConnectableMessagingWithTlsChannelIdTest()831 ExternallyConnectableMessagingWithTlsChannelIdTest()
832 : tls_channel_id_created_(false, false) {
833 }
834
CreateTlsChannelId()835 std::string CreateTlsChannelId() {
836 scoped_refptr<net::URLRequestContextGetter> request_context_getter(
837 profile()->GetRequestContext());
838 std::string domain_bound_private_key;
839 std::string domain_bound_cert;
840 net::ServerBoundCertService::RequestHandle request_handle;
841 content::BrowserThread::PostTask(
842 content::BrowserThread::IO,
843 FROM_HERE,
844 base::Bind(
845 &ExternallyConnectableMessagingWithTlsChannelIdTest::
846 CreateDomainBoundCertOnIOThread,
847 base::Unretained(this),
848 base::Unretained(&domain_bound_private_key),
849 base::Unretained(&domain_bound_cert),
850 base::Unretained(&request_handle),
851 request_context_getter));
852 tls_channel_id_created_.Wait();
853 // Create the expected value.
854 base::StringPiece spki;
855 net::asn1::ExtractSPKIFromDERCert(domain_bound_cert, &spki);
856 base::DictionaryValue jwk_value;
857 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value);
858 std::string tls_channel_id_value;
859 base::JSONWriter::Write(&jwk_value, &tls_channel_id_value);
860 return tls_channel_id_value;
861 }
862
863 private:
CreateDomainBoundCertOnIOThread(std::string * domain_bound_private_key,std::string * domain_bound_cert,net::ServerBoundCertService::RequestHandle * request_handle,scoped_refptr<net::URLRequestContextGetter> request_context_getter)864 void CreateDomainBoundCertOnIOThread(
865 std::string* domain_bound_private_key,
866 std::string* domain_bound_cert,
867 net::ServerBoundCertService::RequestHandle* request_handle,
868 scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
869 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
870 net::ServerBoundCertService* server_bound_cert_service =
871 request_context_getter->GetURLRequestContext()->
872 server_bound_cert_service();
873 int status = server_bound_cert_service->GetOrCreateDomainBoundCert(
874 chromium_org_url().host(),
875 domain_bound_private_key,
876 domain_bound_cert,
877 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
878 GotDomainBoundCert,
879 base::Unretained(this)),
880 request_handle);
881 if (status == net::ERR_IO_PENDING)
882 return;
883 GotDomainBoundCert(status);
884 }
885
GotDomainBoundCert(int status)886 void GotDomainBoundCert(int status) {
887 ASSERT_TRUE(status == net::OK);
888 tls_channel_id_created_.Signal();
889 }
890
891 base::WaitableEvent tls_channel_id_created_;
892 };
893
894 // Tests a web connectable extension that receives TLS channel id on a site
895 // that can connect to it, with a TLS channel ID having been generated.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,WebConnectableWithNonEmptyTlsChannelId)896 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,
897 WebConnectableWithNonEmptyTlsChannelId) {
898 InitializeTestServer();
899 std::string expected_tls_channel_id_value = CreateTlsChannelId();
900
901 const Extension* chromium_connectable =
902 LoadChromiumConnectableExtensionWithTlsChannelId();
903 ASSERT_TRUE(chromium_connectable);
904
905 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
906
907 // Since the extension requests the TLS channel ID, it gets it for a site that
908 // can connect to it, but only if the page also asks to send it.
909 EXPECT_EQ(std::string(),
910 GetTlsChannelIdFromPortConnect(chromium_connectable, false));
911 EXPECT_EQ(std::string(),
912 GetTlsChannelIdFromSendMessage(chromium_connectable, false));
913
914 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
915 std::string tls_channel_id_from_port_connect =
916 GetTlsChannelIdFromPortConnect(chromium_connectable, true);
917 EXPECT_NE(0u, tls_channel_id_from_port_connect.size());
918
919 // The same value is received by both connect and sendMessage.
920 std::string tls_channel_id_from_send_message =
921 GetTlsChannelIdFromSendMessage(chromium_connectable, true);
922 EXPECT_EQ(tls_channel_id_from_port_connect, tls_channel_id_from_send_message);
923
924 // And since a TLS channel ID exists for the domain, the value received is
925 // parseable as a JWK. (In particular, it has the same value we created by
926 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
927 std::string tls_channel_id(tls_channel_id_from_port_connect);
928 EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
929
930 // The TLS channel ID shouldn't change from one connection to the next...
931 std::string tls_channel_id2 =
932 GetTlsChannelIdFromPortConnect(chromium_connectable, true);
933 EXPECT_EQ(tls_channel_id, tls_channel_id2);
934 tls_channel_id2 = GetTlsChannelIdFromSendMessage(chromium_connectable, true);
935 EXPECT_EQ(tls_channel_id, tls_channel_id2);
936
937 // nor should it change when navigating away, revisiting the page and
938 // requesting it again.
939 ui_test_utils::NavigateToURL(browser(), google_com_url());
940 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
941 tls_channel_id2 = GetTlsChannelIdFromPortConnect(chromium_connectable, true);
942 EXPECT_EQ(tls_channel_id, tls_channel_id2);
943 tls_channel_id2 = GetTlsChannelIdFromSendMessage(chromium_connectable, true);
944 EXPECT_EQ(tls_channel_id, tls_channel_id2);
945 }
946
947 // Tests a web connectable extension that receives TLS channel id, but
948 // immediately closes its background page upon receipt of a message.
949 // Same flakiness seen in http://crbug.com/297866
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage)950 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,
951 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage) {
952 InitializeTestServer();
953 std::string expected_tls_channel_id_value = CreateTlsChannelId();
954
955 const Extension* chromium_connectable =
956 LoadChromiumConnectableExtensionWithTlsChannelId();
957
958 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
959 // If the page does ask for it, it isn't empty, even if the background page
960 // closes upon receipt of the connect.
961 std::string tls_channel_id = GetTlsChannelIdFromPortConnect(
962 chromium_connectable, true, close_background_message());
963 EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
964 // A subsequent connect will still succeed, even if the background page was
965 // previously closed.
966 tls_channel_id = GetTlsChannelIdFromPortConnect(chromium_connectable, true);
967 // And the expected value is still retrieved.
968 EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
969 }
970
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MessagingUserGesture)971 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingUserGesture) {
972 const char kManifest[] = "{"
973 " \"name\": \"user_gesture\","
974 " \"version\": \"1.0\","
975 " \"background\": {"
976 " \"scripts\": [\"background.js\"]"
977 " },"
978 " \"manifest_version\": 2"
979 "}";
980
981 TestExtensionDir receiver_dir;
982 receiver_dir.WriteManifest(kManifest);
983 receiver_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
984 "chrome.runtime.onMessageExternal.addListener(\n"
985 " function(msg, sender, reply) {\n"
986 " reply({result:chrome.test.isProcessingUserGesture()});\n"
987 " });");
988 const Extension* receiver = LoadExtension(receiver_dir.unpacked_path());
989 ASSERT_TRUE(receiver);
990
991 TestExtensionDir sender_dir;
992 sender_dir.WriteManifest(kManifest);
993 sender_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "");
994 const Extension* sender = LoadExtension(sender_dir.unpacked_path());
995 ASSERT_TRUE(sender);
996
997 EXPECT_EQ("false",
998 ExecuteScriptInBackgroundPage(sender->id(),
999 base::StringPrintf(
1000 "chrome.test.runWithoutUserGesture(function() {\n"
1001 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1002 " window.domAutomationController.send('' + response.result);\n"
1003 " });\n"
1004 "});", receiver->id().c_str())));
1005
1006 EXPECT_EQ("true",
1007 ExecuteScriptInBackgroundPage(sender->id(),
1008 base::StringPrintf(
1009 "chrome.test.runWithUserGesture(function() {\n"
1010 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1011 " window.domAutomationController.send('' + response.result);\n"
1012 " });\n"
1013 "});", receiver->id().c_str())));
1014 }
1015
1016 // Tests that a hosted app on a connectable site doesn't interfere with the
1017 // connectability of that site.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,HostedAppOnWebsite)1018 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, HostedAppOnWebsite) {
1019 InitializeTestServer();
1020
1021 scoped_refptr<const Extension> app = LoadChromiumHostedApp();
1022
1023 // The presence of the hosted app shouldn't give the ability to send messages.
1024 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1025 EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessagesToMainFrame(app));
1026 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1027
1028 // Once a connectable extension is installed, it should.
1029 const Extension* extension = LoadChromiumConnectableExtension();
1030 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(extension));
1031 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1032 }
1033
1034 // Tests that an invalid extension ID specified in a hosted app does not crash
1035 // the hosted app's renderer.
1036 //
1037 // This is a regression test for http://crbug.com/326250#c12.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,InvalidExtensionIDFromHostedApp)1038 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
1039 InvalidExtensionIDFromHostedApp) {
1040 InitializeTestServer();
1041
1042 // The presence of the chromium hosted app triggers this bug. The chromium
1043 // connectable extension needs to be installed to set up the runtime bindings.
1044 LoadChromiumHostedApp();
1045 LoadChromiumConnectableExtension();
1046
1047 scoped_refptr<const Extension> invalid =
1048 ExtensionBuilder()
1049 // A bit scary that this works...
1050 .SetID("invalid")
1051 .SetManifest(DictionaryBuilder()
1052 .Set("name", "Fake extension")
1053 .Set("version", "1")
1054 .Set("manifest_version", 2))
1055 .Build();
1056
1057 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1058 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
1059 CanConnectAndSendMessagesToMainFrame(invalid));
1060 }
1061
1062 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1063
1064 } // namespace
1065
1066 }; // namespace extensions
1067