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(events::TEST_ON_MESSAGE
, "test.onMessage",
73 event
->restrict_to_browser_context
= profile
;
74 event
->event_url
= event_url
;
78 void Observe(int type
,
79 const content::NotificationSource
& source
,
80 const content::NotificationDetails
& details
) override
{
81 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD
,
83 EventRouter
* event_router
=
84 EventRouter::Get(content::Source
<Profile
>(source
).ptr());
86 // Sends four messages to the extension. All but the third message sent
87 // from the origin http://b.com/ are supposed to arrive.
88 event_router
->BroadcastEvent(BuildEvent(
89 BuildEventArguments(false, "no restriction"),
90 content::Source
<Profile
>(source
).ptr(),
92 event_router
->BroadcastEvent(BuildEvent(
93 BuildEventArguments(false, "http://a.com/"),
94 content::Source
<Profile
>(source
).ptr(),
95 GURL("http://a.com/")));
96 event_router
->BroadcastEvent(BuildEvent(
97 BuildEventArguments(false, "http://b.com/"),
98 content::Source
<Profile
>(source
).ptr(),
99 GURL("http://b.com/")));
100 event_router
->BroadcastEvent(BuildEvent(
101 BuildEventArguments(true, "last message"),
102 content::Source
<Profile
>(source
).ptr(),
106 content::NotificationRegistrar registrar_
;
109 // Tests that message passing between extensions and content scripts works.
110 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, Messaging
) {
111 ASSERT_TRUE(StartEmbeddedTestServer());
112 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_
;
115 // Tests that message passing from one extension to another works.
116 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingExternal
) {
117 ASSERT_TRUE(LoadExtension(
118 test_data_dir_
.AppendASCII("..").AppendASCII("good")
119 .AppendASCII("Extensions")
120 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
121 .AppendASCII("1.0")));
123 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_
;
126 // Tests that messages with event_urls are only passed to extensions with
127 // appropriate permissions.
128 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingEventURL
) {
129 MessageSender sender
;
130 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_
;
133 // Tests connecting from a panel to its extension.
134 class PanelMessagingTest
: public ExtensionApiTest
{
135 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
136 ExtensionApiTest::SetUpCommandLine(command_line
);
137 command_line
->AppendSwitch(switches::kEnablePanels
);
141 IN_PROC_BROWSER_TEST_F(PanelMessagingTest
, MessagingPanel
) {
142 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_
;
145 // XXX(kalman): All web messaging tests disabled on windows due to extreme
146 // flakiness. See http://crbug.com/350517.
149 // Tests externally_connectable between a web page and an extension.
151 // TODO(kalman): Test between extensions. This is already tested in this file,
152 // but not with externally_connectable set in the manifest.
154 // TODO(kalman): Test with host permissions.
155 class ExternallyConnectableMessagingTest
: public ExtensionApiTest
{
157 // Result codes from the test. These must match up with |results| in
158 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
161 NAMESPACE_NOT_DEFINED
= 1,
162 FUNCTION_NOT_DEFINED
= 2,
163 COULD_NOT_ESTABLISH_CONNECTION_ERROR
= 3,
165 INCORRECT_RESPONSE_SENDER
= 5,
166 INCORRECT_RESPONSE_MESSAGE
= 6,
169 bool AppendIframe(const GURL
& src
) {
171 CHECK(content::ExecuteScriptAndExtractBool(
172 browser()->tab_strip_model()->GetActiveWebContents(),
173 "actions.appendIframe('" + src
.spec() + "');", &result
));
177 Result
CanConnectAndSendMessagesToMainFrame(const Extension
* extension
,
178 const char* message
= NULL
) {
179 return CanConnectAndSendMessagesToFrame(
180 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
185 Result
CanConnectAndSendMessagesToIFrame(const Extension
* extension
,
186 const char* message
= NULL
) {
187 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
188 browser()->tab_strip_model()->GetActiveWebContents(),
189 base::Bind(&content::FrameIsChildOfMainFrame
));
190 return CanConnectAndSendMessagesToFrame(frame
, extension
, message
);
193 Result
CanConnectAndSendMessagesToFrame(content::RenderFrameHost
* frame
,
194 const Extension
* extension
,
195 const char* message
) {
197 std::string command
= base::StringPrintf(
198 "assertions.canConnectAndSendMessages('%s', %s, %s)",
199 extension
->id().c_str(),
200 extension
->is_platform_app() ? "true" : "false",
201 message
? base::StringPrintf("'%s'", message
).c_str() : "undefined");
202 CHECK(content::ExecuteScriptAndExtractInt(frame
, command
, &result
));
203 return static_cast<Result
>(result
);
206 testing::AssertionResult
AreAnyNonWebApisDefinedForMainFrame() {
207 return AreAnyNonWebApisDefinedForFrame(
208 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
211 testing::AssertionResult
AreAnyNonWebApisDefinedForIFrame() {
212 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
213 browser()->tab_strip_model()->GetActiveWebContents(),
214 base::Bind(&content::FrameIsChildOfMainFrame
));
215 return AreAnyNonWebApisDefinedForFrame(frame
);
218 testing::AssertionResult
AreAnyNonWebApisDefinedForFrame(
219 content::RenderFrameHost
* frame
) {
220 // All runtime API methods are non-web except for sendRequest and connect.
221 const char* const non_messaging_apis
[] = {
226 "requestUpdateCheck",
235 "onBrowserUpdateAvailable",
241 // Note: no "id" here because this test method is used for hosted apps,
242 // which do have access to runtime.id.
245 // Turn the array into a JS array, which effectively gets eval()ed.
246 std::string as_js_array
;
247 for (size_t i
= 0; i
< arraysize(non_messaging_apis
); ++i
) {
248 as_js_array
+= as_js_array
.empty() ? "[" : ",";
249 as_js_array
+= base::StringPrintf("'%s'", non_messaging_apis
[i
]);
254 CHECK(content::ExecuteScriptAndExtractBool(
256 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array
+ ")",
259 testing::AssertionSuccess() : testing::AssertionFailure();
262 std::string
GetTlsChannelIdFromPortConnect(const Extension
* extension
,
263 bool include_tls_channel_id
,
264 const char* message
= NULL
) {
265 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
267 include_tls_channel_id
,
271 std::string
GetTlsChannelIdFromSendMessage(const Extension
* extension
,
272 bool include_tls_channel_id
,
273 const char* message
= NULL
) {
274 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
276 include_tls_channel_id
,
280 GURL
GetURLForPath(const std::string
& host
, const std::string
& path
) {
281 std::string port
= base::IntToString(embedded_test_server()->port());
282 GURL::Replacements replacements
;
283 replacements
.SetHostStr(host
);
284 replacements
.SetPortStr(port
);
285 return embedded_test_server()->GetURL(path
).ReplaceComponents(replacements
);
288 GURL
chromium_org_url() {
289 return GetURLForPath("www.chromium.org", "/chromium.org.html");
292 GURL
google_com_url() {
293 return GetURLForPath("www.google.com", "/google.com.html");
296 scoped_refptr
<const Extension
> LoadChromiumConnectableExtension() {
297 scoped_refptr
<const Extension
> extension
=
298 LoadExtensionIntoDir(&web_connectable_dir_
,
301 " \"name\": \"chromium_connectable\","
303 " \"externally_connectable\": {"
304 " \"matches\": [\"*://*.chromium.org:*/*\"]"
308 CHECK(extension
.get());
312 scoped_refptr
<const Extension
> LoadChromiumConnectableApp(
313 bool with_event_handlers
= true) {
314 scoped_refptr
<const Extension
> extension
=
315 LoadExtensionIntoDir(&web_connectable_dir_
,
319 " \"scripts\": [\"background.js\"]"
322 " \"externally_connectable\": {"
323 " \"matches\": [\"*://*.chromium.org:*/*\"]"
325 " \"manifest_version\": 2,"
326 " \"name\": \"app_connectable\","
327 " \"version\": \"1.0\""
329 with_event_handlers
);
330 CHECK(extension
.get());
334 scoped_refptr
<const Extension
> LoadNotConnectableExtension() {
335 scoped_refptr
<const Extension
> extension
=
336 LoadExtensionIntoDir(¬_connectable_dir_
,
339 " \"name\": \"not_connectable\","
343 CHECK(extension
.get());
347 scoped_refptr
<const Extension
>
348 LoadChromiumConnectableExtensionWithTlsChannelId() {
349 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_
,
350 connectable_with_tls_channel_id_manifest());
353 scoped_refptr
<const Extension
> LoadChromiumHostedApp() {
354 scoped_refptr
<const Extension
> hosted_app
=
355 LoadExtensionIntoDir(&hosted_app_dir_
,
358 " \"name\": \"chromium_hosted_app\","
359 " \"version\": \"1.0\","
360 " \"manifest_version\": 2,"
362 " \"urls\": [\"%s\"],"
364 " \"web_url\": \"%s\""
368 chromium_org_url().spec().c_str(),
369 chromium_org_url().spec().c_str()));
370 CHECK(hosted_app
.get());
374 void InitializeTestServer() {
375 base::FilePath test_data
;
376 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &test_data
));
377 embedded_test_server()->ServeFilesFromDirectory(test_data
.AppendASCII(
378 "extensions/api_test/messaging/externally_connectable/sites"));
379 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
380 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
383 const char* close_background_message() {
384 return "closeBackgroundPage";
388 scoped_refptr
<const Extension
> LoadExtensionIntoDir(
389 TestExtensionDir
* dir
,
390 const std::string
& manifest
,
391 bool with_event_handlers
= true) {
392 dir
->WriteManifest(manifest
);
393 if (with_event_handlers
) {
395 FILE_PATH_LITERAL("background.js"),
397 "function maybeClose(message) {\n"
398 " if (message.indexOf('%s') >= 0)\n"
399 " window.setTimeout(function() { window.close() }, 0);\n"
401 "chrome.runtime.onMessageExternal.addListener(\n"
402 " function(message, sender, reply) {\n"
403 " reply({ message: message, sender: sender });\n"
404 " maybeClose(message);\n"
406 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
407 " port.onMessage.addListener(function(message) {\n"
408 " port.postMessage({ message: message, sender: port.sender "
410 " maybeClose(message);\n"
413 close_background_message()));
415 dir
->WriteFile(FILE_PATH_LITERAL("background.js"), "");
417 return LoadExtension(dir
->unpacked_path());
420 const char* common_manifest() {
421 return "\"version\": \"1.0\","
423 " \"scripts\": [\"background.js\"],"
424 " \"persistent\": false"
426 "\"manifest_version\": 2";
429 std::string
connectable_with_tls_channel_id_manifest() {
430 return base::StringPrintf(
432 " \"name\": \"chromium_connectable_with_tls_channel_id\","
434 " \"externally_connectable\": {"
435 " \"matches\": [\"*://*.chromium.org:*/*\"],"
436 " \"accepts_tls_channel_id\": true"
442 std::string
GetTlsChannelIdFromAssertion(const char* method
,
443 const Extension
* extension
,
444 bool include_tls_channel_id
,
445 const char* message
) {
447 std::string args
= "'" + extension
->id() + "', ";
448 args
+= include_tls_channel_id
? "true" : "false";
450 args
+= std::string(", '") + message
+ "'";
451 CHECK(content::ExecuteScriptAndExtractString(
452 browser()->tab_strip_model()->GetActiveWebContents(),
453 base::StringPrintf("assertions.%s(%s)", method
, args
.c_str()),
458 TestExtensionDir web_connectable_dir_
;
459 TestExtensionDir not_connectable_dir_
;
460 TestExtensionDir tls_channel_id_connectable_dir_
;
461 TestExtensionDir hosted_app_dir_
;
464 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, NotInstalled
) {
465 InitializeTestServer();
467 scoped_refptr
<const Extension
> extension
=
469 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
470 .SetManifest(DictionaryBuilder()
471 .Set("name", "Fake extension")
473 .Set("manifest_version", 2))
476 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
477 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
478 CanConnectAndSendMessagesToMainFrame(extension
.get()));
479 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
481 ui_test_utils::NavigateToURL(browser(), google_com_url());
482 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
483 CanConnectAndSendMessagesToMainFrame(extension
.get()));
484 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
487 // Tests two extensions on the same sites: one web connectable, one not.
488 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
489 WebConnectableAndNotConnectable
) {
490 InitializeTestServer();
492 // Install the web connectable extension. chromium.org can connect to it,
494 scoped_refptr
<const Extension
> chromium_connectable
=
495 LoadChromiumConnectableExtension();
497 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
499 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
500 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
502 ui_test_utils::NavigateToURL(browser(), google_com_url());
503 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
504 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
505 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
507 // Install the non-connectable extension. Nothing can connect to it.
508 scoped_refptr
<const Extension
> not_connectable
=
509 LoadNotConnectableExtension();
511 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
512 // Namespace will be defined here because |chromium_connectable| can connect
513 // to it - so this will be the "cannot establish connection" error.
514 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
515 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
516 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
518 ui_test_utils::NavigateToURL(browser(), google_com_url());
519 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
520 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
521 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
524 // See http://crbug.com/297866
525 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
526 DISABLED_BackgroundPageClosesOnMessageReceipt
) {
527 InitializeTestServer();
529 // Install the web connectable extension.
530 scoped_refptr
<const Extension
> chromium_connectable
=
531 LoadChromiumConnectableExtension();
533 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
534 // If the background page closes after receipt of the message, it will still
535 // reply to this message...
537 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get(),
538 close_background_message()));
539 // and be re-opened by receipt of a subsequent message.
541 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
544 // Tests a web connectable extension that doesn't receive TLS channel id.
545 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
546 WebConnectableWithoutTlsChannelId
) {
547 InitializeTestServer();
549 // Install the web connectable extension. chromium.org can connect to it,
551 scoped_refptr
<const Extension
> chromium_connectable
=
552 LoadChromiumConnectableExtension();
553 ASSERT_TRUE(chromium_connectable
.get());
555 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
556 // The web connectable extension doesn't request the TLS channel ID, so it
557 // doesn't get it, whether or not the page asks for it.
558 EXPECT_EQ(std::string(),
559 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
560 EXPECT_EQ(std::string(),
561 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
562 EXPECT_EQ(std::string(),
563 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
564 EXPECT_EQ(std::string(),
565 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
568 // Tests a web connectable extension that receives TLS channel id with a site
569 // that can't connect to it.
570 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
571 WebConnectableWithTlsChannelIdWithNonMatchingSite
) {
572 InitializeTestServer();
574 scoped_refptr
<const Extension
> chromium_connectable
=
575 LoadChromiumConnectableExtensionWithTlsChannelId();
576 ASSERT_TRUE(chromium_connectable
.get());
578 ui_test_utils::NavigateToURL(browser(), google_com_url());
579 // The extension requests the TLS channel ID, but it doesn't get it for a
580 // site that can't connect to it, regardless of whether the page asks for it.
581 EXPECT_EQ(base::IntToString(NAMESPACE_NOT_DEFINED
),
582 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
583 EXPECT_EQ(base::IntToString(NAMESPACE_NOT_DEFINED
),
584 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
585 EXPECT_EQ(base::IntToString(NAMESPACE_NOT_DEFINED
),
586 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
587 EXPECT_EQ(base::IntToString(NAMESPACE_NOT_DEFINED
),
588 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true));
591 // Tests a web connectable extension that receives TLS channel id on a site
592 // that can connect to it, but with no TLS channel ID having been generated.
593 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
594 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId
) {
595 InitializeTestServer();
597 scoped_refptr
<const Extension
> chromium_connectable
=
598 LoadChromiumConnectableExtensionWithTlsChannelId();
599 ASSERT_TRUE(chromium_connectable
.get());
601 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
603 // Since the extension requests the TLS channel ID, it gets it for a site that
604 // can connect to it, but only if the page also asks to include it.
605 EXPECT_EQ(std::string(),
606 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
607 EXPECT_EQ(std::string(),
608 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
609 // If the page does ask for it, it isn't empty.
610 std::string tls_channel_id
=
611 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
612 // Because the TLS channel ID has never been generated for this domain,
613 // no TLS channel ID is reported.
614 EXPECT_EQ(std::string(), tls_channel_id
);
617 // Flaky on Linux and Windows. http://crbug.com/315264
618 // Tests a web connectable extension that receives TLS channel id, but
619 // immediately closes its background page upon receipt of a message.
620 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
621 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
) {
622 InitializeTestServer();
624 scoped_refptr
<const Extension
> chromium_connectable
=
625 LoadChromiumConnectableExtensionWithTlsChannelId();
627 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
628 // If the page does ask for it, it isn't empty, even if the background page
629 // closes upon receipt of the connect.
630 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
631 chromium_connectable
.get(), true, close_background_message());
632 // Because the TLS channel ID has never been generated for this domain,
633 // no TLS channel ID is reported.
634 EXPECT_EQ(std::string(), tls_channel_id
);
635 // A subsequent connect will still succeed, even if the background page was
636 // previously closed.
638 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
639 // And the empty value is still retrieved.
640 EXPECT_EQ(std::string(), tls_channel_id
);
643 // Tests that enabling and disabling an extension makes the runtime bindings
644 // appear and disappear.
646 // TODO(kalman): Test with multiple extensions that can be accessed by the same
648 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
649 EnablingAndDisabling
) {
650 InitializeTestServer();
652 scoped_refptr
<const Extension
> chromium_connectable
=
653 LoadChromiumConnectableExtension();
654 scoped_refptr
<const Extension
> not_connectable
=
655 LoadNotConnectableExtension();
657 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
659 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
660 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
661 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
663 DisableExtension(chromium_connectable
->id());
664 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
665 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
667 EnableExtension(chromium_connectable
->id());
669 CanConnectAndSendMessagesToMainFrame(chromium_connectable
.get()));
670 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
671 CanConnectAndSendMessagesToMainFrame(not_connectable
.get()));
674 // Tests connection from incognito tabs when the user denies the connection
675 // request. Spanning mode only. A separate test for apps and extensions.
677 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
678 // somewhere. This is a test that should be shared with the content script logic
679 // so it's not really our specific concern for web connectable.
681 // TODO(kalman): test messages from incognito extensions too.
682 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
683 FromIncognitoDenyApp
) {
684 InitializeTestServer();
686 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
687 ASSERT_TRUE(app
->is_platform_app());
689 Browser
* incognito_browser
= OpenURLOffTheRecord(
690 profile()->GetOffTheRecordProfile(), chromium_org_url());
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
= 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
= 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
= OpenURLOffTheRecord(
791 profile()->GetOffTheRecordProfile(), chromium_org_url());
792 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
793 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
796 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
797 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
799 // Connection allowed even with incognito disabled, because the user
800 // accepted the interactive request.
802 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
803 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
805 // Try again. User has already allowed.
807 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
808 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
811 // Apps can't be allowed in incognito mode, but it's moot because it's
813 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
815 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
818 // Tests connection from incognito tabs when there are multiple tabs open to the
819 // same origin. The user should only need to accept the connection request once.
820 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
821 FromIncognitoPromptApp
) {
822 InitializeTestServer();
824 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
825 ASSERT_TRUE(app
->is_platform_app());
827 // Open an incognito browser with two tabs displaying "chromium.org".
828 Browser
* incognito_browser
= OpenURLOffTheRecord(
829 profile()->GetOffTheRecordProfile(), chromium_org_url());
830 content::RenderFrameHost
* incognito_frame1
=
831 incognito_browser
->tab_strip_model()
832 ->GetActiveWebContents()
834 InfoBarService
* infobar_service1
= InfoBarService::FromWebContents(
835 incognito_browser
->tab_strip_model()->GetActiveWebContents());
837 CHECK(OpenURLOffTheRecord(profile()->GetOffTheRecordProfile(),
838 chromium_org_url()) == incognito_browser
);
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
, IllegalArguments
) {
881 // Tests that malformed arguments to connect() don't crash.
882 // Regression test for crbug.com/472700.
883 InitializeTestServer();
884 LoadChromiumConnectableExtension();
885 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
887 CHECK(content::ExecuteScriptAndExtractBool(
888 browser()->tab_strip_model()->GetActiveWebContents(),
889 "assertions.tryIllegalArguments()", &result
));
893 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
894 FromIncognitoAllowExtension
) {
895 InitializeTestServer();
897 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
899 Browser
* incognito_browser
= OpenURLOffTheRecord(
900 profile()->GetOffTheRecordProfile(), chromium_org_url());
901 content::RenderFrameHost
* incognito_frame
=
902 incognito_browser
->tab_strip_model()
903 ->GetActiveWebContents()
907 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
908 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
910 // No alert is shown.
911 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
912 CanConnectAndSendMessagesToFrame(
913 incognito_frame
, extension
.get(), NULL
));
914 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
917 // Allowing the extension in incognito mode is what allows connections.
918 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
921 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
924 // Tests a connection from an iframe within a tab which doesn't have
925 // permission. Iframe should work.
926 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
927 FromIframeWithPermission
) {
928 InitializeTestServer();
930 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
932 ui_test_utils::NavigateToURL(browser(), google_com_url());
933 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
934 CanConnectAndSendMessagesToMainFrame(extension
.get()));
935 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
937 ASSERT_TRUE(AppendIframe(chromium_org_url()));
939 EXPECT_EQ(OK
, CanConnectAndSendMessagesToIFrame(extension
.get()));
940 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
943 // Tests connection from an iframe without permission within a tab that does.
944 // Iframe shouldn't work.
945 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
946 FromIframeWithoutPermission
) {
947 InitializeTestServer();
949 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
951 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
952 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
953 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
955 ASSERT_TRUE(AppendIframe(google_com_url()));
957 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
958 CanConnectAndSendMessagesToIFrame(extension
.get()));
959 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
962 // Tests externally_connectable between a web page and an extension with a
963 // TLS channel ID created for the origin.
964 class ExternallyConnectableMessagingWithTlsChannelIdTest
:
965 public ExternallyConnectableMessagingTest
{
967 ExternallyConnectableMessagingWithTlsChannelIdTest()
968 : tls_channel_id_created_(false, false) {
971 std::string
CreateTlsChannelId() {
972 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
973 profile()->GetRequestContext());
974 scoped_ptr
<crypto::ECPrivateKey
> channel_id_key
;
975 net::ChannelIDService::Request request
;
976 content::BrowserThread::PostTask(
977 content::BrowserThread::IO
, FROM_HERE
,
978 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
979 CreateDomainBoundCertOnIOThread
,
980 base::Unretained(this), base::Unretained(&channel_id_key
),
981 base::Unretained(&request
), request_context_getter
));
982 tls_channel_id_created_
.Wait();
983 // Create the expected value.
984 std::vector
<uint8
> spki_vector
;
985 if (!channel_id_key
->ExportPublicKey(&spki_vector
))
986 return std::string();
987 base::StringPiece
spki(reinterpret_cast<char*>(
988 vector_as_array(&spki_vector
)), spki_vector
.size());
989 base::DictionaryValue jwk_value
;
990 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki
, &jwk_value
);
991 std::string tls_channel_id_value
;
992 base::JSONWriter::Write(jwk_value
, &tls_channel_id_value
);
993 return tls_channel_id_value
;
997 void CreateDomainBoundCertOnIOThread(
998 scoped_ptr
<crypto::ECPrivateKey
>* channel_id_key
,
999 net::ChannelIDService::Request
* request
,
1000 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
) {
1001 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1002 net::ChannelIDService
* channel_id_service
=
1003 request_context_getter
->GetURLRequestContext()->
1004 channel_id_service();
1005 int status
= channel_id_service
->GetOrCreateChannelID(
1006 chromium_org_url().host(), channel_id_key
,
1007 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
1009 base::Unretained(this)),
1011 if (status
== net::ERR_IO_PENDING
)
1013 GotDomainBoundCert(status
);
1016 void GotDomainBoundCert(int status
) {
1017 ASSERT_TRUE(status
== net::OK
);
1018 tls_channel_id_created_
.Signal();
1021 base::WaitableEvent tls_channel_id_created_
;
1024 // Tests a web connectable extension that receives TLS channel id on a site
1025 // that can connect to it, with a TLS channel ID having been generated.
1026 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1027 WebConnectableWithNonEmptyTlsChannelId
) {
1028 InitializeTestServer();
1029 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1031 scoped_refptr
<const Extension
> chromium_connectable
=
1032 LoadChromiumConnectableExtensionWithTlsChannelId();
1033 ASSERT_TRUE(chromium_connectable
.get());
1035 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1037 // Since the extension requests the TLS channel ID, it gets it for a site that
1038 // can connect to it, but only if the page also asks to send it.
1039 EXPECT_EQ(std::string(),
1040 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
1041 EXPECT_EQ(std::string(),
1042 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
1044 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
1045 std::string tls_channel_id_from_port_connect
=
1046 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1047 EXPECT_NE(0u, tls_channel_id_from_port_connect
.size());
1049 // The same value is received by both connect and sendMessage.
1050 std::string tls_channel_id_from_send_message
=
1051 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1052 EXPECT_EQ(tls_channel_id_from_port_connect
, tls_channel_id_from_send_message
);
1054 // And since a TLS channel ID exists for the domain, the value received is
1055 // parseable as a JWK. (In particular, it has the same value we created by
1056 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
1057 std::string
tls_channel_id(tls_channel_id_from_port_connect
);
1058 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1060 // The TLS channel ID shouldn't change from one connection to the next...
1061 std::string tls_channel_id2
=
1062 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1063 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1065 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1066 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1068 // nor should it change when navigating away, revisiting the page and
1069 // requesting it again.
1070 ui_test_utils::NavigateToURL(browser(), google_com_url());
1071 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1073 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1074 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1076 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1077 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1080 // Tests a web connectable extension that receives TLS channel id, but
1081 // immediately closes its background page upon receipt of a message.
1082 // Same flakiness seen in http://crbug.com/297866
1083 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1084 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage
) {
1085 InitializeTestServer();
1086 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1088 scoped_refptr
<const Extension
> chromium_connectable
=
1089 LoadChromiumConnectableExtensionWithTlsChannelId();
1091 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1092 // If the page does ask for it, it isn't empty, even if the background page
1093 // closes upon receipt of the connect.
1094 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
1095 chromium_connectable
.get(), true, close_background_message());
1096 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1097 // A subsequent connect will still succeed, even if the background page was
1098 // previously closed.
1100 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1101 // And the expected value is still retrieved.
1102 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1105 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingUserGesture
) {
1106 const char kManifest
[] = "{"
1107 " \"name\": \"user_gesture\","
1108 " \"version\": \"1.0\","
1109 " \"background\": {"
1110 " \"scripts\": [\"background.js\"]"
1112 " \"manifest_version\": 2"
1115 TestExtensionDir receiver_dir
;
1116 receiver_dir
.WriteManifest(kManifest
);
1117 receiver_dir
.WriteFile(FILE_PATH_LITERAL("background.js"),
1118 "chrome.runtime.onMessageExternal.addListener(\n"
1119 " function(msg, sender, reply) {\n"
1120 " reply({result:chrome.test.isProcessingUserGesture()});\n"
1122 const Extension
* receiver
= LoadExtension(receiver_dir
.unpacked_path());
1123 ASSERT_TRUE(receiver
);
1125 TestExtensionDir sender_dir
;
1126 sender_dir
.WriteManifest(kManifest
);
1127 sender_dir
.WriteFile(FILE_PATH_LITERAL("background.js"), "");
1128 const Extension
* sender
= LoadExtension(sender_dir
.unpacked_path());
1129 ASSERT_TRUE(sender
);
1132 ExecuteScriptInBackgroundPage(sender
->id(),
1134 "chrome.test.runWithoutUserGesture(function() {\n"
1135 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1136 " window.domAutomationController.send('' + response.result);\n"
1138 "});", receiver
->id().c_str())));
1141 ExecuteScriptInBackgroundPage(sender
->id(),
1143 "chrome.test.runWithUserGesture(function() {\n"
1144 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1145 " window.domAutomationController.send('' + response.result);\n"
1147 "});", receiver
->id().c_str())));
1150 // Tests that a hosted app on a connectable site doesn't interfere with the
1151 // connectability of that site.
1152 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, HostedAppOnWebsite
) {
1153 InitializeTestServer();
1155 scoped_refptr
<const Extension
> app
= LoadChromiumHostedApp();
1157 // The presence of the hosted app shouldn't give the ability to send messages.
1158 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1159 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
1160 CanConnectAndSendMessagesToMainFrame(app
.get()));
1161 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1163 // Once a connectable extension is installed, it should.
1164 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
1165 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
1166 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1169 // Tests that an invalid extension ID specified in a hosted app does not crash
1170 // the hosted app's renderer.
1172 // This is a regression test for http://crbug.com/326250#c12.
1173 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
1174 InvalidExtensionIDFromHostedApp
) {
1175 InitializeTestServer();
1177 // The presence of the chromium hosted app triggers this bug. The chromium
1178 // connectable extension needs to be installed to set up the runtime bindings.
1179 LoadChromiumHostedApp();
1180 LoadChromiumConnectableExtension();
1182 scoped_refptr
<const Extension
> invalid
=
1184 // A bit scary that this works...
1186 .SetManifest(DictionaryBuilder()
1187 .Set("name", "Fake extension")
1188 .Set("version", "1")
1189 .Set("manifest_version", 2))
1192 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1193 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
1194 CanConnectAndSendMessagesToMainFrame(invalid
.get()));
1197 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1201 }; // namespace extensions