diff options
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r-- | chrome/browser/extensions/api/tabs/tabs.cc | 27 | ||||
-rw-r--r-- | chrome/browser/extensions/api/tabs/tabs.h | 5 | ||||
-rw-r--r-- | chrome/browser/extensions/api/tabs/tabs_test.cc | 83 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_registry.cc | 15 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_test_utils.cc | 28 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_test_utils.h | 13 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tabs_apitest.cc | 4 |
7 files changed, 165 insertions, 10 deletions
diff --git a/chrome/browser/extensions/api/tabs/tabs.cc b/chrome/browser/extensions/api/tabs/tabs.cc index 76e34a9..1156651 100644 --- a/chrome/browser/extensions/api/tabs/tabs.cc +++ b/chrome/browser/extensions/api/tabs/tabs.cc @@ -1093,6 +1093,33 @@ bool CreateTabFunction::RunImpl() { return true; } +bool DuplicateTabFunction::RunImpl() { + int tab_id = -1; + EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); + + Browser* browser = NULL; + TabStripModel* tab_strip = NULL; + TabContents* contents = NULL; + int tab_index = -1; + if (!GetTabById(tab_id, profile(), include_incognito(), + &browser, &tab_strip, &contents, &tab_index, &error_)) { + return false; + } + + TabContents* new_contents = chrome::DuplicateTabAt(browser, tab_index); + if (!has_callback()) + return true; + + int new_index = tab_strip->GetIndexOfTabContents(new_contents); + + // Return data about the newly created tab. + SetResult(ExtensionTabUtil::CreateTabValue( + new_contents->web_contents(), + tab_strip, new_index, GetExtension())); + + return true; +} + bool GetTabFunction::RunImpl() { int tab_id = -1; EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); diff --git a/chrome/browser/extensions/api/tabs/tabs.h b/chrome/browser/extensions/api/tabs/tabs.h index 26125ac..b808950 100644 --- a/chrome/browser/extensions/api/tabs/tabs.h +++ b/chrome/browser/extensions/api/tabs/tabs.h @@ -109,6 +109,11 @@ class CreateTabFunction : public SyncExtensionFunction { virtual bool RunImpl() OVERRIDE; DECLARE_EXTENSION_FUNCTION_NAME("tabs.create") }; +class DuplicateTabFunction : public SyncExtensionFunction { + virtual ~DuplicateTabFunction() {} + virtual bool RunImpl() OVERRIDE; + DECLARE_EXTENSION_FUNCTION_NAME("tabs.duplicate") +}; class HighlightTabsFunction : public SyncExtensionFunction { virtual ~HighlightTabsFunction() {} virtual bool RunImpl() OVERRIDE; diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc index dfe8f62..e9c97488 100644 --- a/chrome/browser/extensions/api/tabs/tabs_test.cc +++ b/chrome/browser/extensions/api/tabs/tabs_test.cc @@ -604,3 +604,86 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) { browser()), keys::kInvalidWindowStateError)); } + +IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTab) { + static const char kNewBlankTabArgs[] ="about:blank"; + + content::OpenURLParams params(GURL(kNewBlankTabArgs), content::Referrer(), + NEW_FOREGROUND_TAB, + content::PAGE_TRANSITION_LINK, false); + content::WebContents* web_contents = browser()->OpenURL(params); + int tab_id = ExtensionTabUtil::GetTabId(web_contents); + int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents); + int tab_index = -1; + TabStripModel* tab_strip; + ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index); + + scoped_refptr<DuplicateTabFunction> duplicate_tab_function( + new DuplicateTabFunction()); + scoped_ptr<base::DictionaryValue> test_extension_value( + utils::ParseDictionary( + "{\"name\": \"Test\", \"version\": \"1.0\", \"permissions\": [\"tabs\"]}" + )); + scoped_refptr<extensions::Extension> empty_tab_extension( + utils::CreateExtension(test_extension_value.get())); + duplicate_tab_function->set_extension(empty_tab_extension.get()); + duplicate_tab_function->set_has_callback(true); + + scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary( + utils::RunFunctionAndReturnSingleResult( + duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id), + browser()))); + + int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id"); + int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(), + "windowId"); + int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index"); + EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType()); + // Duplicate tab id should be different from the original tab id. + EXPECT_NE(tab_id, duplicate_tab_id); + EXPECT_EQ(window_id, duplicate_tab_window_id); + EXPECT_EQ(tab_index + 1, duplicate_tab_index); + // The test empty tab extension has tabs permissions, therefore + // |duplicate_result| should contain url, title, and faviconUrl + // in the function result. + EXPECT_TRUE(utils::HasPrivacySensitiveFields(duplicate_result.get())); +} + +IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DuplicateTabNoPermission) { + static const char kNewBlankTabArgs[] ="about:blank"; + + content::OpenURLParams params(GURL(kNewBlankTabArgs), content::Referrer(), + NEW_FOREGROUND_TAB, + content::PAGE_TRANSITION_LINK, false); + content::WebContents* web_contents = browser()->OpenURL(params); + int tab_id = ExtensionTabUtil::GetTabId(web_contents); + int window_id = ExtensionTabUtil::GetWindowIdOfTab(web_contents); + int tab_index = -1; + TabStripModel* tab_strip; + ExtensionTabUtil::GetTabStripModel(web_contents, &tab_strip, &tab_index); + + scoped_refptr<DuplicateTabFunction> duplicate_tab_function( + new DuplicateTabFunction()); + scoped_refptr<extensions::Extension> empty_extension( + utils::CreateEmptyExtension()); + duplicate_tab_function->set_extension(empty_extension.get()); + duplicate_tab_function->set_has_callback(true); + + scoped_ptr<base::DictionaryValue> duplicate_result(utils::ToDictionary( + utils::RunFunctionAndReturnSingleResult( + duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id), + browser()))); + + int duplicate_tab_id = utils::GetInteger(duplicate_result.get(), "id"); + int duplicate_tab_window_id = utils::GetInteger(duplicate_result.get(), + "windowId"); + int duplicate_tab_index = utils::GetInteger(duplicate_result.get(), "index"); + EXPECT_EQ(base::Value::TYPE_DICTIONARY, duplicate_result->GetType()); + // Duplicate tab id should be different from the original tab id. + EXPECT_NE(tab_id, duplicate_tab_id); + EXPECT_EQ(window_id, duplicate_tab_window_id); + EXPECT_EQ(tab_index + 1, duplicate_tab_index); + // The test empty extension has no permissions, therefore |duplicate_result| + // should not contain url, title, and faviconUrl in the function result. + EXPECT_FALSE(utils::HasPrivacySensitiveFields(duplicate_result.get())); +} diff --git a/chrome/browser/extensions/extension_function_registry.cc b/chrome/browser/extensions/extension_function_registry.cc index 0817326..dcca8d2 100644 --- a/chrome/browser/extensions/extension_function_registry.cc +++ b/chrome/browser/extensions/extension_function_registry.cc @@ -97,21 +97,22 @@ void ExtensionFunctionRegistry::ResetFunctions() { RegisterFunction<RemoveWindowFunction>(); // Tabs - RegisterFunction<GetTabFunction>(); + RegisterFunction<CaptureVisibleTabFunction>(); + RegisterFunction<CreateTabFunction>(); + RegisterFunction<DetectTabLanguageFunction>(); + RegisterFunction<DuplicateTabFunction>(); + RegisterFunction<GetAllTabsInWindowFunction>(); RegisterFunction<GetCurrentTabFunction>(); RegisterFunction<GetSelectedTabFunction>(); - RegisterFunction<GetAllTabsInWindowFunction>(); - RegisterFunction<QueryTabsFunction>(); + RegisterFunction<GetTabFunction>(); RegisterFunction<HighlightTabsFunction>(); - RegisterFunction<CreateTabFunction>(); - RegisterFunction<UpdateTabFunction>(); RegisterFunction<MoveTabsFunction>(); + RegisterFunction<QueryTabsFunction>(); RegisterFunction<ReloadTabFunction>(); RegisterFunction<RemoveTabsFunction>(); - RegisterFunction<DetectTabLanguageFunction>(); - RegisterFunction<CaptureVisibleTabFunction>(); RegisterFunction<TabsExecuteScriptFunction>(); RegisterFunction<TabsInsertCSSFunction>(); + RegisterFunction<UpdateTabFunction>(); // Page Actions. RegisterFunction<EnablePageActionsFunction>(); diff --git a/chrome/browser/extensions/extension_function_test_utils.cc b/chrome/browser/extensions/extension_function_test_utils.cc index 820fbde..2f8bfc6 100644 --- a/chrome/browser/extensions/extension_function_test_utils.cc +++ b/chrome/browser/extensions/extension_function_test_utils.cc @@ -9,6 +9,7 @@ #include "base/file_path.h" #include "base/json/json_reader.h" #include "base/values.h" +#include "chrome/browser/extensions/api/tabs/tabs_constants.h" #include "chrome/browser/extensions/extension_function.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/ui/browser.h" @@ -18,6 +19,7 @@ using content::WebContents; using extensions::Extension; +namespace keys = extensions::tabs_constants; namespace { @@ -105,20 +107,40 @@ scoped_refptr<Extension> CreateEmptyExtension() { scoped_refptr<Extension> CreateEmptyExtensionWithLocation( Extension::Location location) { - std::string error; - const FilePath test_extension_path; scoped_ptr<base::DictionaryValue> test_extension_value( ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}")); + return CreateExtension(location, test_extension_value.get()); +} + +scoped_refptr<Extension> CreateExtension( + base::DictionaryValue* test_extension_value) { + return CreateExtension(Extension::INTERNAL, test_extension_value); +} + +scoped_refptr<Extension> CreateExtension( + Extension::Location location, + base::DictionaryValue* test_extension_value) { + std::string error; + const FilePath test_extension_path; scoped_refptr<Extension> extension(Extension::Create( test_extension_path, location, - *test_extension_value.get(), + *test_extension_value, Extension::NO_FLAGS, &error)); EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error; return extension; } +bool HasPrivacySensitiveFields(base::DictionaryValue* val) { + std::string result; + if (val->GetString(keys::kUrlKey, &result) || + val->GetString(keys::kTitleKey, &result) || + val->GetString(keys::kFaviconUrlKey, &result)) + return true; + return false; +} + std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, const std::string& args, Browser* browser) { diff --git a/chrome/browser/extensions/extension_function_test_utils.h b/chrome/browser/extensions/extension_function_test_utils.h index 7bcf84d..cea6e78 100644 --- a/chrome/browser/extensions/extension_function_test_utils.h +++ b/chrome/browser/extensions/extension_function_test_utils.h @@ -54,6 +54,19 @@ scoped_refptr<extensions::Extension> CreateEmptyExtension(); scoped_refptr<extensions::Extension> CreateEmptyExtensionWithLocation( extensions::Extension::Location location); +// Creates an extension instance with a specified extension value that can be +// attached to an ExtensionFunction before running. +scoped_refptr<extensions::Extension> CreateExtension( + base::DictionaryValue* test_extension_value); + +scoped_refptr<extensions::Extension> CreateExtension( + extensions::Extension::Location location, + base::DictionaryValue* test_extension_value); + +// Returns true if |val| contains privacy information, e.g. url, +// title, and faviconUrl. +bool HasPrivacySensitiveFields(base::DictionaryValue* val); + enum RunFunctionFlags { NONE = 0, INCLUDE_INCOGNITO = 1 << 0 diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc index 4c921aa..5395466 100644 --- a/chrome/browser/extensions/extension_tabs_apitest.cc +++ b/chrome/browser/extensions/extension_tabs_apitest.cc @@ -79,6 +79,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Tabs2) { ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "crud2.html")) << message_; } +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabDuplicate) { + ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "duplicate.html")) << message_; +} + IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabUpdate) { ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "update.html")) << message_; } |