Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_messages_apitest.cc
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.
4
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/common/extensions/api/runtime.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/public/browser/notification_registrar.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_system.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"
42
43 namespace extensions {
44 namespace {
45
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());
51   }
52
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();
63   }
64
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();
72   }
73
74   virtual void Observe(int type,
75                        const content::NotificationSource& source,
76                        const content::NotificationDetails& details) OVERRIDE {
77     EventRouter* event_router = ExtensionSystem::Get(
78         content::Source<Profile>(source).ptr())->event_router();
79
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()));
98   }
99
100   content::NotificationRegistrar registrar_;
101 };
102
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_;
107 }
108
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")));
116
117   ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_;
118 }
119
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_;
125 }
126
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);
132   }
133 };
134
135 IN_PROC_BROWSER_TEST_F(PanelMessagingTest, MessagingPanel) {
136   ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_;
137 }
138
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)
142
143 // Tests externally_connectable between a web page and an extension.
144 //
145 // TODO(kalman): Test between extensions. This is already tested in this file,
146 // but not with externally_connectable set in the manifest.
147 //
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,
161   };
162
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;
169   }
170
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);
177   }
178
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);
185   }
186
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);
198   }
199
200   testing::AssertionResult AreAnyNonWebApisDefinedForMainFrame() {
201     return AreAnyNonWebApisDefinedForFrame(
202         browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
203   }
204
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);
210   }
211
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.
237     };
238
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]);
244     }
245     as_js_array += "]";
246
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();
254   }
255
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);
263   }
264
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);
272   }
273
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);
280   }
281
282   GURL chromium_org_url() {
283     return GetURLForPath("www.chromium.org", "/chromium.org.html");
284   }
285
286   GURL google_com_url() {
287     return GetURLForPath("www.google.com", "/google.com.html");
288   }
289
290   scoped_refptr<const Extension> LoadChromiumConnectableExtension() {
291     scoped_refptr<const Extension> extension =
292         LoadExtensionIntoDir(&web_connectable_dir_,
293                              base::StringPrintf(
294                                  "{"
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;
304   }
305
306   scoped_refptr<const Extension> LoadChromiumConnectableApp() {
307     scoped_refptr<const Extension> extension =
308         LoadExtensionIntoDir(&web_connectable_dir_,
309                              "{"
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;
324   }
325
326   scoped_refptr<const Extension> LoadNotConnectableExtension() {
327     scoped_refptr<const Extension> extension =
328         LoadExtensionIntoDir(&not_connectable_dir_,
329                              base::StringPrintf(
330                                  "{"
331                                  "  \"name\": \"not_connectable\","
332                                  "  %s"
333                                  "}",
334                                  common_manifest()));
335     CHECK(extension.get());
336     return extension;
337   }
338
339   scoped_refptr<const Extension>
340   LoadChromiumConnectableExtensionWithTlsChannelId() {
341     return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_,
342                                 connectable_with_tls_channel_id_manifest());
343   }
344
345   scoped_refptr<const Extension> LoadChromiumHostedApp() {
346     scoped_refptr<const Extension> hosted_app =
347         LoadExtensionIntoDir(&hosted_app_dir_,
348                              base::StringPrintf(
349                                  "{"
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;
364   }
365
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());
373   }
374
375   const char* close_background_message() {
376     return "closeBackgroundPage";
377   }
378
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());
403   }
404
405   const char* common_manifest() {
406     return "\"version\": \"1.0\","
407            "\"background\": {"
408            "    \"scripts\": [\"background.js\"],"
409            "    \"persistent\": false"
410            "},"
411            "\"manifest_version\": 2";
412   }
413
414   std::string connectable_with_tls_channel_id_manifest() {
415     return base::StringPrintf(
416         "{"
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());
425   }
426
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;
441   }
442
443   TestExtensionDir web_connectable_dir_;
444   TestExtensionDir not_connectable_dir_;
445   TestExtensionDir tls_channel_id_connectable_dir_;
446   TestExtensionDir hosted_app_dir_;
447 };
448
449 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, NotInstalled) {
450   InitializeTestServer();
451
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();
460
461   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
462   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
463             CanConnectAndSendMessagesToMainFrame(extension));
464   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
465
466   ui_test_utils::NavigateToURL(browser(), google_com_url());
467   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
468             CanConnectAndSendMessagesToMainFrame(extension));
469   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
470 }
471
472 // Tests two extensions on the same sites: one web connectable, one not.
473 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
474                        WebConnectableAndNotConnectable) {
475   InitializeTestServer();
476
477   // Install the web connectable extension. chromium.org can connect to it,
478   // google.com can't.
479   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
480
481   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
482   EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(chromium_connectable));
483   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
484
485   ui_test_utils::NavigateToURL(browser(), google_com_url());
486   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
487             CanConnectAndSendMessagesToMainFrame(chromium_connectable));
488   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
489
490   // Install the non-connectable extension. Nothing can connect to it.
491   const Extension* not_connectable = LoadNotConnectableExtension();
492
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());
499
500   ui_test_utils::NavigateToURL(browser(), google_com_url());
501   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
502             CanConnectAndSendMessagesToMainFrame(not_connectable));
503   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
504 }
505
506 // See http://crbug.com/297866
507 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
508                        DISABLED_BackgroundPageClosesOnMessageReceipt) {
509   InitializeTestServer();
510
511   // Install the web connectable extension.
512   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
513
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));
522 }
523
524 // Tests a web connectable extension that doesn't receive TLS channel id.
525 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
526                        WebConnectableWithoutTlsChannelId) {
527   InitializeTestServer();
528
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);
533
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));
545 }
546
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();
552
553   const Extension* chromium_connectable =
554       LoadChromiumConnectableExtensionWithTlsChannelId();
555   ASSERT_TRUE(chromium_connectable);
556
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));
568 }
569
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();
575
576   const Extension* chromium_connectable =
577       LoadChromiumConnectableExtensionWithTlsChannelId();
578   ASSERT_TRUE(chromium_connectable);
579
580   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
581
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);
594 }
595
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();
602
603   const Extension* chromium_connectable =
604       LoadChromiumConnectableExtensionWithTlsChannelId();
605
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);
619 }
620
621 // Tests that enabling and disabling an extension makes the runtime bindings
622 // appear and disappear.
623 //
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();
629
630   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
631   const Extension* not_connectable = LoadNotConnectableExtension();
632
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));
637
638   DisableExtension(chromium_connectable->id());
639   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
640             CanConnectAndSendMessagesToMainFrame(chromium_connectable));
641
642   EnableExtension(chromium_connectable->id());
643   EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(chromium_connectable));
644   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
645             CanConnectAndSendMessagesToMainFrame(not_connectable));
646 }
647
648 // Tests connection from incognito tabs when the user denies the connection
649 // request. Spanning mode only. A separate test for apps and extensions.
650 //
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.
654 //
655 // TODO(kalman): test messages from incognito extensions too.
656 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
657                        FromIncognitoDenyApp) {
658   InitializeTestServer();
659
660   scoped_refptr<const Extension> app = LoadChromiumConnectableApp();
661   ASSERT_TRUE(app->is_platform_app());
662
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();
668
669   {
670     IncognitoConnectability::ScopedAlertTracker alert_tracker(
671         IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
672
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());
678
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());
683   }
684
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));
689 }
690
691 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
692                        FromIncognitoDenyExtension) {
693   InitializeTestServer();
694
695   scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
696
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();
703
704   {
705     IncognitoConnectability::ScopedAlertTracker alert_tracker(
706         IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
707
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());
713   }
714
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));
719 }
720
721 // Tests connection from incognito tabs when the user accepts the connection
722 // request. Spanning mode only. Separate tests for apps and extensions.
723 //
724 // TODO(kalman): see comment above about split mode.
725 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
726                        FromIncognitoAllowApp) {
727   InitializeTestServer();
728
729   scoped_refptr<const Extension> app = LoadChromiumConnectableApp();
730   ASSERT_TRUE(app->is_platform_app());
731
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();
737
738   {
739     IncognitoConnectability::ScopedAlertTracker alert_tracker(
740         IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
741
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());
746
747     // Try again. User has already allowed.
748     EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame, app, NULL));
749     EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
750   }
751
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));
756 }
757
758 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
759                        FromIncognitoAllowExtension) {
760   InitializeTestServer();
761
762   scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
763
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();
770
771   {
772     IncognitoConnectability::ScopedAlertTracker alert_tracker(
773         IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
774
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());
780   }
781
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));
786 }
787
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();
793
794   const Extension* extension = LoadChromiumConnectableExtension();
795
796   ui_test_utils::NavigateToURL(browser(), google_com_url());
797   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
798             CanConnectAndSendMessagesToMainFrame(extension));
799   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
800
801   ASSERT_TRUE(AppendIframe(chromium_org_url()));
802
803   EXPECT_EQ(OK, CanConnectAndSendMessagesToIFrame(extension));
804   EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
805 }
806
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();
812
813   const Extension* extension = LoadChromiumConnectableExtension();
814
815   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
816   EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(extension));
817   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
818
819   ASSERT_TRUE(AppendIframe(google_com_url()));
820
821   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
822             CanConnectAndSendMessagesToIFrame(extension));
823   EXPECT_FALSE(AreAnyNonWebApisDefinedForIFrame());
824 }
825
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) {
833   }
834
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;
861   }
862
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(content::BrowserThread::CurrentlyOn(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);
884   }
885
886   void GotDomainBoundCert(int status) {
887     ASSERT_TRUE(status == net::OK);
888     tls_channel_id_created_.Signal();
889   }
890
891   base::WaitableEvent tls_channel_id_created_;
892 };
893
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();
900
901   const Extension* chromium_connectable =
902       LoadChromiumConnectableExtensionWithTlsChannelId();
903   ASSERT_TRUE(chromium_connectable);
904
905   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
906
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));
913
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());
918
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);
923
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);
929
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);
936
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);
945 }
946
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();
954
955   const Extension* chromium_connectable =
956       LoadChromiumConnectableExtensionWithTlsChannelId();
957
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);
969 }
970
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                           "}";
980
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);
990
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);
996
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())));
1005
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())));
1014 }
1015
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();
1020
1021   scoped_refptr<const Extension> app = LoadChromiumHostedApp();
1022
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());
1027
1028   // Once a connectable extension is installed, it should.
1029   const Extension* extension = LoadChromiumConnectableExtension();
1030   EXPECT_EQ(OK, CanConnectAndSendMessagesToMainFrame(extension));
1031   EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
1032 }
1033
1034 // Tests that an invalid extension ID specified in a hosted app does not crash
1035 // the hosted app's renderer.
1036 //
1037 // This is a regression test for http://crbug.com/326250#c12.
1038 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
1039                        InvalidExtensionIDFromHostedApp) {
1040   InitializeTestServer();
1041
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();
1046
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();
1056
1057   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
1058   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
1059             CanConnectAndSendMessagesToMainFrame(invalid));
1060 }
1061
1062 #endif  // !defined(OS_WIN) - http://crbug.com/350517.
1063
1064 }  // namespace
1065
1066 };  // namespace extensions