summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/api/tabs/tabs.cc27
-rw-r--r--chrome/browser/extensions/api/tabs/tabs.h5
-rw-r--r--chrome/browser/extensions/api/tabs/tabs_test.cc83
-rw-r--r--chrome/browser/extensions/extension_function_registry.cc15
-rw-r--r--chrome/browser/extensions/extension_function_test_utils.cc28
-rw-r--r--chrome/browser/extensions/extension_function_test_utils.h13
-rw-r--r--chrome/browser/extensions/extension_tabs_apitest.cc4
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_;
}