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_LOADING
,
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 EventRouter
* event_router
=
81 EventRouter::Get(content::Source
<Profile
>(source
).ptr());
83 // Sends four messages to the extension. All but the third message sent
84 // from the origin http://b.com/ are supposed to arrive.
85 event_router
->BroadcastEvent(BuildEvent(
86 BuildEventArguments(false, "no restriction"),
87 content::Source
<Profile
>(source
).ptr(),
89 event_router
->BroadcastEvent(BuildEvent(
90 BuildEventArguments(false, "http://a.com/"),
91 content::Source
<Profile
>(source
).ptr(),
92 GURL("http://a.com/")));
93 event_router
->BroadcastEvent(BuildEvent(
94 BuildEventArguments(false, "http://b.com/"),
95 content::Source
<Profile
>(source
).ptr(),
96 GURL("http://b.com/")));
97 event_router
->BroadcastEvent(BuildEvent(
98 BuildEventArguments(true, "last message"),
99 content::Source
<Profile
>(source
).ptr(),
103 content::NotificationRegistrar registrar_
;
106 // Tests that message passing between extensions and content scripts works.
107 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, Messaging
) {
108 ASSERT_TRUE(StartEmbeddedTestServer());
109 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_
;
112 // Tests that message passing from one extension to another works.
113 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingExternal
) {
114 ASSERT_TRUE(LoadExtension(
115 test_data_dir_
.AppendASCII("..").AppendASCII("good")
116 .AppendASCII("Extensions")
117 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
118 .AppendASCII("1.0")));
120 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_
;
123 // Tests that messages with event_urls are only passed to extensions with
124 // appropriate permissions.
125 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingEventURL
) {
126 MessageSender sender
;
127 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_
;
130 // Tests connecting from a panel to its extension.
131 class PanelMessagingTest
: public ExtensionApiTest
{
132 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
133 ExtensionApiTest::SetUpCommandLine(command_line
);
134 command_line
->AppendSwitch(switches::kEnablePanels
);
138 IN_PROC_BROWSER_TEST_F(PanelMessagingTest
, MessagingPanel
) {
139 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_
;
142 // XXX(kalman): All web messaging tests disabled on windows due to extreme
143 // flakiness. See http://crbug.com/350517.
146 // Tests externally_connectable between a web page and an extension.
148 // TODO(kalman): Test between extensions. This is already tested in this file,
149 // but not with externally_connectable set in the manifest.
151 // TODO(kalman): Test with host permissions.
152 class ExternallyConnectableMessagingTest
: public ExtensionApiTest
{
154 // Result codes from the test. These must match up with |results| in
155 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
158 NAMESPACE_NOT_DEFINED
= 1,
159 FUNCTION_NOT_DEFINED
= 2,
160 COULD_NOT_ESTABLISH_CONNECTION_ERROR
= 3,
162 INCORRECT_RESPONSE_SENDER
= 5,
163 INCORRECT_RESPONSE_MESSAGE
= 6,
166 bool AppendIframe(const GURL
& src
) {
168 CHECK(content::ExecuteScriptAndExtractBool(
169 browser()->tab_strip_model()->GetActiveWebContents(),
170 "actions.appendIframe('" + src
.spec() + "');", &result
));
174 Result
CanConnectAndSendMessagesToMainFrame(const Extension
* extension
,
175 const char* message
= NULL
) {
176 return CanConnectAndSendMessagesToFrame(
177 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
182 Result
CanConnectAndSendMessagesToIFrame(const Extension
* extension
,
183 const char* message
= NULL
) {
184 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
185 browser()->tab_strip_model()->GetActiveWebContents(),
186 base::Bind(&content::FrameIsChildOfMainFrame
));
187 return CanConnectAndSendMessagesToFrame(frame
, extension
, message
);
190 Result
CanConnectAndSendMessagesToFrame(content::RenderFrameHost
* frame
,
191 const Extension
* extension
,
192 const char* message
) {
194 std::string command
= base::StringPrintf(
195 "assertions.canConnectAndSendMessages('%s', %s, %s)",
196 extension
->id().c_str(),
197 extension
->is_platform_app() ? "true" : "false",
198 message
? base::StringPrintf("'%s'", message
).c_str() : "undefined");
199 CHECK(content::ExecuteScriptAndExtractInt(frame
, command
, &result
));
200 return static_cast<Result
>(result
);
203 testing::AssertionResult
AreAnyNonWebApisDefinedForMainFrame() {
204 return AreAnyNonWebApisDefinedForFrame(
205 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
208 testing::AssertionResult
AreAnyNonWebApisDefinedForIFrame() {
209 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
210 browser()->tab_strip_model()->GetActiveWebContents(),
211 base::Bind(&content::FrameIsChildOfMainFrame
));
212 return AreAnyNonWebApisDefinedForFrame(frame
);
215 testing::AssertionResult
AreAnyNonWebApisDefinedForFrame(
216 content::RenderFrameHost
* frame
) {
217 // All runtime API methods are non-web except for sendRequest and connect.
218 const char* const non_messaging_apis
[] = {
223 "requestUpdateCheck",
232 "onBrowserUpdateAvailable",
238 // Note: no "id" here because this test method is used for hosted apps,
239 // which do have access to runtime.id.
242 // Turn the array into a JS array, which effectively gets eval()ed.
243 std::string as_js_array
;
244 for (size_t i
= 0; i
< arraysize(non_messaging_apis
); ++i
) {
245 as_js_array
+= as_js_array
.empty() ? "[" : ",";
246 as_js_array
+= base::StringPrintf("'%s'", non_messaging_apis
[i
]);
251 CHECK(content::ExecuteScriptAndExtractBool(
253 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array
+ ")",
256 testing::AssertionSuccess() : testing::AssertionFailure();
259 std::string
GetTlsChannelIdFromPortConnect(const Extension
* extension
,
260 bool include_tls_channel_id
,
261 const char* message
= NULL
) {
262 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
264 include_tls_channel_id
,
268 std::string
GetTlsChannelIdFromSendMessage(const Extension
* extension
,
269 bool include_tls_channel_id
,
270 const char* message
= NULL
) {
271 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
273 include_tls_channel_id
,
277 GURL
GetURLForPath(const std::string
& host
, const std::string
& path
) {
278 std::string port
= base::IntToString(embedded_test_server()->port());
279 GURL::Replacements replacements
;
280 replacements
.SetHostStr(host
);
281 replacements
.SetPortStr(port
);
282 return embedded_test_server()->GetURL(path
).ReplaceComponents(replacements
);
285 GURL
chromium_org_url() {
286 return GetURLForPath("www.chromium.org", "/chromium.org.html");
289 GURL
google_com_url() {
290 return GetURLForPath("www.google.com", "/google.com.html");
293 scoped_refptr
<const Extension
> LoadChromiumConnectableExtension() {
294 scoped_refptr
<const Extension
> extension
=
295 LoadExtensionIntoDir(&web_connectable_dir_
,
298 " \"name\": \"chromium_connectable\","
300 " \"externally_connectable\": {"
301 " \"matches\": [\"*://*.chromium.org:*/*\"]"
305 CHECK(extension
.get());
309 scoped_refptr
<const Extension
> LoadChromiumConnectableApp(
310 bool with_event_handlers
= true) {
311 scoped_refptr
<const Extension
> extension
=
312 LoadExtensionIntoDir(&web_connectable_dir_
,
316 " \"scripts\": [\"background.js\"]"
319 " \"externally_connectable\": {"
320 " \"matches\": [\"*://*.chromium.org:*/*\"]"
322 " \"manifest_version\": 2,"
323 " \"name\": \"app_connectable\","
324 " \"version\": \"1.0\""
326 with_event_handlers
);
327 CHECK(extension
.get());
331 scoped_refptr
<const Extension
> LoadNotConnectableExtension() {
332 scoped_refptr
<const Extension
> extension
=
333 LoadExtensionIntoDir(¬_connectable_dir_
,
336 " \"name\": \"not_connectable\","
340 CHECK(extension
.get());
344 scoped_refptr
<const Extension
>
345 LoadChromiumConnectableExtensionWithTlsChannelId() {
346 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_
,
347 connectable_with_tls_channel_id_manifest());
350 scoped_refptr
<const Extension
> LoadChromiumHostedApp() {
351 scoped_refptr
<const Extension
> hosted_app
=
352 LoadExtensionIntoDir(&hosted_app_dir_
,
355 " \"name\": \"chromium_hosted_app\","
356 " \"version\": \"1.0\","
357 " \"manifest_version\": 2,"
359 " \"urls\": [\"%s\"],"
361 " \"web_url\": \"%s\""
365 chromium_org_url().spec().c_str(),
366 chromium_org_url().spec().c_str()));
367 CHECK(hosted_app
.get());
371 void InitializeTestServer() {
372 base::FilePath test_data
;
373 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &test_data
));
374 embedded_test_server()->ServeFilesFromDirectory(test_data
.AppendASCII(
375 "extensions/api_test/messaging/externally_connectable/sites"));
376 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
377 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
380 const char* close_background_message() {
381 return "closeBackgroundPage";
385 scoped_refptr
<const Extension
> LoadExtensionIntoDir(
386 TestExtensionDir
* dir
,
387 const std::string
& manifest
,
388 bool with_event_handlers
= true) {
389 dir
->WriteManifest(manifest
);
390 if (with_event_handlers
) {
392 FILE_PATH_LITERAL("background.js"),
394 "function maybeClose(message) {\n"
395 " if (message.indexOf('%s') >= 0)\n"
396 " window.setTimeout(function() { window.close() }, 0);\n"
398 "chrome.runtime.onMessageExternal.addListener(\n"
399 " function(message, sender, reply) {\n"
400 " reply({ message: message, sender: sender });\n"
401 " maybeClose(message);\n"
403 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
404 " port.onMessage.addListener(function(message) {\n"
405 " port.postMessage({ message: message, sender: port.sender "
407 " maybeClose(message);\n"
410 close_background_message()));
412 dir
->WriteFile(FILE_PATH_LITERAL("background.js"), "");
414 return LoadExtension(dir
->unpacked_path());
417 const char* common_manifest() {
418 return "\"version\": \"1.0\","
420 " \"scripts\": [\"background.js\"],"
421 " \"persistent\": false"
423 "\"manifest_version\": 2";
426 std::string
connectable_with_tls_channel_id_manifest() {
427 return base::StringPrintf(
429 " \"name\": \"chromium_connectable_with_tls_channel_id\","
431 " \"externally_connectable\": {"
432 " \"matches\": [\"*://*.chromium.org:*/*\"],"
433 " \"accepts_tls_channel_id\": true"
439 std::string
GetTlsChannelIdFromAssertion(const char* method
,
440 const Extension
* extension
,
441 bool include_tls_channel_id
,
442 const char* message
) {
444 std::string args
= "'" + extension
->id() + "', ";
445 args
+= include_tls_channel_id
? "true" : "false";
447 args
+= std::string(", '") + message
+ "'";
448 CHECK(content::ExecuteScriptAndExtractString(
449 browser()->tab_strip_model()->GetActiveWebContents(),
450 base::StringPrintf("assertions.%s(%s)", method
, args
.c_str()),
455 TestExtensionDir web_connectable_dir_
;
456 TestExtensionDir not_connectable_dir_
;
457 TestExtensionDir tls_channel_id_connectable_dir_
;
458 TestExtensionDir hosted_app_dir_
;
461 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, NotInstalled
) {
462 InitializeTestServer();
464 scoped_refptr
<const Extension
> extension
=
466 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
467 .SetManifest(DictionaryBuilder()
468 .Set("name", "Fake extension")
470 .Set("manifest_version", 2))
473 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
474 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
475 CanConnectAndSendMessagesToMainFrame(extension
.get()));
476 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
478 ui_test_utils::NavigateToURL(browser(), google_com_url());
479 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
480 CanConnectAndSendMessagesToMainFrame(extension
.get()));
481 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
484 // Tests two extensions on the same sites: one web connectable, one not.
485 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
486 WebConnectableAndNotConnectable
) {
487 InitializeTestServer();
489 // Install the web connectable extension. chromium.org can connect to it,
491 scoped_refptr
<const Extension
> chromium_connectable
=
492 LoadChromiumConnectableExtension();
494 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
496 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
497 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
499 ui_test_utils::NavigateToURL(browser(), google_com_url());
500 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
501 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
502 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
504 // Install the non-connectable extension. Nothing can connect to it.
505 scoped_refptr
<const Extension
> not_connectable
=
506 LoadNotConnectableExtension();
508 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
509 // Namespace will be defined here because |chromium_connectable| can connect
510 // to it - so this will be the "cannot establish connection" error.
511 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
512 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
513 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
515 ui_test_utils::NavigateToURL(browser(), google_com_url());
516 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
517 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
518 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
521 // See http://crbug.com/297866
522 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
523 DISABLED_BackgroundPageClosesOnMessageReceipt
) {
524 InitializeTestServer();
526 // Install the web connectable extension.
527 scoped_refptr
<const Extension
> chromium_connectable
=
528 LoadChromiumConnectableExtension();
530 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
531 // If the background page closes after receipt of the message, it will still
532 // reply to this message...
534 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get(),
535 close_background_message()));
536 // and be re-opened by receipt of a subsequent message.
538 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
541 // Tests a web connectable extension that doesn't receive TLS channel id.
542 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
543 WebConnectableWithoutTlsChannelId
) {
544 InitializeTestServer();
546 // Install the web connectable extension. chromium.org can connect to it,
548 scoped_refptr
<const Extension
> chromium_connectable
=
549 LoadChromiumConnectableExtension();
550 ASSERT_TRUE(chromium_connectable
.get());
552 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
553 // The web connectable extension doesn't request the TLS channel ID, so it
554 // doesn't get it, whether or not the page asks for it.
555 EXPECT_EQ(std::string(),
556 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
557 EXPECT_EQ(std::string(),
558 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
559 EXPECT_EQ(std::string(),
560 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
561 EXPECT_EQ(std::string(),
562 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
565 // Tests a web connectable extension that receives TLS channel id with a site
566 // that can't connect to it.
567 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
568 WebConnectableWithTlsChannelIdWithNonMatchingSite
) {
569 InitializeTestServer();
571 scoped_refptr
<const Extension
> chromium_connectable
=
572 LoadChromiumConnectableExtensionWithTlsChannelId();
573 ASSERT_TRUE(chromium_connectable
.get());
575 ui_test_utils::NavigateToURL(browser(), google_com_url());
576 // The extension requests the TLS channel ID, but it doesn't get it for a
577 // site that can't connect to it, regardless of whether the page asks for it.
578 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
579 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
580 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
581 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
582 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
583 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
584 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
585 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
588 // Tests a web connectable extension that receives TLS channel id on a site
589 // that can connect to it, but with no TLS channel ID having been generated.
590 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
591 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId
) {
592 InitializeTestServer();
594 scoped_refptr
<const Extension
> chromium_connectable
=
595 LoadChromiumConnectableExtensionWithTlsChannelId();
596 ASSERT_TRUE(chromium_connectable
.get());
598 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
600 // Since the extension requests the TLS channel ID, it gets it for a site that
601 // can connect to it, but only if the page also asks to include it.
602 EXPECT_EQ(std::string(),
603 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
604 EXPECT_EQ(std::string(),
605 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
606 // If the page does ask for it, it isn't empty.
607 std::string tls_channel_id
=
608 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
609 // Because the TLS channel ID has never been generated for this domain,
610 // no TLS channel ID is reported.
611 EXPECT_EQ(std::string(), tls_channel_id
);
614 // Flaky on Linux and Windows. http://crbug.com/315264
615 // Tests a web connectable extension that receives TLS channel id, but
616 // immediately closes its background page upon receipt of a message.
617 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
618 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
) {
619 InitializeTestServer();
621 scoped_refptr
<const Extension
> chromium_connectable
=
622 LoadChromiumConnectableExtensionWithTlsChannelId();
624 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
625 // If the page does ask for it, it isn't empty, even if the background page
626 // closes upon receipt of the connect.
627 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
628 chromium_connectable
.get(), true, close_background_message());
629 // Because the TLS channel ID has never been generated for this domain,
630 // no TLS channel ID is reported.
631 EXPECT_EQ(std::string(), tls_channel_id
);
632 // A subsequent connect will still succeed, even if the background page was
633 // previously closed.
635 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
636 // And the empty value is still retrieved.
637 EXPECT_EQ(std::string(), tls_channel_id
);
640 // Tests that enabling and disabling an extension makes the runtime bindings
641 // appear and disappear.
643 // TODO(kalman): Test with multiple extensions that can be accessed by the same
645 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
646 EnablingAndDisabling
) {
647 InitializeTestServer();
649 scoped_refptr
<const Extension
> chromium_connectable
=
650 LoadChromiumConnectableExtension();
651 scoped_refptr
<const Extension
> not_connectable
=
652 LoadNotConnectableExtension();
654 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
656 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
657 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
658 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
660 DisableExtension(chromium_connectable
->id());
661 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
662 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
664 EnableExtension(chromium_connectable
->id());
666 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
667 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
668 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
671 // Tests connection from incognito tabs when the user denies the connection
672 // request. Spanning mode only. A separate test for apps and extensions.
674 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
675 // somewhere. This is a test that should be shared with the content script logic
676 // so it's not really our specific concern for web connectable.
678 // TODO(kalman): test messages from incognito extensions too.
679 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
680 FromIncognitoDenyApp
) {
681 InitializeTestServer();
683 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
684 ASSERT_TRUE(app
->is_platform_app());
686 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
687 profile()->GetOffTheRecordProfile(),
689 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
690 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
693 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
694 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
696 // No connection because incognito-enabled hasn't been set for the app, and
697 // the user denied our interactive request.
699 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
700 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
701 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
703 // Try again. User has already denied so alert not shown.
705 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
706 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
707 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
710 // It's not possible to allow an app in incognito.
711 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
712 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
713 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
716 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
717 FromIncognitoDenyExtension
) {
718 InitializeTestServer();
720 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
722 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
723 profile()->GetOffTheRecordProfile(), chromium_org_url());
724 content::RenderFrameHost
* incognito_frame
=
725 incognito_browser
->tab_strip_model()
726 ->GetActiveWebContents()
730 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
731 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
733 // The alert doesn't show for extensions.
734 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
735 CanConnectAndSendMessagesToFrame(
736 incognito_frame
, extension
.get(), NULL
));
737 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
740 // Allowing the extension in incognito mode will bypass the deny.
741 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
744 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
747 // Tests connection from incognito tabs when the extension doesn't have an event
748 // handler for the connection event.
749 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
750 FromIncognitoNoEventHandlerInApp
) {
751 InitializeTestServer();
753 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp(false);
754 ASSERT_TRUE(app
->is_platform_app());
756 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
757 profile()->GetOffTheRecordProfile(), chromium_org_url());
758 content::RenderFrameHost
* incognito_frame
=
759 incognito_browser
->tab_strip_model()
760 ->GetActiveWebContents()
764 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
765 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
767 // No connection because incognito-enabled hasn't been set for the app, and
768 // the app hasn't installed event handlers.
770 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
771 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
772 // No dialog should have been shown.
773 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
777 // Tests connection from incognito tabs when the user accepts the connection
778 // request. Spanning mode only. Separate tests for apps and extensions.
780 // TODO(kalman): see comment above about split mode.
781 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
782 FromIncognitoAllowApp
) {
783 InitializeTestServer();
785 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
786 ASSERT_TRUE(app
->is_platform_app());
788 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
789 profile()->GetOffTheRecordProfile(),
791 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
792 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
795 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
796 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
798 // Connection allowed even with incognito disabled, because the user
799 // accepted the interactive request.
801 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
802 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
804 // Try again. User has already allowed.
806 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
807 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
810 // Apps can't be allowed in incognito mode, but it's moot because it's
812 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
814 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
817 // Tests connection from incognito tabs when there are multiple tabs open to the
818 // same origin. The user should only need to accept the connection request once.
819 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
820 FromIncognitoPromptApp
) {
821 InitializeTestServer();
823 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
824 ASSERT_TRUE(app
->is_platform_app());
826 // Open an incognito browser with two tabs displaying "chromium.org".
827 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
828 profile()->GetOffTheRecordProfile(), chromium_org_url());
829 content::RenderFrameHost
* incognito_frame1
=
830 incognito_browser
->tab_strip_model()
831 ->GetActiveWebContents()
833 InfoBarService
* infobar_service1
= InfoBarService::FromWebContents(
834 incognito_browser
->tab_strip_model()->GetActiveWebContents());
836 CHECK(ui_test_utils::OpenURLOffTheRecord(profile()->GetOffTheRecordProfile(),
837 chromium_org_url()) ==
839 content::RenderFrameHost
* incognito_frame2
=
840 incognito_browser
->tab_strip_model()
841 ->GetActiveWebContents()
843 InfoBarService
* infobar_service2
= InfoBarService::FromWebContents(
844 incognito_browser
->tab_strip_model()->GetActiveWebContents());
845 EXPECT_EQ(2, incognito_browser
->tab_strip_model()->count());
846 EXPECT_NE(incognito_frame1
, incognito_frame2
);
848 // Trigger a infobars in both tabs by trying to send messages.
850 base::StringPrintf("assertions.trySendMessage('%s')", app
->id().c_str());
851 CHECK(content::ExecuteScript(incognito_frame1
, script
));
852 CHECK(content::ExecuteScript(incognito_frame2
, script
));
853 EXPECT_EQ(1U, infobar_service1
->infobar_count());
854 EXPECT_EQ(1U, infobar_service2
->infobar_count());
856 // Navigating away will dismiss the infobar on the active tab only.
857 ui_test_utils::NavigateToURL(incognito_browser
, google_com_url());
858 EXPECT_EQ(1U, infobar_service1
->infobar_count());
859 EXPECT_EQ(0U, infobar_service2
->infobar_count());
861 // Navigate back and accept the infobar this time. Both should be dismissed.
863 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
864 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
866 ui_test_utils::NavigateToURL(incognito_browser
, chromium_org_url());
867 incognito_frame2
= incognito_browser
->tab_strip_model()
868 ->GetActiveWebContents()
870 EXPECT_NE(incognito_frame1
, incognito_frame2
);
872 EXPECT_EQ(1U, infobar_service1
->infobar_count());
873 EXPECT_EQ(OK
, CanConnectAndSendMessagesToFrame(incognito_frame2
, app
.get(),
875 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
876 EXPECT_EQ(0U, infobar_service1
->infobar_count());
880 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
881 FromIncognitoAllowExtension
) {
882 InitializeTestServer();
884 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
886 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
887 profile()->GetOffTheRecordProfile(), chromium_org_url());
888 content::RenderFrameHost
* incognito_frame
=
889 incognito_browser
->tab_strip_model()
890 ->GetActiveWebContents()
894 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
895 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
897 // No alert is shown.
898 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
899 CanConnectAndSendMessagesToFrame(
900 incognito_frame
, extension
.get(), NULL
));
901 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
904 // Allowing the extension in incognito mode is what allows connections.
905 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
908 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
911 // Tests a connection from an iframe within a tab which doesn't have
912 // permission. Iframe should work.
913 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
914 FromIframeWithPermission
) {
915 InitializeTestServer();
917 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
919 ui_test_utils::NavigateToURL(browser(), google_com_url());
920 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
921 CanConnectAndSendMessagesToMainFrame(extension
.get()));
922 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
924 ASSERT_TRUE(AppendIframe(chromium_org_url()));
926 EXPECT_EQ(OK
, CanConnectAndSendMessagesToIFrame(extension
.get()));
927 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
930 // Tests connection from an iframe without permission within a tab that does.
931 // Iframe shouldn't work.
932 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
933 FromIframeWithoutPermission
) {
934 InitializeTestServer();
936 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
938 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
939 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
940 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
942 ASSERT_TRUE(AppendIframe(google_com_url()));
944 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
945 CanConnectAndSendMessagesToIFrame(extension
.get()));
946 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
949 // Tests externally_connectable between a web page and an extension with a
950 // TLS channel ID created for the origin.
951 class ExternallyConnectableMessagingWithTlsChannelIdTest
:
952 public ExternallyConnectableMessagingTest
{
954 ExternallyConnectableMessagingWithTlsChannelIdTest()
955 : tls_channel_id_created_(false, false) {
958 std::string
CreateTlsChannelId() {
959 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
960 profile()->GetRequestContext());
961 std::string channel_id_private_key
;
962 std::string channel_id_cert
;
963 net::ChannelIDService::RequestHandle request_handle
;
964 content::BrowserThread::PostTask(
965 content::BrowserThread::IO
,
968 &ExternallyConnectableMessagingWithTlsChannelIdTest::
969 CreateDomainBoundCertOnIOThread
,
970 base::Unretained(this),
971 base::Unretained(&channel_id_private_key
),
972 base::Unretained(&channel_id_cert
),
973 base::Unretained(&request_handle
),
974 request_context_getter
));
975 tls_channel_id_created_
.Wait();
976 // Create the expected value.
977 base::StringPiece spki
;
978 net::asn1::ExtractSPKIFromDERCert(channel_id_cert
, &spki
);
979 base::DictionaryValue jwk_value
;
980 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki
, &jwk_value
);
981 std::string tls_channel_id_value
;
982 base::JSONWriter::Write(&jwk_value
, &tls_channel_id_value
);
983 return tls_channel_id_value
;
987 void CreateDomainBoundCertOnIOThread(
988 std::string
* channel_id_private_key
,
989 std::string
* channel_id_cert
,
990 net::ChannelIDService::RequestHandle
* request_handle
,
991 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
) {
992 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
993 net::ChannelIDService
* channel_id_service
=
994 request_context_getter
->GetURLRequestContext()->
995 channel_id_service();
996 int status
= channel_id_service
->GetOrCreateChannelID(
997 chromium_org_url().host(),
998 channel_id_private_key
,
1000 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
1002 base::Unretained(this)),
1004 if (status
== net::ERR_IO_PENDING
)
1006 GotDomainBoundCert(status
);
1009 void GotDomainBoundCert(int status
) {
1010 ASSERT_TRUE(status
== net::OK
);
1011 tls_channel_id_created_
.Signal();
1014 base::WaitableEvent tls_channel_id_created_
;
1017 // Tests a web connectable extension that receives TLS channel id on a site
1018 // that can connect to it, with a TLS channel ID having been generated.
1019 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1020 WebConnectableWithNonEmptyTlsChannelId
) {
1021 InitializeTestServer();
1022 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1024 scoped_refptr
<const Extension
> chromium_connectable
=
1025 LoadChromiumConnectableExtensionWithTlsChannelId();
1026 ASSERT_TRUE(chromium_connectable
.get());
1028 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1030 // Since the extension requests the TLS channel ID, it gets it for a site that
1031 // can connect to it, but only if the page also asks to send it.
1032 EXPECT_EQ(std::string(),
1033 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
1034 EXPECT_EQ(std::string(),
1035 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
1037 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
1038 std::string tls_channel_id_from_port_connect
=
1039 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1040 EXPECT_NE(0u, tls_channel_id_from_port_connect
.size());
1042 // The same value is received by both connect and sendMessage.
1043 std::string tls_channel_id_from_send_message
=
1044 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1045 EXPECT_EQ(tls_channel_id_from_port_connect
, tls_channel_id_from_send_message
);
1047 // And since a TLS channel ID exists for the domain, the value received is
1048 // parseable as a JWK. (In particular, it has the same value we created by
1049 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
1050 std::string
tls_channel_id(tls_channel_id_from_port_connect
);
1051 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1053 // The TLS channel ID shouldn't change from one connection to the next...
1054 std::string tls_channel_id2
=
1055 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1056 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1058 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1059 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1061 // nor should it change when navigating away, revisiting the page and
1062 // requesting it again.
1063 ui_test_utils::NavigateToURL(browser(), google_com_url());
1064 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1066 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1067 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1069 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1070 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1073 // Tests a web connectable extension that receives TLS channel id, but
1074 // immediately closes its background page upon receipt of a message.
1075 // Same flakiness seen in http://crbug.com/297866
1076 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1077 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage
) {
1078 InitializeTestServer();
1079 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1081 scoped_refptr
<const Extension
> chromium_connectable
=
1082 LoadChromiumConnectableExtensionWithTlsChannelId();
1084 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1085 // If the page does ask for it, it isn't empty, even if the background page
1086 // closes upon receipt of the connect.
1087 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
1088 chromium_connectable
.get(), true, close_background_message());
1089 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1090 // A subsequent connect will still succeed, even if the background page was
1091 // previously closed.
1093 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1094 // And the expected value is still retrieved.
1095 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1098 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingUserGesture
) {
1099 const char kManifest
[] = "{"
1100 " \"name\": \"user_gesture\","
1101 " \"version\": \"1.0\","
1102 " \"background\": {"
1103 " \"scripts\": [\"background.js\"]"
1105 " \"manifest_version\": 2"
1108 TestExtensionDir receiver_dir
;
1109 receiver_dir
.WriteManifest(kManifest
);
1110 receiver_dir
.WriteFile(FILE_PATH_LITERAL("background.js"),
1111 "chrome.runtime.onMessageExternal.addListener(\n"
1112 " function(msg, sender, reply) {\n"
1113 " reply({result:chrome.test.isProcessingUserGesture()});\n"
1115 const Extension
* receiver
= LoadExtension(receiver_dir
.unpacked_path());
1116 ASSERT_TRUE(receiver
);
1118 TestExtensionDir sender_dir
;
1119 sender_dir
.WriteManifest(kManifest
);
1120 sender_dir
.WriteFile(FILE_PATH_LITERAL("background.js"), "");
1121 const Extension
* sender
= LoadExtension(sender_dir
.unpacked_path());
1122 ASSERT_TRUE(sender
);
1125 ExecuteScriptInBackgroundPage(sender
->id(),
1127 "chrome.test.runWithoutUserGesture(function() {\n"
1128 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1129 " window.domAutomationController.send('' + response.result);\n"
1131 "});", receiver
->id().c_str())));
1134 ExecuteScriptInBackgroundPage(sender
->id(),
1136 "chrome.test.runWithUserGesture(function() {\n"
1137 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1138 " window.domAutomationController.send('' + response.result);\n"
1140 "});", receiver
->id().c_str())));
1143 // Tests that a hosted app on a connectable site doesn't interfere with the
1144 // connectability of that site.
1145 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, HostedAppOnWebsite
) {
1146 InitializeTestServer();
1148 scoped_refptr
<const Extension
> app
= LoadChromiumHostedApp();
1150 // The presence of the hosted app shouldn't give the ability to send messages.
1151 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1152 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
1153 CanConnectAndSendMessagesToMainFrame(app
.get()));
1154 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1156 // Once a connectable extension is installed, it should.
1157 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
1158 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
1159 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1162 // Tests that an invalid extension ID specified in a hosted app does not crash
1163 // the hosted app's renderer.
1165 // This is a regression test for http://crbug.com/326250#c12.
1166 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
1167 InvalidExtensionIDFromHostedApp
) {
1168 InitializeTestServer();
1170 // The presence of the chromium hosted app triggers this bug. The chromium
1171 // connectable extension needs to be installed to set up the runtime bindings.
1172 LoadChromiumHostedApp();
1173 LoadChromiumConnectableExtension();
1175 scoped_refptr
<const Extension
> invalid
=
1177 // A bit scary that this works...
1179 .SetManifest(DictionaryBuilder()
1180 .Set("name", "Fake extension")
1181 .Set("version", "1")
1182 .Set("manifest_version", 2))
1185 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1186 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
1187 CanConnectAndSendMessagesToMainFrame(invalid
.get()));
1190 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1194 }; // namespace extensions