MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / browser / extensions / extension_messages_apitest.cc
blobd727ada9fbef85bd7f26db918215bbe34b6ba730
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/channel_id_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,
50 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
51 content::NotificationService::AllSources());
54 private:
55 static scoped_ptr<base::ListValue> BuildEventArguments(
56 const bool last_message,
57 const std::string& data) {
58 base::DictionaryValue* event = new base::DictionaryValue();
59 event->SetBoolean("lastMessage", last_message);
60 event->SetString("data", data);
61 scoped_ptr<base::ListValue> arguments(new base::ListValue());
62 arguments->Append(event);
63 return arguments.Pass();
66 static scoped_ptr<Event> BuildEvent(scoped_ptr<base::ListValue> event_args,
67 Profile* profile,
68 GURL event_url) {
69 scoped_ptr<Event> event(new Event("test.onMessage", event_args.Pass()));
70 event->restrict_to_browser_context = profile;
71 event->event_url = event_url;
72 return event.Pass();
75 void Observe(int type,
76 const content::NotificationSource& source,
77 const content::NotificationDetails& details) override {
78 EventRouter* event_router =
79 EventRouter::Get(content::Source<Profile>(source).ptr());
81 // Sends four messages to the extension. All but the third message sent
82 // from the origin http://b.com/ are supposed to arrive.
83 event_router->BroadcastEvent(BuildEvent(
84 BuildEventArguments(false, "no restriction"),
85 content::Source<Profile>(source).ptr(),
86 GURL()));
87 event_router->BroadcastEvent(BuildEvent(
88 BuildEventArguments(false, "http://a.com/"),
89 content::Source<Profile>(source).ptr(),
90 GURL("http://a.com/")));
91 event_router->BroadcastEvent(BuildEvent(
92 BuildEventArguments(false, "http://b.com/"),
93 content::Source<Profile>(source).ptr(),
94 GURL("http://b.com/")));
95 event_router->BroadcastEvent(BuildEvent(
96 BuildEventArguments(true, "last message"),
97 content::Source<Profile>(source).ptr(),
98 GURL()));
101 content::NotificationRegistrar registrar_;
104 // Tests that message passing between extensions and content scripts works.
105 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) {
106 ASSERT_TRUE(StartEmbeddedTestServer());
107 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_;
110 // Tests that message passing from one extension to another works.
111 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) {
112 ASSERT_TRUE(LoadExtension(
113 test_data_dir_.AppendASCII("..").AppendASCII("good")
114 .AppendASCII("Extensions")
115 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
116 .AppendASCII("1.0")));
118 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_;
121 // Tests that messages with event_urls are only passed to extensions with
122 // appropriate permissions.
123 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingEventURL) {
124 MessageSender sender;
125 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_;
128 // Tests connecting from a panel to its extension.
129 class PanelMessagingTest : public ExtensionApiTest {
130 void SetUpCommandLine(CommandLine* command_line) override {
131 ExtensionApiTest::SetUpCommandLine(command_line);
132 command_line->AppendSwitch(switches::kEnablePanels);
136 IN_PROC_BROWSER_TEST_F(PanelMessagingTest, MessagingPanel) {
137 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_;
140 // XXX(kalman): All web messaging tests disabled on windows due to extreme
141 // flakiness. See http://crbug.com/350517.
142 #if !defined(OS_WIN)
144 // Tests externally_connectable between a web page and an extension.
146 // TODO(kalman): Test between extensions. This is already tested in this file,
147 // but not with externally_connectable set in the manifest.
149 // TODO(kalman): Test with host permissions.
150 class ExternallyConnectableMessagingTest : public ExtensionApiTest {
151 protected:
152 // Result codes from the test. These must match up with |results| in
153 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
154 enum Result {
155 OK = 0,
156 NAMESPACE_NOT_DEFINED = 1,
157 FUNCTION_NOT_DEFINED = 2,
158 COULD_NOT_ESTABLISH_CONNECTION_ERROR = 3,
159 OTHER_ERROR = 4,
160 INCORRECT_RESPONSE_SENDER = 5,
161 INCORRECT_RESPONSE_MESSAGE = 6,
164 bool AppendIframe(const GURL& src) {
165 bool result;
166 CHECK(content::ExecuteScriptAndExtractBool(
167 browser()->tab_strip_model()->GetActiveWebContents(),
168 "actions.appendIframe('" + src.spec() + "');", &result));
169 return result;
172 Result CanConnectAndSendMessagesToMainFrame(const Extension* extension,
173 const char* message = NULL) {
174 return CanConnectAndSendMessagesToFrame(
175 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
176 extension,
177 message);
180 Result CanConnectAndSendMessagesToIFrame(const Extension* extension,
181 const char* message = NULL) {
182 content::RenderFrameHost* frame = content::FrameMatchingPredicate(
183 browser()->tab_strip_model()->GetActiveWebContents(),
184 base::Bind(&content::FrameIsChildOfMainFrame));
185 return CanConnectAndSendMessagesToFrame(frame, extension, message);
188 Result CanConnectAndSendMessagesToFrame(content::RenderFrameHost* frame,
189 const Extension* extension,
190 const char* message) {
191 int result;
192 std::string command = base::StringPrintf(
193 "assertions.canConnectAndSendMessages('%s', %s, %s)",
194 extension->id().c_str(),
195 extension->is_platform_app() ? "true" : "false",
196 message ? base::StringPrintf("'%s'", message).c_str() : "undefined");
197 CHECK(content::ExecuteScriptAndExtractInt(frame, command, &result));
198 return static_cast<Result>(result);
201 testing::AssertionResult AreAnyNonWebApisDefinedForMainFrame() {
202 return AreAnyNonWebApisDefinedForFrame(
203 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
206 testing::AssertionResult AreAnyNonWebApisDefinedForIFrame() {
207 content::RenderFrameHost* frame = content::FrameMatchingPredicate(
208 browser()->tab_strip_model()->GetActiveWebContents(),
209 base::Bind(&content::FrameIsChildOfMainFrame));
210 return AreAnyNonWebApisDefinedForFrame(frame);
213 testing::AssertionResult AreAnyNonWebApisDefinedForFrame(
214 content::RenderFrameHost* frame) {
215 // All runtime API methods are non-web except for sendRequest and connect.
216 const char* non_messaging_apis[] = {
217 "getBackgroundPage",
218 "getManifest",
219 "getURL",
220 "reload",
221 "requestUpdateCheck",
222 "restart",
223 "connectNative",
224 "sendNativeMessage",
225 "onStartup",
226 "onInstalled",
227 "onSuspend",
228 "onSuspendCanceled",
229 "onUpdateAvailable",
230 "onBrowserUpdateAvailable",
231 "onConnect",
232 "onConnectExternal",
233 "onMessage",
234 "onMessageExternal",
235 "onRestartRequired",
236 // Note: no "id" here because this test method is used for hosted apps,
237 // which do have access to runtime.id.
240 // Turn the array into a JS array, which effectively gets eval()ed.
241 std::string as_js_array;
242 for (size_t i = 0; i < arraysize(non_messaging_apis); ++i) {
243 as_js_array += as_js_array.empty() ? "[" : ",";
244 as_js_array += base::StringPrintf("'%s'", non_messaging_apis[i]);
246 as_js_array += "]";
248 bool any_defined;
249 CHECK(content::ExecuteScriptAndExtractBool(
250 frame,
251 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
252 &any_defined));
253 return any_defined ?
254 testing::AssertionSuccess() : testing::AssertionFailure();
257 std::string GetTlsChannelIdFromPortConnect(const Extension* extension,
258 bool include_tls_channel_id,
259 const char* message = NULL) {
260 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
261 extension,
262 include_tls_channel_id,
263 message);
266 std::string GetTlsChannelIdFromSendMessage(const Extension* extension,
267 bool include_tls_channel_id,
268 const char* message = NULL) {
269 return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
270 extension,
271 include_tls_channel_id,
272 message);
275 GURL GetURLForPath(const std::string& host, const std::string& path) {
276 std::string port = base::IntToString(embedded_test_server()->port());
277 GURL::Replacements replacements;
278 replacements.SetHostStr(host);
279 replacements.SetPortStr(port);
280 return embedded_test_server()->GetURL(path).ReplaceComponents(replacements);
283 GURL chromium_org_url() {
284 return GetURLForPath("www.chromium.org", "/chromium.org.html");
287 GURL google_com_url() {
288 return GetURLForPath("www.google.com", "/google.com.html");
291 scoped_refptr<const Extension> LoadChromiumConnectableExtension() {
292 scoped_refptr<const Extension> extension =
293 LoadExtensionIntoDir(&web_connectable_dir_,
294 base::StringPrintf(
296 " \"name\": \"chromium_connectable\","
297 " %s,"
298 " \"externally_connectable\": {"
299 " \"matches\": [\"*://*.chromium.org:*/*\"]"
300 " }"
301 "}",
302 common_manifest()));
303 CHECK(extension.get());
304 return extension;
307 scoped_refptr<const Extension> LoadChromiumConnectableApp() {
308 scoped_refptr<const Extension> extension =
309 LoadExtensionIntoDir(&web_connectable_dir_,
311 " \"app\": {"
312 " \"background\": {"
313 " \"scripts\": [\"background.js\"]"
314 " }"
315 " },"
316 " \"externally_connectable\": {"
317 " \"matches\": [\"*://*.chromium.org:*/*\"]"
318 " },"
319 " \"manifest_version\": 2,"
320 " \"name\": \"app_connectable\","
321 " \"version\": \"1.0\""
322 "}");
323 CHECK(extension.get());
324 return extension;
327 scoped_refptr<const Extension> LoadNotConnectableExtension() {
328 scoped_refptr<const Extension> extension =
329 LoadExtensionIntoDir(&not_connectable_dir_,
330 base::StringPrintf(
332 " \"name\": \"not_connectable\","
333 " %s"
334 "}",
335 common_manifest()));
336 CHECK(extension.get());
337 return extension;
340 scoped_refptr<const Extension>
341 LoadChromiumConnectableExtensionWithTlsChannelId() {
342 return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_,
343 connectable_with_tls_channel_id_manifest());
346 scoped_refptr<const Extension> LoadChromiumHostedApp() {
347 scoped_refptr<const Extension> hosted_app =
348 LoadExtensionIntoDir(&hosted_app_dir_,
349 base::StringPrintf(
351 " \"name\": \"chromium_hosted_app\","
352 " \"version\": \"1.0\","
353 " \"manifest_version\": 2,"
354 " \"app\": {"
355 " \"urls\": [\"%s\"],"
356 " \"launch\": {"
357 " \"web_url\": \"%s\""
358 " }\n"
359 " }\n"
360 "}",
361 chromium_org_url().spec().c_str(),
362 chromium_org_url().spec().c_str()));
363 CHECK(hosted_app.get());
364 return hosted_app;
367 void InitializeTestServer() {
368 base::FilePath test_data;
369 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
370 embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII(
371 "extensions/api_test/messaging/externally_connectable/sites"));
372 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
373 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
376 const char* close_background_message() {
377 return "closeBackgroundPage";
380 private:
381 scoped_refptr<const Extension> LoadExtensionIntoDir(
382 TestExtensionDir* dir,
383 const std::string& manifest) {
384 dir->WriteManifest(manifest);
385 dir->WriteFile(FILE_PATH_LITERAL("background.js"),
386 base::StringPrintf(
387 "function maybeClose(message) {\n"
388 " if (message.indexOf('%s') >= 0)\n"
389 " window.setTimeout(function() { window.close() }, 0);\n"
390 "}\n"
391 "chrome.runtime.onMessageExternal.addListener(\n"
392 " function(message, sender, reply) {\n"
393 " reply({ message: message, sender: sender });\n"
394 " maybeClose(message);\n"
395 "});\n"
396 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
397 " port.onMessage.addListener(function(message) {\n"
398 " port.postMessage({ message: message, sender: port.sender });\n"
399 " maybeClose(message);\n"
400 " });\n"
401 "});\n",
402 close_background_message()));
403 return LoadExtension(dir->unpacked_path());
406 const char* common_manifest() {
407 return "\"version\": \"1.0\","
408 "\"background\": {"
409 " \"scripts\": [\"background.js\"],"
410 " \"persistent\": false"
411 "},"
412 "\"manifest_version\": 2";
415 std::string connectable_with_tls_channel_id_manifest() {
416 return base::StringPrintf(
418 " \"name\": \"chromium_connectable_with_tls_channel_id\","
419 " %s,"
420 " \"externally_connectable\": {"
421 " \"matches\": [\"*://*.chromium.org:*/*\"],"
422 " \"accepts_tls_channel_id\": true"
423 " }"
424 "}",
425 common_manifest());
428 std::string GetTlsChannelIdFromAssertion(const char* method,
429 const Extension* extension,
430 bool include_tls_channel_id,
431 const char* message) {
432 std::string result;
433 std::string args = "'" + extension->id() + "', ";
434 args += include_tls_channel_id ? "true" : "false";
435 if (message)
436 args += std::string(", '") + message + "'";
437 CHECK(content::ExecuteScriptAndExtractString(
438 browser()->tab_strip_model()->GetActiveWebContents(),
439 base::StringPrintf("assertions.%s(%s)", method, args.c_str()),
440 &result));
441 return result;
444 TestExtensionDir web_connectable_dir_;
445 TestExtensionDir not_connectable_dir_;
446 TestExtensionDir tls_channel_id_connectable_dir_;
447 TestExtensionDir hosted_app_dir_;
450 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, NotInstalled) {
451 InitializeTestServer();
453 scoped_refptr<const Extension> extension =
454 ExtensionBuilder()
455 .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
456 .SetManifest(DictionaryBuilder()
457 .Set("name", "Fake extension")
458 .Set("version", "1")
459 .Set("manifest_version", 2))
460 .Build();
462 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
463 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
464 CanConnectAndSendMessagesToMainFrame(extension.get()));
465 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
467 ui_test_utils::NavigateToURL(browser(), google_com_url());
468 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
469 CanConnectAndSendMessagesToMainFrame(extension.get()));
470 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
473 // Tests two extensions on the same sites: one web connectable, one not.
474 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
475 WebConnectableAndNotConnectable) {
476 InitializeTestServer();
478 // Install the web connectable extension. chromium.org can connect to it,
479 // google.com can't.
480 scoped_refptr<const Extension> chromium_connectable =
481 LoadChromiumConnectableExtension();
483 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
484 EXPECT_EQ(OK,
485 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get()));
486 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
488 ui_test_utils::NavigateToURL(browser(), google_com_url());
489 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
490 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get()));
491 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
493 // Install the non-connectable extension. Nothing can connect to it.
494 scoped_refptr<const Extension> not_connectable =
495 LoadNotConnectableExtension();
497 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
498 // Namespace will be defined here because |chromium_connectable| can connect
499 // to it - so this will be the "cannot establish connection" error.
500 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
501 CanConnectAndSendMessagesToMainFrame(not_connectable.get()));
502 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
504 ui_test_utils::NavigateToURL(browser(), google_com_url());
505 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
506 CanConnectAndSendMessagesToMainFrame(not_connectable.get()));
507 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
510 // See http://crbug.com/297866
511 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
512 DISABLED_BackgroundPageClosesOnMessageReceipt) {
513 InitializeTestServer();
515 // Install the web connectable extension.
516 scoped_refptr<const Extension> chromium_connectable =
517 LoadChromiumConnectableExtension();
519 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
520 // If the background page closes after receipt of the message, it will still
521 // reply to this message...
522 EXPECT_EQ(OK,
523 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get(),
524 close_background_message()));
525 // and be re-opened by receipt of a subsequent message.
526 EXPECT_EQ(OK,
527 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get()));
530 // Tests a web connectable extension that doesn't receive TLS channel id.
531 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
532 WebConnectableWithoutTlsChannelId) {
533 InitializeTestServer();
535 // Install the web connectable extension. chromium.org can connect to it,
536 // google.com can't.
537 scoped_refptr<const Extension> chromium_connectable =
538 LoadChromiumConnectableExtension();
539 ASSERT_TRUE(chromium_connectable.get());
541 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
542 // The web connectable extension doesn't request the TLS channel ID, so it
543 // doesn't get it, whether or not the page asks for it.
544 EXPECT_EQ(std::string(),
545 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), false));
546 EXPECT_EQ(std::string(),
547 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true));
548 EXPECT_EQ(std::string(),
549 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), false));
550 EXPECT_EQ(std::string(),
551 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true));
554 // Tests a web connectable extension that receives TLS channel id with a site
555 // that can't connect to it.
556 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
557 WebConnectableWithTlsChannelIdWithNonMatchingSite) {
558 InitializeTestServer();
560 scoped_refptr<const Extension> chromium_connectable =
561 LoadChromiumConnectableExtensionWithTlsChannelId();
562 ASSERT_TRUE(chromium_connectable.get());
564 ui_test_utils::NavigateToURL(browser(), google_com_url());
565 // The extension requests the TLS channel ID, but it doesn't get it for a
566 // site that can't connect to it, regardless of whether the page asks for it.
567 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
568 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), false));
569 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
570 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true));
571 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
572 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), false));
573 EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
574 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true));
577 // Tests a web connectable extension that receives TLS channel id on a site
578 // that can connect to it, but with no TLS channel ID having been generated.
579 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
580 WebConnectableWithTlsChannelIdWithEmptyTlsChannelId) {
581 InitializeTestServer();
583 scoped_refptr<const Extension> chromium_connectable =
584 LoadChromiumConnectableExtensionWithTlsChannelId();
585 ASSERT_TRUE(chromium_connectable.get());
587 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
589 // Since the extension requests the TLS channel ID, it gets it for a site that
590 // can connect to it, but only if the page also asks to include it.
591 EXPECT_EQ(std::string(),
592 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), false));
593 EXPECT_EQ(std::string(),
594 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), false));
595 // If the page does ask for it, it isn't empty.
596 std::string tls_channel_id =
597 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), true);
598 // Because the TLS channel ID has never been generated for this domain,
599 // no TLS channel ID is reported.
600 EXPECT_EQ(std::string(), tls_channel_id);
603 // Flaky on Linux and Windows. http://crbug.com/315264
604 // Tests a web connectable extension that receives TLS channel id, but
605 // immediately closes its background page upon receipt of a message.
606 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
607 DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage) {
608 InitializeTestServer();
610 scoped_refptr<const Extension> chromium_connectable =
611 LoadChromiumConnectableExtensionWithTlsChannelId();
613 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
614 // If the page does ask for it, it isn't empty, even if the background page
615 // closes upon receipt of the connect.
616 std::string tls_channel_id = GetTlsChannelIdFromPortConnect(
617 chromium_connectable.get(), true, close_background_message());
618 // Because the TLS channel ID has never been generated for this domain,
619 // no TLS channel ID is reported.
620 EXPECT_EQ(std::string(), tls_channel_id);
621 // A subsequent connect will still succeed, even if the background page was
622 // previously closed.
623 tls_channel_id =
624 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), true);
625 // And the empty value is still retrieved.
626 EXPECT_EQ(std::string(), tls_channel_id);
629 // Tests that enabling and disabling an extension makes the runtime bindings
630 // appear and disappear.
632 // TODO(kalman): Test with multiple extensions that can be accessed by the same
633 // host.
634 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
635 EnablingAndDisabling) {
636 InitializeTestServer();
638 scoped_refptr<const Extension> chromium_connectable =
639 LoadChromiumConnectableExtension();
640 scoped_refptr<const Extension> not_connectable =
641 LoadNotConnectableExtension();
643 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
644 EXPECT_EQ(OK,
645 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get()));
646 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
647 CanConnectAndSendMessagesToMainFrame(not_connectable.get()));
649 DisableExtension(chromium_connectable->id());
650 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
651 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get()));
653 EnableExtension(chromium_connectable->id());
654 EXPECT_EQ(OK,
655 CanConnectAndSendMessagesToMainFrame(chromium_connectable.get()));
656 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
657 CanConnectAndSendMessagesToMainFrame(not_connectable.get()));
660 // Tests connection from incognito tabs when the user denies the connection
661 // request. Spanning mode only. A separate test for apps and extensions.
663 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
664 // somewhere. This is a test that should be shared with the content script logic
665 // so it's not really our specific concern for web connectable.
667 // TODO(kalman): test messages from incognito extensions too.
668 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
669 FromIncognitoDenyApp) {
670 InitializeTestServer();
672 scoped_refptr<const Extension> app = LoadChromiumConnectableApp();
673 ASSERT_TRUE(app->is_platform_app());
675 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
676 profile()->GetOffTheRecordProfile(),
677 chromium_org_url());
678 content::RenderFrameHost* incognito_frame = incognito_browser->
679 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
682 IncognitoConnectability::ScopedAlertTracker alert_tracker(
683 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
685 // No connection because incognito-enabled hasn't been set for the app, and
686 // the user denied our interactive request.
687 EXPECT_EQ(
688 COULD_NOT_ESTABLISH_CONNECTION_ERROR,
689 CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL));
690 EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
692 // Try again. User has already denied so alert not shown.
693 EXPECT_EQ(
694 COULD_NOT_ESTABLISH_CONNECTION_ERROR,
695 CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL));
696 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
699 // It's not possible to allow an app in incognito.
700 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app->id(), true);
701 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
702 CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL));
705 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
706 FromIncognitoDenyExtension) {
707 InitializeTestServer();
709 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
711 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
712 profile()->GetOffTheRecordProfile(), chromium_org_url());
713 content::RenderFrameHost* incognito_frame =
714 incognito_browser->tab_strip_model()
715 ->GetActiveWebContents()
716 ->GetMainFrame();
719 IncognitoConnectability::ScopedAlertTracker alert_tracker(
720 IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
722 // The alert doesn't show for extensions.
723 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
724 CanConnectAndSendMessagesToFrame(
725 incognito_frame, extension.get(), NULL));
726 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
729 // Allowing the extension in incognito mode will bypass the deny.
730 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension->id(), true);
731 EXPECT_EQ(
733 CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(), NULL));
736 // Tests connection from incognito tabs when the user accepts the connection
737 // request. Spanning mode only. Separate tests for apps and extensions.
739 // TODO(kalman): see comment above about split mode.
740 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
741 FromIncognitoAllowApp) {
742 InitializeTestServer();
744 scoped_refptr<const Extension> app = LoadChromiumConnectableApp();
745 ASSERT_TRUE(app->is_platform_app());
747 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
748 profile()->GetOffTheRecordProfile(),
749 chromium_org_url());
750 content::RenderFrameHost* incognito_frame = incognito_browser->
751 tab_strip_model()->GetActiveWebContents()->GetMainFrame();
754 IncognitoConnectability::ScopedAlertTracker alert_tracker(
755 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
757 // Connection allowed even with incognito disabled, because the user
758 // accepted the interactive request.
759 EXPECT_EQ(
760 OK, CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL));
761 EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
763 // Try again. User has already allowed.
764 EXPECT_EQ(
765 OK, CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL));
766 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
769 // Apps can't be allowed in incognito mode, but it's moot because it's
770 // already allowed.
771 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(app->id(), true);
772 EXPECT_EQ(OK,
773 CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL));
776 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
777 FromIncognitoAllowExtension) {
778 InitializeTestServer();
780 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
782 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
783 profile()->GetOffTheRecordProfile(), chromium_org_url());
784 content::RenderFrameHost* incognito_frame =
785 incognito_browser->tab_strip_model()
786 ->GetActiveWebContents()
787 ->GetMainFrame();
790 IncognitoConnectability::ScopedAlertTracker alert_tracker(
791 IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
793 // No alert is shown.
794 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
795 CanConnectAndSendMessagesToFrame(
796 incognito_frame, extension.get(), NULL));
797 EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
800 // Allowing the extension in incognito mode is what allows connections.
801 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension->id(), true);
802 EXPECT_EQ(
804 CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(), NULL));
807 // Tests a connection from an iframe within a tab which doesn't have
808 // permission. Iframe should work.
809 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
810 FromIframeWithPermission) {
811 InitializeTestServer();
813 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
815 ui_test_utils::NavigateToURL(browser(), google_com_url());
816 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
817 CanConnectAndSendMessagesToMainFrame(extension.get()));
818 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
820 ASSERT_TRUE(AppendIframe(chromium_org_url()));
822 EXPECT_EQ(OK, CanConnectAndSendMessagesToIFrame(extension.get()));
823 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
826 // Tests connection from an iframe without permission within a tab that does.
827 // Iframe shouldn't work.
828 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
829 FromIframeWithoutPermission) {
830 InitializeTestServer();
832 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
834 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
835 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(extension.get()));
836 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
838 ASSERT_TRUE(AppendIframe(google_com_url()));
840 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
841 CanConnectAndSendMessagesToIFrame(extension.get()));
842 EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
845 // Tests externally_connectable between a web page and an extension with a
846 // TLS channel ID created for the origin.
847 class ExternallyConnectableMessagingWithTlsChannelIdTest :
848 public ExternallyConnectableMessagingTest {
849 public:
850 ExternallyConnectableMessagingWithTlsChannelIdTest()
851 : tls_channel_id_created_(false, false) {
854 std::string CreateTlsChannelId() {
855 scoped_refptr<net::URLRequestContextGetter> request_context_getter(
856 profile()->GetRequestContext());
857 std::string channel_id_private_key;
858 std::string channel_id_cert;
859 net::ChannelIDService::RequestHandle request_handle;
860 content::BrowserThread::PostTask(
861 content::BrowserThread::IO,
862 FROM_HERE,
863 base::Bind(
864 &ExternallyConnectableMessagingWithTlsChannelIdTest::
865 CreateDomainBoundCertOnIOThread,
866 base::Unretained(this),
867 base::Unretained(&channel_id_private_key),
868 base::Unretained(&channel_id_cert),
869 base::Unretained(&request_handle),
870 request_context_getter));
871 tls_channel_id_created_.Wait();
872 // Create the expected value.
873 base::StringPiece spki;
874 net::asn1::ExtractSPKIFromDERCert(channel_id_cert, &spki);
875 base::DictionaryValue jwk_value;
876 net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value);
877 std::string tls_channel_id_value;
878 base::JSONWriter::Write(&jwk_value, &tls_channel_id_value);
879 return tls_channel_id_value;
882 private:
883 void CreateDomainBoundCertOnIOThread(
884 std::string* channel_id_private_key,
885 std::string* channel_id_cert,
886 net::ChannelIDService::RequestHandle* request_handle,
887 scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
888 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
889 net::ChannelIDService* channel_id_service =
890 request_context_getter->GetURLRequestContext()->
891 channel_id_service();
892 int status = channel_id_service->GetOrCreateChannelID(
893 chromium_org_url().host(),
894 channel_id_private_key,
895 channel_id_cert,
896 base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
897 GotDomainBoundCert,
898 base::Unretained(this)),
899 request_handle);
900 if (status == net::ERR_IO_PENDING)
901 return;
902 GotDomainBoundCert(status);
905 void GotDomainBoundCert(int status) {
906 ASSERT_TRUE(status == net::OK);
907 tls_channel_id_created_.Signal();
910 base::WaitableEvent tls_channel_id_created_;
913 // Tests a web connectable extension that receives TLS channel id on a site
914 // that can connect to it, with a TLS channel ID having been generated.
915 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,
916 WebConnectableWithNonEmptyTlsChannelId) {
917 InitializeTestServer();
918 std::string expected_tls_channel_id_value = CreateTlsChannelId();
920 scoped_refptr<const Extension> chromium_connectable =
921 LoadChromiumConnectableExtensionWithTlsChannelId();
922 ASSERT_TRUE(chromium_connectable.get());
924 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
926 // Since the extension requests the TLS channel ID, it gets it for a site that
927 // can connect to it, but only if the page also asks to send it.
928 EXPECT_EQ(std::string(),
929 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), false));
930 EXPECT_EQ(std::string(),
931 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), false));
933 // If the page does ask to send the TLS channel ID, it's sent and non-empty.
934 std::string tls_channel_id_from_port_connect =
935 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), true);
936 EXPECT_NE(0u, tls_channel_id_from_port_connect.size());
938 // The same value is received by both connect and sendMessage.
939 std::string tls_channel_id_from_send_message =
940 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true);
941 EXPECT_EQ(tls_channel_id_from_port_connect, tls_channel_id_from_send_message);
943 // And since a TLS channel ID exists for the domain, the value received is
944 // parseable as a JWK. (In particular, it has the same value we created by
945 // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
946 std::string tls_channel_id(tls_channel_id_from_port_connect);
947 EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
949 // The TLS channel ID shouldn't change from one connection to the next...
950 std::string tls_channel_id2 =
951 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), true);
952 EXPECT_EQ(tls_channel_id, tls_channel_id2);
953 tls_channel_id2 =
954 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true);
955 EXPECT_EQ(tls_channel_id, tls_channel_id2);
957 // nor should it change when navigating away, revisiting the page and
958 // requesting it again.
959 ui_test_utils::NavigateToURL(browser(), google_com_url());
960 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
961 tls_channel_id2 =
962 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), true);
963 EXPECT_EQ(tls_channel_id, tls_channel_id2);
964 tls_channel_id2 =
965 GetTlsChannelIdFromSendMessage(chromium_connectable.get(), true);
966 EXPECT_EQ(tls_channel_id, tls_channel_id2);
969 // Tests a web connectable extension that receives TLS channel id, but
970 // immediately closes its background page upon receipt of a message.
971 // Same flakiness seen in http://crbug.com/297866
972 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,
973 DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage) {
974 InitializeTestServer();
975 std::string expected_tls_channel_id_value = CreateTlsChannelId();
977 scoped_refptr<const Extension> chromium_connectable =
978 LoadChromiumConnectableExtensionWithTlsChannelId();
980 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
981 // If the page does ask for it, it isn't empty, even if the background page
982 // closes upon receipt of the connect.
983 std::string tls_channel_id = GetTlsChannelIdFromPortConnect(
984 chromium_connectable.get(), true, close_background_message());
985 EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
986 // A subsequent connect will still succeed, even if the background page was
987 // previously closed.
988 tls_channel_id =
989 GetTlsChannelIdFromPortConnect(chromium_connectable.get(), true);
990 // And the expected value is still retrieved.
991 EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
994 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingUserGesture) {
995 const char kManifest[] = "{"
996 " \"name\": \"user_gesture\","
997 " \"version\": \"1.0\","
998 " \"background\": {"
999 " \"scripts\": [\"background.js\"]"
1000 " },"
1001 " \"manifest_version\": 2"
1002 "}";
1004 TestExtensionDir receiver_dir;
1005 receiver_dir.WriteManifest(kManifest);
1006 receiver_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
1007 "chrome.runtime.onMessageExternal.addListener(\n"
1008 " function(msg, sender, reply) {\n"
1009 " reply({result:chrome.test.isProcessingUserGesture()});\n"
1010 " });");
1011 const Extension* receiver = LoadExtension(receiver_dir.unpacked_path());
1012 ASSERT_TRUE(receiver);
1014 TestExtensionDir sender_dir;
1015 sender_dir.WriteManifest(kManifest);
1016 sender_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "");
1017 const Extension* sender = LoadExtension(sender_dir.unpacked_path());
1018 ASSERT_TRUE(sender);
1020 EXPECT_EQ("false",
1021 ExecuteScriptInBackgroundPage(sender->id(),
1022 base::StringPrintf(
1023 "chrome.test.runWithoutUserGesture(function() {\n"
1024 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1025 " window.domAutomationController.send('' + response.result);\n"
1026 " });\n"
1027 "});", receiver->id().c_str())));
1029 EXPECT_EQ("true",
1030 ExecuteScriptInBackgroundPage(sender->id(),
1031 base::StringPrintf(
1032 "chrome.test.runWithUserGesture(function() {\n"
1033 " chrome.runtime.sendMessage('%s', {}, function(response) {\n"
1034 " window.domAutomationController.send('' + response.result);\n"
1035 " });\n"
1036 "});", receiver->id().c_str())));
1039 // Tests that a hosted app on a connectable site doesn't interfere with the
1040 // connectability of that site.
1041 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, HostedAppOnWebsite) {
1042 InitializeTestServer();
1044 scoped_refptr<const Extension> app = LoadChromiumHostedApp();
1046 // The presence of the hosted app shouldn't give the ability to send messages.
1047 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1048 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
1049 CanConnectAndSendMessagesToMainFrame(app.get()));
1050 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1052 // Once a connectable extension is installed, it should.
1053 scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
1054 EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(extension.get()));
1055 EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1058 // Tests that an invalid extension ID specified in a hosted app does not crash
1059 // the hosted app's renderer.
1061 // This is a regression test for http://crbug.com/326250#c12.
1062 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
1063 InvalidExtensionIDFromHostedApp) {
1064 InitializeTestServer();
1066 // The presence of the chromium hosted app triggers this bug. The chromium
1067 // connectable extension needs to be installed to set up the runtime bindings.
1068 LoadChromiumHostedApp();
1069 LoadChromiumConnectableExtension();
1071 scoped_refptr<const Extension> invalid =
1072 ExtensionBuilder()
1073 // A bit scary that this works...
1074 .SetID("invalid")
1075 .SetManifest(DictionaryBuilder()
1076 .Set("name", "Fake extension")
1077 .Set("version", "1")
1078 .Set("manifest_version", 2))
1079 .Build();
1081 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1082 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
1083 CanConnectAndSendMessagesToMainFrame(invalid.get()));
1086 #endif // !defined(OS_WIN) - http://crbug.com/350517.
1088 } // namespace
1090 }; // namespace extensions