Temporarily re-enabling SizeAfterPrefChange test with traces (this time for Linux...
[chromium-blink-merge.git] / chrome / browser / extensions / extension_messages_apitest.cc
blob5d219d8d2849a7e6ca0d913772f9d4cdd7a6b1b8
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"
41 #include "url/gurl.h"
43 namespace extensions {
44 namespace {
46 class MessageSender : public content::NotificationObserver {
47 public:
48 MessageSender() {
49 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
50 content::NotificationService::AllSources());
53 private:
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,
66 Profile* profile,
67 GURL event_url) {
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;
71 return event.Pass();
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(),
85 GURL()));
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(),
97 GURL()));
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.
141 #if !defined(OS_WIN)
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 {
150 protected:
151 // Result codes from the test. These must match up with |results| in
152 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
153 enum Result {
154 OK = 0,
155 NAMESPACE_NOT_DEFINED = 1,
156 FUNCTION_NOT_DEFINED = 2,
157 COULD_NOT_ESTABLISH_CONNECTION_ERROR = 3,
158 OTHER_ERROR = 4,
159 INCORRECT_RESPONSE_SENDER = 5,
160 INCORRECT_RESPONSE_MESSAGE = 6,
163 bool AppendIframe(const GURL& src) {
164 bool result;
165 CHECK(content::ExecuteScriptAndExtractBool(
166 browser()->tab_strip_model()->GetActiveWebContents(),
167 "actions.appendIframe('" + src.spec() + "');", &result));
168 return result;
171 Result CanConnectAndSendMessagesToMainFrame(const Extension* extension,
172 const char* message = NULL) {
173 return CanConnectAndSendMessagesToFrame(
174 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
175 extension,
176 message);
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) {
190 int result;
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[] = {
216 "getBackgroundPage",
217 "getManifest",
218 "getURL",
219 "reload",
220 "requestUpdateCheck",
221 "restart",
222 "connectNative",
223 "sendNativeMessage",
224 "onStartup",
225 "onInstalled",
226 "onSuspend",
227 "onSuspendCanceled",
228 "onUpdateAvailable",
229 "onBrowserUpdateAvailable",
230 "onConnect",
231 "onConnectExternal",
232 "onMessage",
233 "onMessageExternal",
234 "onRestartRequired",
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]);
245 as_js_array += "]";
247 bool any_defined;
248 CHECK(content::ExecuteScriptAndExtractBool(
249 frame,
250 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
251 &any_defined));
252 return any_defined ?
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",
260 extension,
261 include_tls_channel_id,
262 message);
265 std::string GetTlsChannelIdFromSendMessage(const Extension* extension,
266 bool include_tls_channel_id,
267 const char* message = NULL) {
268 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
269 extension,
270 include_tls_channel_id,
271 message);
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_,
293 base::StringPrintf(
295 " \"name\": \"chromium_connectable\","
296 " %s,"
297 " \"externally_connectable\": {"
298 " \"matches\": [\"*://*.chromium.org:*/*\"]"
299 " }"
300 "}",
301 common_manifest()));
302 CHECK(extension.get());
303 return extension;
306 scoped_refptr<const Extension> LoadChromiumConnectableApp() {
307 scoped_refptr<const Extension> extension =
308 LoadExtensionIntoDir(&web_connectable_dir_,
310 " \"app\": {"
311 " \"background\": {"
312 " \"scripts\": [\"background.js\"]"
313 " }"
314 " },"
315 " \"externally_connectable\": {"
316 " \"matches\": [\"*://*.chromium.org:*/*\"]"
317 " },"
318 " \"manifest_version\": 2,"
319 " \"name\": \"app_connectable\","
320 " \"version\": \"1.0\""
321 "}");
322 CHECK(extension.get());
323 return extension;
326 scoped_refptr<const Extension> LoadNotConnectableExtension() {
327 scoped_refptr<const Extension> extension =
328 LoadExtensionIntoDir(&not_connectable_dir_,
329 base::StringPrintf(
331 " \"name\": \"not_connectable\","
332 " %s"
333 "}",
334 common_manifest()));
335 CHECK(extension.get());
336 return extension;
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_,
348 base::StringPrintf(
350 " \"name\": \"chromium_hosted_app\","
351 " \"version\": \"1.0\","
352 " \"manifest_version\": 2,"
353 " \"app\": {"
354 " \"urls\": [\"%s\"],"
355 " \"launch\": {"
356 " \"web_url\": \"%s\""
357 " }\n"
358 " }\n"
359 "}",
360 chromium_org_url().spec().c_str(),
361 chromium_org_url().spec().c_str()));
362 CHECK(hosted_app.get());
363 return hosted_app;
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";
379 private:
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"),
385 base::StringPrintf(
386 "function maybeClose(message) {\n"
387 " if (message.indexOf('%s') >= 0)\n"
388 " window.setTimeout(function() { window.close() }, 0);\n"
389 "}\n"
390 "chrome.runtime.onMessageExternal.addListener(\n"
391 " function(message, sender, reply) {\n"
392 " reply({ message: message, sender: sender });\n"
393 " maybeClose(message);\n"
394 "});\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"
399 " });\n"
400 "});\n",
401 close_background_message()));
402 return LoadExtension(dir->unpacked_path());
405 const char* common_manifest() {
406 return "\"version\": \"1.0\","
407 "\"background\": {"
408 " \"scripts\": [\"background.js\"],"
409 " \"persistent\": false"
410 "},"
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\","
418 " %s,"
419 " \"externally_connectable\": {"
420 " \"matches\": [\"*://*.chromium.org:*/*\"],"
421 " \"accepts_tls_channel_id\": true"
422 " }"
423 "}",
424 common_manifest());
427 std::string GetTlsChannelIdFromAssertion(const char* method,
428 const Extension* extension,
429 bool include_tls_channel_id,
430 const char* message) {
431 std::string result;
432 std::string args = "'" + extension->id() + "', ";
433 args += include_tls_channel_id ? "true" : "false";
434 if (message)
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()),
439 &result));
440 return result;
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 =
453 ExtensionBuilder()
454 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
455 .SetManifest(DictionaryBuilder()
456 .Set("name", "Fake extension")
457 .Set("version", "1")
458 .Set("manifest_version", 2))
459 .Build();
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,
478 // google.com can't.
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...
517 EXPECT_EQ(OK,
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,
530 // google.com can't.
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
625 // host.
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(),
665 chromium_org_url());
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()
702 ->GetMainFrame();
705 IncognitoConnectability::ScopedAlertTracker alert_tracker(
706 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
708 // The alert doesn't show for extensions.
709 EXPECT_EQ(
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);
717 EXPECT_EQ(OK,
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(),
734 chromium_org_url());
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
753 // already allowed.
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()
769 ->GetMainFrame();
772 IncognitoConnectability::ScopedAlertTracker alert_tracker(
773 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
775 // No alert is shown.
776 EXPECT_EQ(
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);
784 EXPECT_EQ(OK,
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 {
830 public:
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,
843 FROM_HERE,
844 base::Bind(
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;
863 private:
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,
876 domain_bound_cert,
877 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
878 GotDomainBoundCert,
879 base::Unretained(this)),
880 request_handle);
881 if (status == net::ERR_IO_PENDING)
882 return;
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\","
975 " \"background\": {"
976 " \"scripts\": [\"background.js\"]"
977 " },"
978 " \"manifest_version\": 2"
979 "}";
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"
987 " });");
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());
995 ASSERT_TRUE(sender);
997 EXPECT_EQ("false",
998 ExecuteScriptInBackgroundPage(sender->id(),
999 base::StringPrintf(
1000 "chrome.test.runWithoutUserGesture(function() {\n"
1001 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1002 " window.domAutomationController.send('' + response.result);\n"
1003 " });\n"
1004 "});", receiver->id().c_str())));
1006 EXPECT_EQ("true",
1007 ExecuteScriptInBackgroundPage(sender->id(),
1008 base::StringPrintf(
1009 "chrome.test.runWithUserGesture(function() {\n"
1010 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1011 " window.domAutomationController.send('' + response.result);\n"
1012 " });\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 =
1048 ExtensionBuilder()
1049 // A bit scary that this works...
1050 .SetID("invalid")
1051 .SetManifest(DictionaryBuilder()
1052 .Set("name", "Fake extension")
1053 .Set("version", "1")
1054 .Set("manifest_version", 2))
1055 .Build();
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.
1064 } // namespace
1066 }; // namespace extensions