diff options
author | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-05 22:20:17 +0000 |
---|---|---|
committer | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-05 22:20:17 +0000 |
commit | 5349ac6df87c8ddaa04f398375b571430e7c0372 (patch) | |
tree | 2415e4029ea4dd09b0ab11e4a8da8de5cec2500a /chrome/browser | |
parent | 4388ee404a5df94fc6bf517638989e8db22fd4fa (diff) | |
download | chromium_src-5349ac6df87c8ddaa04f398375b571430e7c0372.zip chromium_src-5349ac6df87c8ddaa04f398375b571430e7c0372.tar.gz chromium_src-5349ac6df87c8ddaa04f398375b571430e7c0372.tar.bz2 |
Add a webstore install method that lets us prompt the user before downloading.
A while back we decided to minimize friction by showing extension/app
permissions inline in the webstore, and let installs done via the private
webstore API skip the regular extension installation confirmation that happens
after downloading and unpacking the .crx file. We've reconsidered this and are
now adding a new private install method that lets us go back to having the
client display the confirmation dialog, but do it before downloading the .crx
file. The webstore just needs to pass the manifest and icon, and then after
downloading the .crx we make sure the unpacked extension's manifest matches
what we had prompted with.
BUG=75821
TEST=(Existing tests should pass; new functionality requires chrome web store
server side changes to test)
Review URL: http://codereview.chromium.org/6794010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80536 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/extensions/crx_installer.cc | 57 | ||||
-rw-r--r-- | chrome/browser/extensions/crx_installer.h | 20 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_dispatcher.cc | 1 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_install_ui.cc | 12 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_webstore_private_api.cc | 261 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_webstore_private_api.h | 74 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.cc | 20 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.h | 17 |
8 files changed, 450 insertions, 12 deletions
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index affc4d0..419f6d3 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -4,6 +4,7 @@ #include "chrome/browser/extensions/crx_installer.h" +#include <map> #include <set> #include "base/file_util.h" @@ -42,6 +43,7 @@ namespace { struct WhitelistedInstallData { WhitelistedInstallData() {} std::set<std::string> ids; + std::map<std::string, linked_ptr<DictionaryValue> > manifests; }; static base::LazyInstance<WhitelistedInstallData> @@ -56,6 +58,36 @@ void CrxInstaller::SetWhitelistedInstallId(const std::string& id) { } // static +void CrxInstaller::SetWhitelistedManifest(const std::string& id, + DictionaryValue* parsed_manifest) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + WhitelistedInstallData& data = g_whitelisted_install_data.Get(); + data.manifests[id] = linked_ptr<DictionaryValue>(parsed_manifest); +} + +// static +const DictionaryValue* CrxInstaller::GetWhitelistedManifest( + const std::string& id) { + WhitelistedInstallData& data = g_whitelisted_install_data.Get(); + if (ContainsKey(data.manifests, id)) + return data.manifests[id].get(); + else + return NULL; +} + +// static +DictionaryValue* CrxInstaller::RemoveWhitelistedManifest( + const std::string& id) { + WhitelistedInstallData& data = g_whitelisted_install_data.Get(); + if (ContainsKey(data.manifests, id)) { + DictionaryValue* manifest = data.manifests[id].release(); + data.manifests.erase(id); + return manifest; + } + return NULL; +} + +// static bool CrxInstaller::IsIdWhitelisted(const std::string& id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; @@ -289,6 +321,17 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, NewRunnableMethod(this, &CrxInstaller::ConfirmInstall)); } +// Helper method to let us compare a whitelisted manifest with the actual +// downloaded extension's manifest, but ignoring the kPublicKey since the +// whitelisted manifest doesn't have that value. +static bool EqualsIgnoringPublicKey( + const DictionaryValue& extension_manifest, + const DictionaryValue& whitelisted_manifest) { + scoped_ptr<DictionaryValue> manifest_copy(extension_manifest.DeepCopy()); + manifest_copy->Remove(extension_manifest_keys::kPublicKey, NULL); + return manifest_copy->Equals(&whitelisted_manifest); +} + void CrxInstaller::ConfirmInstall() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (frontend_->extension_prefs()->IsExtensionBlacklisted(extension_->id())) { @@ -318,9 +361,23 @@ void CrxInstaller::ConfirmInstall() { current_version_ = frontend_->extension_prefs()->GetVersionString(extension_->id()); + // First see if it's whitelisted by id (the old mechanism). bool whitelisted = ClearWhitelistedInstallId(extension_->id()) && extension_->plugins().empty() && is_gallery_install_; + // Now check if it's whitelisted by manifest. + scoped_ptr<DictionaryValue> whitelisted_manifest( + RemoveWhitelistedManifest(extension_->id())); + if (is_gallery_install_ && whitelisted_manifest.get()) { + if (!EqualsIgnoringPublicKey(*extension_->manifest_value(), + *whitelisted_manifest)) { + ReportFailureFromUIThread( + l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID)); + return; + } + whitelisted = true; + } + if (client_ && (!allow_silent_install_ || !whitelisted)) { AddRef(); // Balanced in Proceed() and Abort(). diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index 990b639..df9e2b0 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h @@ -55,6 +55,22 @@ class CrxInstaller // crbug.com/54916 static void SetWhitelistedInstallId(const std::string& id); + // Exempt the next extension install with |id| from displaying a confirmation + // prompt, since the user already agreed to the install via + // beginInstallWithManifest. We require that the extension manifest matches + // |parsed_manifest| which is what was used to prompt with. Ownership of + // |parsed_manifest| is transferred here. + static void SetWhitelistedManifest(const std::string& id, + DictionaryValue* parsed_manifest); + + // Returns the previously stored manifest from a call to + // SetWhitelistedManifest. + static const DictionaryValue* GetWhitelistedManifest(const std::string& id); + + // Removes any whitelisted manifest for |id| and returns it. The caller owns + // the return value and is responsible for deleting it. + static DictionaryValue* RemoveWhitelistedManifest(const std::string& id); + // Returns whether |id| is whitelisted - only call this on the UI thread. static bool IsIdWhitelisted(const std::string& id); @@ -137,6 +153,10 @@ class CrxInstaller const FilePath& extension_dir, const Extension* extension); + // Returns true if we can skip confirmation because the install was + // whitelisted. + bool CanSkipConfirmation(); + // Runs on the UI thread. Confirms with the user (via ExtensionInstallUI) that // it is OK to install this extension. void ConfirmInstall(); diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 8da4119..268c621 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -300,6 +300,7 @@ void FactoryRegistry::ResetFunctions() { RegisterFunction<SetStoreLoginFunction>(); RegisterFunction<PromptBrowserLoginFunction>(); RegisterFunction<BeginInstallFunction>(); + RegisterFunction<BeginInstallWithManifestFunction>(); RegisterFunction<CompleteInstallFunction>(); // WebRequest. diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc index 026b338..8e48f1d 100644 --- a/chrome/browser/extensions/extension_install_ui.cc +++ b/chrome/browser/extensions/extension_install_ui.cc @@ -33,7 +33,6 @@ #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" #if defined(TOOLKIT_GTK) #include "chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h" @@ -186,15 +185,8 @@ void ExtensionInstallUI::SetIcon(SkBitmap* image) { icon_ = *image; else icon_ = SkBitmap(); - if (icon_.empty()) { - if (extension_->is_app()) { - icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_APP_DEFAULT_ICON); - } else { - icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_EXTENSION_DEFAULT_ICON); - } - } + if (icon_.empty()) + icon_ = Extension::GetDefaultIcon(extension_->is_app()); } void ExtensionInstallUI::OnImageLoaded( diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index f6369cef..524d8fe 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -7,11 +7,13 @@ #include <string> #include <vector> +#include "base/memory/scoped_temp_dir.h" #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_prefs.h" +#include "chrome/browser/extensions/extension_install_dialog2.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/net/gaia/token_service.h" #include "chrome/browser/profiles/profile_manager.h" @@ -33,9 +35,12 @@ namespace { const char kLoginKey[] = "login"; const char kTokenKey[] = "token"; +const char kImageDecodeError[] = "Image decode failed"; const char kInvalidIdError[] = "Invalid id"; +const char kInvalidManifestError[] = "Invalid manifest"; const char kNoPreviousBeginInstallError[] = "* does not match a previous call to beginInstall"; +const char kUserCancelledError[] = "User cancelled install"; const char kUserGestureRequiredError[] = "This function must be called during a user gesture"; @@ -137,6 +142,259 @@ bool BeginInstallFunction::RunImpl() { return true; } +// This is a class to help BeginInstallWithManifestFunction manage sending +// JSON manifests and base64-encoded icon data to the utility process for +// parsing. +class SafeBeginInstallHelper : public UtilityProcessHost::Client { + public: + SafeBeginInstallHelper(BeginInstallWithManifestFunction* client, + const std::string& icon_data, + const std::string& manifest) + : client_(client), + icon_data_(icon_data), + manifest_(manifest), + utility_host_(NULL), + icon_decode_complete_(false), + manifest_parse_complete_(false), + parse_error_(BeginInstallWithManifestFunction::UNKNOWN_ERROR) {} + + void Start() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + NewRunnableMethod(this, + &SafeBeginInstallHelper::StartWorkOnIOThread, + g_browser_process->resource_dispatcher_host())); + } + + void StartWorkOnIOThread(ResourceDispatcherHost* rdh) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + utility_host_ = new UtilityProcessHost(rdh, this, BrowserThread::IO); + utility_host_->StartBatchMode(); + if (icon_data_.empty()) + icon_decode_complete_ = true; + else + utility_host_->StartImageDecodingBase64(icon_data_); + utility_host_->StartJSONParsing(manifest_); + } + + // Implementing pieces of the UtilityProcessHost::Client interface. + virtual void OnDecodeImageSucceeded(const SkBitmap& decoded_image) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + icon_ = decoded_image; + icon_decode_complete_ = true; + ReportResultsIfComplete(); + } + virtual void OnDecodeImageFailed() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + icon_decode_complete_ = true; + error_ = std::string(kImageDecodeError); + parse_error_ = BeginInstallWithManifestFunction::ICON_ERROR; + ReportResultsIfComplete(); + } + virtual void OnJSONParseSucceeded(const ListValue& wrapper) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + manifest_parse_complete_ = true; + Value* value = NULL; + CHECK(wrapper.Get(0, &value)); + if (value->IsType(Value::TYPE_DICTIONARY)) { + parsed_manifest_.reset( + static_cast<DictionaryValue*>(value)->DeepCopy()); + } else { + parse_error_ = BeginInstallWithManifestFunction::MANIFEST_ERROR; + } + ReportResultsIfComplete(); + } + + virtual void OnJSONParseFailed(const std::string& error_message) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + manifest_parse_complete_ = true; + error_ = error_message; + parse_error_ = BeginInstallWithManifestFunction::MANIFEST_ERROR; + ReportResultsIfComplete(); + } + + void ReportResultsIfComplete() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + if (!icon_decode_complete_ || !manifest_parse_complete_) + return; + + // The utility_host_ will take care of deleting itself after this call. + utility_host_->EndBatchMode(); + utility_host_ = NULL; + + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + NewRunnableMethod(this, + &SafeBeginInstallHelper::ReportResultFromUIThread)); + } + + void ReportResultFromUIThread() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (error_.empty() && parsed_manifest_.get()) + client_->OnParseSuccess(icon_, parsed_manifest_.release()); + else + client_->OnParseFailure(parse_error_, error_); + } + + private: + ~SafeBeginInstallHelper() {} + + // The client who we'll report results back to. + BeginInstallWithManifestFunction* client_; + + // The data to parse. + std::string icon_data_; + std::string manifest_; + + UtilityProcessHost* utility_host_; + + // Flags for whether we're done doing icon decoding and manifest parsing. + bool icon_decode_complete_; + bool manifest_parse_complete_; + + // The results of succesful decoding/parsing. + SkBitmap icon_; + scoped_ptr<DictionaryValue> parsed_manifest_; + + // A details string for keeping track of any errors. + std::string error_; + + // A code to distinguish between an error with the icon, and an error with the + // manifest. + BeginInstallWithManifestFunction::ResultCode parse_error_; +}; + +bool BeginInstallWithManifestFunction::RunImpl() { + if (!IsWebStoreURL(profile_, source_url())) { + SetResult(PERMISSION_DENIED); + return false; + } + + if (!user_gesture() && !ignore_user_gesture_for_tests) { + SetResult(NO_GESTURE); + error_ = kUserGestureRequiredError; + return false; + } + + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_)); + if (!Extension::IdIsValid(id_)) { + SetResult(INVALID_ID); + error_ = kInvalidIdError; + return false; + } + + EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &icon_data_)); + EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &manifest_)); + + scoped_refptr<SafeBeginInstallHelper> helper = + new SafeBeginInstallHelper(this, icon_data_, manifest_); + // The helper will call us back via OnParseSucces or OnParseFailure. + helper->Start(); + + // Matched with a Release in OnSuccess/OnFailure. + AddRef(); + + // The response is sent asynchronously in OnSuccess/OnFailure. + return true; +} + + +void BeginInstallWithManifestFunction::SetResult(ResultCode code) { + switch (code) { + case ERROR_NONE: + result_.reset(Value::CreateStringValue("")); + break; + case UNKNOWN_ERROR: + result_.reset(Value::CreateStringValue("unknown_error")); + break; + case USER_CANCELLED: + result_.reset(Value::CreateStringValue("user_cancelled")); + break; + case MANIFEST_ERROR: + result_.reset(Value::CreateStringValue("manifest_error")); + break; + case ICON_ERROR: + result_.reset(Value::CreateStringValue("icon_error")); + break; + case INVALID_ID: + result_.reset(Value::CreateStringValue("invalid_id")); + break; + case PERMISSION_DENIED: + result_.reset(Value::CreateStringValue("permission_denied")); + break; + case NO_GESTURE: + result_.reset(Value::CreateStringValue("no_gesture")); + break; + default: + CHECK(false); + } +} + + +void BeginInstallWithManifestFunction::OnParseSuccess( + const SkBitmap& icon, DictionaryValue* parsed_manifest) { + CHECK(parsed_manifest); + icon_ = icon; + parsed_manifest_.reset(parsed_manifest); + + // Create a dummy extension and show the extension install confirmation + // dialog. + std::string init_errors; + dummy_extension_ = Extension::Create( + FilePath(), + Extension::INTERNAL, + *static_cast<DictionaryValue*>(parsed_manifest_.get()), + Extension::NO_FLAGS, + &init_errors); + if (!dummy_extension_.get()) { + OnParseFailure(MANIFEST_ERROR, std::string(kInvalidManifestError)); + return; + } + if (icon_.empty()) + icon_ = Extension::GetDefaultIcon(dummy_extension_->is_app()); + + ShowExtensionInstallDialog2(profile(), + this, + dummy_extension_.get(), + &icon_, + dummy_extension_->GetPermissionMessages(), + ExtensionInstallUI::INSTALL_PROMPT); + + // Control flow finishes up in InstallUIProceed or InstallUIAbort. +} + +void BeginInstallWithManifestFunction::OnParseFailure( + ResultCode result_code, const std::string& error_message) { + SetResult(result_code); + error_ = error_message; + SendResponse(false); + + // Matches the AddRef in RunImpl(). + Release(); +} + +void BeginInstallWithManifestFunction::InstallUIProceed() { + CrxInstaller::SetWhitelistedManifest(id_, parsed_manifest_.release()); + SetResult(ERROR_NONE); + SendResponse(true); + + // Matches the AddRef in RunImpl(). + Release(); +} + +void BeginInstallWithManifestFunction::InstallUIAbort() { + error_ = std::string(kUserCancelledError); + SetResult(USER_CANCELLED); + SendResponse(false); + + // Matches the AddRef in RunImpl(). + Release(); +} + bool CompleteInstallFunction::RunImpl() { if (!IsWebStoreURL(profile_, source_url())) return false; @@ -148,7 +406,8 @@ bool CompleteInstallFunction::RunImpl() { return false; } - if (!CrxInstaller::IsIdWhitelisted(id)) { + if (!CrxInstaller::IsIdWhitelisted(id) && + !CrxInstaller::GetWhitelistedManifest(id)) { error_ = ExtensionErrorUtils::FormatErrorMessage( kNoPreviousBeginInstallError, id); return false; diff --git a/chrome/browser/extensions/extension_webstore_private_api.h b/chrome/browser/extensions/extension_webstore_private_api.h index f307f43..c20049a 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.h +++ b/chrome/browser/extensions/extension_webstore_private_api.h @@ -6,8 +6,11 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H_ #pragma once +#include <string> + #include "chrome/browser/browser_signin.h" #include "chrome/browser/extensions/extension_function.h" +#include "chrome/browser/extensions/extension_install_ui.h" #include "chrome/common/net/gaia/google_service_auth_error.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" @@ -25,6 +28,8 @@ class WebstorePrivateApi { static void SetTestingBrowserSignin(BrowserSignin* signin); }; +// TODO(asargent): this is being deprecated in favor of +// BeginInstallWithManifestFunction. See crbug.com/75821 for details. class BeginInstallFunction : public SyncExtensionFunction { public: // For use only in tests - sets a flag that can cause this function to ignore @@ -35,6 +40,75 @@ class BeginInstallFunction : public SyncExtensionFunction { DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.beginInstall"); }; +class BeginInstallWithManifestFunction : public AsyncExtensionFunction, + public ExtensionInstallUI::Delegate { + public: + // Result codes for the return value. If you change this, make sure to + // update the description for the beginInstallWithManifest callback in + // extension_api.json. + enum ResultCode { + ERROR_NONE = 0, + + // An unspecified error occurred. + UNKNOWN_ERROR, + + // The user cancelled the confirmation dialog instead of accepting it. + USER_CANCELLED, + + // The manifest failed to parse correctly. + MANIFEST_ERROR, + + // There was a problem parsing the base64 encoded icon data. + ICON_ERROR, + + // The extension id was invalid. + INVALID_ID, + + // The page does not have permission to call this function. + PERMISSION_DENIED, + + // The function was not called during a user gesture. + NO_GESTURE, + }; + + // For use only in tests - sets a flag that can cause this function to ignore + // the normal requirement that it is called during a user gesture. + static void SetIgnoreUserGestureForTests(bool ignore); + + // Called when we've successfully parsed the manifest and icon data in the + // utility process. Ownership of parsed_manifest is transferred. + void OnParseSuccess(const SkBitmap& icon, DictionaryValue* parsed_manifest); + + // Called to indicate a parse failure. The |result_code| parameter should + // indicate whether the problem was with the manifest or icon data. + void OnParseFailure(ResultCode result_code, const std::string& error_message); + + // Implementing ExtensionInstallUI::Delegate interface. + virtual void InstallUIProceed() OVERRIDE; + virtual void InstallUIAbort() OVERRIDE; + + protected: + virtual bool RunImpl(); + + // Sets the result_ as a string based on |code|. + void SetResult(ResultCode code); + + private: + // These store the input parameters to the function. + std::string id_; + std::string manifest_; + std::string icon_data_; + + // The results of parsing manifest_ and icon_data_ go into these two. + scoped_ptr<DictionaryValue> parsed_manifest_; + SkBitmap icon_; + + // A dummy Extension object we create for the purposes of using + // ExtensionInstallUI to prompt for confirmation of the install. + scoped_refptr<Extension> dummy_extension_; + DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.beginInstallWithManifest"); +}; + class CompleteInstallFunction : public SyncExtensionFunction { virtual bool RunImpl(); DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.completeInstall"); diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc index 0ad3150e..888da1e 100644 --- a/chrome/browser/utility_process_host.cc +++ b/chrome/browser/utility_process_host.cc @@ -65,6 +65,15 @@ bool UtilityProcessHost::StartImageDecoding( return true; } +bool UtilityProcessHost::StartImageDecodingBase64( + const std::string& base64_encoded_data) { + if (!StartProcess(FilePath())) + return false; + + Send(new UtilityMsg_DecodeImageBase64(base64_encoded_data)); + return true; +} + bool UtilityProcessHost::StartIDBKeysFromValuesAndKeyPath( int id, const std::vector<SerializedScriptValue>& serialized_values, const string16& key_path) { @@ -86,6 +95,13 @@ bool UtilityProcessHost::StartInjectIDBKey( return true; } +bool UtilityProcessHost::StartJSONParsing(const std::string& json) { + if (!StartProcess(FilePath())) + return false; + Send(new UtilityMsg_ParseJSON(json)); + return true; +} + bool UtilityProcessHost::StartBatchMode() { CHECK(!is_batch_mode_); is_batch_mode_ = StartProcess(FilePath()); @@ -209,6 +225,10 @@ bool UtilityProcessHost::Client::OnMessageReceived( Client::OnIDBKeysFromValuesAndKeyPathFailed) IPC_MESSAGE_HANDLER(UtilityHostMsg_InjectIDBKey_Finished, Client::OnInjectIDBKeyFinished) + IPC_MESSAGE_HANDLER(UtilityHostMsg_ParseJSON_Succeeded, + Client::OnJSONParseSucceeded) + IPC_MESSAGE_HANDLER(UtilityHostMsg_ParseJSON_Failed, + Client::OnJSONParseFailed) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() return handled; diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h index f1aea70..fa8a9c6 100644 --- a/chrome/browser/utility_process_host.h +++ b/chrome/browser/utility_process_host.h @@ -18,6 +18,7 @@ class DictionaryValue; class IndexedDBKey; +class ListValue; class SerializedScriptValue; class SkBitmap; @@ -95,6 +96,13 @@ class UtilityProcessHost : public BrowserChildProcessHost { virtual void OnInjectIDBKeyFinished( const SerializedScriptValue& new_value) {} + // Called when we're finished parsing a JSON string. Note that if parsing + // was successful, the result Value is contained in the first element of + // |wrapper| (we do this to get around a trickiness with passing a Value + // by const reference via our IPC system). + virtual void OnJSONParseSucceeded(const ListValue& wrapper) {} + virtual void OnJSONParseFailed(const std::string& error_message) {} + protected: friend class base::RefCountedThreadSafe<Client>; @@ -129,8 +137,11 @@ class UtilityProcessHost : public BrowserChildProcessHost { // Start parsing an extensions auto-update manifest xml file. bool StartUpdateManifestParse(const std::string& xml); - // Start image decoding. + // Start image decoding. The image can be any format WebCore understands. + // Results are reported to either OnDecodeImageSuceeded() or + // OnDecodeImageFailed(). bool StartImageDecoding(const std::vector<unsigned char>& encoded_data); + bool StartImageDecodingBase64(const std::string& base64_encoded_data); // Starts extracting |key_path| from |serialized_values|, and replies with the // corresponding IndexedDBKeys via OnIDBKeysFromValuesAndKeyPathSucceeded. @@ -144,6 +155,10 @@ class UtilityProcessHost : public BrowserChildProcessHost { const SerializedScriptValue& value, const string16& key_path); + // Starts parsing a JSON string into a Value object. The result is reported + // to the client via OnJSONParseSucceeded or OnJSONParseFailed. + bool StartJSONParsing(const std::string& json); + // Starts utility process in batch mode. Caller must call EndBatchMode() // to finish the utility process. bool StartBatchMode(); |