diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-10 23:25:28 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-10 23:25:28 +0000 |
commit | a03d4448faf2c40f4ef444a88cb9aace5b98e8c4 (patch) | |
tree | 1553e184051b0dbe4bb37b90864d0370906f0e60 | |
parent | b26ac2f54696af35118a6b0944c9ce697fb62b34 (diff) | |
download | chromium_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
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" + ] + } +} |