summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-10 23:25:28 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-10 23:25:28 +0000
commita03d4448faf2c40f4ef444a88cb9aace5b98e8c4 (patch)
tree1553e184051b0dbe4bb37b90864d0370906f0e60
parentb26ac2f54696af35118a6b0944c9ce697fb62b34 (diff)
downloadchromium_src-a03d4448faf2c40f4ef444a88cb9aace5b98e8c4.zip
chromium_src-a03d4448faf2c40f4ef444a88cb9aace5b98e8c4.tar.gz
chromium_src-a03d4448faf2c40f4ef444a88cb9aace5b98e8c4.tar.bz2
Introduce background.scripts feature for extension manifests.
This optimizes for the common use case where background pages just include a reference to one or more script files and no additional HTML. BUG=107791 Review URL: http://codereview.chromium.org/9150008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@117110 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc2
-rw-r--r--chrome/browser/background/background_contents_service.cc19
-rw-r--r--chrome/browser/extensions/background_scripts_apitest.cc9
-rw-r--r--chrome/browser/extensions/extension_event_router.cc4
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc5
-rw-r--r--chrome/browser/extensions/extension_protocols.cc46
-rw-r--r--chrome/browser/extensions/extension_service.cc4
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc4
-rw-r--r--chrome/browser/extensions/network_delay_listener.cc4
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/extension.cc44
-rw-r--r--chrome/common/extensions/extension.h15
-rw-r--r--chrome/common/extensions/extension_constants.cc11
-rw-r--r--chrome/common/extensions/extension_constants.h8
-rw-r--r--chrome/common/extensions/extension_file_util.cc18
-rw-r--r--chrome/common/extensions/extension_file_util_unittest.cc67
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc29
-rw-r--r--chrome/test/data/extensions/api_test/alert/manifest.json2
-rw-r--r--chrome/test/data/extensions/api_test/alert/test.html6
-rw-r--r--chrome/test/data/extensions/api_test/background_scripts/a.js5
-rw-r--r--chrome/test/data/extensions/api_test/background_scripts/b.js17
-rw-r--r--chrome/test/data/extensions/api_test/background_scripts/manifest.json9
-rw-r--r--chrome/test/data/extensions/manifest_tests/background_scripts.json10
24 files changed, 299 insertions, 43 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 300fb80..8ecd3f3 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4172,6 +4172,9 @@ Update checks have repeatedly failed for the extension "<ph name="EXTENSION_NAME
<message name="IDS_EXTENSION_LOAD_ICON_FOR_BROWSER_ACTION_FAILED" desc="">
Could not load icon '<ph name="ICON">$1<ex>icon.png</ex></ph>' for browser action.
</message>
+ <message name="IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED" desc="">
+ Could not load background script '<ph name="BACKGROUND_SCRIPT">$1<ex>script.js</ex></ph>'.
+ </message>
<message name="IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED" desc="">
Could not load background page '<ph name="BACKGROUND_PAGE">$1<ex>page.html</ex></ph>'.
</message>
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index fd810cf..1d422ef 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -4473,7 +4473,7 @@ void TestingAutomationProvider::GetExtensionsInfo(
extension_value->SetString("public_key", extension->public_key());
extension_value->SetString("description", extension->description());
extension_value->SetString("background_url",
- extension->background_url().spec());
+ extension->GetBackgroundURL().spec());
extension_value->SetString("options_url",
extension->options_url().spec());
extension_value->Set("host_permissions",
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index 5072851..f1308eb 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -239,7 +239,7 @@ void BackgroundContentsService::Observe(
if (extension_service) {
const Extension* extension =
extension_service->GetExtensionById(UTF16ToUTF8(appid), false);
- if (extension && extension->background_url().is_valid())
+ if (extension && extension->has_background_page())
break;
}
RegisterBackgroundContents(bgcontents);
@@ -250,7 +250,7 @@ void BackgroundContentsService::Observe(
content::Details<const Extension>(details).ptr();
Profile* profile = content::Source<Profile>(source).ptr();
if (extension->is_hosted_app() &&
- extension->background_url().is_valid()) {
+ extension->has_background_page()) {
// If there is a background page specified in the manifest for a hosted
// app, then blow away registered urls in the pref.
ShutdownAssociatedBackgroundContents(ASCIIToUTF16(extension->id()));
@@ -260,7 +260,7 @@ void BackgroundContentsService::Observe(
// Now load the manifest-specified background page. If service isn't
// ready, then the background page will be loaded from the
// EXTENSIONS_READY callback.
- LoadBackgroundContents(profile, extension->background_url(),
+ LoadBackgroundContents(profile, extension->GetBackgroundURL(),
ASCIIToUTF16("background"), UTF8ToUTF16(extension->id()));
}
}
@@ -314,7 +314,7 @@ void BackgroundContentsService::Observe(
// BackgroundContents in place.
const Extension* extension =
content::Details<UnloadedExtensionInfo>(details)->extension;
- if (extension->background_url().is_valid())
+ if (extension->has_background_page())
ShutdownAssociatedBackgroundContents(ASCIIToUTF16(extension->id()));
break;
}
@@ -378,9 +378,9 @@ void BackgroundContentsService::LoadBackgroundContentsForExtension(
const Extension* extension =
profile->GetExtensionService()->GetExtensionById(extension_id, false);
DCHECK(!extension || extension->is_hosted_app());
- if (extension && extension->background_url().is_valid()) {
+ if (extension && extension->has_background_page()) {
LoadBackgroundContents(profile,
- extension->background_url(),
+ extension->GetBackgroundURL(),
ASCIIToUTF16("background"),
UTF8ToUTF16(extension->id()));
return;
@@ -425,10 +425,9 @@ void BackgroundContentsService::LoadBackgroundContentsFromManifests(
ExtensionSet::const_iterator iter = extensions->begin();
for (; iter != extensions->end(); ++iter) {
const Extension* extension = *iter;
- if (extension->is_hosted_app() &&
- extension->background_url().is_valid()) {
+ if (extension->is_hosted_app() && extension->has_background_page()) {
LoadBackgroundContents(profile,
- extension->background_url(),
+ extension->GetBackgroundURL(),
ASCIIToUTF16("background"),
UTF8ToUTF16(extension->id()));
}
diff --git a/chrome/browser/extensions/background_scripts_apitest.cc b/chrome/browser/extensions/background_scripts_apitest.cc
new file mode 100644
index 0000000..292f6bc
--- /dev/null
+++ b/chrome/browser/extensions/background_scripts_apitest.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BackgroundScripts) {
+ ASSERT_TRUE(RunExtensionTest("background_scripts")) << message_;
+}
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index d2f1179..f18ec66 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -224,10 +224,10 @@ bool ExtensionEventRouter::CanDispatchEventNow(
const Extension* extension = profile_->GetExtensionService()->
GetExtensionById(extension_id, false); // exclude disabled extensions
- if (extension && extension->background_url().is_valid()) {
+ if (extension && extension->has_background_page()) {
ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
if (!pm->GetBackgroundHostForExtension(extension_id)) {
- pm->CreateBackgroundHost(extension, extension->background_url());
+ pm->CreateBackgroundHost(extension, extension->GetBackgroundURL());
return false;
}
}
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index 99f9753..6b91f33 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -69,8 +69,9 @@ static void CreateBackgroundHostForExtensionLoad(
// Start the process for the master page, if it exists and we're not lazy.
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableLazyBackgroundPages) &&
- extension->background_url().is_valid())
- manager->CreateBackgroundHost(extension, extension->background_url());
+ extension->has_background_page()) {
+ manager->CreateBackgroundHost(extension, extension->GetBackgroundURL());
+ }
}
static void CreateBackgroundHostsForProfileStartup(
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index 9221c5c..d0a03c5 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,6 +12,7 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/extension_info_map.h"
@@ -101,6 +102,42 @@ class URLRequestResourceBundleJob : public net::URLRequestSimpleJob {
net::HttpResponseInfo response_info_;
};
+class GeneratedBackgroundPageJob : public net::URLRequestSimpleJob {
+ public:
+ GeneratedBackgroundPageJob(net::URLRequest* request,
+ const scoped_refptr<const Extension> extension,
+ const std::string& content_security_policy)
+ : net::URLRequestSimpleJob(request),
+ extension_(extension) {
+ response_info_.headers = BuildHttpHeaders(content_security_policy);
+ }
+
+ // Overridden from URLRequestSimpleJob:
+ virtual bool GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data) const OVERRIDE {
+ *mime_type = "text/html";
+ *charset = "utf-8";
+
+ *data = "<!DOCTYPE html>\n<body>\n";
+ for (size_t i = 0; i < extension_->background_scripts().size(); ++i) {
+ *data += "<script src=\"";
+ *data += extension_->background_scripts()[i];
+ *data += "\"></script>\n";
+ }
+
+ return true;
+ }
+
+ virtual void GetResponseInfo(net::HttpResponseInfo* info) {
+ *info = response_info_;
+ }
+
+ private:
+ scoped_refptr<const Extension> extension_;
+ net::HttpResponseInfo response_info_;
+};
+
class URLRequestExtensionJob : public net::URLRequestFileJob {
public:
URLRequestExtensionJob(net::URLRequest* request,
@@ -221,6 +258,13 @@ ExtensionProtocolHandler::MaybeCreateJob(net::URLRequest* request) const {
if (extension)
content_security_policy = extension->content_security_policy();
+ std::string path = request->url().path();
+ if (path.size() > 1 &&
+ path.substr(1) == extension_filenames::kGeneratedBackgroundPageFilename) {
+ return new GeneratedBackgroundPageJob(
+ request, extension, content_security_policy);
+ }
+
FilePath resources_path;
if (PathService::Get(chrome::DIR_RESOURCES, &resources_path) &&
directory_path.DirName() == resources_path) {
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 655a80e..90920de2 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -2474,12 +2474,12 @@ ExtensionIdSet ExtensionService::GetAppIds() const {
}
bool ExtensionService::IsBackgroundPageReady(const Extension* extension) {
- return (extension->background_url().is_empty() ||
+ return (!extension->has_background_page() ||
extension_runtime_data_[extension->id()].background_page_ready);
}
void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
- DCHECK(!extension->background_url().is_empty());
+ DCHECK(extension->has_background_page());
extension_runtime_data_[extension->id()].background_page_ready = true;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 7494b0a..b582dfb7 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -1097,7 +1097,7 @@ TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) {
EXPECT_EQ(std::string("My extension 2"), loaded_[1]->name());
EXPECT_EQ(std::string(""), loaded_[1]->description());
EXPECT_EQ(loaded_[1]->GetResourceURL("background.html"),
- loaded_[1]->background_url());
+ loaded_[1]->GetBackgroundURL());
EXPECT_EQ(0u, loaded_[1]->content_scripts().size());
// We don't parse the plugins section on Chrome OS.
#if defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/network_delay_listener.cc b/chrome/browser/extensions/network_delay_listener.cc
index c417e1c..11574e7 100644
--- a/chrome/browser/extensions/network_delay_listener.cc
+++ b/chrome/browser/extensions/network_delay_listener.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -129,7 +129,7 @@ void NetworkDelayListener::Observe(
// We only wait for background pages to load. If the extension has no
// background page, ignore it.
if (service->extension_prefs()->DelaysNetworkRequests(extension->id()) &&
- !extension->background_url().is_empty()) {
+ extension->has_background_page()) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&NetworkDelayListener::OnExtensionPending,
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 817440f..c5c97bf 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2539,6 +2539,7 @@
'browser/extensions/app_process_apitest.cc',
'browser/extensions/autoupdate_interceptor.cc',
'browser/extensions/autoupdate_interceptor.h',
+ 'browser/extensions/background_scripts_apitest.cc',
'browser/extensions/browser_action_apitest.cc',
'browser/extensions/browser_action_test_util.h',
'browser/extensions/browser_action_test_util_gtk.cc',
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 10c849e..98727ba9 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -373,6 +373,15 @@ GURL Extension::GetResourceURL(const GURL& extension_url,
return ret_val;
}
+GURL Extension::GetBackgroundURL() const {
+ if (!background_scripts_.empty()) {
+ return GetResourceURL(
+ extension_filenames::kGeneratedBackgroundPageFilename);
+ } else {
+ return background_url_;
+ }
+}
+
bool Extension::IsResourceWebAccessible(const std::string& relative_path)
const {
// For old manifest versions which do not specify web_accessible_resources
@@ -1189,6 +1198,33 @@ bool Extension::LoadWebIntentServices(const extensions::Manifest* manifest,
return true;
}
+bool Extension::LoadBackgroundScripts(const extensions::Manifest* manifest,
+ string16* error) {
+ Value* background_scripts_value = NULL;
+ if (!manifest->Get(keys::kBackgroundScripts, &background_scripts_value))
+ return true;
+
+ CHECK(background_scripts_value);
+ if (background_scripts_value->GetType() != Value::TYPE_LIST) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts);
+ return false;
+ }
+
+ ListValue* background_scripts =
+ static_cast<ListValue*>(background_scripts_value);
+ for (size_t i = 0; i < background_scripts->GetSize(); ++i) {
+ std::string script;
+ if (!background_scripts->GetString(i, &script)) {
+ *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidBackgroundScript, base::IntToString(i));
+ return false;
+ }
+ background_scripts_.push_back(script);
+ }
+
+ return true;
+}
+
bool Extension::LoadBackgroundPage(
const extensions::Manifest* manifest,
const ExtensionAPIPermissionSet& api_permissions,
@@ -1208,6 +1244,11 @@ bool Extension::LoadBackgroundPage(
return false;
}
+ if (!background_scripts_.empty()) {
+ *error = ASCIIToUTF16(errors::kInvalidBackgroundCombination);
+ return false;
+ }
+
if (is_hosted_app()) {
// Make sure "background" permission is set.
if (!api_permissions.count(ExtensionAPIPermission::kBackground)) {
@@ -1970,6 +2011,9 @@ bool Extension::InitFromValue(extensions::Manifest* manifest, int flags,
}
}
+ if (!LoadBackgroundScripts(manifest, error))
+ return false;
+
if (!LoadBackgroundPage(manifest, api_permissions, error))
return false;
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index ad85a5b..6c3ed47 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -526,7 +526,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
const std::vector<InputComponentInfo>& input_components() const {
return input_components_;
}
- const GURL& background_url() const { return background_url_; }
+ bool has_background_page() const {
+ return background_url_.is_valid() || !background_scripts_.empty();
+ }
+ const std::vector<std::string>& background_scripts() const {
+ return background_scripts_;
+ }
const GURL& options_url() const { return options_url_; }
const GURL& devtools_url() const { return devtools_url_; }
const ExtensionPermissionSet* optional_permission_set() const {
@@ -588,6 +593,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
return theme_display_properties_.get();
}
+ GURL GetBackgroundURL() const;
+
private:
friend class base::RefCountedThreadSafe<Extension>;
@@ -664,6 +671,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
string16* error);
bool LoadWebIntentServices(const extensions::Manifest* manifest,
string16* error);
+ bool LoadBackgroundScripts(const extensions::Manifest* manifest,
+ string16* error);
bool LoadBackgroundPage(const extensions::Manifest* manifest,
const ExtensionAPIPermissionSet& api_permissions,
string16* error);
@@ -796,6 +805,10 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// loaded in the background.
GURL background_url_;
+ // Optional list of scripts to use to generate a background page. If this is
+ // present, background_url_ will be empty and generated by GetBackgroundURL().
+ std::vector<std::string> background_scripts_;
+
// Optional URL to a page for setting options/preferences.
GURL options_url_;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 7ba2516..b68b92f 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -18,6 +18,7 @@ const char kApp[] = "app";
const char kBackground[] = "background";
const char kBackgroundPage[] = "background.page";
const char kBackgroundPageLegacy[] = "background_page";
+const char kBackgroundScripts[] = "background.scripts";
const char kBrowserAction[] = "browser_action";
const char kChromeURLOverrides[] = "chrome_url_overrides";
const char kContentScripts[] = "content_scripts";
@@ -167,6 +168,13 @@ const char kInvalidAllFrames[] =
"Invalid value for 'content_scripts[*].all_frames'.";
const char kInvalidBackground[] =
"Invalid value for 'background_page'.";
+const char kInvalidBackgroundCombination[] =
+ "The background.page and background.scripts properties cannot be used at "
+ "the same time.";
+const char kInvalidBackgroundScript[] =
+ "Invalid value for 'background.scripts[*]'.";
+const char kInvalidBackgroundScripts[] =
+ "Invalid value for 'background.scripts'.";
const char kInvalidBackgroundInHostedApp[] =
"Invalid value for 'background_page'. Hosted apps must specify an "
"absolute HTTPS URL for the background page.";
@@ -486,6 +494,9 @@ const char kDecodedImagesFilename[] = "DECODED_IMAGES";
// The file to write our decoded message catalogs to, relative to the
// extension_path.
const char kDecodedMessageCatalogsFilename[] = "DECODED_MESSAGE_CATALOGS";
+
+const char kGeneratedBackgroundPageFilename[] =
+ "_generated_background_page.html";
}
namespace extension_misc {
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 177454b..f20cedf 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -19,6 +19,7 @@ namespace extension_manifest_keys {
extern const char kBackground[];
extern const char kBackgroundPage[];
extern const char kBackgroundPageLegacy[];
+ extern const char kBackgroundScripts[];
extern const char kBrowserAction[];
extern const char kBrowseURLs[];
extern const char kChromeURLOverrides[];
@@ -151,6 +152,9 @@ namespace extension_manifest_errors {
extern const char kFeatureNotAllowed[];
extern const char kInvalidAllFrames[];
extern const char kInvalidBackground[];
+ extern const char kInvalidBackgroundCombination[];
+ extern const char kInvalidBackgroundScript[];
+ extern const char kInvalidBackgroundScripts[];
extern const char kInvalidBackgroundInHostedApp[];
extern const char kInvalidBrowserAction[];
extern const char kInvalidBrowseURL[];
@@ -325,6 +329,10 @@ namespace extension_filenames {
// The file to write our decoded message catalogs to, relative to the
// extension_path.
extern const char kDecodedMessageCatalogsFilename[];
+
+ // The filename to use for a background page generated from
+ // background.scripts.
+ extern const char kGeneratedBackgroundPageFilename[];
}
namespace extension_misc {
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
index e091242..ebc0644 100644
--- a/chrome/common/extensions/extension_file_util.cc
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -288,12 +288,26 @@ bool ValidateExtension(const Extension* extension, std::string* error) {
}
}
+ // Validate that background scripts exist.
+ for (size_t i = 0; i < extension->background_scripts().size(); ++i) {
+ if (!file_util::PathExists(
+ extension->GetResource(
+ extension->background_scripts()[i]).GetFilePath())) {
+ *error = l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED,
+ UTF8ToUTF16(extension->background_scripts()[i]));
+ return false;
+ }
+ }
+
// Validate background page location, except for hosted apps, which should use
// an external URL. Background page for hosted apps are verified when the
// extension is created (in Extension::InitFromValue)
- if (!extension->background_url().is_empty() && !extension->is_hosted_app()) {
+ if (extension->has_background_page() &&
+ !extension->is_hosted_app() &&
+ extension->background_scripts().empty()) {
FilePath page_path = ExtensionURLToRelativeFilePath(
- extension->background_url());
+ extension->GetBackgroundURL());
const FilePath path = extension->GetResource(page_path).GetFilePath();
if (path.empty() || !file_util::PathExists(path)) {
*error =
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
index f9c7ef4..fb3ac3d 100644
--- a/chrome/common/extensions/extension_file_util_unittest.cc
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,7 +13,9 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
namespace keys = extension_manifest_keys;
@@ -260,20 +262,32 @@ TEST(ExtensionFileUtil, ExtensionURLToRelativeFilePath) {
}
static scoped_refptr<Extension> LoadExtensionManifest(
+ DictionaryValue* manifest,
+ const FilePath& manifest_dir,
+ Extension::Location location,
+ int extra_flags,
+ std::string* error) {
+ scoped_refptr<Extension> extension = Extension::Create(
+ manifest_dir, location, *manifest, extra_flags, error);
+ return extension;
+}
+
+static scoped_refptr<Extension> LoadExtensionManifest(
const std::string& manifest_value,
const FilePath& manifest_dir,
Extension::Location location,
int extra_flags,
std::string* error) {
JSONStringValueSerializer serializer(manifest_value);
- scoped_ptr<Value> result(serializer.Deserialize(NULL, error));
- if (!result.get())
+ Value* result = serializer.Deserialize(NULL, error);
+ if (!result)
return NULL;
-
- scoped_refptr<Extension> extension = Extension::Create(
- manifest_dir, location, *static_cast<DictionaryValue*>(result.get()),
- extra_flags, error);
- return extension;
+ CHECK_EQ(Value::TYPE_DICTIONARY, result->GetType());
+ return LoadExtensionManifest(static_cast<DictionaryValue*>(result),
+ manifest_dir,
+ location,
+ extra_flags,
+ error);
}
#if defined(OS_WIN)
@@ -304,6 +318,43 @@ TEST(ExtensionFileUtil, ValidateThemeUTF8) {
error;
}
+TEST(ExtensionFileUtil, BackgroundScriptsMustExist) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ value->SetString("name", "test");
+ value->SetString("version", "1");
+ value->SetInteger("manifest_version", 1);
+
+ ListValue* scripts = new ListValue();
+ scripts->Append(Value::CreateStringValue("foo.js"));
+ value->Set("background.scripts", scripts);
+
+ std::string error;
+ scoped_refptr<Extension> extension = LoadExtensionManifest(
+ value.get(), temp.path(), Extension::LOAD, 0, &error);
+ ASSERT_TRUE(extension.get()) << error;
+
+ EXPECT_FALSE(extension_file_util::ValidateExtension(extension, &error));
+ EXPECT_EQ(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED, ASCIIToUTF16("foo.js")),
+ error);
+
+ scripts->Clear();
+ scripts->Append(Value::CreateStringValue("http://google.com/foo.js"));
+
+ extension = LoadExtensionManifest(value.get(), temp.path(), Extension::LOAD,
+ 0, &error);
+ ASSERT_TRUE(extension.get()) << error;
+
+ EXPECT_FALSE(extension_file_util::ValidateExtension(extension, &error));
+ EXPECT_EQ(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED,
+ ASCIIToUTF16("http://google.com/foo.js")),
+ error);
+}
+
// TODO(aa): More tests as motivation allows. Maybe steal some from
// ExtensionService? Many of them could probably be tested here without the
// MessageLoop shenanigans.
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index 02bb993..f8089e2 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -984,7 +984,7 @@ TEST_F(ExtensionManifestTest, BackgroundPage) {
scoped_refptr<Extension> extension(
LoadAndExpectSuccess("background_page.json"));
ASSERT_TRUE(extension);
- EXPECT_EQ("/foo.html", extension->background_url().path());
+ EXPECT_EQ("/foo.html", extension->GetBackgroundURL().path());
std::string error;
scoped_ptr<DictionaryValue> manifest(
@@ -992,12 +992,35 @@ TEST_F(ExtensionManifestTest, BackgroundPage) {
ASSERT_TRUE(manifest.get());
extension = LoadAndExpectSuccess(Manifest(manifest.get(), ""));
ASSERT_TRUE(extension);
- EXPECT_EQ("/foo.html", extension->background_url().path());
+ EXPECT_EQ("/foo.html", extension->GetBackgroundURL().path());
manifest->SetInteger(keys::kManifestVersion, 2);
extension = LoadAndExpectSuccess(Manifest(manifest.get(), ""));
ASSERT_TRUE(extension);
- EXPECT_FALSE(extension->background_url().is_valid());
+ EXPECT_FALSE(extension->GetBackgroundURL().is_valid());
+}
+
+TEST_F(ExtensionManifestTest, BackgroundScripts) {
+ std::string error;
+ scoped_ptr<DictionaryValue> manifest(
+ LoadManifestFile("background_scripts.json", &error));
+ ASSERT_TRUE(manifest.get());
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess(Manifest(manifest.get(), "")));
+ ASSERT_TRUE(extension);
+ EXPECT_EQ(2u, extension->background_scripts().size());
+ EXPECT_EQ("foo.js", extension->background_scripts()[0u]);
+ EXPECT_EQ("bar/baz.js", extension->background_scripts()[1u]);
+
+ EXPECT_TRUE(extension->has_background_page());
+ EXPECT_EQ(std::string("/") +
+ extension_filenames::kGeneratedBackgroundPageFilename,
+ extension->GetBackgroundURL().path());
+
+ manifest->SetString("background_page", "monkey.html");
+ LoadAndExpectError(Manifest(manifest.get(), ""),
+ errors::kInvalidBackgroundCombination);
}
TEST_F(ExtensionManifestTest, PageActionManifestVersion2) {
diff --git a/chrome/test/data/extensions/api_test/alert/manifest.json b/chrome/test/data/extensions/api_test/alert/manifest.json
index 5f1c232..d76f2f4 100644
--- a/chrome/test/data/extensions/api_test/alert/manifest.json
+++ b/chrome/test/data/extensions/api_test/alert/manifest.json
@@ -4,6 +4,6 @@
"manifest_version": 2,
"description": "Pops up an alert dialog from the bg page",
"background": {
- "page": "test.html"
+ "scripts": ["test.js"]
}
}
diff --git a/chrome/test/data/extensions/api_test/alert/test.html b/chrome/test/data/extensions/api_test/alert/test.html
deleted file mode 100644
index 3efb342..0000000
--- a/chrome/test/data/extensions/api_test/alert/test.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!--
- * Copyright (c) 2011 The Chromium Authors. All rights reserved. Use of this
- * source code is governed by a BSD-style license that can be found in the
- * LICENSE file.
--->
-<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/background_scripts/a.js b/chrome/test/data/extensions/api_test/background_scripts/a.js
new file mode 100644
index 0000000..de548ae
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/background_scripts/a.js
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var test = "hi!";
diff --git a/chrome/test/data/extensions/api_test/background_scripts/b.js b/chrome/test/data/extensions/api_test/background_scripts/b.js
new file mode 100644
index 0000000..4271738
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/background_scripts/b.js
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// We're just testing that multiple scripts get added to a page in-order
+// and are run.
+chrome.test.assertEq("hi!", test);
+
+// Also test the injection point is consistent. We want to inject into body
+// because having a document.body element is convenient for some scripts.
+var scripts = document.querySelectorAll("script");
+chrome.test.assertEq(2, scripts.length);
+for (var i = 0, script; script = scripts[i]; i++) {
+ chrome.test.assertEq("BODY", script.parentElement.nodeName);
+}
+
+chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/background_scripts/manifest.json b/chrome/test/data/extensions/api_test/background_scripts/manifest.json
new file mode 100644
index 0000000..ea6573e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/background_scripts/manifest.json
@@ -0,0 +1,9 @@
+{
+ "name": "Background Scripts Test",
+ "version": "1",
+ "manifest_version": 2,
+ "description": "Test functionality of the background.scripts key",
+ "background": {
+ "scripts": ["a.js", "b.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/manifest_tests/background_scripts.json b/chrome/test/data/extensions/manifest_tests/background_scripts.json
new file mode 100644
index 0000000..18d8d6f
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/background_scripts.json
@@ -0,0 +1,10 @@
+{
+ "name": "test",
+ "version": "1",
+ "background": {
+ "scripts": [
+ "foo.js",
+ "bar/baz.js"
+ ]
+ }
+}