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.
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/strings/utf_string_conversions.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
18 #include "chrome/browser/extensions/extension_apitest.h"
19 #include "chrome/browser/extensions/test_extension_dir.h"
20 #include "chrome/browser/infobars/infobar_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/test/base/ui_test_utils.h"
27 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "extensions/browser/event_router.h"
31 #include "extensions/browser/extension_prefs.h"
32 #include "extensions/browser/extension_system.h"
33 #include "extensions/common/api/runtime.h"
34 #include "extensions/common/extension_builder.h"
35 #include "extensions/common/value_builder.h"
36 #include "net/cert/asn1_util.h"
37 #include "net/cert/jwk_serializer.h"
38 #include "net/dns/mock_host_resolver.h"
39 #include "net/ssl/channel_id_service.h"
40 #include "net/test/embedded_test_server/embedded_test_server.h"
41 #include "net/url_request/url_request_context.h"
42 #include "net/url_request/url_request_context_getter.h"
45 namespace extensions
{
48 class MessageSender
: public content::NotificationObserver
{
52 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD
,
53 content::NotificationService::AllSources());
57 static scoped_ptr
<base::ListValue
> BuildEventArguments(
58 const bool last_message
,
59 const std::string
& data
) {
60 base::DictionaryValue
* event
= new base::DictionaryValue();
61 event
->SetBoolean("lastMessage", last_message
);
62 event
->SetString("data", data
);
63 scoped_ptr
<base::ListValue
> arguments(new base::ListValue());
64 arguments
->Append(event
);
65 return arguments
.Pass();
68 static scoped_ptr
<Event
> BuildEvent(scoped_ptr
<base::ListValue
> event_args
,
71 scoped_ptr
<Event
> event(new Event("test.onMessage", event_args
.Pass()));
72 event
->restrict_to_browser_context
= profile
;
73 event
->event_url
= event_url
;
77 void Observe(int type
,
78 const content::NotificationSource
& source
,
79 const content::NotificationDetails
& details
) override
{
80 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD
,
82 EventRouter
* event_router
=
83 EventRouter::Get(content::Source
<Profile
>(source
).ptr());
85 // Sends four messages to the extension. All but the third message sent
86 // from the origin http://b.com/ are supposed to arrive.
87 event_router
->BroadcastEvent(BuildEvent(
88 BuildEventArguments(false, "no restriction"),
89 content::Source
<Profile
>(source
).ptr(),
91 event_router
->BroadcastEvent(BuildEvent(
92 BuildEventArguments(false, "http://a.com/"),
93 content::Source
<Profile
>(source
).ptr(),
94 GURL("http://a.com/")));
95 event_router
->BroadcastEvent(BuildEvent(
96 BuildEventArguments(false, "http://b.com/"),
97 content::Source
<Profile
>(source
).ptr(),
98 GURL("http://b.com/")));
99 event_router
->BroadcastEvent(BuildEvent(
100 BuildEventArguments(true, "last message"),
101 content::Source
<Profile
>(source
).ptr(),
105 content::NotificationRegistrar registrar_
;
108 // Tests that message passing between extensions and content scripts works.
109 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, Messaging
) {
110 ASSERT_TRUE(StartEmbeddedTestServer());
111 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_
;
114 // Tests that message passing from one extension to another works.
115 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingExternal
) {
116 ASSERT_TRUE(LoadExtension(
117 test_data_dir_
.AppendASCII("..").AppendASCII("good")
118 .AppendASCII("Extensions")
119 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
120 .AppendASCII("1.0")));
122 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_
;
125 // Tests that messages with event_urls are only passed to extensions with
126 // appropriate permissions.
127 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingEventURL
) {
128 MessageSender sender
;
129 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_
;
132 // Tests connecting from a panel to its extension.
133 class PanelMessagingTest
: public ExtensionApiTest
{
134 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
135 ExtensionApiTest::SetUpCommandLine(command_line
);
136 command_line
->AppendSwitch(switches::kEnablePanels
);
140 IN_PROC_BROWSER_TEST_F(PanelMessagingTest
, MessagingPanel
) {
141 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_
;
144 // XXX(kalman): All web messaging tests disabled on windows due to extreme
145 // flakiness. See http://crbug.com/350517.
148 // Tests externally_connectable between a web page and an extension.
150 // TODO(kalman): Test between extensions. This is already tested in this file,
151 // but not with externally_connectable set in the manifest.
153 // TODO(kalman): Test with host permissions.
154 class ExternallyConnectableMessagingTest
: public ExtensionApiTest
{
156 // Result codes from the test. These must match up with |results| in
157 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
160 NAMESPACE_NOT_DEFINED
= 1,
161 FUNCTION_NOT_DEFINED
= 2,
162 COULD_NOT_ESTABLISH_CONNECTION_ERROR
= 3,
164 INCORRECT_RESPONSE_SENDER
= 5,
165 INCORRECT_RESPONSE_MESSAGE
= 6,
168 bool AppendIframe(const GURL
& src
) {
170 CHECK(content::ExecuteScriptAndExtractBool(
171 browser()->tab_strip_model()->GetActiveWebContents(),
172 "actions.appendIframe('" + src
.spec() + "');", &result
));
176 Result
CanConnectAndSendMessagesToMainFrame(const Extension
* extension
,
177 const char* message
= NULL
) {
178 return CanConnectAndSendMessagesToFrame(
179 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
184 Result
CanConnectAndSendMessagesToIFrame(const Extension
* extension
,
185 const char* message
= NULL
) {
186 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
187 browser()->tab_strip_model()->GetActiveWebContents(),
188 base::Bind(&content::FrameIsChildOfMainFrame
));
189 return CanConnectAndSendMessagesToFrame(frame
, extension
, message
);
192 Result
CanConnectAndSendMessagesToFrame(content::RenderFrameHost
* frame
,
193 const Extension
* extension
,
194 const char* message
) {
196 std::string command
= base::StringPrintf(
197 "assertions.canConnectAndSendMessages('%s', %s, %s)",
198 extension
->id().c_str(),
199 extension
->is_platform_app() ? "true" : "false",
200 message
? base::StringPrintf("'%s'", message
).c_str() : "undefined");
201 CHECK(content::ExecuteScriptAndExtractInt(frame
, command
, &result
));
202 return static_cast<Result
>(result
);
205 testing::AssertionResult
AreAnyNonWebApisDefinedForMainFrame() {
206 return AreAnyNonWebApisDefinedForFrame(
207 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
210 testing::AssertionResult
AreAnyNonWebApisDefinedForIFrame() {
211 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
212 browser()->tab_strip_model()->GetActiveWebContents(),
213 base::Bind(&content::FrameIsChildOfMainFrame
));
214 return AreAnyNonWebApisDefinedForFrame(frame
);
217 testing::AssertionResult
AreAnyNonWebApisDefinedForFrame(
218 content::RenderFrameHost
* frame
) {
219 // All runtime API methods are non-web except for sendRequest and connect.
220 const char* const non_messaging_apis
[] = {
225 "requestUpdateCheck",
234 "onBrowserUpdateAvailable",
240 // Note: no "id" here because this test method is used for hosted apps,
241 // which do have access to runtime.id.
244 // Turn the array into a JS array, which effectively gets eval()ed.
245 std::string as_js_array
;
246 for (size_t i
= 0; i
< arraysize(non_messaging_apis
); ++i
) {
247 as_js_array
+= as_js_array
.empty() ? "[" : ",";
248 as_js_array
+= base::StringPrintf("'%s'", non_messaging_apis
[i
]);
253 CHECK(content::ExecuteScriptAndExtractBool(
255 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array
+ ")",
258 testing::AssertionSuccess() : testing::AssertionFailure();
261 std::string
GetTlsChannelIdFromPortConnect(const Extension
* extension
,
262 bool include_tls_channel_id
,
263 const char* message
= NULL
) {
264 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
266 include_tls_channel_id
,
270 std::string
GetTlsChannelIdFromSendMessage(const Extension
* extension
,
271 bool include_tls_channel_id
,
272 const char* message
= NULL
) {
273 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
275 include_tls_channel_id
,
279 GURL
GetURLForPath(const std::string
& host
, const std::string
& path
) {
280 std::string port
= base::IntToString(embedded_test_server()->port());
281 GURL::Replacements replacements
;
282 replacements
.SetHostStr(host
);
283 replacements
.SetPortStr(port
);
284 return embedded_test_server()->GetURL(path
).ReplaceComponents(replacements
);
287 GURL
chromium_org_url() {
288 return GetURLForPath("www.chromium.org", "/chromium.org.html");
291 GURL
google_com_url() {
292 return GetURLForPath("www.google.com", "/google.com.html");
295 scoped_refptr
<const Extension
> LoadChromiumConnectableExtension() {
296 scoped_refptr
<const Extension
> extension
=
297 LoadExtensionIntoDir(&web_connectable_dir_
,
300 " \"name\": \"chromium_connectable\","
302 " \"externally_connectable\": {"
303 " \"matches\": [\"*://*.chromium.org:*/*\"]"
307 CHECK(extension
.get());
311 scoped_refptr
<const Extension
> LoadChromiumConnectableApp(
312 bool with_event_handlers
= true) {
313 scoped_refptr
<const Extension
> extension
=
314 LoadExtensionIntoDir(&web_connectable_dir_
,
318 " \"scripts\": [\"background.js\"]"
321 " \"externally_connectable\": {"
322 " \"matches\": [\"*://*.chromium.org:*/*\"]"
324 " \"manifest_version\": 2,"
325 " \"name\": \"app_connectable\","
326 " \"version\": \"1.0\""
328 with_event_handlers
);
329 CHECK(extension
.get());
333 scoped_refptr
<const Extension
> LoadNotConnectableExtension() {
334 scoped_refptr
<const Extension
> extension
=
335 LoadExtensionIntoDir(¬_connectable_dir_
,
338 " \"name\": \"not_connectable\","
342 CHECK(extension
.get());
346 scoped_refptr
<const Extension
>
347 LoadChromiumConnectableExtensionWithTlsChannelId() {
348 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_
,
349 connectable_with_tls_channel_id_manifest());
352 scoped_refptr
<const Extension
> LoadChromiumHostedApp() {
353 scoped_refptr
<const Extension
> hosted_app
=
354 LoadExtensionIntoDir(&hosted_app_dir_
,
357 " \"name\": \"chromium_hosted_app\","
358 " \"version\": \"1.0\","
359 " \"manifest_version\": 2,"
361 " \"urls\": [\"%s\"],"
363 " \"web_url\": \"%s\""
367 chromium_org_url().spec().c_str(),
368 chromium_org_url().spec().c_str()));
369 CHECK(hosted_app
.get());
373 void InitializeTestServer() {
374 base::FilePath test_data
;
375 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &test_data
));
376 embedded_test_server()->ServeFilesFromDirectory(test_data
.AppendASCII(
377 "extensions/api_test/messaging/externally_connectable/sites"));
378 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
379 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
382 const char* close_background_message() {
383 return "closeBackgroundPage";
387 scoped_refptr
<const Extension
> LoadExtensionIntoDir(
388 TestExtensionDir
* dir
,
389 const std::string
& manifest
,
390 bool with_event_handlers
= true) {
391 dir
->WriteManifest(manifest
);
392 if (with_event_handlers
) {
394 FILE_PATH_LITERAL("background.js"),
396 "function maybeClose(message) {\n"
397 " if (message.indexOf('%s') >= 0)\n"
398 " window.setTimeout(function() { window.close() }, 0);\n"
400 "chrome.runtime.onMessageExternal.addListener(\n"
401 " function(message, sender, reply) {\n"
402 " reply({ message: message, sender: sender });\n"
403 " maybeClose(message);\n"
405 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
406 " port.onMessage.addListener(function(message) {\n"
407 " port.postMessage({ message: message, sender: port.sender "
409 " maybeClose(message);\n"
412 close_background_message()));
414 dir
->WriteFile(FILE_PATH_LITERAL("background.js"), "");
416 return LoadExtension(dir
->unpacked_path());
419 const char* common_manifest() {
420 return "\"version\": \"1.0\","
422 " \"scripts\": [\"background.js\"],"
423 " \"persistent\": false"
425 "\"manifest_version\": 2";
428 std::string
connectable_with_tls_channel_id_manifest() {
429 return base::StringPrintf(
431 " \"name\": \"chromium_connectable_with_tls_channel_id\","
433 " \"externally_connectable\": {"
434 " \"matches\": [\"*://*.chromium.org:*/*\"],"
435 " \"accepts_tls_channel_id\": true"
441 std::string
GetTlsChannelIdFromAssertion(const char* method
,
442 const Extension
* extension
,
443 bool include_tls_channel_id
,
444 const char* message
) {
446 std::string args
= "'" + extension
->id() + "', ";
447 args
+= include_tls_channel_id
? "true" : "false";
449 args
+= std::string(", '") + message
+ "'";
450 CHECK(content::ExecuteScriptAndExtractString(
451 browser()->tab_strip_model()->GetActiveWebContents(),
452 base::StringPrintf("assertions.%s(%s)", method
, args
.c_str()),
457 TestExtensionDir web_connectable_dir_
;
458 TestExtensionDir not_connectable_dir_
;
459 TestExtensionDir tls_channel_id_connectable_dir_
;
460 TestExtensionDir hosted_app_dir_
;
463 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, NotInstalled
) {
464 InitializeTestServer();
466 scoped_refptr
<const Extension
> extension
=
468 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
469 .SetManifest(DictionaryBuilder()
470 .Set("name", "Fake extension")
472 .Set("manifest_version", 2))
475 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
476 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
477 CanConnectAndSendMessagesToMainFrame(extension
.get()));
478 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
480 ui_test_utils::NavigateToURL(browser(), google_com_url());
481 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
482 CanConnectAndSendMessagesToMainFrame(extension
.get()));
483 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
486 // Tests two extensions on the same sites: one web connectable, one not.
487 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
488 WebConnectableAndNotConnectable
) {
489 InitializeTestServer();
491 // Install the web connectable extension. chromium.org can connect to it,
493 scoped_refptr
<const Extension
> chromium_connectable
=
494 LoadChromiumConnectableExtension();
496 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
498 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
499 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
501 ui_test_utils::NavigateToURL(browser(), google_com_url());
502 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
503 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
504 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
506 // Install the non-connectable extension. Nothing can connect to it.
507 scoped_refptr
<const Extension
> not_connectable
=
508 LoadNotConnectableExtension();
510 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
511 // Namespace will be defined here because |chromium_connectable| can connect
512 // to it - so this will be the "cannot establish connection" error.
513 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
514 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
515 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
517 ui_test_utils::NavigateToURL(browser(), google_com_url());
518 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
519 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
520 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
523 // See http://crbug.com/297866
524 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
525 DISABLED_BackgroundPageClosesOnMessageReceipt
) {
526 InitializeTestServer();
528 // Install the web connectable extension.
529 scoped_refptr
<const Extension
> chromium_connectable
=
530 LoadChromiumConnectableExtension();
532 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
533 // If the background page closes after receipt of the message, it will still
534 // reply to this message...
536 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get(),
537 close_background_message()));
538 // and be re-opened by receipt of a subsequent message.
540 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
543 // Tests a web connectable extension that doesn't receive TLS channel id.
544 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
545 WebConnectableWithoutTlsChannelId
) {
546 InitializeTestServer();
548 // Install the web connectable extension. chromium.org can connect to it,
550 scoped_refptr
<const Extension
> chromium_connectable
=
551 LoadChromiumConnectableExtension();
552 ASSERT_TRUE(chromium_connectable
.get());
554 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
555 // The web connectable extension doesn't request the TLS channel ID, so it
556 // doesn't get it, whether or not the page asks for it.
557 EXPECT_EQ(std::string(),
558 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
559 EXPECT_EQ(std::string(),
560 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
561 EXPECT_EQ(std::string(),
562 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
563 EXPECT_EQ(std::string(),
564 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
567 // Tests a web connectable extension that receives TLS channel id with a site
568 // that can't connect to it.
569 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
570 WebConnectableWithTlsChannelIdWithNonMatchingSite
) {
571 InitializeTestServer();
573 scoped_refptr
<const Extension
> chromium_connectable
=
574 LoadChromiumConnectableExtensionWithTlsChannelId();
575 ASSERT_TRUE(chromium_connectable
.get());
577 ui_test_utils::NavigateToURL(browser(), google_com_url());
578 // The extension requests the TLS channel ID, but it doesn't get it for a
579 // site that can't connect to it, regardless of whether the page asks for it.
580 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
581 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
582 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
583 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
584 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
585 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
586 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
587 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
590 // Tests a web connectable extension that receives TLS channel id on a site
591 // that can connect to it, but with no TLS channel ID having been generated.
592 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
593 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId
) {
594 InitializeTestServer();
596 scoped_refptr
<const Extension
> chromium_connectable
=
597 LoadChromiumConnectableExtensionWithTlsChannelId();
598 ASSERT_TRUE(chromium_connectable
.get());
600 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
602 // Since the extension requests the TLS channel ID, it gets it for a site that
603 // can connect to it, but only if the page also asks to include it.
604 EXPECT_EQ(std::string(),
605 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
606 EXPECT_EQ(std::string(),
607 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
608 // If the page does ask for it, it isn't empty.
609 std::string tls_channel_id
=
610 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
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
);
616 // Flaky on Linux and Windows. http://crbug.com/315264
617 // Tests a web connectable extension that receives TLS channel id, but
618 // immediately closes its background page upon receipt of a message.
619 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
620 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
) {
621 InitializeTestServer();
623 scoped_refptr
<const Extension
> chromium_connectable
=
624 LoadChromiumConnectableExtensionWithTlsChannelId();
626 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
627 // If the page does ask for it, it isn't empty, even if the background page
628 // closes upon receipt of the connect.
629 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
630 chromium_connectable
.get(), true, close_background_message());
631 // Because the TLS channel ID has never been generated for this domain,
632 // no TLS channel ID is reported.
633 EXPECT_EQ(std::string(), tls_channel_id
);
634 // A subsequent connect will still succeed, even if the background page was
635 // previously closed.
637 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
638 // And the empty value is still retrieved.
639 EXPECT_EQ(std::string(), tls_channel_id
);
642 // Tests that enabling and disabling an extension makes the runtime bindings
643 // appear and disappear.
645 // TODO(kalman): Test with multiple extensions that can be accessed by the same
647 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
648 EnablingAndDisabling
) {
649 InitializeTestServer();
651 scoped_refptr
<const Extension
> chromium_connectable
=
652 LoadChromiumConnectableExtension();
653 scoped_refptr
<const Extension
> not_connectable
=
654 LoadNotConnectableExtension();
656 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
658 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
659 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
660 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
662 DisableExtension(chromium_connectable
->id());
663 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
664 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
666 EnableExtension(chromium_connectable
->id());
668 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
669 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
670 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
673 // Tests connection from incognito tabs when the user denies the connection
674 // request. Spanning mode only. A separate test for apps and extensions.
676 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
677 // somewhere. This is a test that should be shared with the content script logic
678 // so it's not really our specific concern for web connectable.
680 // TODO(kalman): test messages from incognito extensions too.
681 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
682 FromIncognitoDenyApp
) {
683 InitializeTestServer();
685 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
686 ASSERT_TRUE(app
->is_platform_app());
688 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
689 profile()->GetOffTheRecordProfile(),
691 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
692 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
695 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
696 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
698 // No connection because incognito-enabled hasn't been set for the app, and
699 // the user denied our interactive request.
701 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
702 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
703 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
705 // Try again. User has already denied so alert not shown.
707 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
708 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
709 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
712 // It's not possible to allow an app in incognito.
713 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
714 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
715 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
718 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
719 FromIncognitoDenyExtension
) {
720 InitializeTestServer();
722 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
724 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
725 profile()->GetOffTheRecordProfile(), chromium_org_url());
726 content::RenderFrameHost
* incognito_frame
=
727 incognito_browser
->tab_strip_model()
728 ->GetActiveWebContents()
732 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
733 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
735 // The alert doesn't show for extensions.
736 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
737 CanConnectAndSendMessagesToFrame(
738 incognito_frame
, extension
.get(), NULL
));
739 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
742 // Allowing the extension in incognito mode will bypass the deny.
743 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
746 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
749 // Tests connection from incognito tabs when the extension doesn't have an event
750 // handler for the connection event.
751 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
752 FromIncognitoNoEventHandlerInApp
) {
753 InitializeTestServer();
755 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp(false);
756 ASSERT_TRUE(app
->is_platform_app());
758 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
759 profile()->GetOffTheRecordProfile(), chromium_org_url());
760 content::RenderFrameHost
* incognito_frame
=
761 incognito_browser
->tab_strip_model()
762 ->GetActiveWebContents()
766 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
767 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
769 // No connection because incognito-enabled hasn't been set for the app, and
770 // the app hasn't installed event handlers.
772 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
773 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
774 // No dialog should have been shown.
775 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
779 // Tests connection from incognito tabs when the user accepts the connection
780 // request. Spanning mode only. Separate tests for apps and extensions.
782 // TODO(kalman): see comment above about split mode.
783 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
784 FromIncognitoAllowApp
) {
785 InitializeTestServer();
787 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
788 ASSERT_TRUE(app
->is_platform_app());
790 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
791 profile()->GetOffTheRecordProfile(),
793 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
794 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
797 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
798 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
800 // Connection allowed even with incognito disabled, because the user
801 // accepted the interactive request.
803 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
804 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
806 // Try again. User has already allowed.
808 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
809 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
812 // Apps can't be allowed in incognito mode, but it's moot because it's
814 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
816 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
819 // Tests connection from incognito tabs when there are multiple tabs open to the
820 // same origin. The user should only need to accept the connection request once.
821 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
822 FromIncognitoPromptApp
) {
823 InitializeTestServer();
825 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
826 ASSERT_TRUE(app
->is_platform_app());
828 // Open an incognito browser with two tabs displaying "chromium.org".
829 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
830 profile()->GetOffTheRecordProfile(), chromium_org_url());
831 content::RenderFrameHost
* incognito_frame1
=
832 incognito_browser
->tab_strip_model()
833 ->GetActiveWebContents()
835 InfoBarService
* infobar_service1
= InfoBarService::FromWebContents(
836 incognito_browser
->tab_strip_model()->GetActiveWebContents());
838 CHECK(ui_test_utils::OpenURLOffTheRecord(profile()->GetOffTheRecordProfile(),
839 chromium_org_url()) ==
841 content::RenderFrameHost
* incognito_frame2
=
842 incognito_browser
->tab_strip_model()
843 ->GetActiveWebContents()
845 InfoBarService
* infobar_service2
= InfoBarService::FromWebContents(
846 incognito_browser
->tab_strip_model()->GetActiveWebContents());
847 EXPECT_EQ(2, incognito_browser
->tab_strip_model()->count());
848 EXPECT_NE(incognito_frame1
, incognito_frame2
);
850 // Trigger a infobars in both tabs by trying to send messages.
852 base::StringPrintf("assertions.trySendMessage('%s')", app
->id().c_str());
853 CHECK(content::ExecuteScript(incognito_frame1
, script
));
854 CHECK(content::ExecuteScript(incognito_frame2
, script
));
855 EXPECT_EQ(1U, infobar_service1
->infobar_count());
856 EXPECT_EQ(1U, infobar_service2
->infobar_count());
858 // Navigating away will dismiss the infobar on the active tab only.
859 ui_test_utils::NavigateToURL(incognito_browser
, google_com_url());
860 EXPECT_EQ(1U, infobar_service1
->infobar_count());
861 EXPECT_EQ(0U, infobar_service2
->infobar_count());
863 // Navigate back and accept the infobar this time. Both should be dismissed.
865 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
866 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
868 ui_test_utils::NavigateToURL(incognito_browser
, chromium_org_url());
869 incognito_frame2
= incognito_browser
->tab_strip_model()
870 ->GetActiveWebContents()
872 EXPECT_NE(incognito_frame1
, incognito_frame2
);
874 EXPECT_EQ(1U, infobar_service1
->infobar_count());
875 EXPECT_EQ(OK
, CanConnectAndSendMessagesToFrame(incognito_frame2
, app
.get(),
877 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
878 EXPECT_EQ(0U, infobar_service1
->infobar_count());
882 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
883 FromIncognitoAllowExtension
) {
884 InitializeTestServer();
886 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
888 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
889 profile()->GetOffTheRecordProfile(), chromium_org_url());
890 content::RenderFrameHost
* incognito_frame
=
891 incognito_browser
->tab_strip_model()
892 ->GetActiveWebContents()
896 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
897 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
899 // No alert is shown.
900 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
901 CanConnectAndSendMessagesToFrame(
902 incognito_frame
, extension
.get(), NULL
));
903 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
906 // Allowing the extension in incognito mode is what allows connections.
907 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
910 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
913 // Tests a connection from an iframe within a tab which doesn't have
914 // permission. Iframe should work.
915 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
916 FromIframeWithPermission
) {
917 InitializeTestServer();
919 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
921 ui_test_utils::NavigateToURL(browser(), google_com_url());
922 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
923 CanConnectAndSendMessagesToMainFrame(extension
.get()));
924 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
926 ASSERT_TRUE(AppendIframe(chromium_org_url()));
928 EXPECT_EQ(OK
, CanConnectAndSendMessagesToIFrame(extension
.get()));
929 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
932 // Tests connection from an iframe without permission within a tab that does.
933 // Iframe shouldn't work.
934 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
935 FromIframeWithoutPermission
) {
936 InitializeTestServer();
938 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
940 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
941 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
942 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
944 ASSERT_TRUE(AppendIframe(google_com_url()));
946 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
947 CanConnectAndSendMessagesToIFrame(extension
.get()));
948 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
951 // Tests externally_connectable between a web page and an extension with a
952 // TLS channel ID created for the origin.
953 class ExternallyConnectableMessagingWithTlsChannelIdTest
:
954 public ExternallyConnectableMessagingTest
{
956 ExternallyConnectableMessagingWithTlsChannelIdTest()
957 : tls_channel_id_created_(false, false) {
960 std::string
CreateTlsChannelId() {
961 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
962 profile()->GetRequestContext());
963 std::string channel_id_private_key
;
964 std::string channel_id_cert
;
965 net::ChannelIDService::RequestHandle request_handle
;
966 content::BrowserThread::PostTask(
967 content::BrowserThread::IO
,
970 &ExternallyConnectableMessagingWithTlsChannelIdTest::
971 CreateDomainBoundCertOnIOThread
,
972 base::Unretained(this),
973 base::Unretained(&channel_id_private_key
),
974 base::Unretained(&channel_id_cert
),
975 base::Unretained(&request_handle
),
976 request_context_getter
));
977 tls_channel_id_created_
.Wait();
978 // Create the expected value.
979 base::StringPiece spki
;
980 net::asn1::ExtractSPKIFromDERCert(channel_id_cert
, &spki
);
981 base::DictionaryValue jwk_value
;
982 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki
, &jwk_value
);
983 std::string tls_channel_id_value
;
984 base::JSONWriter::Write(&jwk_value
, &tls_channel_id_value
);
985 return tls_channel_id_value
;
989 void CreateDomainBoundCertOnIOThread(
990 std::string
* channel_id_private_key
,
991 std::string
* channel_id_cert
,
992 net::ChannelIDService::RequestHandle
* request_handle
,
993 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
) {
994 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
995 net::ChannelIDService
* channel_id_service
=
996 request_context_getter
->GetURLRequestContext()->
997 channel_id_service();
998 int status
= channel_id_service
->GetOrCreateChannelID(
999 chromium_org_url().host(),
1000 channel_id_private_key
,
1002 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
1004 base::Unretained(this)),
1006 if (status
== net::ERR_IO_PENDING
)
1008 GotDomainBoundCert(status
);
1011 void GotDomainBoundCert(int status
) {
1012 ASSERT_TRUE(status
== net::OK
);
1013 tls_channel_id_created_
.Signal();
1016 base::WaitableEvent tls_channel_id_created_
;
1019 // Tests a web connectable extension that receives TLS channel id on a site
1020 // that can connect to it, with a TLS channel ID having been generated.
1021 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1022 WebConnectableWithNonEmptyTlsChannelId
) {
1023 InitializeTestServer();
1024 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1026 scoped_refptr
<const Extension
> chromium_connectable
=
1027 LoadChromiumConnectableExtensionWithTlsChannelId();
1028 ASSERT_TRUE(chromium_connectable
.get());
1030 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1032 // Since the extension requests the TLS channel ID, it gets it for a site that
1033 // can connect to it, but only if the page also asks to send it.
1034 EXPECT_EQ(std::string(),
1035 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
1036 EXPECT_EQ(std::string(),
1037 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
1039 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
1040 std::string tls_channel_id_from_port_connect
=
1041 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1042 EXPECT_NE(0u, tls_channel_id_from_port_connect
.size());
1044 // The same value is received by both connect and sendMessage.
1045 std::string tls_channel_id_from_send_message
=
1046 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1047 EXPECT_EQ(tls_channel_id_from_port_connect
, tls_channel_id_from_send_message
);
1049 // And since a TLS channel ID exists for the domain, the value received is
1050 // parseable as a JWK. (In particular, it has the same value we created by
1051 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
1052 std::string
tls_channel_id(tls_channel_id_from_port_connect
);
1053 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1055 // The TLS channel ID shouldn't change from one connection to the next...
1056 std::string tls_channel_id2
=
1057 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1058 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1060 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1061 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1063 // nor should it change when navigating away, revisiting the page and
1064 // requesting it again.
1065 ui_test_utils::NavigateToURL(browser(), google_com_url());
1066 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1068 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1069 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1071 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1072 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1075 // Tests a web connectable extension that receives TLS channel id, but
1076 // immediately closes its background page upon receipt of a message.
1077 // Same flakiness seen in http://crbug.com/297866
1078 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1079 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage
) {
1080 InitializeTestServer();
1081 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1083 scoped_refptr
<const Extension
> chromium_connectable
=
1084 LoadChromiumConnectableExtensionWithTlsChannelId();
1086 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1087 // If the page does ask for it, it isn't empty, even if the background page
1088 // closes upon receipt of the connect.
1089 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
1090 chromium_connectable
.get(), true, close_background_message());
1091 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1092 // A subsequent connect will still succeed, even if the background page was
1093 // previously closed.
1095 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1096 // And the expected value is still retrieved.
1097 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1100 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingUserGesture
) {
1101 const char kManifest
[] = "{"
1102 " \"name\": \"user_gesture\","
1103 " \"version\": \"1.0\","
1104 " \"background\": {"
1105 " \"scripts\": [\"background.js\"]"
1107 " \"manifest_version\": 2"
1110 TestExtensionDir receiver_dir
;
1111 receiver_dir
.WriteManifest(kManifest
);
1112 receiver_dir
.WriteFile(FILE_PATH_LITERAL("background.js"),
1113 "chrome.runtime.onMessageExternal.addListener(\n"
1114 " function(msg, sender, reply) {\n"
1115 " reply({result:chrome.test.isProcessingUserGesture()});\n"
1117 const Extension
* receiver
= LoadExtension(receiver_dir
.unpacked_path());
1118 ASSERT_TRUE(receiver
);
1120 TestExtensionDir sender_dir
;
1121 sender_dir
.WriteManifest(kManifest
);
1122 sender_dir
.WriteFile(FILE_PATH_LITERAL("background.js"), "");
1123 const Extension
* sender
= LoadExtension(sender_dir
.unpacked_path());
1124 ASSERT_TRUE(sender
);
1127 ExecuteScriptInBackgroundPage(sender
->id(),
1129 "chrome.test.runWithoutUserGesture(function() {\n"
1130 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1131 " window.domAutomationController.send('' + response.result);\n"
1133 "});", receiver
->id().c_str())));
1136 ExecuteScriptInBackgroundPage(sender
->id(),
1138 "chrome.test.runWithUserGesture(function() {\n"
1139 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1140 " window.domAutomationController.send('' + response.result);\n"
1142 "});", receiver
->id().c_str())));
1145 // Tests that a hosted app on a connectable site doesn't interfere with the
1146 // connectability of that site.
1147 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, HostedAppOnWebsite
) {
1148 InitializeTestServer();
1150 scoped_refptr
<const Extension
> app
= LoadChromiumHostedApp();
1152 // The presence of the hosted app shouldn't give the ability to send messages.
1153 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1154 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
1155 CanConnectAndSendMessagesToMainFrame(app
.get()));
1156 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1158 // Once a connectable extension is installed, it should.
1159 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
1160 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
1161 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1164 // Tests that an invalid extension ID specified in a hosted app does not crash
1165 // the hosted app's renderer.
1167 // This is a regression test for http://crbug.com/326250#c12.
1168 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
1169 InvalidExtensionIDFromHostedApp
) {
1170 InitializeTestServer();
1172 // The presence of the chromium hosted app triggers this bug. The chromium
1173 // connectable extension needs to be installed to set up the runtime bindings.
1174 LoadChromiumHostedApp();
1175 LoadChromiumConnectableExtension();
1177 scoped_refptr
<const Extension
> invalid
=
1179 // A bit scary that this works...
1181 .SetManifest(DictionaryBuilder()
1182 .Set("name", "Fake extension")
1183 .Set("version", "1")
1184 .Set("manifest_version", 2))
1187 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1188 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
1189 CanConnectAndSendMessagesToMainFrame(invalid
.get()));
1192 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1196 }; // namespace extensions