Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_messages_apitest.cc
blobb3d191e53a2f82bf8e5b79b0dc2980c4bc1a7ab5
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"
39 #include "url/gurl.h"
41 namespace extensions {
42 namespace {
44 class MessageSender : public content::NotificationObserver {
45 public:
46 MessageSender() {
47 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
48 content::NotificationService::AllSources());
51 private:
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,
64 Profile* profile,
65 GURL event_url) {
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;
69 return event.Pass();
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(),
83 GURL()));
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(),
95 GURL()));
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 {
144 protected:
145 // Result codes from the test. These must match up with |results| in
146 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
147 enum Result {
148 OK = 0,
149 NAMESPACE_NOT_DEFINED = 1,
150 FUNCTION_NOT_DEFINED = 2,
151 COULD_NOT_ESTABLISH_CONNECTION_ERROR = 3,
152 OTHER_ERROR = 4,
153 INCORRECT_RESPONSE_SENDER = 5,
154 INCORRECT_RESPONSE_MESSAGE = 6,
157 bool AppendIframe(const GURL& src) {
158 bool result;
159 CHECK(content::ExecuteScriptAndExtractBool(
160 browser()->tab_strip_model()->GetActiveWebContents(),
161 "actions.appendIframe('" + src.spec() + "');", &result));
162 return 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,
173 message);
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) {
190 int result;
191 std::string args = "'" + extension_id + "'";
192 if (message)
193 args += std::string(", '") + message + "'";
194 CHECK(content::ExecuteScriptInFrameAndExtractInt(
195 browser->tab_strip_model()->GetActiveWebContents(),
196 frame_xpath,
197 base::StringPrintf("assertions.canConnectAndSendMessages(%s)",
198 args.c_str()),
199 &result));
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[] = {
210 "getBackgroundPage",
211 "getManifest",
212 "getURL",
213 "reload",
214 "requestUpdateCheck",
215 "restart",
216 "connectNative",
217 "sendNativeMessage",
218 "onStartup",
219 "onInstalled",
220 "onSuspend",
221 "onSuspendCanceled",
222 "onUpdateAvailable",
223 "onBrowserUpdateAvailable",
224 "onConnect",
225 "onConnectExternal",
226 "onMessage",
227 "onMessageExternal",
228 "onRestartRequired",
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]);
239 as_js_array += "]";
241 bool any_defined;
242 CHECK(content::ExecuteScriptInFrameAndExtractBool(
243 browser()->tab_strip_model()->GetActiveWebContents(),
244 frame_xpath,
245 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
246 &any_defined));
247 return any_defined ?
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",
255 extension_id,
256 include_tls_channel_id,
257 message);
260 std::string GetTlsChannelIdFromSendMessage(const std::string& extension_id,
261 bool include_tls_channel_id,
262 const char* message = NULL) {
263 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
264 extension_id,
265 include_tls_channel_id,
266 message);
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\","
290 " %s,"
291 " \"externally_connectable\": {"
292 " \"matches\": [\"*://*.chromium.org:*/*\"]"
293 " }"
294 "}",
295 common_manifest()));
296 CHECK(extension);
297 return extension;
300 const Extension* LoadNotConnectableExtension() {
301 const Extension* extension =
302 LoadExtensionIntoDir(&not_connectable_dir_, base::StringPrintf(
304 " \"name\": \"not_connectable\","
305 " %s"
306 "}",
307 common_manifest()));
308 CHECK(extension);
309 return extension;
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,"
324 " \"app\": {"
325 " \"urls\": [\"%s\"],"
326 " \"launch\": {"
327 " \"web_url\": \"%s\""
328 " }\n"
329 " }\n"
330 "}", chromium_org_url().spec().c_str(),
331 chromium_org_url().spec().c_str()));
332 CHECK(hosted_app);
333 return hosted_app;
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";
349 private:
350 const Extension* LoadExtensionIntoDir(TestExtensionDir* dir,
351 const std::string& manifest) {
352 dir->WriteManifest(manifest);
353 dir->WriteFile(FILE_PATH_LITERAL("background.js"),
354 base::StringPrintf(
355 "function maybeClose(message) {\n"
356 " if (message.indexOf('%s') >= 0)\n"
357 " window.setTimeout(function() { window.close() }, 0);\n"
358 "}\n"
359 "chrome.runtime.onMessageExternal.addListener(\n"
360 " function(message, sender, reply) {\n"
361 " reply({ message: message, sender: sender });\n"
362 " maybeClose(message);\n"
363 "});\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"
368 " });\n"
369 "});\n",
370 close_background_message()));
371 return LoadExtension(dir->unpacked_path());
374 const char* common_manifest() {
375 return "\"version\": \"1.0\","
376 "\"background\": {"
377 " \"scripts\": [\"background.js\"],"
378 " \"persistent\": false"
379 "},"
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\","
387 " %s,"
388 " \"externally_connectable\": {"
389 " \"matches\": [\"*://*.chromium.org:*/*\"],"
390 " \"accepts_tls_channel_id\": true"
391 " }"
392 "}",
393 common_manifest());
396 std::string GetTlsChannelIdFromAssertion(const char* method,
397 const std::string& extension_id,
398 bool include_tls_channel_id,
399 const char* message) {
400 std::string result;
401 std::string args = "'" + extension_id + "', ";
402 args += include_tls_channel_id ? "true" : "false";
403 if (message)
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()),
408 &result));
409 return result;
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,
438 // google.com can't.
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,
490 // google.com can't.
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(),
571 true,
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.
578 tls_channel_id =
579 GetTlsChannelIdFromPortConnect(chromium_connectable->id(),
580 true);
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
589 // host.
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(),
628 chromium_org_url());
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(),
663 chromium_org_url());
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 {
727 public:
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,
740 FROM_HERE,
741 base::Bind(
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;
760 private:
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,
773 domain_bound_cert,
774 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
775 GotDomainBoundCert,
776 base::Unretained(this)),
777 request_handle);
778 if (status == net::ERR_IO_PENDING)
779 return;
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);
831 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());
839 tls_channel_id2 =
840 GetTlsChannelIdFromPortConnect(chromium_connectable->id(), true);
841 EXPECT_EQ(tls_channel_id, tls_channel_id2);
842 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(),
863 true,
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.
868 tls_channel_id =
869 GetTlsChannelIdFromPortConnect(chromium_connectable->id(),
870 true);
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\","
879 " \"background\": {"
880 " \"scripts\": [\"background.js\"]"
881 " },"
882 " \"manifest_version\": 2"
883 "}";
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"
891 " });");
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());
899 ASSERT_TRUE(sender);
901 EXPECT_EQ("false",
902 ExecuteScriptInBackgroundPage(sender->id(),
903 base::StringPrintf(
904 "chrome.test.runWithoutUserGesture(function() {\n"
905 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
906 " window.domAutomationController.send('' + response.result);\n"
907 " });\n"
908 "});", receiver->id().c_str())));
910 EXPECT_EQ("true",
911 ExecuteScriptInBackgroundPage(sender->id(),
912 base::StringPrintf(
913 "chrome.test.runWithUserGesture(function() {\n"
914 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
915 " window.domAutomationController.send('' + response.result);\n"
916 " });\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"));
956 } // namespace
958 }; // namespace extensions