Home | History | Annotate | Download | only in extensions
      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:
     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 =
     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.
    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_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 
    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
   1067