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/extension_prefs.h"
19 #include "chrome/browser/extensions/extension_system.h"
20 #include "chrome/browser/extensions/test_extension_dir.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/common/extensions/api/runtime.h"
27 #include "chrome/test/base/ui_test_utils.h"
28 #include "content/public/browser/notification_registrar.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/test/browser_test_utils.h"
31 #include "extensions/browser/event_router.h"
32 #include "net/cert/asn1_util.h"
33 #include "net/cert/jwk_serializer.h"
34 #include "net/dns/mock_host_resolver.h"
35 #include "net/ssl/server_bound_cert_service.h"
36 #include "net/test/embedded_test_server/embedded_test_server.h"
37 #include "net/url_request/url_request_context.h"
38 #include "net/url_request/url_request_context_getter.h"
41 namespace extensions
{
44 class MessageSender
: public content::NotificationObserver
{
47 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING
,
48 content::NotificationService::AllSources());
52 static scoped_ptr
<base::ListValue
> BuildEventArguments(
53 const bool last_message
,
54 const std::string
& data
) {
55 base::DictionaryValue
* event
= new base::DictionaryValue();
56 event
->SetBoolean("lastMessage", last_message
);
57 event
->SetString("data", data
);
58 scoped_ptr
<base::ListValue
> arguments(new base::ListValue());
59 arguments
->Append(event
);
60 return arguments
.Pass();
63 static scoped_ptr
<Event
> BuildEvent(scoped_ptr
<base::ListValue
> event_args
,
66 scoped_ptr
<Event
> event(new Event("test.onMessage", event_args
.Pass()));
67 event
->restrict_to_browser_context
= profile
;
68 event
->event_url
= event_url
;
72 virtual void Observe(int type
,
73 const content::NotificationSource
& source
,
74 const content::NotificationDetails
& details
) OVERRIDE
{
75 EventRouter
* event_router
= ExtensionSystem::Get(
76 content::Source
<Profile
>(source
).ptr())->event_router();
78 // Sends four messages to the extension. All but the third message sent
79 // from the origin http://b.com/ are supposed to arrive.
80 event_router
->BroadcastEvent(BuildEvent(
81 BuildEventArguments(false, "no restriction"),
82 content::Source
<Profile
>(source
).ptr(),
84 event_router
->BroadcastEvent(BuildEvent(
85 BuildEventArguments(false, "http://a.com/"),
86 content::Source
<Profile
>(source
).ptr(),
87 GURL("http://a.com/")));
88 event_router
->BroadcastEvent(BuildEvent(
89 BuildEventArguments(false, "http://b.com/"),
90 content::Source
<Profile
>(source
).ptr(),
91 GURL("http://b.com/")));
92 event_router
->BroadcastEvent(BuildEvent(
93 BuildEventArguments(true, "last message"),
94 content::Source
<Profile
>(source
).ptr(),
98 content::NotificationRegistrar registrar_
;
101 // Tests that message passing between extensions and content scripts works.
102 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, Messaging
) {
103 ASSERT_TRUE(StartEmbeddedTestServer());
104 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_
;
107 // Tests that message passing from one extension to another works.
108 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingExternal
) {
109 ASSERT_TRUE(LoadExtension(
110 test_data_dir_
.AppendASCII("..").AppendASCII("good")
111 .AppendASCII("Extensions")
112 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
113 .AppendASCII("1.0")));
115 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_
;
118 // Tests that messages with event_urls are only passed to extensions with
119 // appropriate permissions.
120 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingEventURL
) {
121 MessageSender sender
;
122 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_
;
125 // Tests connecting from a panel to its extension.
126 class PanelMessagingTest
: public ExtensionApiTest
{
127 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
128 ExtensionApiTest::SetUpCommandLine(command_line
);
129 command_line
->AppendSwitch(switches::kEnablePanels
);
133 IN_PROC_BROWSER_TEST_F(PanelMessagingTest
, MessagingPanel
) {
134 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_
;
137 // Tests externally_connectable between a web page and an extension.
139 // TODO(kalman): Test between extensions. This is already tested in this file,
140 // but not with externally_connectable set in the manifest.
142 // TODO(kalman): Test with host permissions.
143 class ExternallyConnectableMessagingTest
: public ExtensionApiTest
{
145 // Result codes from the test. These must match up with |results| in
146 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
149 NAMESPACE_NOT_DEFINED
= 1,
150 FUNCTION_NOT_DEFINED
= 2,
151 COULD_NOT_ESTABLISH_CONNECTION_ERROR
= 3,
153 INCORRECT_RESPONSE_SENDER
= 5,
154 INCORRECT_RESPONSE_MESSAGE
= 6,
157 bool AppendIframe(const GURL
& src
) {
159 CHECK(content::ExecuteScriptAndExtractBool(
160 browser()->tab_strip_model()->GetActiveWebContents(),
161 "actions.appendIframe('" + src
.spec() + "');", &result
));
165 Result
CanConnectAndSendMessages(const std::string
& extension_id
) {
166 return CanConnectAndSendMessages(browser(), extension_id
, "");
169 Result
CanConnectAndSendMessages(const std::string
& extension_id
,
170 const char* frame_xpath
,
171 const char* message
) {
172 return CanConnectAndSendMessages(browser(), extension_id
, frame_xpath
,
176 Result
CanConnectAndSendMessages(Browser
* browser
,
177 const std::string
& extension_id
) {
178 return CanConnectAndSendMessages(browser
, extension_id
, "");
181 Result
CanConnectAndSendMessages(const std::string
& extension_id
,
182 const char* frame_xpath
) {
183 return CanConnectAndSendMessages(browser(), extension_id
, frame_xpath
);
186 Result
CanConnectAndSendMessages(Browser
* browser
,
187 const std::string
& extension_id
,
188 const char* frame_xpath
,
189 const char* message
= NULL
) {
191 std::string args
= "'" + extension_id
+ "'";
193 args
+= std::string(", '") + message
+ "'";
194 CHECK(content::ExecuteScriptInFrameAndExtractInt(
195 browser
->tab_strip_model()->GetActiveWebContents(),
197 base::StringPrintf("assertions.canConnectAndSendMessages(%s)",
200 return static_cast<Result
>(result
);
203 testing::AssertionResult
AreAnyNonWebApisDefined() {
204 return AreAnyNonWebApisDefined("");
207 testing::AssertionResult
AreAnyNonWebApisDefined(const char* frame_xpath
) {
208 // All runtime API methods are non-web except for sendRequest and connect.
209 const char* non_messaging_apis
[] = {
214 "requestUpdateCheck",
223 "onBrowserUpdateAvailable",
229 // Note: no "id" here because this test method is used for hosted apps,
230 // which do have access to runtime.id.
233 // Turn the array into a JS array, which effectively gets eval()ed.
234 std::string as_js_array
;
235 for (size_t i
= 0; i
< arraysize(non_messaging_apis
); ++i
) {
236 as_js_array
+= as_js_array
.empty() ? "[" : ",";
237 as_js_array
+= base::StringPrintf("'%s'", non_messaging_apis
[i
]);
242 CHECK(content::ExecuteScriptInFrameAndExtractBool(
243 browser()->tab_strip_model()->GetActiveWebContents(),
245 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array
+ ")",
248 testing::AssertionSuccess() : testing::AssertionFailure();
251 std::string
GetTlsChannelIdFromPortConnect(const std::string
& extension_id
,
252 bool include_tls_channel_id
,
253 const char* message
= NULL
) {
254 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
256 include_tls_channel_id
,
260 std::string
GetTlsChannelIdFromSendMessage(const std::string
& extension_id
,
261 bool include_tls_channel_id
,
262 const char* message
= NULL
) {
263 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
265 include_tls_channel_id
,
269 GURL
GetURLForPath(const std::string
& host
, const std::string
& path
) {
270 std::string port
= base::IntToString(embedded_test_server()->port());
271 GURL::Replacements replacements
;
272 replacements
.SetHostStr(host
);
273 replacements
.SetPortStr(port
);
274 return embedded_test_server()->GetURL(path
).ReplaceComponents(replacements
);
277 GURL
chromium_org_url() {
278 return GetURLForPath("www.chromium.org", "/chromium.org.html");
281 GURL
google_com_url() {
282 return GetURLForPath("www.google.com", "/google.com.html");
285 const Extension
* LoadChromiumConnectableExtension() {
286 const Extension
* extension
=
287 LoadExtensionIntoDir(&web_connectable_dir_
, base::StringPrintf(
289 " \"name\": \"chromium_connectable\","
291 " \"externally_connectable\": {"
292 " \"matches\": [\"*://*.chromium.org:*/*\"]"
300 const Extension
* LoadNotConnectableExtension() {
301 const Extension
* extension
=
302 LoadExtensionIntoDir(¬_connectable_dir_
, base::StringPrintf(
304 " \"name\": \"not_connectable\","
312 const Extension
* LoadChromiumConnectableExtensionWithTlsChannelId() {
313 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_
,
314 connectable_with_tls_channel_id_manifest());
317 const Extension
* LoadChromiumHostedApp() {
318 const Extension
* hosted_app
=
319 LoadExtensionIntoDir(&hosted_app_dir_
, base::StringPrintf(
321 " \"name\": \"chromium_hosted_app\","
322 " \"version\": \"1.0\","
323 " \"manifest_version\": 2,"
325 " \"urls\": [\"%s\"],"
327 " \"web_url\": \"%s\""
330 "}", chromium_org_url().spec().c_str(),
331 chromium_org_url().spec().c_str()));
336 void InitializeTestServer() {
337 base::FilePath test_data
;
338 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &test_data
));
339 embedded_test_server()->ServeFilesFromDirectory(test_data
.AppendASCII(
340 "extensions/api_test/messaging/externally_connectable/sites"));
341 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
342 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
345 const char* close_background_message() {
346 return "closeBackgroundPage";
350 const Extension
* LoadExtensionIntoDir(TestExtensionDir
* dir
,
351 const std::string
& manifest
) {
352 dir
->WriteManifest(manifest
);
353 dir
->WriteFile(FILE_PATH_LITERAL("background.js"),
355 "function maybeClose(message) {\n"
356 " if (message.indexOf('%s') >= 0)\n"
357 " window.setTimeout(function() { window.close() }, 0);\n"
359 "chrome.runtime.onMessageExternal.addListener(\n"
360 " function(message, sender, reply) {\n"
361 " reply({ message: message, sender: sender });\n"
362 " maybeClose(message);\n"
364 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
365 " port.onMessage.addListener(function(message) {\n"
366 " port.postMessage({ message: message, sender: port.sender });\n"
367 " maybeClose(message);\n"
370 close_background_message()));
371 return LoadExtension(dir
->unpacked_path());
374 const char* common_manifest() {
375 return "\"version\": \"1.0\","
377 " \"scripts\": [\"background.js\"],"
378 " \"persistent\": false"
380 "\"manifest_version\": 2";
383 std::string
connectable_with_tls_channel_id_manifest() {
384 return base::StringPrintf(
386 " \"name\": \"chromium_connectable_with_tls_channel_id\","
388 " \"externally_connectable\": {"
389 " \"matches\": [\"*://*.chromium.org:*/*\"],"
390 " \"accepts_tls_channel_id\": true"
396 std::string
GetTlsChannelIdFromAssertion(const char* method
,
397 const std::string
& extension_id
,
398 bool include_tls_channel_id
,
399 const char* message
) {
401 std::string args
= "'" + extension_id
+ "', ";
402 args
+= include_tls_channel_id
? "true" : "false";
404 args
+= std::string(", '") + message
+ "'";
405 CHECK(content::ExecuteScriptAndExtractString(
406 browser()->tab_strip_model()->GetActiveWebContents(),
407 base::StringPrintf("assertions.%s(%s)", method
, args
.c_str()),
412 TestExtensionDir web_connectable_dir_
;
413 TestExtensionDir not_connectable_dir_
;
414 TestExtensionDir tls_channel_id_connectable_dir_
;
415 TestExtensionDir hosted_app_dir_
;
418 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, NotInstalled
) {
419 InitializeTestServer();
421 const char kFakeId
[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
423 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
424 EXPECT_EQ(NAMESPACE_NOT_DEFINED
, CanConnectAndSendMessages(kFakeId
));
425 EXPECT_FALSE(AreAnyNonWebApisDefined());
427 ui_test_utils::NavigateToURL(browser(), google_com_url());
428 EXPECT_EQ(NAMESPACE_NOT_DEFINED
, CanConnectAndSendMessages(kFakeId
));
429 EXPECT_FALSE(AreAnyNonWebApisDefined());
432 // Tests two extensions on the same sites: one web connectable, one not.
433 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
434 WebConnectableAndNotConnectable
) {
435 InitializeTestServer();
437 // Install the web connectable extension. chromium.org can connect to it,
439 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
441 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
442 EXPECT_EQ(OK
, CanConnectAndSendMessages(chromium_connectable
->id()));
443 EXPECT_FALSE(AreAnyNonWebApisDefined());
445 ui_test_utils::NavigateToURL(browser(), google_com_url());
446 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
447 CanConnectAndSendMessages(chromium_connectable
->id()));
448 EXPECT_FALSE(AreAnyNonWebApisDefined());
450 // Install the non-connectable extension. Nothing can connect to it.
451 const Extension
* not_connectable
= LoadNotConnectableExtension();
453 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
454 // Namespace will be defined here because |chromium_connectable| can connect
455 // to it - so this will be the "cannot establish connection" error.
456 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
457 CanConnectAndSendMessages(not_connectable
->id()));
458 EXPECT_FALSE(AreAnyNonWebApisDefined());
460 ui_test_utils::NavigateToURL(browser(), google_com_url());
461 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
462 CanConnectAndSendMessages(not_connectable
->id()));
463 EXPECT_FALSE(AreAnyNonWebApisDefined());
466 // See http://crbug.com/297866
467 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
468 DISABLED_BackgroundPageClosesOnMessageReceipt
) {
469 InitializeTestServer();
471 // Install the web connectable extension.
472 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
474 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
475 // If the background page closes after receipt of the message, it will still
476 // reply to this message...
477 EXPECT_EQ(OK
, CanConnectAndSendMessages(chromium_connectable
->id(),
479 close_background_message()));
480 // and be re-opened by receipt of a subsequent message.
481 EXPECT_EQ(OK
, CanConnectAndSendMessages(chromium_connectable
->id()));
484 // Tests a web connectable extension that doesn't receive TLS channel id.
485 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
486 WebConnectableWithoutTlsChannelId
) {
487 InitializeTestServer();
489 // Install the web connectable extension. chromium.org can connect to it,
491 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
492 ASSERT_TRUE(chromium_connectable
);
494 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
495 // The web connectable extension doesn't request the TLS channel ID, so it
496 // doesn't get it, whether or not the page asks for it.
497 EXPECT_EQ(std::string(),
498 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), false));
499 EXPECT_EQ(std::string(),
500 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true));
501 EXPECT_EQ(std::string(),
502 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), false));
503 EXPECT_EQ(std::string(),
504 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true));
507 // Tests a web connectable extension that receives TLS channel id with a site
508 // that can't connect to it.
509 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
510 WebConnectableWithTlsChannelIdWithNonMatchingSite
) {
511 InitializeTestServer();
513 const Extension
* chromium_connectable
=
514 LoadChromiumConnectableExtensionWithTlsChannelId();
515 ASSERT_TRUE(chromium_connectable
);
517 ui_test_utils::NavigateToURL(browser(), google_com_url());
518 // The extension requests the TLS channel ID, but it doesn't get it for a
519 // site that can't connect to it, regardless of whether the page asks for it.
520 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
521 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), false));
522 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
523 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true));
524 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
525 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), false));
526 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED
),
527 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true));
530 // Tests a web connectable extension that receives TLS channel id on a site
531 // that can connect to it, but with no TLS channel ID having been generated.
532 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
533 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId
) {
534 InitializeTestServer();
536 const Extension
* chromium_connectable
=
537 LoadChromiumConnectableExtensionWithTlsChannelId();
538 ASSERT_TRUE(chromium_connectable
);
540 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
542 // Since the extension requests the TLS channel ID, it gets it for a site that
543 // can connect to it, but only if the page also asks to include it.
544 EXPECT_EQ(std::string(),
545 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), false));
546 EXPECT_EQ(std::string(),
547 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), false));
548 // If the page does ask for it, it isn't empty.
549 std::string tls_channel_id
=
550 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), true);
551 // Because the TLS channel ID has never been generated for this domain,
552 // no TLS channel ID is reported.
553 EXPECT_EQ(std::string(), tls_channel_id
);
556 // Flaky on Linux and Windows. http://crbug.com/315264
557 // Tests a web connectable extension that receives TLS channel id, but
558 // immediately closes its background page upon receipt of a message.
559 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
560 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
) {
561 InitializeTestServer();
563 const Extension
* chromium_connectable
=
564 LoadChromiumConnectableExtensionWithTlsChannelId();
566 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
567 // If the page does ask for it, it isn't empty, even if the background page
568 // closes upon receipt of the connect.
569 std::string tls_channel_id
=
570 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(),
572 close_background_message());
573 // Because the TLS channel ID has never been generated for this domain,
574 // no TLS channel ID is reported.
575 EXPECT_EQ(std::string(), tls_channel_id
);
576 // A subsequent connect will still succeed, even if the background page was
577 // previously closed.
579 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(),
581 // And the empty value is still retrieved.
582 EXPECT_EQ(std::string(), tls_channel_id
);
585 // Tests that enabling and disabling an extension makes the runtime bindings
586 // appear and disappear.
588 // TODO(kalman): Test with multiple extensions that can be accessed by the same
590 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
591 EnablingAndDisabling
) {
592 InitializeTestServer();
594 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
595 const Extension
* not_connectable
= LoadNotConnectableExtension();
597 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
598 EXPECT_EQ(OK
, CanConnectAndSendMessages(chromium_connectable
->id()));
599 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
600 CanConnectAndSendMessages(not_connectable
->id()));
602 DisableExtension(chromium_connectable
->id());
603 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
604 CanConnectAndSendMessages(chromium_connectable
->id()));
606 EnableExtension(chromium_connectable
->id());
607 EXPECT_EQ(OK
, CanConnectAndSendMessages(chromium_connectable
->id()));
608 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
609 CanConnectAndSendMessages(not_connectable
->id()));
612 // Tests connection from incognito tabs when the user denies the connection
613 // request. Spanning mode only.
615 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
616 // somewhere. This is a test that should be shared with the content script logic
617 // so it's not really our specific concern for web connectable.
619 // TODO(kalman): test messages from incognito extensions too.
620 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, FromIncognitoDeny
) {
621 InitializeTestServer();
623 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
624 const std::string
& id
= chromium_connectable
->id();
626 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
627 profile()->GetOffTheRecordProfile(),
630 // No connection because incognito-enabled hasn't been set for the extension,
631 // and the user denied our interactive request.
633 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
634 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY
);
636 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
637 CanConnectAndSendMessages(incognito_browser
, id
));
638 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
640 // Try again. User has already denied.
641 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
642 CanConnectAndSendMessages(incognito_browser
, id
));
643 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
646 // Allowing the extension in incognito mode will bypass the deny.
647 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id
, true);
648 EXPECT_EQ(OK
, CanConnectAndSendMessages(incognito_browser
, id
));
651 // Tests connection from incognito tabs when the user accepts the connection
652 // request. Spanning mode only.
654 // TODO(kalman): see comment above about split mode.
655 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, FromIncognitoAllow
) {
656 InitializeTestServer();
658 const Extension
* chromium_connectable
= LoadChromiumConnectableExtension();
659 const std::string
& id
= chromium_connectable
->id();
661 Browser
* incognito_browser
= ui_test_utils::OpenURLOffTheRecord(
662 profile()->GetOffTheRecordProfile(),
665 // Connection allowed even with incognito disabled, because the user accepted
666 // the interactive request.
668 IncognitoConnectability::ScopedAlertTracker
alert_tracker(
669 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW
);
671 EXPECT_EQ(OK
, CanConnectAndSendMessages(incognito_browser
, id
));
672 EXPECT_EQ(1, alert_tracker
.GetAndResetAlertCount());
674 // Try again. User has already allowed.
675 EXPECT_EQ(OK
, CanConnectAndSendMessages(incognito_browser
, id
));
676 EXPECT_EQ(0, alert_tracker
.GetAndResetAlertCount());
679 // Allowing the extension in incognito mode will continue to allow.
680 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id
, true);
681 EXPECT_EQ(OK
, CanConnectAndSendMessages(incognito_browser
, id
));
684 // Tests a connection from an iframe within a tab which doesn't have
685 // permission. Iframe should work.
686 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
687 FromIframeWithPermission
) {
688 InitializeTestServer();
690 const Extension
* extension
= LoadChromiumConnectableExtension();
692 ui_test_utils::NavigateToURL(browser(), google_com_url());
693 EXPECT_EQ(NAMESPACE_NOT_DEFINED
, CanConnectAndSendMessages(extension
->id()));
694 EXPECT_FALSE(AreAnyNonWebApisDefined());
696 ASSERT_TRUE(AppendIframe(chromium_org_url()));
698 const char* frame_xpath
= "//iframe[1]";
699 EXPECT_EQ(OK
, CanConnectAndSendMessages(extension
->id(), frame_xpath
));
700 EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath
));
703 // Tests connection from an iframe without permission within a tab that does.
704 // Iframe shouldn't work.
705 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
706 FromIframeWithoutPermission
) {
707 InitializeTestServer();
709 const Extension
* extension
= LoadChromiumConnectableExtension();
711 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
712 EXPECT_EQ(OK
, CanConnectAndSendMessages(extension
->id()));
713 EXPECT_FALSE(AreAnyNonWebApisDefined());
715 ASSERT_TRUE(AppendIframe(google_com_url()));
717 const char* frame_xpath
= "//iframe[1]";
718 EXPECT_EQ(NAMESPACE_NOT_DEFINED
,
719 CanConnectAndSendMessages(extension
->id(), frame_xpath
));
720 EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath
));
723 // Tests externally_connectable between a web page and an extension with a
724 // TLS channel ID created for the origin.
725 class ExternallyConnectableMessagingWithTlsChannelIdTest
:
726 public ExternallyConnectableMessagingTest
{
728 ExternallyConnectableMessagingWithTlsChannelIdTest()
729 : tls_channel_id_created_(false, false) {
732 std::string
CreateTlsChannelId() {
733 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
734 profile()->GetRequestContext());
735 std::string domain_bound_private_key
;
736 std::string domain_bound_cert
;
737 net::ServerBoundCertService::RequestHandle request_handle
;
738 content::BrowserThread::PostTask(
739 content::BrowserThread::IO
,
742 &ExternallyConnectableMessagingWithTlsChannelIdTest::
743 CreateDomainBoundCertOnIOThread
,
744 base::Unretained(this),
745 base::Unretained(&domain_bound_private_key
),
746 base::Unretained(&domain_bound_cert
),
747 base::Unretained(&request_handle
),
748 request_context_getter
));
749 tls_channel_id_created_
.Wait();
750 // Create the expected value.
751 base::StringPiece spki
;
752 net::asn1::ExtractSPKIFromDERCert(domain_bound_cert
, &spki
);
753 base::DictionaryValue jwk_value
;
754 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki
, &jwk_value
);
755 std::string tls_channel_id_value
;
756 base::JSONWriter::Write(&jwk_value
, &tls_channel_id_value
);
757 return tls_channel_id_value
;
761 void CreateDomainBoundCertOnIOThread(
762 std::string
* domain_bound_private_key
,
763 std::string
* domain_bound_cert
,
764 net::ServerBoundCertService::RequestHandle
* request_handle
,
765 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter
) {
766 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO
));
767 net::ServerBoundCertService
* server_bound_cert_service
=
768 request_context_getter
->GetURLRequestContext()->
769 server_bound_cert_service();
770 int status
= server_bound_cert_service
->GetOrCreateDomainBoundCert(
771 chromium_org_url().host(),
772 domain_bound_private_key
,
774 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
776 base::Unretained(this)),
778 if (status
== net::ERR_IO_PENDING
)
780 GotDomainBoundCert(status
);
783 void GotDomainBoundCert(int status
) {
784 ASSERT_TRUE(status
== net::OK
);
785 tls_channel_id_created_
.Signal();
788 base::WaitableEvent tls_channel_id_created_
;
791 // Tests a web connectable extension that receives TLS channel id on a site
792 // that can connect to it, with a TLS channel ID having been generated.
793 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
794 WebConnectableWithNonEmptyTlsChannelId
) {
795 InitializeTestServer();
796 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
798 const Extension
* chromium_connectable
=
799 LoadChromiumConnectableExtensionWithTlsChannelId();
800 ASSERT_TRUE(chromium_connectable
);
802 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
804 // Since the extension requests the TLS channel ID, it gets it for a site that
805 // can connect to it, but only if the page also asks to send it.
806 EXPECT_EQ(std::string(),
807 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), false));
808 EXPECT_EQ(std::string(),
809 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), false));
811 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
812 std::string tls_channel_id_from_port_connect
=
813 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), true);
814 EXPECT_NE(0u, tls_channel_id_from_port_connect
.size());
816 // The same value is received by both connect and sendMessage.
817 std::string tls_channel_id_from_send_message
=
818 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true);
819 EXPECT_EQ(tls_channel_id_from_port_connect
, tls_channel_id_from_send_message
);
821 // And since a TLS channel ID exists for the domain, the value received is
822 // parseable as a JWK. (In particular, it has the same value we created by
823 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
824 std::string
tls_channel_id(tls_channel_id_from_port_connect
);
825 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
827 // The TLS channel ID shouldn't change from one connection to the next...
828 std::string tls_channel_id2
=
829 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), true);
830 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
832 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true);
833 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
835 // nor should it change when navigating away, revisiting the page and
836 // requesting it again.
837 ui_test_utils::NavigateToURL(browser(), google_com_url());
838 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
840 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(), true);
841 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
843 GetTlsChannelIdFromSendMessage(chromium_connectable
->id(), true);
844 EXPECT_EQ(tls_channel_id
, tls_channel_id2
);
847 // Tests a web connectable extension that receives TLS channel id, but
848 // immediately closes its background page upon receipt of a message.
849 // Same flakiness seen in http://crbug.com/297866
850 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest
,
851 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage
) {
852 InitializeTestServer();
853 std::string expected_tls_channel_id_value
= CreateTlsChannelId();
855 const Extension
* chromium_connectable
=
856 LoadChromiumConnectableExtensionWithTlsChannelId();
858 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
859 // If the page does ask for it, it isn't empty, even if the background page
860 // closes upon receipt of the connect.
861 std::string tls_channel_id
=
862 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(),
864 close_background_message());
865 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
866 // A subsequent connect will still succeed, even if the background page was
867 // previously closed.
869 GetTlsChannelIdFromPortConnect(chromium_connectable
->id(),
871 // And the expected value is still retrieved.
872 EXPECT_EQ(expected_tls_channel_id_value
, tls_channel_id
);
875 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, MessagingUserGesture
) {
876 const char kManifest
[] = "{"
877 " \"name\": \"user_gesture\","
878 " \"version\": \"1.0\","
880 " \"scripts\": [\"background.js\"]"
882 " \"manifest_version\": 2"
885 TestExtensionDir receiver_dir
;
886 receiver_dir
.WriteManifest(kManifest
);
887 receiver_dir
.WriteFile(FILE_PATH_LITERAL("background.js"),
888 "chrome.runtime.onMessageExternal.addListener(\n"
889 " function(msg, sender, reply) {\n"
890 " reply({result:chrome.test.isProcessingUserGesture()});\n"
892 const Extension
* receiver
= LoadExtension(receiver_dir
.unpacked_path());
893 ASSERT_TRUE(receiver
);
895 TestExtensionDir sender_dir
;
896 sender_dir
.WriteManifest(kManifest
);
897 sender_dir
.WriteFile(FILE_PATH_LITERAL("background.js"), "");
898 const Extension
* sender
= LoadExtension(sender_dir
.unpacked_path());
902 ExecuteScriptInBackgroundPage(sender
->id(),
904 "chrome.test.runWithoutUserGesture(function() {\n"
905 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
906 " window.domAutomationController.send('' + response.result);\n"
908 "});", receiver
->id().c_str())));
911 ExecuteScriptInBackgroundPage(sender
->id(),
913 "chrome.test.runWithUserGesture(function() {\n"
914 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
915 " window.domAutomationController.send('' + response.result);\n"
917 "});", receiver
->id().c_str())));
920 // Tests that a hosted app on a connectable site doesn't interfere with the
921 // connectability of that site.
922 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
, HostedAppOnWebsite
) {
923 InitializeTestServer();
925 LoadChromiumHostedApp();
927 // The presence of the hosted app shouldn't give the ability to send messages.
928 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
929 EXPECT_EQ(NAMESPACE_NOT_DEFINED
, CanConnectAndSendMessages(""));
930 EXPECT_FALSE(AreAnyNonWebApisDefined());
932 // Once a connectable extension is installed, it should.
933 const Extension
* extension
= LoadChromiumConnectableExtension();
934 EXPECT_EQ(OK
, CanConnectAndSendMessages(extension
->id()));
935 EXPECT_FALSE(AreAnyNonWebApisDefined());
938 // Tests that an invalid extension ID specified in a hosted app does not crash
939 // the hosted app's renderer.
941 // This is a regression test for http://crbug.com/326250#c12.
942 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest
,
943 InvalidExtensionIDFromHostedApp
) {
944 InitializeTestServer();
946 // The presence of the chromium hosted app triggers this bug. The chromium
947 // connectable extension needs to be installed to set up the runtime bindings.
948 LoadChromiumHostedApp();
949 LoadChromiumConnectableExtension();
951 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
952 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR
,
953 CanConnectAndSendMessages("invalid"));
958 }; // namespace extensions