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
= ui_test_utils::OpenURLOffTheRecord(
690 profile()->GetOffTheRecordProfile(),
692 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
693 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
696 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
697 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
699 // No connection because incognito-enabled hasn't been set for the app, and
700 // the user denied our interactive request.
702 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
703 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
704 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
706 // Try again. User has already denied so alert not shown.
708 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
709 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
710 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
713 // It's not possible to allow an app in incognito.
714 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
715 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
716 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
719 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
720 FromIncognitoDenyExtension
) {
721 InitializeTestServer();
723 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
725 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
726 profile()->GetOffTheRecordProfile(), chromium_org_url());
727 content::RenderFrameHost
* incognito_frame
=
728 incognito_browser
->tab_strip_model()
729 ->GetActiveWebContents()
733 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
734 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
736 // The alert doesn't show for extensions.
737 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
738 CanConnectAndSendMessagesToFrame(
739 incognito_frame
, extension
.get(), NULL
));
740 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
743 // Allowing the extension in incognito mode will bypass the deny.
744 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
747 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
750 // Tests connection from incognito tabs when the extension doesn't have an event
751 // handler for the connection event.
752 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
753 FromIncognitoNoEventHandlerInApp
) {
754 InitializeTestServer();
756 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp(false);
757 ASSERT_TRUE(app
->is_platform_app());
759 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
760 profile()->GetOffTheRecordProfile(), chromium_org_url());
761 content::RenderFrameHost
* incognito_frame
=
762 incognito_browser
->tab_strip_model()
763 ->GetActiveWebContents()
767 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
768 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
770 // No connection because incognito-enabled hasn't been set for the app, and
771 // the app hasn't installed event handlers.
773 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
774 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
775 // No dialog should have been shown.
776 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
780 // Tests connection from incognito tabs when the user accepts the connection
781 // request. Spanning mode only. Separate tests for apps and extensions.
783 // TODO(kalman): see comment above about split mode.
784 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
785 FromIncognitoAllowApp
) {
786 InitializeTestServer();
788 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
789 ASSERT_TRUE(app
->is_platform_app());
791 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
792 profile()->GetOffTheRecordProfile(),
794 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
795 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
798 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
799 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
801 // Connection allowed even with incognito disabled, because the user
802 // accepted the interactive request.
804 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
805 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
807 // Try again. User has already allowed.
809 OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
810 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
813 // Apps can't be allowed in incognito mode, but it's moot because it's
815 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
817 CanConnectAndSendMessagesToFrame(incognito_frame
, app
.get(), NULL
));
820 // Tests connection from incognito tabs when there are multiple tabs open to the
821 // same origin. The user should only need to accept the connection request once.
822 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
823 FromIncognitoPromptApp
) {
824 InitializeTestServer();
826 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
827 ASSERT_TRUE(app
->is_platform_app());
829 // Open an incognito browser with two tabs displaying "chromium.org".
830 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
831 profile()->GetOffTheRecordProfile(), chromium_org_url());
832 content::RenderFrameHost
* incognito_frame1
=
833 incognito_browser
->tab_strip_model()
834 ->GetActiveWebContents()
836 InfoBarService
* infobar_service1
= InfoBarService::FromWebContents(
837 incognito_browser
->tab_strip_model()->GetActiveWebContents());
839 CHECK(ui_test_utils::OpenURLOffTheRecord(profile()->GetOffTheRecordProfile(),
840 chromium_org_url()) ==
842 content::RenderFrameHost
* incognito_frame2
=
843 incognito_browser
->tab_strip_model()
844 ->GetActiveWebContents()
846 InfoBarService
* infobar_service2
= InfoBarService::FromWebContents(
847 incognito_browser
->tab_strip_model()->GetActiveWebContents());
848 EXPECT_EQ(2, incognito_browser
->tab_strip_model()->count());
849 EXPECT_NE(incognito_frame1
, incognito_frame2
);
851 // Trigger a infobars in both tabs by trying to send messages.
853 base::StringPrintf("assertions.trySendMessage('%s')", app
->id().c_str());
854 CHECK(content::ExecuteScript(incognito_frame1
, script
));
855 CHECK(content::ExecuteScript(incognito_frame2
, script
));
856 EXPECT_EQ(1U, infobar_service1
->infobar_count());
857 EXPECT_EQ(1U, infobar_service2
->infobar_count());
859 // Navigating away will dismiss the infobar on the active tab only.
860 ui_test_utils::NavigateToURL(incognito_browser
, google_com_url());
861 EXPECT_EQ(1U, infobar_service1
->infobar_count());
862 EXPECT_EQ(0U, infobar_service2
->infobar_count());
864 // Navigate back and accept the infobar this time. Both should be dismissed.
866 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
867 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
869 ui_test_utils::NavigateToURL(incognito_browser
, chromium_org_url());
870 incognito_frame2
= incognito_browser
->tab_strip_model()
871 ->GetActiveWebContents()
873 EXPECT_NE(incognito_frame1
, incognito_frame2
);
875 EXPECT_EQ(1U, infobar_service1
->infobar_count());
876 EXPECT_EQ(OK
, CanConnectAndSendMessagesToFrame(incognito_frame2
, app
.get(),
878 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
879 EXPECT_EQ(0U, infobar_service1
->infobar_count());
883 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, IllegalArguments
) {
884 // Tests that malformed arguments to connect() don't crash.
885 // Regression test for crbug.com/472700.
886 InitializeTestServer();
887 LoadChromiumConnectableExtension();
888 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
890 CHECK(content::ExecuteScriptAndExtractBool(
891 browser()->tab_strip_model()->GetActiveWebContents(),
892 "assertions.tryIllegalArguments()", &result
));
896 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
897 FromIncognitoAllowExtension
) {
898 InitializeTestServer();
900 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
902 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
903 profile()->GetOffTheRecordProfile(), chromium_org_url());
904 content::RenderFrameHost
* incognito_frame
=
905 incognito_browser
->tab_strip_model()
906 ->GetActiveWebContents()
910 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
911 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
913 // No alert is shown.
914 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
915 CanConnectAndSendMessagesToFrame(
916 incognito_frame
, extension
.get(), NULL
));
917 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
920 // Allowing the extension in incognito mode is what allows connections.
921 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
924 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
.get(), NULL
));
927 // Tests a connection from an iframe within a tab which doesn't have
928 // permission. Iframe should work.
929 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
930 FromIframeWithPermission
) {
931 InitializeTestServer();
933 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
935 ui_test_utils::NavigateToURL(browser(), google_com_url());
936 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
937 CanConnectAndSendMessagesToMainFrame(extension
.get()));
938 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
940 ASSERT_TRUE(AppendIframe(chromium_org_url()));
942 EXPECT_EQ(OK
, CanConnectAndSendMessagesToIFrame(extension
.get()));
943 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
946 // Tests connection from an iframe without permission within a tab that does.
947 // Iframe shouldn't work.
948 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
949 FromIframeWithoutPermission
) {
950 InitializeTestServer();
952 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
954 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
955 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
956 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
958 ASSERT_TRUE(AppendIframe(google_com_url()));
960 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
961 CanConnectAndSendMessagesToIFrame(extension
.get()));
962 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
965 // Tests externally_connectable between a web page and an extension with a
966 // TLS channel ID created for the origin.
967 class ExternallyConnectableMessagingWithTlsChannelIdTest
:
968 public ExternallyConnectableMessagingTest
{
970 ExternallyConnectableMessagingWithTlsChannelIdTest()
971 : tls_channel_id_created_(false, false) {
974 std::string
CreateTlsChannelId() {
975 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
976 profile()->GetRequestContext());
977 scoped_ptr
<crypto::ECPrivateKey
> channel_id_key
;
978 net::ChannelIDService::Request request
;
979 content::BrowserThread::PostTask(
980 content::BrowserThread::IO
, FROM_HERE
,
981 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
982 CreateDomainBoundCertOnIOThread
,
983 base::Unretained(this), base::Unretained(&channel_id_key
),
984 base::Unretained(&request
), request_context_getter
));
985 tls_channel_id_created_
.Wait();
986 // Create the expected value.
987 std::vector
<uint8
> spki_vector
;
988 if (!channel_id_key
->ExportPublicKey(&spki_vector
))
989 return std::string();
990 base::StringPiece
spki(reinterpret_cast<char*>(
991 vector_as_array(&spki_vector
)), spki_vector
.size());
992 base::DictionaryValue jwk_value
;
993 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki
, &jwk_value
);
994 std::string tls_channel_id_value
;
995 base::JSONWriter::Write(jwk_value
, &tls_channel_id_value
);
996 return tls_channel_id_value
;
1000 void CreateDomainBoundCertOnIOThread(
1001 scoped_ptr
<crypto::ECPrivateKey
>* channel_id_key
,
1002 net::ChannelIDService::Request
* request
,
1003 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
) {
1004 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1005 net::ChannelIDService
* channel_id_service
=
1006 request_context_getter
->GetURLRequestContext()->
1007 channel_id_service();
1008 int status
= channel_id_service
->GetOrCreateChannelID(
1009 chromium_org_url().host(), channel_id_key
,
1010 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
1012 base::Unretained(this)),
1014 if (status
== net::ERR_IO_PENDING
)
1016 GotDomainBoundCert(status
);
1019 void GotDomainBoundCert(int status
) {
1020 ASSERT_TRUE(status
== net::OK
);
1021 tls_channel_id_created_
.Signal();
1024 base::WaitableEvent tls_channel_id_created_
;
1027 // Tests a web connectable extension that receives TLS channel id on a site
1028 // that can connect to it, with a TLS channel ID having been generated.
1029 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1030 WebConnectableWithNonEmptyTlsChannelId
) {
1031 InitializeTestServer();
1032 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1034 scoped_refptr
<const Extension
> chromium_connectable
=
1035 LoadChromiumConnectableExtensionWithTlsChannelId();
1036 ASSERT_TRUE(chromium_connectable
.get());
1038 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1040 // Since the extension requests the TLS channel ID, it gets it for a site that
1041 // can connect to it, but only if the page also asks to send it.
1042 EXPECT_EQ(std::string(),
1043 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), false));
1044 EXPECT_EQ(std::string(),
1045 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), false));
1047 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
1048 std::string tls_channel_id_from_port_connect
=
1049 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1050 EXPECT_NE(0u, tls_channel_id_from_port_connect
.size());
1052 // The same value is received by both connect and sendMessage.
1053 std::string tls_channel_id_from_send_message
=
1054 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1055 EXPECT_EQ(tls_channel_id_from_port_connect
, tls_channel_id_from_send_message
);
1057 // And since a TLS channel ID exists for the domain, the value received is
1058 // parseable as a JWK. (In particular, it has the same value we created by
1059 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
1060 std::string
tls_channel_id(tls_channel_id_from_port_connect
);
1061 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1063 // The TLS channel ID shouldn't change from one connection to the next...
1064 std::string tls_channel_id2
=
1065 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1066 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1068 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1069 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1071 // nor should it change when navigating away, revisiting the page and
1072 // requesting it again.
1073 ui_test_utils::NavigateToURL(browser(), google_com_url());
1074 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1076 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1077 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1079 GetTlsChannelIdFromSendMessage(chromium_connectable
.get(), true);
1080 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
1083 // Tests a web connectable extension that receives TLS channel id, but
1084 // immediately closes its background page upon receipt of a message.
1085 // Same flakiness seen in http://crbug.com/297866
1086 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
1087 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage
) {
1088 InitializeTestServer();
1089 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
1091 scoped_refptr
<const Extension
> chromium_connectable
=
1092 LoadChromiumConnectableExtensionWithTlsChannelId();
1094 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1095 // If the page does ask for it, it isn't empty, even if the background page
1096 // closes upon receipt of the connect.
1097 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
1098 chromium_connectable
.get(), true, close_background_message());
1099 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1100 // A subsequent connect will still succeed, even if the background page was
1101 // previously closed.
1103 GetTlsChannelIdFromPortConnect(chromium_connectable
.get(), true);
1104 // And the expected value is still retrieved.
1105 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
1108 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingUserGesture
) {
1109 const char kManifest
[] = "{"
1110 " \"name\": \"user_gesture\","
1111 " \"version\": \"1.0\","
1112 " \"background\": {"
1113 " \"scripts\": [\"background.js\"]"
1115 " \"manifest_version\": 2"
1118 TestExtensionDir receiver_dir
;
1119 receiver_dir
.WriteManifest(kManifest
);
1120 receiver_dir
.WriteFile(FILE_PATH_LITERAL("background.js"),
1121 "chrome.runtime.onMessageExternal.addListener(\n"
1122 " function(msg, sender, reply) {\n"
1123 " reply({result:chrome.test.isProcessingUserGesture()});\n"
1125 const Extension
* receiver
= LoadExtension(receiver_dir
.unpacked_path());
1126 ASSERT_TRUE(receiver
);
1128 TestExtensionDir sender_dir
;
1129 sender_dir
.WriteManifest(kManifest
);
1130 sender_dir
.WriteFile(FILE_PATH_LITERAL("background.js"), "");
1131 const Extension
* sender
= LoadExtension(sender_dir
.unpacked_path());
1132 ASSERT_TRUE(sender
);
1135 ExecuteScriptInBackgroundPage(sender
->id(),
1137 "chrome.test.runWithoutUserGesture(function() {\n"
1138 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1139 " window.domAutomationController.send('' + response.result);\n"
1141 "});", receiver
->id().c_str())));
1144 ExecuteScriptInBackgroundPage(sender
->id(),
1146 "chrome.test.runWithUserGesture(function() {\n"
1147 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1148 " window.domAutomationController.send('' + response.result);\n"
1150 "});", receiver
->id().c_str())));
1153 // Tests that a hosted app on a connectable site doesn't interfere with the
1154 // connectability of that site.
1155 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, HostedAppOnWebsite
) {
1156 InitializeTestServer();
1158 scoped_refptr
<const Extension
> app
= LoadChromiumHostedApp();
1160 // The presence of the hosted app shouldn't give the ability to send messages.
1161 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1162 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
1163 CanConnectAndSendMessagesToMainFrame(app
.get()));
1164 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1166 // Once a connectable extension is installed, it should.
1167 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
1168 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
.get()));
1169 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1172 // Tests that an invalid extension ID specified in a hosted app does not crash
1173 // the hosted app's renderer.
1175 // This is a regression test for http://crbug.com/326250#c12.
1176 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
1177 InvalidExtensionIDFromHostedApp
) {
1178 InitializeTestServer();
1180 // The presence of the chromium hosted app triggers this bug. The chromium
1181 // connectable extension needs to be installed to set up the runtime bindings.
1182 LoadChromiumHostedApp();
1183 LoadChromiumConnectableExtension();
1185 scoped_refptr
<const Extension
> invalid
=
1187 // A bit scary that this works...
1189 .SetManifest(DictionaryBuilder()
1190 .Set("name", "Fake extension")
1191 .Set("version", "1")
1192 .Set("manifest_version", 2))
1195 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1196 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
1197 CanConnectAndSendMessagesToMainFrame(invalid
.get()));
1200 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1204 }; // namespace extensions