• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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"
42 
43 namespace extensions {
44 namespace {
45 
46 class MessageSender : public content::NotificationObserver {
47  public:
MessageSender()48   MessageSender() {
49     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
50                    content::NotificationService::AllSources());
51   }
52 
53  private:
BuildEventArguments(const bool last_message,const std::string & data)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 
BuildEvent(scoped_ptr<base::ListValue> event_args,Profile * profile,GURL event_url)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 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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());
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.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,Messaging)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.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MessagingExternal)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.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MessagingEventURL)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 {
SetUpCommandLine(CommandLine * command_line)129   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
130     ExtensionApiTest::SetUpCommandLine(command_line);
131     command_line->AppendSwitch(switches::kEnablePanels);
132   }
133 };
134 
IN_PROC_BROWSER_TEST_F(PanelMessagingTest,MessagingPanel)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 
AppendIframe(const GURL & src)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 
CanConnectAndSendMessagesToMainFrame(const Extension * extension,const char * message=NULL)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 
CanConnectAndSendMessagesToIFrame(const Extension * extension,const char * message=NULL)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 
CanConnectAndSendMessagesToFrame(content::RenderFrameHost * frame,const Extension * extension,const char * 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);
198   }
199 
AreAnyNonWebApisDefinedForMainFrame()200   testing::AssertionResult AreAnyNonWebApisDefinedForMainFrame() {
201     return AreAnyNonWebApisDefinedForFrame(
202         browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
203   }
204 
AreAnyNonWebApisDefinedForIFrame()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 
AreAnyNonWebApisDefinedForFrame(content::RenderFrameHost * 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.
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 
GetTlsChannelIdFromPortConnect(const Extension * extension,bool include_tls_channel_id,const char * message=NULL)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 
GetTlsChannelIdFromSendMessage(const Extension * extension,bool include_tls_channel_id,const char * message=NULL)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 
GetURLForPath(const std::string & host,const std::string & path)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 
chromium_org_url()282   GURL chromium_org_url() {
283     return GetURLForPath("www.chromium.org", "/chromium.org.html");
284   }
285 
google_com_url()286   GURL google_com_url() {
287     return GetURLForPath("www.google.com", "/google.com.html");
288   }
289 
LoadChromiumConnectableExtension()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 
LoadChromiumConnectableApp()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 
LoadNotConnectableExtension()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>
LoadChromiumConnectableExtensionWithTlsChannelId()340   LoadChromiumConnectableExtensionWithTlsChannelId() {
341     return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_,
342                                 connectable_with_tls_channel_id_manifest());
343   }
344 
LoadChromiumHostedApp()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 
InitializeTestServer()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 
close_background_message()375   const char* close_background_message() {
376     return "closeBackgroundPage";
377   }
378 
379  private:
LoadExtensionIntoDir(TestExtensionDir * dir,const std::string & manifest)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 
common_manifest()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 
connectable_with_tls_channel_id_manifest()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 
GetTlsChannelIdFromAssertion(const char * method,const Extension * extension,bool include_tls_channel_id,const char * message)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 
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,NotInstalled)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableAndNotConnectable)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
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,DISABLED_BackgroundPageClosesOnMessageReceipt)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableWithoutTlsChannelId)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableWithTlsChannelIdWithNonMatchingSite)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,WebConnectableWithTlsChannelIdWithEmptyTlsChannelId)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,EnablingAndDisabling)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoDenyApp)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 
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoDenyExtension)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoAllowApp)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 
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIncognitoAllowExtension)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIframeWithPermission)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,FromIframeWithoutPermission)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:
ExternallyConnectableMessagingWithTlsChannelIdTest()831   ExternallyConnectableMessagingWithTlsChannelIdTest()
832       : tls_channel_id_created_(false, false) {
833   }
834 
CreateTlsChannelId()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:
CreateDomainBoundCertOnIOThread(std::string * domain_bound_private_key,std::string * domain_bound_cert,net::ServerBoundCertService::RequestHandle * request_handle,scoped_refptr<net::URLRequestContextGetter> request_context_getter)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);
884   }
885 
GotDomainBoundCert(int status)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,WebConnectableWithNonEmptyTlsChannelId)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
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage)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 
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MessagingUserGesture)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,HostedAppOnWebsite)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.
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,InvalidExtensionIDFromHostedApp)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
1067