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/extension_prefs.h"
     19 #include "chrome/browser/extensions/extension_system.h"
     20 #include "chrome/browser/extensions/test_extension_dir.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/ui/browser.h"
     23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     24 #include "chrome/common/chrome_paths.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/common/extensions/api/runtime.h"
     27 #include "chrome/test/base/ui_test_utils.h"
     28 #include "content/public/browser/notification_registrar.h"
     29 #include "content/public/browser/notification_service.h"
     30 #include "content/public/test/browser_test_utils.h"
     31 #include "extensions/browser/event_router.h"
     32 #include "net/cert/asn1_util.h"
     33 #include "net/cert/jwk_serializer.h"
     34 #include "net/dns/mock_host_resolver.h"
     35 #include "net/ssl/server_bound_cert_service.h"
     36 #include "net/test/embedded_test_server/embedded_test_server.h"
     37 #include "net/url_request/url_request_context.h"
     38 #include "net/url_request/url_request_context_getter.h"
     39 #include "url/gurl.h"
     40 
     41 namespace extensions {
     42 namespace {
     43 
     44 class MessageSender : public content::NotificationObserver {
     45  public:
     46   MessageSender() {
     47     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
     48                    content::NotificationService::AllSources());
     49   }
     50 
     51  private:
     52   static scoped_ptr<base::ListValue> BuildEventArguments(
     53       const bool last_message,
     54       const std::string& data) {
     55     DictionaryValue* event = new DictionaryValue();
     56     event->SetBoolean("lastMessage", last_message);
     57     event->SetString("data", data);
     58     scoped_ptr<base::ListValue> arguments(new base::ListValue());
     59     arguments->Append(event);
     60     return arguments.Pass();
     61   }
     62 
     63   static scoped_ptr<Event> BuildEvent(scoped_ptr<base::ListValue> event_args,
     64                                       Profile* profile,
     65                                       GURL event_url) {
     66     scoped_ptr<Event> event(new Event("test.onMessage", event_args.Pass()));
     67     event->restrict_to_browser_context = profile;
     68     event->event_url = event_url;
     69     return event.Pass();
     70   }
     71 
     72   virtual void Observe(int type,
     73                        const content::NotificationSource& source,
     74                        const content::NotificationDetails& details) OVERRIDE {
     75     EventRouter* event_router = ExtensionSystem::Get(
     76         content::Source<Profile>(source).ptr())->event_router();
     77 
     78     // Sends four messages to the extension. All but the third message sent
     79     // from the origin http://b.com/ are supposed to arrive.
     80     event_router->BroadcastEvent(BuildEvent(
     81         BuildEventArguments(false, "no restriction"),
     82         content::Source<Profile>(source).ptr(),
     83         GURL()));
     84     event_router->BroadcastEvent(BuildEvent(
     85         BuildEventArguments(false, "http://a.com/"),
     86         content::Source<Profile>(source).ptr(),
     87         GURL("http://a.com/")));
     88     event_router->BroadcastEvent(BuildEvent(
     89         BuildEventArguments(false, "http://b.com/"),
     90         content::Source<Profile>(source).ptr(),
     91         GURL("http://b.com/")));
     92     event_router->BroadcastEvent(BuildEvent(
     93         BuildEventArguments(true, "last message"),
     94         content::Source<Profile>(source).ptr(),
     95         GURL()));
     96   }
     97 
     98   content::NotificationRegistrar registrar_;
     99 };
    100 
    101 // Tests that message passing between extensions and content scripts works.
    102 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) {
    103   ASSERT_TRUE(StartEmbeddedTestServer());
    104   ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_;
    105 }
    106 
    107 // Tests that message passing from one extension to another works.
    108 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) {
    109   ASSERT_TRUE(LoadExtension(
    110       test_data_dir_.AppendASCII("..").AppendASCII("good")
    111                     .AppendASCII("Extensions")
    112                     .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
    113                     .AppendASCII("1.0")));
    114 
    115   ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_;
    116 }
    117 
    118 // Tests that messages with event_urls are only passed to extensions with
    119 // appropriate permissions.
    120 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingEventURL) {
    121   MessageSender sender;
    122   ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_;
    123 }
    124 
    125 // Tests connecting from a panel to its extension.
    126 class PanelMessagingTest : public ExtensionApiTest {
    127   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    128     ExtensionApiTest::SetUpCommandLine(command_line);
    129     command_line->AppendSwitch(switches::kEnablePanels);
    130   }
    131 };
    132 
    133 IN_PROC_BROWSER_TEST_F(PanelMessagingTest, MessagingPanel) {
    134   ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_;
    135 }
    136 
    137 // Tests externally_connectable between a web page and an extension.
    138 //
    139 // TODO(kalman): Test between extensions. This is already tested in this file,
    140 // but not with externally_connectable set in the manifest.
    141 //
    142 // TODO(kalman): Test with host permissions.
    143 class ExternallyConnectableMessagingTest : public ExtensionApiTest {
    144  protected:
    145   // Result codes from the test. These must match up with |results| in
    146   // c/t/d/extensions/api_test/externally_connectable/assertions.json.
    147   enum Result {
    148     OK = 0,
    149     NAMESPACE_NOT_DEFINED = 1,
    150     FUNCTION_NOT_DEFINED = 2,
    151     COULD_NOT_ESTABLISH_CONNECTION_ERROR = 3,
    152     OTHER_ERROR = 4,
    153     INCORRECT_RESPONSE_SENDER = 5,
    154     INCORRECT_RESPONSE_MESSAGE = 6,
    155   };
    156 
    157   bool AppendIframe(const GURL& src) {
    158     bool result;
    159     CHECK(content::ExecuteScriptAndExtractBool(
    160         browser()->tab_strip_model()->GetActiveWebContents(),
    161         "actions.appendIframe('" + src.spec() + "');", &result));
    162     return result;
    163   }
    164 
    165   Result CanConnectAndSendMessages(const std::string& extension_id) {
    166     return CanConnectAndSendMessages(browser(), extension_id, "");
    167   }
    168 
    169   Result CanConnectAndSendMessages(const std::string& extension_id,
    170                                    const char* frame_xpath,
    171                                    const char* message) {
    172     return CanConnectAndSendMessages(browser(), extension_id, frame_xpath,
    173                                      message);
    174   }
    175 
    176   Result CanConnectAndSendMessages(Browser* browser,
    177                                    const std::string& extension_id) {
    178     return CanConnectAndSendMessages(browser, extension_id, "");
    179   }
    180 
    181   Result CanConnectAndSendMessages(const std::string& extension_id,
    182                                    const char* frame_xpath) {
    183     return CanConnectAndSendMessages(browser(), extension_id, frame_xpath);
    184   }
    185 
    186   Result CanConnectAndSendMessages(Browser* browser,
    187                                    const std::string& extension_id,
    188                                    const char* frame_xpath,
    189                                    const char* message = NULL) {
    190     int result;
    191     std::string args = "'" + extension_id + "'";
    192     if (message)
    193       args += std::string(", '") + message + "'";
    194     CHECK(content::ExecuteScriptInFrameAndExtractInt(
    195         browser->tab_strip_model()->GetActiveWebContents(),
    196         frame_xpath,
    197         base::StringPrintf("assertions.canConnectAndSendMessages(%s)",
    198                            args.c_str()),
    199         &result));
    200     return static_cast<Result>(result);
    201   }
    202 
    203   testing::AssertionResult AreAnyNonWebApisDefined() {
    204     return AreAnyNonWebApisDefined("");
    205   }
    206 
    207   testing::AssertionResult AreAnyNonWebApisDefined(const char* frame_xpath) {
    208     // All runtime API methods are non-web except for sendRequest and connect.
    209     const char* non_messaging_apis[] = {
    210         "getBackgroundPage",
    211         "getManifest",
    212         "getURL",
    213         "reload",
    214         "requestUpdateCheck",
    215         "restart",
    216         "connectNative",
    217         "sendNativeMessage",
    218         "onStartup",
    219         "onInstalled",
    220         "onSuspend",
    221         "onSuspendCanceled",
    222         "onUpdateAvailable",
    223         "onBrowserUpdateAvailable",
    224         "onConnect",
    225         "onConnectExternal",
    226         "onMessage",
    227         "onMessageExternal",
    228         "onRestartRequired",
    229         // Note: no "id" here because this test method is used for hosted apps,
    230         // which do have access to runtime.id.
    231     };
    232 
    233     // Turn the array into a JS array, which effectively gets eval()ed.
    234     std::string as_js_array;
    235     for (size_t i = 0; i < arraysize(non_messaging_apis); ++i) {
    236       as_js_array += as_js_array.empty() ? "[" : ",";
    237       as_js_array += base::StringPrintf("'%s'", non_messaging_apis[i]);
    238     }
    239     as_js_array += "]";
    240 
    241     bool any_defined;
    242     CHECK(content::ExecuteScriptInFrameAndExtractBool(
    243         browser()->tab_strip_model()->GetActiveWebContents(),
    244         frame_xpath,
    245         "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
    246         &any_defined));
    247     return any_defined ?
    248         testing::AssertionSuccess() : testing::AssertionFailure();
    249   }
    250 
    251   std::string GetTlsChannelIdFromPortConnect(const std::string& extension_id,
    252                                              bool include_tls_channel_id,
    253                                              const char* message = NULL) {
    254     return GetTlsChannelIdFromAssertion("getTlsChannelIdFromPortConnect",
    255                                         extension_id,
    256                                         include_tls_channel_id,
    257                                         message);
    258   }
    259 
    260   std::string GetTlsChannelIdFromSendMessage(const std::string& extension_id,
    261                                              bool include_tls_channel_id,
    262                                              const char* message = NULL) {
    263     return GetTlsChannelIdFromAssertion("getTlsChannelIdFromSendMessage",
    264                                         extension_id,
    265                                         include_tls_channel_id,
    266                                         message);
    267   }
    268 
    269   GURL GetURLForPath(const std::string& host, const std::string& path) {
    270     std::string port = base::IntToString(embedded_test_server()->port());
    271     GURL::Replacements replacements;
    272     replacements.SetHostStr(host);
    273     replacements.SetPortStr(port);
    274     return embedded_test_server()->GetURL(path).ReplaceComponents(replacements);
    275   }
    276 
    277   GURL chromium_org_url() {
    278     return GetURLForPath("www.chromium.org", "/chromium.org.html");
    279   }
    280 
    281   GURL google_com_url() {
    282     return GetURLForPath("www.google.com", "/google.com.html");
    283   }
    284 
    285   const Extension* LoadChromiumConnectableExtension() {
    286     const Extension* extension =
    287         LoadExtensionIntoDir(&web_connectable_dir_, base::StringPrintf(
    288             "{"
    289             "  \"name\": \"chromium_connectable\","
    290             "  %s,"
    291             "  \"externally_connectable\": {"
    292             "    \"matches\": [\"*://*.chromium.org:*/*\"]"
    293             "  }"
    294             "}",
    295             common_manifest()));
    296     CHECK(extension);
    297     return extension;
    298   }
    299 
    300   const Extension* LoadNotConnectableExtension() {
    301     const Extension* extension =
    302         LoadExtensionIntoDir(&not_connectable_dir_, base::StringPrintf(
    303             "{"
    304             "  \"name\": \"not_connectable\","
    305             "  %s"
    306             "}",
    307             common_manifest()));
    308     CHECK(extension);
    309     return extension;
    310   }
    311 
    312   const Extension* LoadChromiumConnectableExtensionWithTlsChannelId() {
    313     return LoadExtensionIntoDir(&tls_channel_id_connectable_dir_,
    314                                 connectable_with_tls_channel_id_manifest());
    315   }
    316 
    317   const Extension* LoadChromiumHostedApp() {
    318     const Extension* hosted_app =
    319         LoadExtensionIntoDir(&hosted_app_dir_, base::StringPrintf(
    320             "{"
    321             "  \"name\": \"chromium_hosted_app\","
    322             "  \"version\": \"1.0\","
    323             "  \"manifest_version\": 2,"
    324             "  \"app\": {"
    325             "    \"urls\": [\"%s\"],"
    326             "    \"launch\": {"
    327             "      \"web_url\": \"%s\""
    328             "    }\n"
    329             "  }\n"
    330             "}", chromium_org_url().spec().c_str(),
    331                  chromium_org_url().spec().c_str()));
    332     CHECK(hosted_app);
    333     return hosted_app;
    334   }
    335 
    336   void InitializeTestServer() {
    337     base::FilePath test_data;
    338     EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
    339     embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII(
    340         "extensions/api_test/messaging/externally_connectable/sites"));
    341     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    342     host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
    343   }
    344 
    345   const char* close_background_message() {
    346     return "closeBackgroundPage";
    347   }
    348 
    349  private:
    350   const Extension* LoadExtensionIntoDir(TestExtensionDir* dir,
    351                                         const std::string& manifest) {
    352     dir->WriteManifest(manifest);
    353     dir->WriteFile(FILE_PATH_LITERAL("background.js"),
    354                    base::StringPrintf(
    355         "function maybeClose(message) {\n"
    356         "  if (message.indexOf('%s') >= 0)\n"
    357         "    window.setTimeout(function() { window.close() }, 0);\n"
    358         "}\n"
    359         "chrome.runtime.onMessageExternal.addListener(\n"
    360         "    function(message, sender, reply) {\n"
    361         "  reply({ message: message, sender: sender });\n"
    362         "  maybeClose(message);\n"
    363         "});\n"
    364         "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
    365         "  port.onMessage.addListener(function(message) {\n"
    366         "    port.postMessage({ message: message, sender: port.sender });\n"
    367         "    maybeClose(message);\n"
    368         "  });\n"
    369         "});\n",
    370                    close_background_message()));
    371     return LoadExtension(dir->unpacked_path());
    372   }
    373 
    374   const char* common_manifest() {
    375     return "\"version\": \"1.0\","
    376            "\"background\": {"
    377            "    \"scripts\": [\"background.js\"],"
    378            "    \"persistent\": false"
    379            "},"
    380            "\"manifest_version\": 2";
    381   }
    382 
    383   std::string connectable_with_tls_channel_id_manifest() {
    384     return base::StringPrintf(
    385         "{"
    386         "  \"name\": \"chromium_connectable_with_tls_channel_id\","
    387         "  %s,"
    388         "  \"externally_connectable\": {"
    389         "    \"matches\": [\"*://*.chromium.org:*/*\"],"
    390         "    \"accepts_tls_channel_id\": true"
    391         "  }"
    392         "}",
    393         common_manifest());
    394   }
    395 
    396   std::string GetTlsChannelIdFromAssertion(const char* method,
    397                                            const std::string& extension_id,
    398                                            bool include_tls_channel_id,
    399                                            const char* message) {
    400     std::string result;
    401     std::string args = "'" + extension_id + "', ";
    402     args += include_tls_channel_id ? "true" : "false";
    403     if (message)
    404       args += std::string(", '") + message + "'";
    405     CHECK(content::ExecuteScriptAndExtractString(
    406         browser()->tab_strip_model()->GetActiveWebContents(),
    407         base::StringPrintf("assertions.%s(%s)", method, args.c_str()),
    408         &result));
    409     return result;
    410   }
    411 
    412   TestExtensionDir web_connectable_dir_;
    413   TestExtensionDir not_connectable_dir_;
    414   TestExtensionDir tls_channel_id_connectable_dir_;
    415   TestExtensionDir hosted_app_dir_;
    416 };
    417 
    418 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, NotInstalled) {
    419   InitializeTestServer();
    420 
    421   const char kFakeId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    422 
    423   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    424   EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(kFakeId));
    425   EXPECT_FALSE(AreAnyNonWebApisDefined());
    426 
    427   ui_test_utils::NavigateToURL(browser(), google_com_url());
    428   EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(kFakeId));
    429   EXPECT_FALSE(AreAnyNonWebApisDefined());
    430 }
    431 
    432 // Tests two extensions on the same sites: one web connectable, one not.
    433 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    434                        WebConnectableAndNotConnectable) {
    435   InitializeTestServer();
    436 
    437   // Install the web connectable extension. chromium.org can connect to it,
    438   // google.com can't.
    439   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
    440 
    441   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    442   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
    443   EXPECT_FALSE(AreAnyNonWebApisDefined());
    444 
    445   ui_test_utils::NavigateToURL(browser(), google_com_url());
    446   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
    447             CanConnectAndSendMessages(chromium_connectable->id()));
    448   EXPECT_FALSE(AreAnyNonWebApisDefined());
    449 
    450   // Install the non-connectable extension. Nothing can connect to it.
    451   const Extension* not_connectable = LoadNotConnectableExtension();
    452 
    453   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    454   // Namespace will be defined here because |chromium_connectable| can connect
    455   // to it - so this will be the "cannot establish connection" error.
    456   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
    457             CanConnectAndSendMessages(not_connectable->id()));
    458   EXPECT_FALSE(AreAnyNonWebApisDefined());
    459 
    460   ui_test_utils::NavigateToURL(browser(), google_com_url());
    461   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
    462             CanConnectAndSendMessages(not_connectable->id()));
    463   EXPECT_FALSE(AreAnyNonWebApisDefined());
    464 }
    465 
    466 // See http://crbug.com/297866
    467 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    468                        DISABLED_BackgroundPageClosesOnMessageReceipt) {
    469   InitializeTestServer();
    470 
    471   // Install the web connectable extension.
    472   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
    473 
    474   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    475   // If the background page closes after receipt of the message, it will still
    476   // reply to this message...
    477   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id(),
    478                                           "",
    479                                           close_background_message()));
    480   // and be re-opened by receipt of a subsequent message.
    481   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
    482 }
    483 
    484 // Tests a web connectable extension that doesn't receive TLS channel id.
    485 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    486                        WebConnectableWithoutTlsChannelId) {
    487   InitializeTestServer();
    488 
    489   // Install the web connectable extension. chromium.org can connect to it,
    490   // google.com can't.
    491   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
    492   ASSERT_TRUE(chromium_connectable);
    493 
    494   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    495   // The web connectable extension doesn't request the TLS channel ID, so it
    496   // doesn't get it, whether or not the page asks for it.
    497   EXPECT_EQ(std::string(),
    498             GetTlsChannelIdFromPortConnect(chromium_connectable->id(), false));
    499   EXPECT_EQ(std::string(),
    500             GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true));
    501   EXPECT_EQ(std::string(),
    502             GetTlsChannelIdFromPortConnect(chromium_connectable->id(), false));
    503   EXPECT_EQ(std::string(),
    504             GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true));
    505 }
    506 
    507 // Tests a web connectable extension that receives TLS channel id with a site
    508 // that can't connect to it.
    509 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    510                        WebConnectableWithTlsChannelIdWithNonMatchingSite) {
    511   InitializeTestServer();
    512 
    513   const Extension* chromium_connectable =
    514       LoadChromiumConnectableExtensionWithTlsChannelId();
    515   ASSERT_TRUE(chromium_connectable);
    516 
    517   ui_test_utils::NavigateToURL(browser(), google_com_url());
    518   // The extension requests the TLS channel ID, but it doesn't get it for a
    519   // site that can't connect to it, regardless of whether the page asks for it.
    520   EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
    521             GetTlsChannelIdFromPortConnect(chromium_connectable->id(), false));
    522   EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
    523             GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true));
    524   EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
    525             GetTlsChannelIdFromPortConnect(chromium_connectable->id(), false));
    526   EXPECT_EQ(base::StringPrintf("%d", NAMESPACE_NOT_DEFINED),
    527             GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true));
    528 }
    529 
    530 // Tests a web connectable extension that receives TLS channel id on a site
    531 // that can connect to it, but with no TLS channel ID having been generated.
    532 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    533                        WebConnectableWithTlsChannelIdWithEmptyTlsChannelId) {
    534   InitializeTestServer();
    535 
    536   const Extension* chromium_connectable =
    537       LoadChromiumConnectableExtensionWithTlsChannelId();
    538   ASSERT_TRUE(chromium_connectable);
    539 
    540   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    541 
    542   // Since the extension requests the TLS channel ID, it gets it for a site that
    543   // can connect to it, but only if the page also asks to include it.
    544   EXPECT_EQ(std::string(),
    545       GetTlsChannelIdFromPortConnect(chromium_connectable->id(), false));
    546   EXPECT_EQ(std::string(),
    547       GetTlsChannelIdFromSendMessage(chromium_connectable->id(), false));
    548   // If the page does ask for it, it isn't empty.
    549   std::string tls_channel_id =
    550       GetTlsChannelIdFromPortConnect(chromium_connectable->id(), true);
    551   // Because the TLS channel ID has never been generated for this domain,
    552   // no TLS channel ID is reported.
    553   EXPECT_EQ(std::string(), tls_channel_id);
    554 }
    555 
    556 // Flaky on Linux. http://crbug.com/315264
    557 #if defined(OS_LINUX)
    558 #define MAYBE_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage \
    559     DISABLED_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
    560 #else
    561 #define MAYBE_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage \
    562     WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage
    563 #endif
    564 // Tests a web connectable extension that receives TLS channel id, but
    565 // immediately closes its background page upon receipt of a message.
    566 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    567     MAYBE_WebConnectableWithEmptyTlsChannelIdAndClosedBackgroundPage) {
    568   InitializeTestServer();
    569 
    570   const Extension* chromium_connectable =
    571       LoadChromiumConnectableExtensionWithTlsChannelId();
    572 
    573   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    574   // If the page does ask for it, it isn't empty, even if the background page
    575   // closes upon receipt of the connect.
    576   std::string tls_channel_id =
    577       GetTlsChannelIdFromPortConnect(chromium_connectable->id(),
    578                                      true,
    579                                      close_background_message());
    580   // Because the TLS channel ID has never been generated for this domain,
    581   // no TLS channel ID is reported.
    582   EXPECT_EQ(std::string(), tls_channel_id);
    583   // A subsequent connect will still succeed, even if the background page was
    584   // previously closed.
    585   tls_channel_id =
    586       GetTlsChannelIdFromPortConnect(chromium_connectable->id(),
    587                                      true);
    588    // And the empty value is still retrieved.
    589   EXPECT_EQ(std::string(), tls_channel_id);
    590 }
    591 
    592 // Tests that enabling and disabling an extension makes the runtime bindings
    593 // appear and disappear.
    594 //
    595 // TODO(kalman): Test with multiple extensions that can be accessed by the same
    596 // host.
    597 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    598                        EnablingAndDisabling) {
    599   InitializeTestServer();
    600 
    601   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
    602   const Extension* not_connectable = LoadNotConnectableExtension();
    603 
    604   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    605   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
    606   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
    607             CanConnectAndSendMessages(not_connectable->id()));
    608 
    609   DisableExtension(chromium_connectable->id());
    610   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
    611             CanConnectAndSendMessages(chromium_connectable->id()));
    612 
    613   EnableExtension(chromium_connectable->id());
    614   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
    615   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
    616             CanConnectAndSendMessages(not_connectable->id()));
    617 }
    618 
    619 // Tests connection from incognito tabs when the user denies the connection
    620 // request. Spanning mode only.
    621 //
    622 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
    623 // somewhere. This is a test that should be shared with the content script logic
    624 // so it's not really our specific concern for web connectable.
    625 //
    626 // TODO(kalman): test messages from incognito extensions too.
    627 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognitoDeny) {
    628   InitializeTestServer();
    629 
    630   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
    631   const std::string& id = chromium_connectable->id();
    632 
    633   Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
    634       profile()->GetOffTheRecordProfile(),
    635       chromium_org_url());
    636 
    637   // No connection because incognito-enabled hasn't been set for the extension,
    638   // and the user denied our interactive request.
    639   {
    640     IncognitoConnectability::ScopedAlertTracker alert_tracker(
    641         IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
    642 
    643     EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
    644               CanConnectAndSendMessages(incognito_browser, id));
    645     EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
    646 
    647     // Try again. User has already denied.
    648     EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
    649               CanConnectAndSendMessages(incognito_browser, id));
    650     EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
    651   }
    652 
    653   // Allowing the extension in incognito mode will bypass the deny.
    654   ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id, true);
    655   EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
    656 }
    657 
    658 // Tests connection from incognito tabs when the user accepts the connection
    659 // request. Spanning mode only.
    660 //
    661 // TODO(kalman): see comment above about split mode.
    662 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognitoAllow) {
    663   InitializeTestServer();
    664 
    665   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
    666   const std::string& id = chromium_connectable->id();
    667 
    668   Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
    669       profile()->GetOffTheRecordProfile(),
    670       chromium_org_url());
    671 
    672   // Connection allowed even with incognito disabled, because the user accepted
    673   // the interactive request.
    674   {
    675     IncognitoConnectability::ScopedAlertTracker alert_tracker(
    676         IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
    677 
    678     EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
    679     EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount());
    680 
    681     // Try again. User has already allowed.
    682     EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
    683     EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
    684   }
    685 
    686   // Allowing the extension in incognito mode will continue to allow.
    687   ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id, true);
    688   EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
    689 }
    690 
    691 // Tests a connection from an iframe within a tab which doesn't have
    692 // permission. Iframe should work.
    693 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    694                        FromIframeWithPermission) {
    695   InitializeTestServer();
    696 
    697   const Extension* extension = LoadChromiumConnectableExtension();
    698 
    699   ui_test_utils::NavigateToURL(browser(), google_com_url());
    700   EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(extension->id()));
    701   EXPECT_FALSE(AreAnyNonWebApisDefined());
    702 
    703   ASSERT_TRUE(AppendIframe(chromium_org_url()));
    704 
    705   const char* frame_xpath = "//iframe[1]";
    706   EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id(), frame_xpath));
    707   EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath));
    708 }
    709 
    710 // Tests connection from an iframe without permission within a tab that does.
    711 // Iframe shouldn't work.
    712 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    713                        FromIframeWithoutPermission) {
    714   InitializeTestServer();
    715 
    716   const Extension* extension = LoadChromiumConnectableExtension();
    717 
    718   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    719   EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id()));
    720   EXPECT_FALSE(AreAnyNonWebApisDefined());
    721 
    722   ASSERT_TRUE(AppendIframe(google_com_url()));
    723 
    724   const char* frame_xpath = "//iframe[1]";
    725   EXPECT_EQ(NAMESPACE_NOT_DEFINED,
    726             CanConnectAndSendMessages(extension->id(), frame_xpath));
    727   EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath));
    728 }
    729 
    730 // Tests externally_connectable between a web page and an extension with a
    731 // TLS channel ID created for the origin.
    732 class ExternallyConnectableMessagingWithTlsChannelIdTest :
    733   public ExternallyConnectableMessagingTest {
    734  public:
    735   ExternallyConnectableMessagingWithTlsChannelIdTest()
    736       : tls_channel_id_created_(false, false) {
    737   }
    738 
    739   std::string CreateTlsChannelId() {
    740     scoped_refptr<net::URLRequestContextGetter> request_context_getter(
    741         profile()->GetRequestContext());
    742   std::string domain_bound_private_key;
    743   std::string domain_bound_cert;
    744   net::ServerBoundCertService::RequestHandle request_handle;
    745     content::BrowserThread::PostTask(
    746         content::BrowserThread::IO,
    747         FROM_HERE,
    748         base::Bind(
    749             &ExternallyConnectableMessagingWithTlsChannelIdTest::
    750                 CreateDomainBoundCertOnIOThread,
    751             base::Unretained(this),
    752             base::Unretained(&domain_bound_private_key),
    753             base::Unretained(&domain_bound_cert),
    754             base::Unretained(&request_handle),
    755             request_context_getter));
    756     tls_channel_id_created_.Wait();
    757     // Create the expected value.
    758     base::StringPiece spki;
    759     net::asn1::ExtractSPKIFromDERCert(domain_bound_cert, &spki);
    760     base::DictionaryValue jwk_value;
    761     net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value);
    762     std::string tls_channel_id_value;
    763     base::JSONWriter::Write(&jwk_value, &tls_channel_id_value);
    764     return tls_channel_id_value;
    765   }
    766 
    767  private:
    768   void CreateDomainBoundCertOnIOThread(
    769       std::string* domain_bound_private_key,
    770       std::string* domain_bound_cert,
    771       net::ServerBoundCertService::RequestHandle* request_handle,
    772       scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
    773     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
    774     net::ServerBoundCertService* server_bound_cert_service =
    775         request_context_getter->GetURLRequestContext()->
    776             server_bound_cert_service();
    777     int status = server_bound_cert_service->GetOrCreateDomainBoundCert(
    778         chromium_org_url().host(),
    779         domain_bound_private_key,
    780         domain_bound_cert,
    781         base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
    782                    GotDomainBoundCert,
    783                    base::Unretained(this)),
    784         request_handle);
    785     if (status == net::ERR_IO_PENDING)
    786       return;
    787     GotDomainBoundCert(status);
    788   }
    789 
    790   void GotDomainBoundCert(int status) {
    791     ASSERT_TRUE(status == net::OK);
    792     tls_channel_id_created_.Signal();
    793   }
    794 
    795   base::WaitableEvent tls_channel_id_created_;
    796 };
    797 
    798 // Tests a web connectable extension that receives TLS channel id on a site
    799 // that can connect to it, with a TLS channel ID having been generated.
    800 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,
    801                        WebConnectableWithNonEmptyTlsChannelId) {
    802   InitializeTestServer();
    803   std::string expected_tls_channel_id_value = CreateTlsChannelId();
    804 
    805   const Extension* chromium_connectable =
    806       LoadChromiumConnectableExtensionWithTlsChannelId();
    807   ASSERT_TRUE(chromium_connectable);
    808 
    809   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    810 
    811   // Since the extension requests the TLS channel ID, it gets it for a site that
    812   // can connect to it, but only if the page also asks to send it.
    813   EXPECT_EQ(std::string(),
    814       GetTlsChannelIdFromPortConnect(chromium_connectable->id(), false));
    815   EXPECT_EQ(std::string(),
    816       GetTlsChannelIdFromSendMessage(chromium_connectable->id(), false));
    817 
    818   // If the page does ask to send the TLS channel ID, it's sent and non-empty.
    819   std::string tls_channel_id_from_port_connect =
    820       GetTlsChannelIdFromPortConnect(chromium_connectable->id(), true);
    821   EXPECT_NE(0u, tls_channel_id_from_port_connect.size());
    822 
    823   // The same value is received by both connect and sendMessage.
    824   std::string tls_channel_id_from_send_message =
    825       GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true);
    826   EXPECT_EQ(tls_channel_id_from_port_connect, tls_channel_id_from_send_message);
    827 
    828   // And since a TLS channel ID exists for the domain, the value received is
    829   // parseable as a JWK. (In particular, it has the same value we created by
    830   // converting the public key to JWK with net::ConvertSpkiFromDerToJwk.)
    831   std::string tls_channel_id(tls_channel_id_from_port_connect);
    832   EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
    833 
    834   // The TLS channel ID shouldn't change from one connection to the next...
    835   std::string tls_channel_id2 =
    836       GetTlsChannelIdFromPortConnect(chromium_connectable->id(), true);
    837   EXPECT_EQ(tls_channel_id, tls_channel_id2);
    838   tls_channel_id2 =
    839       GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true);
    840   EXPECT_EQ(tls_channel_id, tls_channel_id2);
    841 
    842   // nor should it change when navigating away, revisiting the page and
    843   // requesting it again.
    844   ui_test_utils::NavigateToURL(browser(), google_com_url());
    845   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    846   tls_channel_id2 =
    847       GetTlsChannelIdFromPortConnect(chromium_connectable->id(), true);
    848   EXPECT_EQ(tls_channel_id, tls_channel_id2);
    849   tls_channel_id2 =
    850       GetTlsChannelIdFromSendMessage(chromium_connectable->id(), true);
    851   EXPECT_EQ(tls_channel_id, tls_channel_id2);
    852 }
    853 
    854 // Tests a web connectable extension that receives TLS channel id, but
    855 // immediately closes its background page upon receipt of a message.
    856 // Same flakiness seen in http://crbug.com/297866
    857 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingWithTlsChannelIdTest,
    858     DISABLED_WebConnectableWithNonEmptyTlsChannelIdAndClosedBackgroundPage) {
    859   InitializeTestServer();
    860   std::string expected_tls_channel_id_value = CreateTlsChannelId();
    861 
    862   const Extension* chromium_connectable =
    863       LoadChromiumConnectableExtensionWithTlsChannelId();
    864 
    865   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    866   // If the page does ask for it, it isn't empty, even if the background page
    867   // closes upon receipt of the connect.
    868   std::string tls_channel_id =
    869       GetTlsChannelIdFromPortConnect(chromium_connectable->id(),
    870                                      true,
    871                                      close_background_message());
    872   EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
    873   // A subsequent connect will still succeed, even if the background page was
    874   // previously closed.
    875   tls_channel_id =
    876       GetTlsChannelIdFromPortConnect(chromium_connectable->id(),
    877                                      true);
    878    // And the expected value is still retrieved.
    879   EXPECT_EQ(expected_tls_channel_id_value, tls_channel_id);
    880 }
    881 
    882 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingUserGesture) {
    883   const char kManifest[] = "{"
    884                           "  \"name\": \"user_gesture\","
    885                           "  \"version\": \"1.0\","
    886                           "  \"background\": {"
    887                           "    \"scripts\": [\"background.js\"]"
    888                           "  },"
    889                           "  \"manifest_version\": 2"
    890                           "}";
    891 
    892   TestExtensionDir receiver_dir;
    893   receiver_dir.WriteManifest(kManifest);
    894   receiver_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
    895       "chrome.runtime.onMessageExternal.addListener(\n"
    896       "    function(msg, sender, reply) {\n"
    897       "      reply({result:chrome.test.isProcessingUserGesture()});\n"
    898       "    });");
    899   const Extension* receiver = LoadExtension(receiver_dir.unpacked_path());
    900   ASSERT_TRUE(receiver);
    901 
    902   TestExtensionDir sender_dir;
    903   sender_dir.WriteManifest(kManifest);
    904   sender_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "");
    905   const Extension* sender = LoadExtension(sender_dir.unpacked_path());
    906   ASSERT_TRUE(sender);
    907 
    908   EXPECT_EQ("false",
    909       ExecuteScriptInBackgroundPage(sender->id(),
    910                                     base::StringPrintf(
    911           "chrome.test.runWithoutUserGesture(function() {\n"
    912           "  chrome.runtime.sendMessage('%s', {}, function(response)  {\n"
    913           "    window.domAutomationController.send('' + response.result);\n"
    914           "  });\n"
    915           "});", receiver->id().c_str())));
    916 
    917   EXPECT_EQ("true",
    918       ExecuteScriptInBackgroundPage(sender->id(),
    919                                     base::StringPrintf(
    920           "chrome.test.runWithUserGesture(function() {\n"
    921           "  chrome.runtime.sendMessage('%s', {}, function(response)  {\n"
    922           "    window.domAutomationController.send('' + response.result);\n"
    923           "  });\n"
    924           "});", receiver->id().c_str())));
    925 }
    926 
    927 // Tests that a hosted app on a connectable site doesn't interfere with the
    928 // connectability of that site.
    929 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, HostedAppOnWebsite) {
    930   InitializeTestServer();
    931 
    932   LoadChromiumHostedApp();
    933 
    934   // The presence of the hosted app shouldn't give the ability to send messages.
    935   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    936   EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(""));
    937   EXPECT_FALSE(AreAnyNonWebApisDefined());
    938 
    939   // Once a connectable extension is installed, it should.
    940   const Extension* extension = LoadChromiumConnectableExtension();
    941   EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id()));
    942   EXPECT_FALSE(AreAnyNonWebApisDefined());
    943 }
    944 
    945 // Tests that an invalid extension ID specified in a hosted app does not crash
    946 // the hosted app's renderer.
    947 //
    948 // This is a regression test for http://crbug.com/326250#c12.
    949 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
    950                        InvalidExtensionIDFromHostedApp) {
    951   InitializeTestServer();
    952 
    953   // The presence of the chromium hosted app triggers this bug. The chromium
    954   // connectable extension needs to be installed to set up the runtime bindings.
    955   LoadChromiumHostedApp();
    956   LoadChromiumConnectableExtension();
    957 
    958   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
    959   EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR ,
    960             CanConnectAndSendMessages("invalid"));
    961 }
    962 
    963 }  // namespace
    964 
    965 };  // namespace extensions
    966