summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorerikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-06 15:42:39 +0000
committererikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-06 15:42:39 +0000
commitba3996771f6d19298ee655992b2f6291a314ea76 (patch)
treee5d88f89e7e98aa6ee60af431dc5dfa426d727b2 /chrome
parent44a91f51ec8dd8d1373e28ef6f3f0ab410db942f (diff)
downloadchromium_src-ba3996771f6d19298ee655992b2f6291a314ea76.zip
chromium_src-ba3996771f6d19298ee655992b2f6291a314ea76.tar.gz
chromium_src-ba3996771f6d19298ee655992b2f6291a314ea76.tar.bz2
detect preferences errors
BUG=38352 TEST=none Review URL: http://codereview.chromium.org/1120006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43715 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/autocomplete/search_provider.cc2
-rw-r--r--chrome/browser/automation/automation_provider.cc8
-rw-r--r--chrome/browser/bookmarks/bookmark_storage.cc2
-rw-r--r--chrome/browser/browser_theme_pack_unittest.cc2
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm2
-rw-r--r--chrome/browser/extensions/extension_prefs.h3
-rw-r--r--chrome/browser/extensions/extension_ui_unittest.cc2
-rw-r--r--chrome/browser/extensions/extensions_service.cc5
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc6
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.cc17
-rw-r--r--chrome/browser/extensions/image_loading_tracker_unittest.cc8
-rw-r--r--chrome/browser/geolocation/network_location_request.cc2
-rw-r--r--chrome/browser/page_state.cc2
-rw-r--r--chrome/browser/pref_service.cc99
-rw-r--r--chrome/browser/pref_service.h28
-rw-r--r--chrome/browser/pref_service_uitest.cc2
-rw-r--r--chrome/browser/sync/glue/preference_change_processor.cc2
-rw-r--r--chrome/browser/sync/glue/preference_model_associator.cc2
-rw-r--r--chrome/common/extensions/extension_file_util.cc2
-rw-r--r--chrome/common/extensions/extension_l10n_util.cc2
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc2
-rw-r--r--chrome/common/extensions/extension_unittest.cc7
-rw-r--r--chrome/common/extensions/extension_unpacker.cc4
-rw-r--r--chrome/common/json_value_serializer.cc61
-rw-r--r--chrome/common/json_value_serializer.h42
-rw-r--r--chrome/common/json_value_serializer_perftest.cc4
-rw-r--r--chrome/common/json_value_serializer_unittest.cc18
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc2
-rw-r--r--chrome/installer/util/google_chrome_distribution_unittest.cc2
-rw-r--r--chrome/installer/util/master_preferences.cc2
-rw-r--r--chrome/renderer/extensions/extension_api_json_validity_unittest.cc2
-rw-r--r--chrome/test/automation/javascript_execution_controller.cc2
-rw-r--r--chrome/test/automation/tab_proxy.cc2
-rw-r--r--chrome/test/ui/dom_checker_uitest.cc2
-rw-r--r--chrome/test/ui/javascript_test_util.cc2
-rw-r--r--chrome/test/ui/ui_test.cc2
36 files changed, 274 insertions, 80 deletions
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index ba33df0..9a01fef 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -183,7 +183,7 @@ void SearchProvider::OnURLFetchComplete(const URLFetcher* source,
if (status.is_success() && response_code == 200) {
JSONStringValueSerializer deserializer(json_data);
deserializer.set_allow_trailing_comma(true);
- scoped_ptr<Value> root_val(deserializer.Deserialize(NULL));
+ scoped_ptr<Value> root_val(deserializer.Deserialize(NULL, NULL));
const std::wstring& input_text =
is_keyword_results ? keyword_input_text_ : input_.text();
have_suggest_results_ =
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index cc4ea58..67e73f0 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -1573,7 +1573,7 @@ void AutomationProvider::SendJSONRequest(
} else {
base::JSONReader reader;
std::string error;
- values.reset(reader.ReadAndReturnError(json_request, true, &error));
+ values.reset(reader.ReadAndReturnError(json_request, true, NULL, &error));
if (!error.empty()) {
error_string = error;
}
@@ -1656,11 +1656,11 @@ class SetProxyConfigTask : public Task {
virtual void Run() {
// First, deserialize the JSON string. If this fails, log and bail.
JSONStringValueSerializer deserializer(proxy_config_);
- std::string error_message;
- scoped_ptr<Value> root(deserializer.Deserialize(&error_message));
+ std::string error_msg;
+ scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg));
if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) {
DLOG(WARNING) << "Received bad JSON string for ProxyConfig: "
- << error_message;
+ << error_msg;
return;
}
diff --git a/chrome/browser/bookmarks/bookmark_storage.cc b/chrome/browser/bookmarks/bookmark_storage.cc
index 0b7d895..fd145b0 100644
--- a/chrome/browser/bookmarks/bookmark_storage.cc
+++ b/chrome/browser/bookmarks/bookmark_storage.cc
@@ -74,7 +74,7 @@ class BookmarkStorage::LoadTask : public Task {
bool bookmark_file_exists = file_util::PathExists(path_);
if (bookmark_file_exists) {
JSONFileValueSerializer serializer(path_);
- scoped_ptr<Value> root(serializer.Deserialize(NULL));
+ scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));
if (root.get()) {
// Building the index can take a while, so we do it on the background
diff --git a/chrome/browser/browser_theme_pack_unittest.cc b/chrome/browser/browser_theme_pack_unittest.cc
index 1a05582..0b7912f 100644
--- a/chrome/browser/browser_theme_pack_unittest.cc
+++ b/chrome/browser/browser_theme_pack_unittest.cc
@@ -406,7 +406,7 @@ TEST_F(BrowserThemePackTest, CanBuildAndReadPack) {
std::string error;
JSONFileValueSerializer serializer(manifest_path);
scoped_ptr<DictionaryValue> valid_value(
- static_cast<DictionaryValue*>(serializer.Deserialize(&error)));
+ static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
EXPECT_EQ("", error);
ASSERT_TRUE(valid_value.get());
ASSERT_TRUE(extension.InitFromValue(*valid_value, true, &error));
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm b/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
index f1a02d9..aa1e586 100644
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
+++ b/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
@@ -53,7 +53,7 @@ public:
std::string error;
JSONFileValueSerializer serializer(path);
scoped_ptr<DictionaryValue> value(static_cast<DictionaryValue*>(
- serializer.Deserialize(&error)));
+ serializer.Deserialize(NULL, &error)));
if (!value.get()) {
LOG(ERROR) << error;
return;
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 43d270e..f9a5aa6 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -113,6 +113,9 @@ class ExtensionPrefs {
static void RegisterUserPrefs(PrefService* prefs);
+ // The underlying PrefService.
+ PrefService* pref_service() const { return prefs_; }
+
private:
// Converts absolute paths in the pref to paths relative to the
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc
index f1bd648..96af1c8 100644
--- a/chrome/browser/extensions/extension_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -16,7 +16,7 @@ namespace {
Value* value;
JSONFileValueSerializer serializer(path);
- value = serializer.Deserialize(error);
+ value = serializer.Deserialize(NULL, error);
return static_cast<DictionaryValue*>(value);
}
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index de78366..756c750 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -421,7 +421,7 @@ void ExtensionsService::LoadComponentExtensions() {
component_extension_manifests_.begin();
it != component_extension_manifests_.end(); ++it) {
JSONStringValueSerializer serializer(it->manifest);
- scoped_ptr<Value> manifest(serializer.Deserialize(NULL));
+ scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
if (!manifest.get()) {
NOTREACHED() << "Failed to retrieve manifest for extension";
continue;
@@ -757,6 +757,9 @@ void ExtensionsService::ReloadExtensions() {
}
void ExtensionsService::GarbageCollectExtensions() {
+ if (extension_prefs_->pref_service()->read_only())
+ return;
+
InstalledExtensionSet installed(extension_prefs_.get());
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
index 38932c9..9888e8f 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -150,11 +150,9 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
// We also parse the file into a dictionary to compare what we get back
// from the provider.
JSONStringValueSerializer serializer(json_data);
- std::string error_msg;
- Value* json_value = serializer.Deserialize(&error_msg);
+ Value* json_value = serializer.Deserialize(NULL, NULL);
- if (!error_msg.empty() || !json_value ||
- !json_value->IsType(Value::TYPE_DICTIONARY)) {
+ if (!json_value || !json_value->IsType(Value::TYPE_DICTIONARY)) {
NOTREACHED() << L"Unable to deserialize json data";
return -1;
} else {
diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc
index 841f156..c51f4f2 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.cc
+++ b/chrome/browser/extensions/external_pref_extension_provider.cc
@@ -98,19 +98,16 @@ Version* ExternalPrefExtensionProvider::RegisteredVersion(
void ExternalPrefExtensionProvider::SetPreferences(
ValueSerializer* serializer) {
std::string error_msg;
- Value* extensions = serializer->Deserialize(&error_msg);
+ Value* extensions = serializer->Deserialize(NULL, &error_msg);
scoped_ptr<DictionaryValue> dictionary(new DictionaryValue());
- if (!error_msg.empty()) {
+ if (!extensions) {
LOG(WARNING) << L"Unable to deserialize json data: "
- << error_msg.c_str();
+ << error_msg;
} else {
- // This can be null if the json file specified does not exist.
- if (extensions) {
- if (!extensions->IsType(Value::TYPE_DICTIONARY)) {
- NOTREACHED() << L"Invalid json data";
- } else {
- dictionary.reset(static_cast<DictionaryValue*>(extensions));
- }
+ if (!extensions->IsType(Value::TYPE_DICTIONARY)) {
+ NOTREACHED() << L"Invalid json data";
+ } else {
+ dictionary.reset(static_cast<DictionaryValue*>(extensions));
}
}
prefs_.reset(dictionary.release());
diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc
index 65b47e8..83b4347 100644
--- a/chrome/browser/extensions/image_loading_tracker_unittest.cc
+++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc
@@ -56,12 +56,14 @@ class ImageLoadingTrackerTest : public testing::Test,
}
test_file = test_file.AppendASCII("extensions")
.AppendASCII("image_loading_tracker");
+ int error_code = 0;
std::string error;
JSONFileValueSerializer serializer(test_file.AppendASCII("app.json"));
scoped_ptr<DictionaryValue> valid_value(
- static_cast<DictionaryValue*>(serializer.Deserialize(&error)));
- EXPECT_EQ("", error);
- if (error != "")
+ static_cast<DictionaryValue*>(serializer.Deserialize(&error_code,
+ &error)));
+ EXPECT_EQ(0, error_code) << error;
+ if (error_code != 0)
return NULL;
EXPECT_TRUE(valid_value.get());
diff --git a/chrome/browser/geolocation/network_location_request.cc b/chrome/browser/geolocation/network_location_request.cc
index 01bfd93..5e38eff 100644
--- a/chrome/browser/geolocation/network_location_request.cc
+++ b/chrome/browser/geolocation/network_location_request.cc
@@ -292,7 +292,7 @@ bool ParseServerResponse(const std::string& response_body,
// Parse the response, ignoring comments.
std::string error_msg;
scoped_ptr<Value> response_value(base::JSONReader::ReadAndReturnError(
- response_body, false, &error_msg));
+ response_body, false, NULL, &error_msg));
if (response_value == NULL) {
LOG(WARNING) << "ParseServerResponse() : JSONReader failed : "
<< error_msg << ".\n";
diff --git a/chrome/browser/page_state.cc b/chrome/browser/page_state.cc
index 26b6daf..bf431ca 100644
--- a/chrome/browser/page_state.cc
+++ b/chrome/browser/page_state.cc
@@ -43,7 +43,7 @@ void PageState::InitWithBytes(const std::string& bytes) {
state_.reset(new DictionaryValue);
JSONStringValueSerializer serializer(bytes);
- scoped_ptr<Value> root(serializer.Deserialize(NULL));
+ scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));
if (!root.get()) {
NOTREACHED();
diff --git a/chrome/browser/pref_service.cc b/chrome/browser/pref_service.cc
index d30b544..65f1afc 100644
--- a/chrome/browser/pref_service.cc
+++ b/chrome/browser/pref_service.cc
@@ -8,6 +8,7 @@
#include <string>
#include "app/l10n_util.h"
+#include "base/histogram.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
@@ -15,8 +16,10 @@
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
+#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
namespace {
@@ -62,12 +65,21 @@ Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) {
return Value::CreateNullValue();
}
+// Forwards a notification after a PostMessage so that we can wait for the
+// MessageLoop to run.
+void NotifyReadError(PrefService* pref, int message_id) {
+ Source<PrefService> source(pref);
+ NotificationService::current()->Notify(NotificationType::PROFILE_ERROR,
+ source, Details<int>(&message_id));
+}
+
} // namespace
PrefService::PrefService(const FilePath& pref_filename)
: persistent_(new DictionaryValue),
- writer_(pref_filename) {
- ReloadPersistentPrefs();
+ writer_(pref_filename),
+ read_only_(false) {
+ InitFromDisk();
}
PrefService::~PrefService() {
@@ -88,21 +100,82 @@ PrefService::~PrefService() {
pref_observers_.end());
pref_observers_.clear();
- if (writer_.HasPendingWrite())
+ if (writer_.HasPendingWrite() && !read_only_)
writer_.DoScheduledWrite();
}
+void PrefService::InitFromDisk() {
+ PrefReadError error = LoadPersistentPrefs();
+ if (error == PREF_READ_ERROR_NONE)
+ return;
+
+ // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
+ // an example problem that this can cause.
+ // Do some diagnosis and try to avoid losing data.
+ int message_id = 0;
+ if (error <= PREF_READ_ERROR_JSON_TYPE) {
+ // JSON errors indicate file corruption of some sort.
+ // It's possible the user hand-edited the file, so don't clobber it yet.
+ // Give them a chance to recover the file.
+ // TODO(erikkay) maybe we should just move it aside and continue.
+ read_only_ = true;
+ message_id = IDS_PREFERENCES_CORRUPT_ERROR;
+ } if (error == PREF_READ_ERROR_NO_FILE) {
+ // If the file just doesn't exist, maybe this is first run. In any case
+ // there's no harm in writing out default prefs in this case.
+ } else {
+ // If the file exists but is simply unreadable, put the file into a state
+ // where we don't try to save changes. Otherwise, we could clobber the
+ // existing prefs.
+ read_only_ = true;
+ message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
+ }
+
+ if (message_id) {
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&NotifyReadError, this, message_id));
+ }
+ UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20);
+}
+
bool PrefService::ReloadPersistentPrefs() {
- DCHECK(CalledOnValidThread());
+ return (LoadPersistentPrefs() == PREF_READ_ERROR_NONE);
+}
+PrefService::PrefReadError PrefService::LoadPersistentPrefs() {
+ DCHECK(CalledOnValidThread());
JSONFileValueSerializer serializer(writer_.path());
- scoped_ptr<Value> root(serializer.Deserialize(NULL));
- if (!root.get())
- return false;
+
+ int error_code = 0;
+ std::string error_msg;
+ scoped_ptr<Value> root(serializer.Deserialize(&error_code, &error_msg));
+ if (!root.get()) {
+ PLOG(ERROR) << "Error reading Preferences: " << error_msg << " " <<
+ writer_.path().value();
+ PrefReadError pref_error;
+ switch (error_code) {
+ case JSONFileValueSerializer::JSON_ACCESS_DENIED:
+ pref_error = PREF_READ_ERROR_ACCESS_DENIED;
+ break;
+ case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
+ pref_error = PREF_READ_ERROR_FILE_OTHER;
+ break;
+ case JSONFileValueSerializer::JSON_FILE_LOCKED:
+ pref_error = PREF_READ_ERROR_FILE_LOCKED;
+ break;
+ case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
+ pref_error = PREF_READ_ERROR_NO_FILE;
+ break;
+ default:
+ pref_error = PREF_READ_ERROR_JSON_PARSE;
+ break;
+ }
+ return pref_error;
+ }
// Preferences should always have a dictionary root.
if (!root->IsType(Value::TYPE_DICTIONARY))
- return false;
+ return PREF_READ_ERROR_JSON_TYPE;
persistent_.reset(static_cast<DictionaryValue*>(root.release()));
for (PreferenceSet::iterator it = prefs_.begin();
@@ -110,7 +183,7 @@ bool PrefService::ReloadPersistentPrefs() {
(*it)->root_pref_ = persistent_.get();
}
- return true;
+ return PREF_READ_ERROR_NONE;
}
bool PrefService::SavePersistentPrefs() {
@@ -120,12 +193,20 @@ bool PrefService::SavePersistentPrefs() {
if (!SerializeData(&data))
return false;
+ // Lie about our ability to save.
+ if (read_only_)
+ return true;
+
writer_.WriteNow(data);
return true;
}
void PrefService::ScheduleSavePersistentPrefs() {
DCHECK(CalledOnValidThread());
+
+ if (read_only_)
+ return;
+
writer_.ScheduleWrite(this);
}
diff --git a/chrome/browser/pref_service.h b/chrome/browser/pref_service.h
index f1819ad..75d829e 100644
--- a/chrome/browser/pref_service.h
+++ b/chrome/browser/pref_service.h
@@ -186,7 +186,23 @@ class PrefService : public NonThreadSafe,
// ImportantFileWriter::DataSerializer
virtual bool SerializeData(std::string* output);
+ bool read_only() const { return read_only_; }
+
private:
+ // Unique integer code for each type of error so we can report them
+ // distinctly in a histogram.
+ // NOTE: Don't change the order here as it will change the server's meaning
+ // of the histogram.
+ enum PrefReadError {
+ PREF_READ_ERROR_NONE = 0,
+ PREF_READ_ERROR_JSON_PARSE,
+ PREF_READ_ERROR_JSON_TYPE,
+ PREF_READ_ERROR_ACCESS_DENIED,
+ PREF_READ_ERROR_FILE_OTHER,
+ PREF_READ_ERROR_FILE_LOCKED,
+ PREF_READ_ERROR_NO_FILE,
+ };
+
// Add a preference to the PreferenceMap. If the pref already exists, return
// false. This method takes ownership of |pref|.
void RegisterPreference(Preference* pref);
@@ -203,6 +219,13 @@ class PrefService : public NonThreadSafe,
void FireObserversIfChanged(const wchar_t* pref_name,
const Value* old_value);
+ // Load from disk. Returns a non-zero error code on failure.
+ PrefReadError LoadPersistentPrefs();
+
+ // Load preferences from disk, attempting to diagnose and handle errors.
+ // This should only be called from the constructor.
+ void InitFromDisk();
+
scoped_ptr<DictionaryValue> persistent_;
// Helper for safe writing pref data.
@@ -220,6 +243,11 @@ class PrefService : public NonThreadSafe,
friend class ScopedPrefUpdate;
+ // Whether the service is in a pseudo-read-only mode where changes are not
+ // actually persisted to disk. This happens in some cases when there are
+ // read errors during startup.
+ bool read_only_;
+
DISALLOW_COPY_AND_ASSIGN(PrefService);
};
diff --git a/chrome/browser/pref_service_uitest.cc b/chrome/browser/pref_service_uitest.cc
index 79f00d3..87dcb2c 100644
--- a/chrome/browser/pref_service_uitest.cc
+++ b/chrome/browser/pref_service_uitest.cc
@@ -86,7 +86,7 @@ TEST_F(PreferenceServiceTest, PreservedWindowPlacementIsLoaded) {
ASSERT_TRUE(file_util::PathExists(tmp_pref_file_));
JSONFileValueSerializer deserializer(tmp_pref_file_);
- scoped_ptr<Value> root(deserializer.Deserialize(NULL));
+ scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
diff --git a/chrome/browser/sync/glue/preference_change_processor.cc b/chrome/browser/sync/glue/preference_change_processor.cc
index 6203c55..6f5ac4d 100644
--- a/chrome/browser/sync/glue/preference_change_processor.cc
+++ b/chrome/browser/sync/glue/preference_change_processor.cc
@@ -161,7 +161,7 @@ Value* PreferenceChangeProcessor::ReadPreference(
scoped_ptr<Value> value(reader.JsonToValue(preference.value(), false, false));
if (!value.get()) {
LOG(ERROR) << "Failed to deserialize preference value: "
- << reader.error_message();
+ << reader.GetErrorMessage();
error_handler()->OnUnrecoverableError();
return NULL;
}
diff --git a/chrome/browser/sync/glue/preference_model_associator.cc b/chrome/browser/sync/glue/preference_model_associator.cc
index 169da24..5021b4b 100644
--- a/chrome/browser/sync/glue/preference_model_associator.cc
+++ b/chrome/browser/sync/glue/preference_model_associator.cc
@@ -84,7 +84,7 @@ bool PreferenceModelAssociator::AssociateModels() {
std::wstring pref_name = UTF8ToWide(preference.name());
if (!value.get()) {
LOG(ERROR) << "Failed to deserialize preference value: "
- << reader.error_message();
+ << reader.GetErrorMessage();
error_handler_->OnUnrecoverableError();
return false;
}
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
index 8347381..33cb805 100644
--- a/chrome/common/extensions/extension_file_util.cc
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -117,7 +117,7 @@ Extension* LoadExtension(const FilePath& extension_path,
}
JSONFileValueSerializer serializer(manifest_path);
- scoped_ptr<Value> root(serializer.Deserialize(error));
+ scoped_ptr<Value> root(serializer.Deserialize(NULL, error));
if (!root.get()) {
if (error->empty()) {
// If |error| is empty, than the file could not be read.
diff --git a/chrome/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index cd6ad60..a52d4cc 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -250,7 +250,7 @@ static DictionaryValue* LoadMessageFile(const FilePath& locale_path,
FilePath file = locale_path.AppendASCII(extension_locale)
.Append(Extension::kMessagesFilename);
JSONFileValueSerializer messages_serializer(file);
- Value *dictionary = messages_serializer.Deserialize(error);
+ Value *dictionary = messages_serializer.Deserialize(NULL, error);
if (!dictionary && error->empty()) {
// JSONFileValueSerializer just returns NULL if file cannot be found. It
// doesn't set the error, so we have to do it.
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index 37c4696..ad2091e 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -31,7 +31,7 @@ class ManifestTest : public testing::Test {
JSONFileValueSerializer serializer(path);
scoped_ptr<DictionaryValue> value(
- static_cast<DictionaryValue*>(serializer.Deserialize(error)));
+ static_cast<DictionaryValue*>(serializer.Deserialize(NULL, error)));
if (!value.get())
return NULL;
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index fc88ab3..e204dcb 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -50,6 +50,7 @@ TEST(ExtensionTest, InitFromValueInvalid) {
FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
Extension extension(path);
+ int error_code = 0;
std::string error;
ExtensionErrorReporter::Init(false);
@@ -65,8 +66,10 @@ TEST(ExtensionTest, InitFromValueInvalid) {
JSONFileValueSerializer serializer(extensions_path);
scoped_ptr<DictionaryValue> valid_value(
- static_cast<DictionaryValue*>(serializer.Deserialize(&error)));
+ static_cast<DictionaryValue*>(serializer.Deserialize(&error_code,
+ &error)));
EXPECT_EQ("", error);
+ EXPECT_EQ(0, error_code);
ASSERT_TRUE(valid_value.get());
ASSERT_TRUE(extension.InitFromValue(*valid_value, true, &error));
ASSERT_EQ("", error);
@@ -654,7 +657,7 @@ static Extension* LoadManifest(const std::string& dir,
.AppendASCII(test_file);
JSONFileValueSerializer serializer(path);
- scoped_ptr<Value> result(serializer.Deserialize(NULL));
+ scoped_ptr<Value> result(serializer.Deserialize(NULL, NULL));
if (!result.get())
return NULL;
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc
index ae2e0e3..dad10f4 100644
--- a/chrome/common/extensions/extension_unpacker.cc
+++ b/chrome/common/extensions/extension_unpacker.cc
@@ -101,7 +101,7 @@ DictionaryValue* ExtensionUnpacker::ReadManifest() {
JSONFileValueSerializer serializer(manifest_path);
std::string error;
- scoped_ptr<Value> root(serializer.Deserialize(&error));
+ scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
if (!root.get()) {
SetError(error);
return NULL;
@@ -281,7 +281,7 @@ bool ExtensionUnpacker::ReadMessageCatalog(const FilePath& message_path) {
std::string error;
JSONFileValueSerializer serializer(message_path);
scoped_ptr<DictionaryValue> root(
- static_cast<DictionaryValue*>(serializer.Deserialize(&error)));
+ static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
if (!root.get()) {
std::string messages_file = WideToASCII(message_path.ToWStringHack());
if (error.empty()) {
diff --git a/chrome/common/json_value_serializer.cc b/chrome/common/json_value_serializer.cc
index 1e739e6..df92afd 100644
--- a/chrome/common/json_value_serializer.cc
+++ b/chrome/common/json_value_serializer.cc
@@ -9,6 +9,11 @@
#include "base/json/json_writer.h"
#include "base/string_util.h"
+const char* JSONFileValueSerializer::kAccessDenied = "Access denied.";
+const char* JSONFileValueSerializer::kCannotReadFile = "Can't read file.";
+const char* JSONFileValueSerializer::kFileLocked = "File locked.";
+const char* JSONFileValueSerializer::kNoSuchFile = "File doesn't exist.";
+
JSONStringValueSerializer::~JSONStringValueSerializer() {}
bool JSONStringValueSerializer::Serialize(const Value& root) {
@@ -19,13 +24,15 @@ bool JSONStringValueSerializer::Serialize(const Value& root) {
return true;
}
-Value* JSONStringValueSerializer::Deserialize(std::string* error_message) {
+Value* JSONStringValueSerializer::Deserialize(int* error_code,
+ std::string* error_str) {
if (!json_string_)
return NULL;
return base::JSONReader::ReadAndReturnError(*json_string_,
allow_trailing_comma_,
- error_message);
+ error_code,
+ error_str);
}
/******* File Serializer *******/
@@ -47,11 +54,55 @@ bool JSONFileValueSerializer::Serialize(const Value& root) {
return true;
}
-Value* JSONFileValueSerializer::Deserialize(std::string* error_message) {
+int JSONFileValueSerializer::ReadFileToString(std::string* json_string) {
+ DCHECK(json_string);
+ if (!file_util::ReadFileToString(json_file_path_, json_string)) {
+#if defined(OS_WIN)
+ int error = ::GetLastError();
+ if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) {
+ return JSON_FILE_LOCKED;
+ } else if (error == ERROR_ACCESS_DENIED) {
+ return JSON_ACCESS_DENIED;
+ }
+#endif
+ if (!file_util::PathExists(json_file_path_))
+ return JSON_NO_SUCH_FILE;
+ else
+ return JSON_CANNOT_READ_FILE;
+ }
+ return JSON_NO_ERROR;
+}
+
+const char* JSONFileValueSerializer::GetErrorMessageForCode(int error_code) {
+ switch (error_code) {
+ case JSON_NO_ERROR:
+ return "";
+ case JSON_ACCESS_DENIED:
+ return kAccessDenied;
+ case JSON_CANNOT_READ_FILE:
+ return kCannotReadFile;
+ case JSON_FILE_LOCKED:
+ return kFileLocked;
+ case JSON_NO_SUCH_FILE:
+ return kNoSuchFile;
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
+Value* JSONFileValueSerializer::Deserialize(int* error_code,
+ std::string* error_str) {
std::string json_string;
- if (!file_util::ReadFileToString(json_file_path_, &json_string)) {
+ int error = ReadFileToString(&json_string);
+ if (error != JSON_NO_ERROR) {
+ if (error_code)
+ *error_code = error;
+ if (error_str)
+ *error_str = GetErrorMessageForCode(error);
return NULL;
}
+
JSONStringValueSerializer serializer(json_string);
- return serializer.Deserialize(error_message);
+ return serializer.Deserialize(error_code, error_str);
}
diff --git a/chrome/common/json_value_serializer.h b/chrome/common/json_value_serializer.h
index 1f1e556..7919cfe 100644
--- a/chrome/common/json_value_serializer.h
+++ b/chrome/common/json_value_serializer.h
@@ -41,9 +41,12 @@ class JSONStringValueSerializer : public ValueSerializer {
// Attempt to deserialize the data structure encoded in the string passed
// in to the constructor into a structure of Value objects. If the return
- // value is NULL and |error_message| is non-null, |error_message| will contain
- // a string describing the error.
- Value* Deserialize(std::string* error_message);
+ // value is NULL, and if |error_code| is non-null, |error_code| will
+ // contain an integer error code (either JsonFileError or JsonParseError).
+ // If |error_message| is non-null, it will be filled in with a formatted
+ // error message including the location of the error if appropriate.
+ // The caller takes ownership of the returned value.
+ Value* Deserialize(int* error_code, std::string* error_message);
void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
bool pretty_print() { return pretty_print_; }
@@ -85,14 +88,39 @@ class JSONFileValueSerializer : public ValueSerializer {
// Attempt to deserialize the data structure encoded in the file passed
// in to the constructor into a structure of Value objects. If the return
- // value is NULL, and if |error_message| is non-null, |error_message| will
- // contain a string describing the error. The caller takes ownership of the
- // returned value.
- Value* Deserialize(std::string* error_message);
+ // value is NULL, and if |error_code| is non-null, |error_code| will
+ // contain an integer error code (either JsonFileError or JsonParseError).
+ // If |error_message| is non-null, it will be filled in with a formatted
+ // error message including the location of the error if appropriate.
+ // The caller takes ownership of the returned value.
+ Value* Deserialize(int* error_code, std::string* error_message);
+
+ // This enum is designed to safely overlap with JSONReader::JsonParseError.
+ enum JsonFileError {
+ JSON_NO_ERROR = 0,
+ JSON_ACCESS_DENIED = 1000,
+ JSON_CANNOT_READ_FILE,
+ JSON_FILE_LOCKED,
+ JSON_NO_SUCH_FILE
+ };
+
+ // File-specific error messages that can be returned.
+ static const char* kAccessDenied;
+ static const char* kCannotReadFile;
+ static const char* kFileLocked;
+ static const char* kNoSuchFile;
+
+ // Convert an error code into an error message. |error_code| is assumed to
+ // be a JsonFileError.
+ static const char* GetErrorMessageForCode(int error_code);
private:
FilePath json_file_path_;
+ // A wrapper for file_util::ReadFileToString which returns a non-zero
+ // JsonFileError if there were file errors.
+ int ReadFileToString(std::string* json_string);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
};
diff --git a/chrome/common/json_value_serializer_perftest.cc b/chrome/common/json_value_serializer_perftest.cc
index 0032260..504ddb2 100644
--- a/chrome/common/json_value_serializer_perftest.cc
+++ b/chrome/common/json_value_serializer_perftest.cc
@@ -53,7 +53,7 @@ TEST_F(JSONValueSerializerTests, Reading) {
for (int i = 0; i < kIterations; ++i) {
for (size_t j = 0; j < test_cases_.size(); ++j) {
JSONStringValueSerializer reader(test_cases_[j]);
- scoped_ptr<Value> root(reader.Deserialize(NULL));
+ scoped_ptr<Value> root(reader.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
}
}
@@ -67,7 +67,7 @@ TEST_F(JSONValueSerializerTests, CompactWriting) {
std::vector<Value*> test_cases;
for (size_t i = 0; i < test_cases_.size(); ++i) {
JSONStringValueSerializer reader(test_cases_[i]);
- Value* root = reader.Deserialize(NULL);
+ Value* root = reader.Deserialize(NULL, NULL);
ASSERT_TRUE(root);
test_cases.push_back(root);
}
diff --git a/chrome/common/json_value_serializer_unittest.cc b/chrome/common/json_value_serializer_unittest.cc
index 14f4f5d..3f40dcc 100644
--- a/chrome/common/json_value_serializer_unittest.cc
+++ b/chrome/common/json_value_serializer_unittest.cc
@@ -17,7 +17,7 @@ TEST(JSONValueSerializerTest, Roundtrip) {
const std::string original_serialization =
"{\"bool\":true,\"int\":42,\"list\":[1,2],\"null\":null,\"real\":3.14}";
JSONStringValueSerializer serializer(original_serialization);
- scoped_ptr<Value> root(serializer.Deserialize(NULL));
+ scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
@@ -130,7 +130,7 @@ TEST(JSONValueSerializerTest, UnicodeStrings) {
// escaped ascii text -> json
JSONStringValueSerializer deserializer(expected);
- scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL));
+ scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
static_cast<DictionaryValue*>(deserial_root.get());
@@ -154,7 +154,7 @@ TEST(JSONValueSerializerTest, HexStrings) {
// escaped ascii text -> json
JSONStringValueSerializer deserializer(expected);
- scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL));
+ scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
static_cast<DictionaryValue*>(deserial_root.get());
@@ -165,7 +165,7 @@ TEST(JSONValueSerializerTest, HexStrings) {
// Test converting escaped regular chars
std::string escaped_chars = "{\"test\":\"\\u0067\\u006f\"}";
JSONStringValueSerializer deserializer2(escaped_chars);
- deserial_root.reset(deserializer2.Deserialize(NULL));
+ deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
dict_root = static_cast<DictionaryValue*>(deserial_root.get());
ASSERT_TRUE(dict_root->GetString(L"test", &test_value));
@@ -181,9 +181,9 @@ TEST(JSONValueSerializerTest, AllowTrailingComma) {
JSONStringValueSerializer serializer(test_with_commas);
serializer.set_allow_trailing_comma(true);
JSONStringValueSerializer serializer_expected(test_no_commas);
- root.reset(serializer.Deserialize(NULL));
+ root.reset(serializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
- root_expected.reset(serializer_expected.Deserialize(NULL));
+ root_expected.reset(serializer_expected.Deserialize(NULL, NULL));
ASSERT_TRUE(root_expected.get());
ASSERT_TRUE(root->Equals(root_expected.get()));
}
@@ -267,7 +267,7 @@ TEST_F(JSONFileValueSerializerTest, Roundtrip) {
JSONFileValueSerializer deserializer(original_file_path);
scoped_ptr<Value> root;
- root.reset(deserializer.Deserialize(NULL));
+ root.reset(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
@@ -317,7 +317,7 @@ TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
JSONFileValueSerializer deserializer(original_file_path);
scoped_ptr<Value> root;
- root.reset(deserializer.Deserialize(NULL));
+ root.reset(deserializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
// Now try writing.
@@ -343,6 +343,6 @@ TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
ASSERT_TRUE(file_util::PathExists(source_file_path));
JSONFileValueSerializer serializer(source_file_path);
scoped_ptr<Value> root;
- root.reset(serializer.Deserialize(NULL));
+ root.reset(serializer.Deserialize(NULL, NULL));
ASSERT_TRUE(root.get());
}
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index 64c432b..7029fef0 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -193,7 +193,7 @@ bool GoogleChromeDistribution::ExtractUninstallMetricsFromFile(
JSONFileValueSerializer json_serializer(FilePath::FromWStringHack(file_path));
std::string json_error_string;
- scoped_ptr<Value> root(json_serializer.Deserialize(NULL));
+ scoped_ptr<Value> root(json_serializer.Deserialize(NULL, NULL));
if (!root.get())
return false;
diff --git a/chrome/installer/util/google_chrome_distribution_unittest.cc b/chrome/installer/util/google_chrome_distribution_unittest.cc
index 0df160c..cc63e00 100644
--- a/chrome/installer/util/google_chrome_distribution_unittest.cc
+++ b/chrome/installer/util/google_chrome_distribution_unittest.cc
@@ -217,7 +217,7 @@ TEST_F(GoogleChromeDistributionTest, TestExtractUninstallMetrics) {
JSONStringValueSerializer json_deserializer(pref_string);
std::string error_message;
- scoped_ptr<Value> root(json_deserializer.Deserialize(&error_message));
+ scoped_ptr<Value> root(json_deserializer.Deserialize(NULL, &error_message));
ASSERT_TRUE(root.get());
std::wstring uninstall_metrics_string;
diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc
index 3406e33..e78872e 100644
--- a/chrome/installer/util/master_preferences.cc
+++ b/chrome/installer/util/master_preferences.cc
@@ -169,7 +169,7 @@ DictionaryValue* ParseDistributionPreferences(
return NULL;
JSONStringValueSerializer json(json_data);
- scoped_ptr<Value> root(json.Deserialize(NULL));
+ scoped_ptr<Value> root(json.Deserialize(NULL, NULL));
if (!root.get())
return NULL;
diff --git a/chrome/renderer/extensions/extension_api_json_validity_unittest.cc b/chrome/renderer/extensions/extension_api_json_validity_unittest.cc
index 7a54d77..eb7f199 100644
--- a/chrome/renderer/extensions/extension_api_json_validity_unittest.cc
+++ b/chrome/renderer/extensions/extension_api_json_validity_unittest.cc
@@ -92,7 +92,7 @@ TEST_F(ExtensionApiJsonValidityTest, Basic) {
// Check that extension_api.json can be parsed as JSON.
JSONFileValueSerializer serializer(extension_api_json);
- scoped_ptr<Value> root(serializer.Deserialize(&error_message));
+ scoped_ptr<Value> root(serializer.Deserialize(NULL, &error_message));
ASSERT_TRUE(root.get()) << error_message;
ASSERT_EQ(Value::TYPE_LIST, root->GetType());
ListValue* root_list = static_cast<ListValue*>(root.get());
diff --git a/chrome/test/automation/javascript_execution_controller.cc b/chrome/test/automation/javascript_execution_controller.cc
index 26d32d0..3cd0753 100644
--- a/chrome/test/automation/javascript_execution_controller.cc
+++ b/chrome/test/automation/javascript_execution_controller.cc
@@ -72,7 +72,7 @@ bool JavaScriptExecutionController::ParseJSON(const std::string& json,
scoped_ptr<Value>* result) {
JSONStringValueSerializer parse(json);
std::string parsing_error;
- scoped_ptr<Value> root_value(parse.Deserialize(&parsing_error));
+ scoped_ptr<Value> root_value(parse.Deserialize(NULL, &parsing_error));
if (!root_value.get()) {
if (parsing_error.length())
diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc
index 6f2f9a6..83fee1f 100644
--- a/chrome/test/automation/tab_proxy.cc
+++ b/chrome/test/automation/tab_proxy.cc
@@ -341,7 +341,7 @@ bool TabProxy::ExecuteAndExtractValue(const std::wstring& frame_xpath,
json.append("]");
JSONStringValueSerializer deserializer(json);
- *value = deserializer.Deserialize(NULL);
+ *value = deserializer.Deserialize(NULL, NULL);
return *value != NULL;
}
diff --git a/chrome/test/ui/dom_checker_uitest.cc b/chrome/test/ui/dom_checker_uitest.cc
index f235423..84af7da 100644
--- a/chrome/test/ui/dom_checker_uitest.cc
+++ b/chrome/test/ui/dom_checker_uitest.cc
@@ -164,7 +164,7 @@ class DomCheckerTest : public UITest {
std::string json = WideToUTF8(json_wide);
JSONStringValueSerializer deserializer(json);
- scoped_ptr<Value> value(deserializer.Deserialize(NULL));
+ scoped_ptr<Value> value(deserializer.Deserialize(NULL, NULL));
EXPECT_TRUE(value.get());
if (!value.get())
diff --git a/chrome/test/ui/javascript_test_util.cc b/chrome/test/ui/javascript_test_util.cc
index f2f7f7b..8f07809 100644
--- a/chrome/test/ui/javascript_test_util.cc
+++ b/chrome/test/ui/javascript_test_util.cc
@@ -15,7 +15,7 @@ bool JsonDictionaryToMap(const std::string& json,
std::map<std::string, std::string>* results) {
DCHECK(results != NULL);
JSONStringValueSerializer deserializer(json);
- scoped_ptr<Value> root(deserializer.Deserialize(NULL));
+ scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL));
// Note that we don't use ASSERT_TRUE here (and in some other places) as it
// doesn't work inside a function with a return type other than void.
diff --git a/chrome/test/ui/ui_test.cc b/chrome/test/ui/ui_test.cc
index ff952ba..9ad2aa1 100644
--- a/chrome/test/ui/ui_test.cc
+++ b/chrome/test/ui/ui_test.cc
@@ -706,7 +706,7 @@ static DictionaryValue* LoadDictionaryValueFromPath(const FilePath& path) {
return NULL;
JSONFileValueSerializer serializer(path);
- scoped_ptr<Value> root_value(serializer.Deserialize(NULL));
+ scoped_ptr<Value> root_value(serializer.Deserialize(NULL, NULL));
if (!root_value.get() || root_value->GetType() != Value::TYPE_DICTIONARY)
return NULL;