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/synchronization/waitable_event.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
17 #include "chrome/browser/extensions/extension_apitest.h"
18 #include "chrome/browser/extensions/test_extension_dir.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "content/public/browser/notification_registrar.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "extensions/browser/event_router.h"
29 #include "extensions/browser/extension_prefs.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/common/api/runtime.h"
32 #include "extensions/common/extension_builder.h"
33 #include "extensions/common/value_builder.h"
34 #include "net/cert/asn1_util.h"
35 #include "net/cert/jwk_serializer.h"
36 #include "net/dns/mock_host_resolver.h"
37 #include "net/ssl/server_bound_cert_service.h"
38 #include "net/test/embedded_test_server/embedded_test_server.h"
39 #include "net/url_request/url_request_context.h"
40 #include "net/url_request/url_request_context_getter.h"
43 namespace extensions
{
46 class MessageSender
: public content::NotificationObserver
{
49 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING
,
50 content::NotificationService::AllSources());
54 static scoped_ptr
<base::ListValue
> BuildEventArguments(
55 const bool last_message
,
56 const std::string
& data
) {
57 base::DictionaryValue
* event
= new base::DictionaryValue();
58 event
->SetBoolean("lastMessage", last_message
);
59 event
->SetString("data", data
);
60 scoped_ptr
<base::ListValue
> arguments(new base::ListValue());
61 arguments
->Append(event
);
62 return arguments
.Pass();
65 static scoped_ptr
<Event
> BuildEvent(scoped_ptr
<base::ListValue
> event_args
,
68 scoped_ptr
<Event
> event(new Event("test.onMessage", event_args
.Pass()));
69 event
->restrict_to_browser_context
= profile
;
70 event
->event_url
= event_url
;
74 virtual void Observe(int type
,
75 const content::NotificationSource
& source
,
76 const content::NotificationDetails
& details
) OVERRIDE
{
77 EventRouter
* event_router
=
78 EventRouter::Get(content::Source
<Profile
>(source
).ptr());
80 // Sends four messages to the extension. All but the third message sent
81 // from the origin http://b.com/ are supposed to arrive.
82 event_router
->BroadcastEvent(BuildEvent(
83 BuildEventArguments(false, "no restriction"),
84 content::Source
<Profile
>(source
).ptr(),
86 event_router
->BroadcastEvent(BuildEvent(
87 BuildEventArguments(false, "http://a.com/"),
88 content::Source
<Profile
>(source
).ptr(),
89 GURL("http://a.com/")));
90 event_router
->BroadcastEvent(BuildEvent(
91 BuildEventArguments(false, "http://b.com/"),
92 content::Source
<Profile
>(source
).ptr(),
93 GURL("http://b.com/")));
94 event_router
->BroadcastEvent(BuildEvent(
95 BuildEventArguments(true, "last message"),
96 content::Source
<Profile
>(source
).ptr(),
100 content::NotificationRegistrar registrar_
;
103 // Tests that message passing between extensions and content scripts works.
104 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, Messaging
) {
105 ASSERT_TRUE(StartEmbeddedTestServer());
106 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_
;
109 // Tests that message passing from one extension to another works.
110 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingExternal
) {
111 ASSERT_TRUE(LoadExtension(
112 test_data_dir_
.AppendASCII("..").AppendASCII("good")
113 .AppendASCII("Extensions")
114 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
115 .AppendASCII("1.0")));
117 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_
;
120 // Tests that messages with event_urls are only passed to extensions with
121 // appropriate permissions.
122 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingEventURL
) {
123 MessageSender sender
;
124 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_
;
127 // Tests connecting from a panel to its extension.
128 class PanelMessagingTest
: public ExtensionApiTest
{
129 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
130 ExtensionApiTest::SetUpCommandLine(command_line
);
131 command_line
->AppendSwitch(switches::kEnablePanels
);
135 IN_PROC_BROWSER_TEST_F(PanelMessagingTest
, MessagingPanel
) {
136 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_
;
139 // XXX(kalman): All web messaging tests disabled on windows due to extreme
140 // flakiness. See http://crbug.com/350517.
143 // Tests externally_connectable between a web page and an extension.
145 // TODO(kalman): Test between extensions. This is already tested in this file,
146 // but not with externally_connectable set in the manifest.
148 // TODO(kalman): Test with host permissions.
149 class ExternallyConnectableMessagingTest
: public ExtensionApiTest
{
151 // Result codes from the test. These must match up with |results| in
152 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
155 NAMESPACE_NOT_DEFINED
= 1,
156 FUNCTION_NOT_DEFINED
= 2,
157 COULD_NOT_ESTABLISH_CONNECTION_ERROR
= 3,
159 INCORRECT_RESPONSE_SENDER
= 5,
160 INCORRECT_RESPONSE_MESSAGE
= 6,
163 bool AppendIframe(const GURL
& src
) {
165 CHECK(content::ExecuteScriptAndExtractBool(
166 browser()->tab_strip_model()->GetActiveWebContents(),
167 "actions.appendIframe('" + src
.spec() + "');", &result
));
171 Result
CanConnectAndSendMessagesToMainFrame(const Extension
* extension
,
172 const char* message
= NULL
) {
173 return CanConnectAndSendMessagesToFrame(
174 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
179 Result
CanConnectAndSendMessagesToIFrame(const Extension
* extension
,
180 const char* message
= NULL
) {
181 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
182 browser()->tab_strip_model()->GetActiveWebContents(),
183 base::Bind(&content::FrameIsChildOfMainFrame
));
184 return CanConnectAndSendMessagesToFrame(frame
, extension
, message
);
187 Result
CanConnectAndSendMessagesToFrame(content::RenderFrameHost
* frame
,
188 const Extension
* extension
,
189 const char* message
) {
191 std::string command
= base::StringPrintf(
192 "assertions.canConnectAndSendMessages('%s', %s, %s)",
193 extension
->id().c_str(),
194 extension
->is_platform_app() ? "true" : "false",
195 message
? base::StringPrintf("'%s'", message
).c_str() : "undefined");
196 CHECK(content::ExecuteScriptAndExtractInt(frame
, command
, &result
));
197 return static_cast<Result
>(result
);
200 testing::AssertionResult
AreAnyNonWebApisDefinedForMainFrame() {
201 return AreAnyNonWebApisDefinedForFrame(
202 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
205 testing::AssertionResult
AreAnyNonWebApisDefinedForIFrame() {
206 content::RenderFrameHost
* frame
= content::FrameMatchingPredicate(
207 browser()->tab_strip_model()->GetActiveWebContents(),
208 base::Bind(&content::FrameIsChildOfMainFrame
));
209 return AreAnyNonWebApisDefinedForFrame(frame
);
212 testing::AssertionResult
AreAnyNonWebApisDefinedForFrame(
213 content::RenderFrameHost
* frame
) {
214 // All runtime API methods are non-web except for sendRequest and connect.
215 const char* non_messaging_apis
[] = {
220 "requestUpdateCheck",
229 "onBrowserUpdateAvailable",
235 // Note: no "id" here because this test method is used for hosted apps,
236 // which do have access to runtime.id.
239 // Turn the array into a JS array, which effectively gets eval()ed.
240 std::string as_js_array
;
241 for (size_t i
= 0; i
< arraysize(non_messaging_apis
); ++i
) {
242 as_js_array
+= as_js_array
.empty() ? "[" : ",";
243 as_js_array
+= base::StringPrintf("'%s'", non_messaging_apis
[i
]);
248 CHECK(content::ExecuteScriptAndExtractBool(
250 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array
+ ")",
253 testing::AssertionSuccess() : testing::AssertionFailure();
256 std::string
GetTlsChannelIdFromPortConnect(const Extension
* extension
,
257 bool include_tls_channel_id
,
258 const char* message
= NULL
) {
259 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
261 include_tls_channel_id
,
265 std::string
GetTlsChannelIdFromSendMessage(const Extension
* extension
,
266 bool include_tls_channel_id
,
267 const char* message
= NULL
) {
268 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
270 include_tls_channel_id
,
274 GURL
GetURLForPath(const std::string
& host
, const std::string
& path
) {
275 std::string port
= base::IntToString(embedded_test_server()->port());
276 GURL::Replacements replacements
;
277 replacements
.SetHostStr(host
);
278 replacements
.SetPortStr(port
);
279 return embedded_test_server()->GetURL(path
).ReplaceComponents(replacements
);
282 GURL
chromium_org_url() {
283 return GetURLForPath("www.chromium.org", "/chromium.org.html");
286 GURL
google_com_url() {
287 return GetURLForPath("www.google.com", "/google.com.html");
290 scoped_refptr
<const Extension
> LoadChromiumConnectableExtension() {
291 scoped_refptr
<const Extension
> extension
=
292 LoadExtensionIntoDir(&web_connectable_dir_
,
295 " \"name\": \"chromium_connectable\","
297 " \"externally_connectable\": {"
298 " \"matches\": [\"*://*.chromium.org:*/*\"]"
302 CHECK(extension
.get());
306 scoped_refptr
<const Extension
> LoadChromiumConnectableApp() {
307 scoped_refptr
<const Extension
> extension
=
308 LoadExtensionIntoDir(&web_connectable_dir_
,
312 " \"scripts\": [\"background.js\"]"
315 " \"externally_connectable\": {"
316 " \"matches\": [\"*://*.chromium.org:*/*\"]"
318 " \"manifest_version\": 2,"
319 " \"name\": \"app_connectable\","
320 " \"version\": \"1.0\""
322 CHECK(extension
.get());
326 scoped_refptr
<const Extension
> LoadNotConnectableExtension() {
327 scoped_refptr
<const Extension
> extension
=
328 LoadExtensionIntoDir(¬_connectable_dir_
,
331 " \"name\": \"not_connectable\","
335 CHECK(extension
.get());
339 scoped_refptr
<const Extension
>
340 LoadChromiumConnectableExtensionWithTlsChannelId() {
341 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_
,
342 connectable_with_tls_channel_id_manifest());
345 scoped_refptr
<const Extension
> LoadChromiumHostedApp() {
346 scoped_refptr
<const Extension
> hosted_app
=
347 LoadExtensionIntoDir(&hosted_app_dir_
,
350 " \"name\": \"chromium_hosted_app\","
351 " \"version\": \"1.0\","
352 " \"manifest_version\": 2,"
354 " \"urls\": [\"%s\"],"
356 " \"web_url\": \"%s\""
360 chromium_org_url().spec().c_str(),
361 chromium_org_url().spec().c_str()));
362 CHECK(hosted_app
.get());
366 void InitializeTestServer() {
367 base::FilePath test_data
;
368 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &test_data
));
369 embedded_test_server()->ServeFilesFromDirectory(test_data
.AppendASCII(
370 "extensions/api_test/messaging/externally_connectable/sites"));
371 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
372 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
375 const char* close_background_message() {
376 return "closeBackgroundPage";
380 scoped_refptr
<const Extension
> LoadExtensionIntoDir(
381 TestExtensionDir
* dir
,
382 const std::string
& manifest
) {
383 dir
->WriteManifest(manifest
);
384 dir
->WriteFile(FILE_PATH_LITERAL("background.js"),
386 "function maybeClose(message) {\n"
387 " if (message.indexOf('%s') >= 0)\n"
388 " window.setTimeout(function() { window.close() }, 0);\n"
390 "chrome.runtime.onMessageExternal.addListener(\n"
391 " function(message, sender, reply) {\n"
392 " reply({ message: message, sender: sender });\n"
393 " maybeClose(message);\n"
395 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
396 " port.onMessage.addListener(function(message) {\n"
397 " port.postMessage({ message: message, sender: port.sender });\n"
398 " maybeClose(message);\n"
401 close_background_message()));
402 return LoadExtension(dir
->unpacked_path());
405 const char* common_manifest() {
406 return "\"version\": \"1.0\","
408 " \"scripts\": [\"background.js\"],"
409 " \"persistent\": false"
411 "\"manifest_version\": 2";
414 std::string
connectable_with_tls_channel_id_manifest() {
415 return base::StringPrintf(
417 " \"name\": \"chromium_connectable_with_tls_channel_id\","
419 " \"externally_connectable\": {"
420 " \"matches\": [\"*://*.chromium.org:*/*\"],"
421 " \"accepts_tls_channel_id\": true"
427 std::string
GetTlsChannelIdFromAssertion(const char* method
,
428 const Extension
* extension
,
429 bool include_tls_channel_id
,
430 const char* message
) {
432 std::string args
= "'" + extension
->id() + "', ";
433 args
+= include_tls_channel_id
? "true" : "false";
435 args
+= std::string(", '") + message
+ "'";
436 CHECK(content::ExecuteScriptAndExtractString(
437 browser()->tab_strip_model()->GetActiveWebContents(),
438 base::StringPrintf("assertions.%s(%s)", method
, args
.c_str()),
443 TestExtensionDir web_connectable_dir_
;
444 TestExtensionDir not_connectable_dir_
;
445 TestExtensionDir tls_channel_id_connectable_dir_
;
446 TestExtensionDir hosted_app_dir_
;
449 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, NotInstalled
) {
450 InitializeTestServer();
452 scoped_refptr
<const Extension
> extension
=
454 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
455 .SetManifest(DictionaryBuilder()
456 .Set("name", "Fake extension")
458 .Set("manifest_version", 2))
461 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
462 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
463 CanConnectAndSendMessagesToMainFrame(extension
));
464 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
466 ui_test_utils::NavigateToURL(browser(), google_com_url());
467 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
468 CanConnectAndSendMessagesToMainFrame(extension
));
469 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
472 // Tests two extensions on the same sites: one web connectable, one not.
473 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
474 WebConnectableAndNotConnectable
) {
475 InitializeTestServer();
477 // Install the web connectable extension. chromium.org can connect to it,
479 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
481 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
482 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(chromium_connectable
));
483 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
485 ui_test_utils::NavigateToURL(browser(), google_com_url());
486 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
487 CanConnectAndSendMessagesToMainFrame(chromium_connectable
));
488 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
490 // Install the non-connectable extension. Nothing can connect to it.
491 const Extension
* not_connectable
= LoadNotConnectableExtension();
493 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
494 // Namespace will be defined here because |chromium_connectable| can connect
495 // to it - so this will be the "cannot establish connection" error.
496 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
497 CanConnectAndSendMessagesToMainFrame(not_connectable
));
498 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
500 ui_test_utils::NavigateToURL(browser(), google_com_url());
501 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
502 CanConnectAndSendMessagesToMainFrame(not_connectable
));
503 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
506 // See http://crbug.com/297866
507 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
508 DISABLED_BackgroundPageClosesOnMessageReceipt
) {
509 InitializeTestServer();
511 // Install the web connectable extension.
512 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
514 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
515 // If the background page closes after receipt of the message, it will still
516 // reply to this message...
518 CanConnectAndSendMessagesToMainFrame(chromium_connectable
,
519 close_background_message()));
520 // and be re-opened by receipt of a subsequent message.
521 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(chromium_connectable
));
524 // Tests a web connectable extension that doesn't receive TLS channel id.
525 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
526 WebConnectableWithoutTlsChannelId
) {
527 InitializeTestServer();
529 // Install the web connectable extension. chromium.org can connect to it,
531 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
532 ASSERT_TRUE(chromium_connectable
);
534 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
535 // The web connectable extension doesn't request the TLS channel ID, so it
536 // doesn't get it, whether or not the page asks for it.
537 EXPECT_EQ(std::string(),
538 GetTlsChannelIdFromPortConnect(chromium_connectable
, false));
539 EXPECT_EQ(std::string(),
540 GetTlsChannelIdFromSendMessage(chromium_connectable
, true));
541 EXPECT_EQ(std::string(),
542 GetTlsChannelIdFromPortConnect(chromium_connectable
, false));
543 EXPECT_EQ(std::string(),
544 GetTlsChannelIdFromSendMessage(chromium_connectable
, true));
547 // Tests a web connectable extension that receives TLS channel id with a site
548 // that can't connect to it.
549 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
550 WebConnectableWithTlsChannelIdWithNonMatchingSite
) {
551 InitializeTestServer();
553 const Extension
* chromium_connectable
=
554 LoadChromiumConnectableExtensionWithTlsChannelId();
555 ASSERT_TRUE(chromium_connectable
);
557 ui_test_utils::NavigateToURL(browser(), google_com_url());
558 // The extension requests the TLS channel ID, but it doesn't get it for a
559 // site that can't connect to it, regardless of whether the page asks for it.
560 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
561 GetTlsChannelIdFromPortConnect(chromium_connectable
, false));
562 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
563 GetTlsChannelIdFromSendMessage(chromium_connectable
, true));
564 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
565 GetTlsChannelIdFromPortConnect(chromium_connectable
, false));
566 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
567 GetTlsChannelIdFromSendMessage(chromium_connectable
, true));
570 // Tests a web connectable extension that receives TLS channel id on a site
571 // that can connect to it, but with no TLS channel ID having been generated.
572 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
573 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId
) {
574 InitializeTestServer();
576 const Extension
* chromium_connectable
=
577 LoadChromiumConnectableExtensionWithTlsChannelId();
578 ASSERT_TRUE(chromium_connectable
);
580 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
582 // Since the extension requests the TLS channel ID, it gets it for a site that
583 // can connect to it, but only if the page also asks to include it.
584 EXPECT_EQ(std::string(),
585 GetTlsChannelIdFromPortConnect(chromium_connectable
, false));
586 EXPECT_EQ(std::string(),
587 GetTlsChannelIdFromSendMessage(chromium_connectable
, false));
588 // If the page does ask for it, it isn't empty.
589 std::string tls_channel_id
=
590 GetTlsChannelIdFromPortConnect(chromium_connectable
, true);
591 // Because the TLS channel ID has never been generated for this domain,
592 // no TLS channel ID is reported.
593 EXPECT_EQ(std::string(), tls_channel_id
);
596 // Flaky on Linux and Windows. http://crbug.com/315264
597 // Tests a web connectable extension that receives TLS channel id, but
598 // immediately closes its background page upon receipt of a message.
599 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
600 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
) {
601 InitializeTestServer();
603 const Extension
* chromium_connectable
=
604 LoadChromiumConnectableExtensionWithTlsChannelId();
606 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
607 // If the page does ask for it, it isn't empty, even if the background page
608 // closes upon receipt of the connect.
609 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
610 chromium_connectable
, true, close_background_message());
611 // Because the TLS channel ID has never been generated for this domain,
612 // no TLS channel ID is reported.
613 EXPECT_EQ(std::string(), tls_channel_id
);
614 // A subsequent connect will still succeed, even if the background page was
615 // previously closed.
616 tls_channel_id
= GetTlsChannelIdFromPortConnect(chromium_connectable
, true);
617 // And the empty value is still retrieved.
618 EXPECT_EQ(std::string(), tls_channel_id
);
621 // Tests that enabling and disabling an extension makes the runtime bindings
622 // appear and disappear.
624 // TODO(kalman): Test with multiple extensions that can be accessed by the same
626 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
627 EnablingAndDisabling
) {
628 InitializeTestServer();
630 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
631 const Extension
* not_connectable
= LoadNotConnectableExtension();
633 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
634 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(chromium_connectable
));
635 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
636 CanConnectAndSendMessagesToMainFrame(not_connectable
));
638 DisableExtension(chromium_connectable
->id());
639 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
640 CanConnectAndSendMessagesToMainFrame(chromium_connectable
));
642 EnableExtension(chromium_connectable
->id());
643 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(chromium_connectable
));
644 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
645 CanConnectAndSendMessagesToMainFrame(not_connectable
));
648 // Tests connection from incognito tabs when the user denies the connection
649 // request. Spanning mode only. A separate test for apps and extensions.
651 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
652 // somewhere. This is a test that should be shared with the content script logic
653 // so it's not really our specific concern for web connectable.
655 // TODO(kalman): test messages from incognito extensions too.
656 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
657 FromIncognitoDenyApp
) {
658 InitializeTestServer();
660 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
661 ASSERT_TRUE(app
->is_platform_app());
663 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
664 profile()->GetOffTheRecordProfile(),
666 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
667 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
670 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
671 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
673 // No connection because incognito-enabled hasn't been set for the app, and
674 // the user denied our interactive request.
675 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
676 CanConnectAndSendMessagesToFrame(incognito_frame
, app
, NULL
));
677 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
679 // Try again. User has already denied so alert not shown.
680 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
681 CanConnectAndSendMessagesToFrame(incognito_frame
, app
, NULL
));
682 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
685 // It's not possible to allow an app in incognito.
686 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
687 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
688 CanConnectAndSendMessagesToFrame(incognito_frame
, app
, NULL
));
691 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
692 FromIncognitoDenyExtension
) {
693 InitializeTestServer();
695 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
697 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
698 profile()->GetOffTheRecordProfile(), chromium_org_url());
699 content::RenderFrameHost
* incognito_frame
=
700 incognito_browser
->tab_strip_model()
701 ->GetActiveWebContents()
705 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
706 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
708 // The alert doesn't show for extensions.
710 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
711 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
, NULL
));
712 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
715 // Allowing the extension in incognito mode will bypass the deny.
716 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
718 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
, NULL
));
721 // Tests connection from incognito tabs when the user accepts the connection
722 // request. Spanning mode only. Separate tests for apps and extensions.
724 // TODO(kalman): see comment above about split mode.
725 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
726 FromIncognitoAllowApp
) {
727 InitializeTestServer();
729 scoped_refptr
<const Extension
> app
= LoadChromiumConnectableApp();
730 ASSERT_TRUE(app
->is_platform_app());
732 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
733 profile()->GetOffTheRecordProfile(),
735 content::RenderFrameHost
* incognito_frame
= incognito_browser
->
736 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
739 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
740 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
742 // Connection allowed even with incognito disabled, because the user
743 // accepted the interactive request.
744 EXPECT_EQ(OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
, NULL
));
745 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
747 // Try again. User has already allowed.
748 EXPECT_EQ(OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
, NULL
));
749 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
752 // Apps can't be allowed in incognito mode, but it's moot because it's
754 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app
->id(), true);
755 EXPECT_EQ(OK
, CanConnectAndSendMessagesToFrame(incognito_frame
, app
, NULL
));
758 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
759 FromIncognitoAllowExtension
) {
760 InitializeTestServer();
762 scoped_refptr
<const Extension
> extension
= LoadChromiumConnectableExtension();
764 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
765 profile()->GetOffTheRecordProfile(), chromium_org_url());
766 content::RenderFrameHost
* incognito_frame
=
767 incognito_browser
->tab_strip_model()
768 ->GetActiveWebContents()
772 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
773 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
775 // No alert is shown.
777 COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
778 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
, NULL
));
779 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
782 // Allowing the extension in incognito mode is what allows connections.
783 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension
->id(), true);
785 CanConnectAndSendMessagesToFrame(incognito_frame
, extension
, NULL
));
788 // Tests a connection from an iframe within a tab which doesn't have
789 // permission. Iframe should work.
790 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
791 FromIframeWithPermission
) {
792 InitializeTestServer();
794 const Extension
* extension
= LoadChromiumConnectableExtension();
796 ui_test_utils::NavigateToURL(browser(), google_com_url());
797 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
798 CanConnectAndSendMessagesToMainFrame(extension
));
799 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
801 ASSERT_TRUE(AppendIframe(chromium_org_url()));
803 EXPECT_EQ(OK
, CanConnectAndSendMessagesToIFrame(extension
));
804 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
807 // Tests connection from an iframe without permission within a tab that does.
808 // Iframe shouldn't work.
809 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
810 FromIframeWithoutPermission
) {
811 InitializeTestServer();
813 const Extension
* extension
= LoadChromiumConnectableExtension();
815 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
816 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
));
817 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
819 ASSERT_TRUE(AppendIframe(google_com_url()));
821 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
822 CanConnectAndSendMessagesToIFrame(extension
));
823 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
826 // Tests externally_connectable between a web page and an extension with a
827 // TLS channel ID created for the origin.
828 class ExternallyConnectableMessagingWithTlsChannelIdTest
:
829 public ExternallyConnectableMessagingTest
{
831 ExternallyConnectableMessagingWithTlsChannelIdTest()
832 : tls_channel_id_created_(false, false) {
835 std::string
CreateTlsChannelId() {
836 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
837 profile()->GetRequestContext());
838 std::string domain_bound_private_key
;
839 std::string domain_bound_cert
;
840 net::ServerBoundCertService::RequestHandle request_handle
;
841 content::BrowserThread::PostTask(
842 content::BrowserThread::IO
,
845 &ExternallyConnectableMessagingWithTlsChannelIdTest::
846 CreateDomainBoundCertOnIOThread
,
847 base::Unretained(this),
848 base::Unretained(&domain_bound_private_key
),
849 base::Unretained(&domain_bound_cert
),
850 base::Unretained(&request_handle
),
851 request_context_getter
));
852 tls_channel_id_created_
.Wait();
853 // Create the expected value.
854 base::StringPiece spki
;
855 net::asn1::ExtractSPKIFromDERCert(domain_bound_cert
, &spki
);
856 base::DictionaryValue jwk_value
;
857 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki
, &jwk_value
);
858 std::string tls_channel_id_value
;
859 base::JSONWriter::Write(&jwk_value
, &tls_channel_id_value
);
860 return tls_channel_id_value
;
864 void CreateDomainBoundCertOnIOThread(
865 std::string
* domain_bound_private_key
,
866 std::string
* domain_bound_cert
,
867 net::ServerBoundCertService::RequestHandle
* request_handle
,
868 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
) {
869 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
870 net::ServerBoundCertService
* server_bound_cert_service
=
871 request_context_getter
->GetURLRequestContext()->
872 server_bound_cert_service();
873 int status
= server_bound_cert_service
->GetOrCreateDomainBoundCert(
874 chromium_org_url().host(),
875 domain_bound_private_key
,
877 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
879 base::Unretained(this)),
881 if (status
== net::ERR_IO_PENDING
)
883 GotDomainBoundCert(status
);
886 void GotDomainBoundCert(int status
) {
887 ASSERT_TRUE(status
== net::OK
);
888 tls_channel_id_created_
.Signal();
891 base::WaitableEvent tls_channel_id_created_
;
894 // Tests a web connectable extension that receives TLS channel id on a site
895 // that can connect to it, with a TLS channel ID having been generated.
896 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
897 WebConnectableWithNonEmptyTlsChannelId
) {
898 InitializeTestServer();
899 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
901 const Extension
* chromium_connectable
=
902 LoadChromiumConnectableExtensionWithTlsChannelId();
903 ASSERT_TRUE(chromium_connectable
);
905 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
907 // Since the extension requests the TLS channel ID, it gets it for a site that
908 // can connect to it, but only if the page also asks to send it.
909 EXPECT_EQ(std::string(),
910 GetTlsChannelIdFromPortConnect(chromium_connectable
, false));
911 EXPECT_EQ(std::string(),
912 GetTlsChannelIdFromSendMessage(chromium_connectable
, false));
914 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
915 std::string tls_channel_id_from_port_connect
=
916 GetTlsChannelIdFromPortConnect(chromium_connectable
, true);
917 EXPECT_NE(0u, tls_channel_id_from_port_connect
.size());
919 // The same value is received by both connect and sendMessage.
920 std::string tls_channel_id_from_send_message
=
921 GetTlsChannelIdFromSendMessage(chromium_connectable
, true);
922 EXPECT_EQ(tls_channel_id_from_port_connect
, tls_channel_id_from_send_message
);
924 // And since a TLS channel ID exists for the domain, the value received is
925 // parseable as a JWK. (In particular, it has the same value we created by
926 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
927 std::string
tls_channel_id(tls_channel_id_from_port_connect
);
928 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
930 // The TLS channel ID shouldn't change from one connection to the next...
931 std::string tls_channel_id2
=
932 GetTlsChannelIdFromPortConnect(chromium_connectable
, true);
933 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
934 tls_channel_id2
= GetTlsChannelIdFromSendMessage(chromium_connectable
, true);
935 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
937 // nor should it change when navigating away, revisiting the page and
938 // requesting it again.
939 ui_test_utils::NavigateToURL(browser(), google_com_url());
940 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
941 tls_channel_id2
= GetTlsChannelIdFromPortConnect(chromium_connectable
, true);
942 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
943 tls_channel_id2
= GetTlsChannelIdFromSendMessage(chromium_connectable
, true);
944 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
947 // Tests a web connectable extension that receives TLS channel id, but
948 // immediately closes its background page upon receipt of a message.
949 // Same flakiness seen in http://crbug.com/297866
950 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
951 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage
) {
952 InitializeTestServer();
953 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
955 const Extension
* chromium_connectable
=
956 LoadChromiumConnectableExtensionWithTlsChannelId();
958 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
959 // If the page does ask for it, it isn't empty, even if the background page
960 // closes upon receipt of the connect.
961 std::string tls_channel_id
= GetTlsChannelIdFromPortConnect(
962 chromium_connectable
, true, close_background_message());
963 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
964 // A subsequent connect will still succeed, even if the background page was
965 // previously closed.
966 tls_channel_id
= GetTlsChannelIdFromPortConnect(chromium_connectable
, true);
967 // And the expected value is still retrieved.
968 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
971 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingUserGesture
) {
972 const char kManifest
[] = "{"
973 " \"name\": \"user_gesture\","
974 " \"version\": \"1.0\","
976 " \"scripts\": [\"background.js\"]"
978 " \"manifest_version\": 2"
981 TestExtensionDir receiver_dir
;
982 receiver_dir
.WriteManifest(kManifest
);
983 receiver_dir
.WriteFile(FILE_PATH_LITERAL("background.js"),
984 "chrome.runtime.onMessageExternal.addListener(\n"
985 " function(msg, sender, reply) {\n"
986 " reply({result:chrome.test.isProcessingUserGesture()});\n"
988 const Extension
* receiver
= LoadExtension(receiver_dir
.unpacked_path());
989 ASSERT_TRUE(receiver
);
991 TestExtensionDir sender_dir
;
992 sender_dir
.WriteManifest(kManifest
);
993 sender_dir
.WriteFile(FILE_PATH_LITERAL("background.js"), "");
994 const Extension
* sender
= LoadExtension(sender_dir
.unpacked_path());
998 ExecuteScriptInBackgroundPage(sender
->id(),
1000 "chrome.test.runWithoutUserGesture(function() {\n"
1001 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1002 " window.domAutomationController.send('' + response.result);\n"
1004 "});", receiver
->id().c_str())));
1007 ExecuteScriptInBackgroundPage(sender
->id(),
1009 "chrome.test.runWithUserGesture(function() {\n"
1010 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1011 " window.domAutomationController.send('' + response.result);\n"
1013 "});", receiver
->id().c_str())));
1016 // Tests that a hosted app on a connectable site doesn't interfere with the
1017 // connectability of that site.
1018 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, HostedAppOnWebsite
) {
1019 InitializeTestServer();
1021 scoped_refptr
<const Extension
> app
= LoadChromiumHostedApp();
1023 // The presence of the hosted app shouldn't give the ability to send messages.
1024 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1025 EXPECT_EQ(NAMESPACE_NOT_DEFINED
, CanConnectAndSendMessagesToMainFrame(app
));
1026 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1028 // Once a connectable extension is installed, it should.
1029 const Extension
* extension
= LoadChromiumConnectableExtension();
1030 EXPECT_EQ(OK
, CanConnectAndSendMessagesToMainFrame(extension
));
1031 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1034 // Tests that an invalid extension ID specified in a hosted app does not crash
1035 // the hosted app's renderer.
1037 // This is a regression test for http://crbug.com/326250#c12.
1038 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
1039 InvalidExtensionIDFromHostedApp
) {
1040 InitializeTestServer();
1042 // The presence of the chromium hosted app triggers this bug. The chromium
1043 // connectable extension needs to be installed to set up the runtime bindings.
1044 LoadChromiumHostedApp();
1045 LoadChromiumConnectableExtension();
1047 scoped_refptr
<const Extension
> invalid
=
1049 // A bit scary that this works...
1051 .SetManifest(DictionaryBuilder()
1052 .Set("name", "Fake extension")
1053 .Set("version", "1")
1054 .Set("manifest_version", 2))
1057 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1058 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
1059 CanConnectAndSendMessagesToMainFrame(invalid
));
1062 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1066 }; // namespace extensions