Index: content/renderer/dom_storage/local_storage_cached_area.cc |
diff --git a/content/renderer/dom_storage/local_storage_cached_area.cc b/content/renderer/dom_storage/local_storage_cached_area.cc |
index cb975a1d9ec302bac6e3505a874e1de13b427cc6..1f191a20da2ddd9b3d3814b3f745b02c67ed3825 100644 |
--- a/content/renderer/dom_storage/local_storage_cached_area.cc |
+++ b/content/renderer/dom_storage/local_storage_cached_area.cc |
@@ -6,6 +6,8 @@ |
#include "base/bind.h" |
#include "base/metrics/histogram_macros.h" |
+#include "base/rand_util.h" |
+#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_split.h" |
#include "base/time/time.h" |
#include "content/common/dom_storage/dom_storage_map.h" |
@@ -41,9 +43,10 @@ LocalStorageCachedArea::LocalStorageCachedArea( |
const url::Origin& origin, |
mojom::StoragePartitionService* storage_partition_service, |
LocalStorageCachedAreas* cached_areas) |
- : origin_(origin), binding_(this), cached_areas_(cached_areas) { |
+ : origin_(origin), binding_(this), |
+ cached_areas_(cached_areas), weak_factory_(this) { |
storage_partition_service->OpenLocalStorage( |
- origin_, mojo::GetProxy(&leveldb_)); |
+ origin_, binding_.CreateInterfacePtrAndBind(), mojo::GetProxy(&leveldb_)); |
} |
LocalStorageCachedArea::~LocalStorageCachedArea() { |
@@ -86,7 +89,7 @@ bool LocalStorageCachedArea::SetItem(const base::string16& key, |
mojo::Array<uint8_t>::From(value), |
PackSource(page_url, storage_area_id), |
base::Bind(&LocalStorageCachedArea::OnSetItemComplete, |
- base::Unretained(this), key)); |
+ weak_factory_.GetWeakPtr(), key)); |
return true; |
} |
@@ -103,7 +106,7 @@ void LocalStorageCachedArea::RemoveItem(const base::string16& key, |
leveldb_->Delete(mojo::Array<uint8_t>::From(key), |
PackSource(page_url, storage_area_id), |
base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete, |
- base::Unretained(this), key)); |
+ weak_factory_.GetWeakPtr(), key)); |
} |
void LocalStorageCachedArea::Clear(const GURL& page_url, |
@@ -112,11 +115,10 @@ void LocalStorageCachedArea::Clear(const GURL& page_url, |
Reset(); |
map_ = new DOMStorageMap(kPerStorageAreaQuota); |
- |
- leveldb_->DeleteAll(binding_.CreateInterfacePtrAndBind(), |
- PackSource(page_url, storage_area_id), |
+ ignore_all_mutations_ = true; |
+ leveldb_->DeleteAll(PackSource(page_url, storage_area_id), |
base::Bind(&LocalStorageCachedArea::OnClearComplete, |
- base::Unretained(this))); |
+ weak_factory_.GetWeakPtr())); |
} |
void LocalStorageCachedArea::AreaCreated(LocalStorageArea* area) { |
@@ -127,39 +129,21 @@ void LocalStorageCachedArea::AreaDestroyed(LocalStorageArea* area) { |
areas_.erase(area->id()); |
} |
+void LocalStorageCachedArea::KeyAdded(mojo::Array<uint8_t> key, |
+ mojo::Array<uint8_t> value, |
+ const mojo::String& source) { |
+ base::NullableString16 null_value; |
+ KeyAddedOrChanged(std::move(key), std::move(value), |
+ null_value, source); |
+} |
+ |
void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key, |
mojo::Array<uint8_t> new_value, |
mojo::Array<uint8_t> old_value, |
const mojo::String& source) { |
- GURL page_url; |
- std::string storage_area_id; |
- UnpackSource(source, &page_url, &storage_area_id); |
- |
- base::string16 key_string = key.To<base::string16>(); |
- base::string16 new_value_string = new_value.To<base::string16>(); |
- |
- blink::WebStorageArea* originating_area = nullptr; |
- if (areas_.find(storage_area_id) != areas_.end()) { |
- // The source storage area is in this process. |
- originating_area = areas_[storage_area_id]; |
- } else { |
- // This was from another process or the storage area is gone. If the former, |
- // apply it to our cache if we haven't already changed it and are waiting |
- // for the confirmation callback. In the latter case, we won't do anything |
- // because ignore_key_mutations_ won't be updated until the callback runs. |
- if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { |
- // We turn off quota checking here to accomodate the over budget allowance |
- // that's provided in the browser process. |
- base::NullableString16 unused; |
- map_->set_quota(std::numeric_limits<int32_t>::max()); |
- map_->SetItem(key_string, new_value_string, &unused); |
- map_->set_quota(kPerStorageAreaQuota); |
- } |
- } |
- |
- blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
- key_string, old_value.To<base::string16>(), new_value_string, |
- GURL(origin_.Serialize()), page_url, originating_area); |
+ base::NullableString16 old_value_str(old_value.To<base::string16>(), false); |
+ KeyAddedOrChanged(std::move(key), std::move(new_value), |
+ old_value_str, source); |
} |
void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, |
@@ -175,7 +159,7 @@ void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, |
if (areas_.find(storage_area_id) != areas_.end()) { |
// The source storage area is in this process. |
originating_area = areas_[storage_area_id]; |
- } else { |
+ } else if (map_ && !ignore_all_mutations_) { |
// This was from another process or the storage area is gone. If the former, |
// remove it from our cache if we haven't already changed it and are waiting |
// for the confirmation callback. In the latter case, we won't do anything |
@@ -200,7 +184,7 @@ void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { |
if (areas_.find(storage_area_id) != areas_.end()) { |
// The source storage area is in this process. |
originating_area = areas_[storage_area_id]; |
- } else { |
+ } else if (map_ && !ignore_all_mutations_) { |
scoped_refptr<DOMStorageMap> old = map_; |
map_ = new DOMStorageMap(kPerStorageAreaQuota); |
@@ -223,14 +207,65 @@ void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { |
originating_area); |
} |
+void LocalStorageCachedArea::GetAllComplete(const mojo::String& source) { |
+ // Since the GetAll method is synchronous, we need this asynchronously |
+ // delivered notification to avoid applying changes to the returned array |
+ // that we already have. |
+ if (source.To<std::string>() == get_all_request_id_) { |
+ DCHECK(ignore_all_mutations_); |
+ DCHECK(!get_all_request_id_.empty()); |
+ ignore_all_mutations_ = false; |
+ get_all_request_id_.clear(); |
+ } |
+} |
+ |
+void LocalStorageCachedArea::KeyAddedOrChanged( |
+ mojo::Array<uint8_t> key, |
+ mojo::Array<uint8_t> new_value, |
+ const base::NullableString16& old_value, |
+ const mojo::String& source) { |
+ GURL page_url; |
+ std::string storage_area_id; |
+ UnpackSource(source, &page_url, &storage_area_id); |
+ |
+ base::string16 key_string = key.To<base::string16>(); |
+ base::string16 new_value_string = new_value.To<base::string16>(); |
+ |
+ blink::WebStorageArea* originating_area = nullptr; |
+ if (areas_.find(storage_area_id) != areas_.end()) { |
+ // The source storage area is in this process. |
+ originating_area = areas_[storage_area_id]; |
+ } else if (map_ && !ignore_all_mutations_) { |
+ // This was from another process or the storage area is gone. If the former, |
+ // apply it to our cache if we haven't already changed it and are waiting |
+ // for the confirmation callback. In the latter case, we won't do anything |
+ // because ignore_key_mutations_ won't be updated until the callback runs. |
+ if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { |
+ // We turn off quota checking here to accomodate the over budget allowance |
+ // that's provided in the browser process. |
+ base::NullableString16 unused; |
+ map_->set_quota(std::numeric_limits<int32_t>::max()); |
+ map_->SetItem(key_string, new_value_string, &unused); |
+ map_->set_quota(kPerStorageAreaQuota); |
+ } |
+ } |
+ |
+ blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
+ key_string, old_value, new_value_string, |
+ GURL(origin_.Serialize()), page_url, originating_area); |
+ |
+} |
+ |
void LocalStorageCachedArea::EnsureLoaded() { |
if (map_) |
return; |
base::TimeTicks before = base::TimeTicks::Now(); |
+ ignore_all_mutations_ = true; |
+ get_all_request_id_ = base::Uint64ToString(base::RandUint64()); |
leveldb::DatabaseError status = leveldb::DatabaseError::OK; |
mojo::Array<content::mojom::KeyValuePtr> data; |
- leveldb_->GetAll(binding_.CreateInterfacePtrAndBind(), &status, &data); |
+ leveldb_->GetAll(get_all_request_id_, &status, &data); |
DOMStorageValuesMap values; |
for (size_t i = 0; i < data.size(); ++i) { |
@@ -264,8 +299,8 @@ void LocalStorageCachedArea::EnsureLoaded() { |
} |
void LocalStorageCachedArea::OnSetItemComplete(const base::string16& key, |
- leveldb::DatabaseError result) { |
- if (result != leveldb::DatabaseError::OK) { |
+ bool success) { |
+ if (!success) { |
Reset(); |
return; |
} |
@@ -277,22 +312,25 @@ void LocalStorageCachedArea::OnSetItemComplete(const base::string16& key, |
} |
void LocalStorageCachedArea::OnRemoveItemComplete( |
- const base::string16& key, leveldb::DatabaseError result) { |
- DCHECK_EQ(result, leveldb::DatabaseError::OK); |
+ const base::string16& key, bool success) { |
+ DCHECK(success); |
auto found = ignore_key_mutations_.find(key); |
DCHECK(found != ignore_key_mutations_.end()); |
if (--found->second == 0) |
ignore_key_mutations_.erase(found); |
} |
-void LocalStorageCachedArea::OnClearComplete(leveldb::DatabaseError result) { |
- DCHECK_EQ(result, leveldb::DatabaseError::OK); |
+void LocalStorageCachedArea::OnClearComplete(bool success) { |
+ DCHECK(success); |
+ DCHECK(ignore_all_mutations_); |
+ ignore_all_mutations_ = false; |
} |
void LocalStorageCachedArea::Reset() { |
- binding_.Close(); |
map_ = NULL; |
ignore_key_mutations_.clear(); |
+ ignore_all_mutations_ = false; |
+ weak_factory_.InvalidateWeakPtrs(); |
} |
} // namespace content |