| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/dom_storage/local_storage_cached_area.h" | 5 #include "content/renderer/dom_storage/local_storage_cached_area.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
| 9 #include "base/rand_util.h" | 9 #include "base/rand_util.h" |
| 10 #include "base/strings/string16.h" |
| 10 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
| 12 #include "base/time/time.h" | 13 #include "base/time/time.h" |
| 13 #include "content/common/dom_storage/dom_storage_map.h" | 14 #include "content/common/dom_storage/dom_storage_map.h" |
| 14 #include "content/common/storage_partition_service.mojom.h" | 15 #include "content/common/storage_partition_service.mojom.h" |
| 15 #include "content/renderer/dom_storage/local_storage_area.h" | 16 #include "content/renderer/dom_storage/local_storage_area.h" |
| 16 #include "content/renderer/dom_storage/local_storage_cached_areas.h" | 17 #include "content/renderer/dom_storage/local_storage_cached_areas.h" |
| 17 #include "mojo/common/common_type_converters.h" | |
| 18 #include "third_party/WebKit/public/platform/WebURL.h" | 18 #include "third_party/WebKit/public/platform/WebURL.h" |
| 19 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h" | 19 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h" |
| 20 #include "url/gurl.h" | 20 #include "url/gurl.h" |
| 21 | 21 |
| 22 namespace { |
| 23 |
| 24 base::string16 Uint8VectorToString16(const std::vector<uint8_t>& input) { |
| 25 return base::string16(reinterpret_cast<const base::char16*>(input.data()), |
| 26 input.size() / sizeof(base::char16)); |
| 27 } |
| 28 |
| 29 std::vector<uint8_t> String16ToUint8Vector(const base::string16& input) { |
| 30 const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data()); |
| 31 return std::vector<uint8_t>(data, data + input.size() * sizeof(base::char16)); |
| 32 } |
| 33 |
| 34 } // namespace |
| 35 |
| 22 namespace content { | 36 namespace content { |
| 23 | 37 |
| 24 // These methods are used to pack and unpack the page_url/storage_area_id into | 38 // These methods are used to pack and unpack the page_url/storage_area_id into |
| 25 // source strings to/from the browser. | 39 // source strings to/from the browser. |
| 26 std::string PackSource(const GURL& page_url, | 40 std::string PackSource(const GURL& page_url, |
| 27 const std::string& storage_area_id) { | 41 const std::string& storage_area_id) { |
| 28 return page_url.spec() + "\n" + storage_area_id; | 42 return page_url.spec() + "\n" + storage_area_id; |
| 29 } | 43 } |
| 30 | 44 |
| 31 void UnpackSource(const mojo::String& source, | 45 void UnpackSource(const std::string& source, |
| 32 GURL* page_url, | 46 GURL* page_url, |
| 33 std::string* storage_area_id) { | 47 std::string* storage_area_id) { |
| 34 std::vector<std::string> result = base::SplitString( | 48 std::vector<std::string> result = base::SplitString( |
| 35 source.To<std::string>(), "\n", base::KEEP_WHITESPACE, | 49 source, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
| 36 base::SPLIT_WANT_ALL); | |
| 37 DCHECK_EQ(result.size(), 2u); | 50 DCHECK_EQ(result.size(), 2u); |
| 38 *page_url = GURL(result[0]); | 51 *page_url = GURL(result[0]); |
| 39 *storage_area_id = result[1]; | 52 *storage_area_id = result[1]; |
| 40 } | 53 } |
| 41 | 54 |
| 42 LocalStorageCachedArea::LocalStorageCachedArea( | 55 LocalStorageCachedArea::LocalStorageCachedArea( |
| 43 const url::Origin& origin, | 56 const url::Origin& origin, |
| 44 mojom::StoragePartitionService* storage_partition_service, | 57 mojom::StoragePartitionService* storage_partition_service, |
| 45 LocalStorageCachedAreas* cached_areas) | 58 LocalStorageCachedAreas* cached_areas) |
| 46 : origin_(origin), binding_(this), | 59 : origin_(origin), binding_(this), |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 if (key.length() + value.length() > kPerStorageAreaQuota) | 91 if (key.length() + value.length() > kPerStorageAreaQuota) |
| 79 return false; | 92 return false; |
| 80 | 93 |
| 81 EnsureLoaded(); | 94 EnsureLoaded(); |
| 82 base::NullableString16 unused; | 95 base::NullableString16 unused; |
| 83 if (!map_->SetItem(key, value, &unused)) | 96 if (!map_->SetItem(key, value, &unused)) |
| 84 return false; | 97 return false; |
| 85 | 98 |
| 86 // Ignore mutations to |key| until OnSetItemComplete. | 99 // Ignore mutations to |key| until OnSetItemComplete. |
| 87 ignore_key_mutations_[key]++; | 100 ignore_key_mutations_[key]++; |
| 88 leveldb_->Put(mojo::Array<uint8_t>::From(key), | 101 leveldb_->Put(String16ToUint8Vector(key), String16ToUint8Vector(value), |
| 89 mojo::Array<uint8_t>::From(value), | |
| 90 PackSource(page_url, storage_area_id), | 102 PackSource(page_url, storage_area_id), |
| 91 base::Bind(&LocalStorageCachedArea::OnSetItemComplete, | 103 base::Bind(&LocalStorageCachedArea::OnSetItemComplete, |
| 92 weak_factory_.GetWeakPtr(), key)); | 104 weak_factory_.GetWeakPtr(), key)); |
| 93 return true; | 105 return true; |
| 94 } | 106 } |
| 95 | 107 |
| 96 void LocalStorageCachedArea::RemoveItem(const base::string16& key, | 108 void LocalStorageCachedArea::RemoveItem(const base::string16& key, |
| 97 const GURL& page_url, | 109 const GURL& page_url, |
| 98 const std::string& storage_area_id) { | 110 const std::string& storage_area_id) { |
| 99 EnsureLoaded(); | 111 EnsureLoaded(); |
| 100 base::string16 unused; | 112 base::string16 unused; |
| 101 if (!map_->RemoveItem(key, &unused)) | 113 if (!map_->RemoveItem(key, &unused)) |
| 102 return; | 114 return; |
| 103 | 115 |
| 104 // Ignore mutations to |key| until OnRemoveItemComplete. | 116 // Ignore mutations to |key| until OnRemoveItemComplete. |
| 105 ignore_key_mutations_[key]++; | 117 ignore_key_mutations_[key]++; |
| 106 leveldb_->Delete(mojo::Array<uint8_t>::From(key), | 118 leveldb_->Delete(String16ToUint8Vector(key), |
| 107 PackSource(page_url, storage_area_id), | 119 PackSource(page_url, storage_area_id), |
| 108 base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete, | 120 base::Bind(&LocalStorageCachedArea::OnRemoveItemComplete, |
| 109 weak_factory_.GetWeakPtr(), key)); | 121 weak_factory_.GetWeakPtr(), key)); |
| 110 } | 122 } |
| 111 | 123 |
| 112 void LocalStorageCachedArea::Clear(const GURL& page_url, | 124 void LocalStorageCachedArea::Clear(const GURL& page_url, |
| 113 const std::string& storage_area_id) { | 125 const std::string& storage_area_id) { |
| 114 // No need to prime the cache in this case. | 126 // No need to prime the cache in this case. |
| 115 | 127 |
| 116 Reset(); | 128 Reset(); |
| 117 map_ = new DOMStorageMap(kPerStorageAreaQuota); | 129 map_ = new DOMStorageMap(kPerStorageAreaQuota); |
| 118 ignore_all_mutations_ = true; | 130 ignore_all_mutations_ = true; |
| 119 leveldb_->DeleteAll(PackSource(page_url, storage_area_id), | 131 leveldb_->DeleteAll(PackSource(page_url, storage_area_id), |
| 120 base::Bind(&LocalStorageCachedArea::OnClearComplete, | 132 base::Bind(&LocalStorageCachedArea::OnClearComplete, |
| 121 weak_factory_.GetWeakPtr())); | 133 weak_factory_.GetWeakPtr())); |
| 122 } | 134 } |
| 123 | 135 |
| 124 void LocalStorageCachedArea::AreaCreated(LocalStorageArea* area) { | 136 void LocalStorageCachedArea::AreaCreated(LocalStorageArea* area) { |
| 125 areas_[area->id()] = area; | 137 areas_[area->id()] = area; |
| 126 } | 138 } |
| 127 | 139 |
| 128 void LocalStorageCachedArea::AreaDestroyed(LocalStorageArea* area) { | 140 void LocalStorageCachedArea::AreaDestroyed(LocalStorageArea* area) { |
| 129 areas_.erase(area->id()); | 141 areas_.erase(area->id()); |
| 130 } | 142 } |
| 131 | 143 |
| 132 void LocalStorageCachedArea::KeyAdded(mojo::Array<uint8_t> key, | 144 void LocalStorageCachedArea::KeyAdded(const std::vector<uint8_t>& key, |
| 133 mojo::Array<uint8_t> value, | 145 const std::vector<uint8_t>& value, |
| 134 const mojo::String& source) { | 146 const std::string& source) { |
| 135 base::NullableString16 null_value; | 147 base::NullableString16 null_value; |
| 136 KeyAddedOrChanged(std::move(key), std::move(value), | 148 KeyAddedOrChanged(key, value, null_value, source); |
| 137 null_value, source); | |
| 138 } | 149 } |
| 139 | 150 |
| 140 void LocalStorageCachedArea::KeyChanged(mojo::Array<uint8_t> key, | 151 void LocalStorageCachedArea::KeyChanged(const std::vector<uint8_t>& key, |
| 141 mojo::Array<uint8_t> new_value, | 152 const std::vector<uint8_t>& new_value, |
| 142 mojo::Array<uint8_t> old_value, | 153 const std::vector<uint8_t>& old_value, |
| 143 const mojo::String& source) { | 154 const std::string& source) { |
| 144 base::NullableString16 old_value_str(old_value.To<base::string16>(), false); | 155 base::NullableString16 old_value_str(Uint8VectorToString16(old_value), false); |
| 145 KeyAddedOrChanged(std::move(key), std::move(new_value), | 156 KeyAddedOrChanged(key, new_value, old_value_str, source); |
| 146 old_value_str, source); | |
| 147 } | 157 } |
| 148 | 158 |
| 149 void LocalStorageCachedArea::KeyDeleted(mojo::Array<uint8_t> key, | 159 void LocalStorageCachedArea::KeyDeleted(const std::vector<uint8_t>& key, |
| 150 mojo::Array<uint8_t> old_value, | 160 const std::vector<uint8_t>& old_value, |
| 151 const mojo::String& source) { | 161 const std::string& source) { |
| 152 GURL page_url; | 162 GURL page_url; |
| 153 std::string storage_area_id; | 163 std::string storage_area_id; |
| 154 UnpackSource(source, &page_url, &storage_area_id); | 164 UnpackSource(source, &page_url, &storage_area_id); |
| 155 | 165 |
| 156 base::string16 key_string = key.To<base::string16>(); | 166 base::string16 key_string = Uint8VectorToString16(key); |
| 157 | 167 |
| 158 blink::WebStorageArea* originating_area = nullptr; | 168 blink::WebStorageArea* originating_area = nullptr; |
| 159 if (areas_.find(storage_area_id) != areas_.end()) { | 169 if (areas_.find(storage_area_id) != areas_.end()) { |
| 160 // The source storage area is in this process. | 170 // The source storage area is in this process. |
| 161 originating_area = areas_[storage_area_id]; | 171 originating_area = areas_[storage_area_id]; |
| 162 } else if (map_ && !ignore_all_mutations_) { | 172 } else if (map_ && !ignore_all_mutations_) { |
| 163 // This was from another process or the storage area is gone. If the former, | 173 // This was from another process or the storage area is gone. If the former, |
| 164 // remove it from our cache if we haven't already changed it and are waiting | 174 // remove it from our cache if we haven't already changed it and are waiting |
| 165 // for the confirmation callback. In the latter case, we won't do anything | 175 // for the confirmation callback. In the latter case, we won't do anything |
| 166 // because ignore_key_mutations_ won't be updated until the callback runs. | 176 // because ignore_key_mutations_ won't be updated until the callback runs. |
| 167 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { | 177 if (ignore_key_mutations_.find(key_string) != ignore_key_mutations_.end()) { |
| 168 base::string16 unused; | 178 base::string16 unused; |
| 169 map_->RemoveItem(key_string, &unused); | 179 map_->RemoveItem(key_string, &unused); |
| 170 } | 180 } |
| 171 } | 181 } |
| 172 | 182 |
| 173 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( | 183 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
| 174 key_string, old_value.To<base::string16>(), base::NullableString16(), | 184 key_string, Uint8VectorToString16(old_value), base::NullableString16(), |
| 175 GURL(origin_.Serialize()), page_url, originating_area); | 185 GURL(origin_.Serialize()), page_url, originating_area); |
| 176 } | 186 } |
| 177 | 187 |
| 178 void LocalStorageCachedArea::AllDeleted(const mojo::String& source) { | 188 void LocalStorageCachedArea::AllDeleted(const std::string& source) { |
| 179 GURL page_url; | 189 GURL page_url; |
| 180 std::string storage_area_id; | 190 std::string storage_area_id; |
| 181 UnpackSource(source, &page_url, &storage_area_id); | 191 UnpackSource(source, &page_url, &storage_area_id); |
| 182 | 192 |
| 183 blink::WebStorageArea* originating_area = nullptr; | 193 blink::WebStorageArea* originating_area = nullptr; |
| 184 if (areas_.find(storage_area_id) != areas_.end()) { | 194 if (areas_.find(storage_area_id) != areas_.end()) { |
| 185 // The source storage area is in this process. | 195 // The source storage area is in this process. |
| 186 originating_area = areas_[storage_area_id]; | 196 originating_area = areas_[storage_area_id]; |
| 187 } else if (map_ && !ignore_all_mutations_) { | 197 } else if (map_ && !ignore_all_mutations_) { |
| 188 scoped_refptr<DOMStorageMap> old = map_; | 198 scoped_refptr<DOMStorageMap> old = map_; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 200 ++iter; | 210 ++iter; |
| 201 } | 211 } |
| 202 } | 212 } |
| 203 | 213 |
| 204 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( | 214 blink::WebStorageEventDispatcher::dispatchLocalStorageEvent( |
| 205 base::NullableString16(), base::NullableString16(), | 215 base::NullableString16(), base::NullableString16(), |
| 206 base::NullableString16(), GURL(origin_.Serialize()), page_url, | 216 base::NullableString16(), GURL(origin_.Serialize()), page_url, |
| 207 originating_area); | 217 originating_area); |
| 208 } | 218 } |
| 209 | 219 |
| 210 void LocalStorageCachedArea::GetAllComplete(const mojo::String& source) { | 220 void LocalStorageCachedArea::GetAllComplete(const std::string& source) { |
| 211 // Since the GetAll method is synchronous, we need this asynchronously | 221 // Since the GetAll method is synchronous, we need this asynchronously |
| 212 // delivered notification to avoid applying changes to the returned array | 222 // delivered notification to avoid applying changes to the returned array |
| 213 // that we already have. | 223 // that we already have. |
| 214 if (source.To<std::string>() == get_all_request_id_) { | 224 if (source == get_all_request_id_) { |
| 215 DCHECK(ignore_all_mutations_); | 225 DCHECK(ignore_all_mutations_); |
| 216 DCHECK(!get_all_request_id_.empty()); | 226 DCHECK(!get_all_request_id_.empty()); |
| 217 ignore_all_mutations_ = false; | 227 ignore_all_mutations_ = false; |
| 218 get_all_request_id_.clear(); | 228 get_all_request_id_.clear(); |
| 219 } | 229 } |
| 220 } | 230 } |
| 221 | 231 |
| 222 void LocalStorageCachedArea::KeyAddedOrChanged( | 232 void LocalStorageCachedArea::KeyAddedOrChanged( |
| 223 mojo::Array<uint8_t> key, | 233 const std::vector<uint8_t>& key, |
| 224 mojo::Array<uint8_t> new_value, | 234 const std::vector<uint8_t>& new_value, |
| 225 const base::NullableString16& old_value, | 235 const base::NullableString16& old_value, |
| 226 const mojo::String& source) { | 236 const std::string& source) { |
| 227 GURL page_url; | 237 GURL page_url; |
| 228 std::string storage_area_id; | 238 std::string storage_area_id; |
| 229 UnpackSource(source, &page_url, &storage_area_id); | 239 UnpackSource(source, &page_url, &storage_area_id); |
| 230 | 240 |
| 231 base::string16 key_string = key.To<base::string16>(); | 241 base::string16 key_string = Uint8VectorToString16(key); |
| 232 base::string16 new_value_string = new_value.To<base::string16>(); | 242 base::string16 new_value_string = Uint8VectorToString16(new_value); |
| 233 | 243 |
| 234 blink::WebStorageArea* originating_area = nullptr; | 244 blink::WebStorageArea* originating_area = nullptr; |
| 235 if (areas_.find(storage_area_id) != areas_.end()) { | 245 if (areas_.find(storage_area_id) != areas_.end()) { |
| 236 // The source storage area is in this process. | 246 // The source storage area is in this process. |
| 237 originating_area = areas_[storage_area_id]; | 247 originating_area = areas_[storage_area_id]; |
| 238 } else if (map_ && !ignore_all_mutations_) { | 248 } else if (map_ && !ignore_all_mutations_) { |
| 239 // This was from another process or the storage area is gone. If the former, | 249 // This was from another process or the storage area is gone. If the former, |
| 240 // apply it to our cache if we haven't already changed it and are waiting | 250 // apply it to our cache if we haven't already changed it and are waiting |
| 241 // for the confirmation callback. In the latter case, we won't do anything | 251 // for the confirmation callback. In the latter case, we won't do anything |
| 242 // because ignore_key_mutations_ won't be updated until the callback runs. | 252 // because ignore_key_mutations_ won't be updated until the callback runs. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 257 } | 267 } |
| 258 | 268 |
| 259 void LocalStorageCachedArea::EnsureLoaded() { | 269 void LocalStorageCachedArea::EnsureLoaded() { |
| 260 if (map_) | 270 if (map_) |
| 261 return; | 271 return; |
| 262 | 272 |
| 263 base::TimeTicks before = base::TimeTicks::Now(); | 273 base::TimeTicks before = base::TimeTicks::Now(); |
| 264 ignore_all_mutations_ = true; | 274 ignore_all_mutations_ = true; |
| 265 get_all_request_id_ = base::Uint64ToString(base::RandUint64()); | 275 get_all_request_id_ = base::Uint64ToString(base::RandUint64()); |
| 266 leveldb::mojom::DatabaseError status = leveldb::mojom::DatabaseError::OK; | 276 leveldb::mojom::DatabaseError status = leveldb::mojom::DatabaseError::OK; |
| 267 mojo::Array<content::mojom::KeyValuePtr> data; | 277 std::vector<content::mojom::KeyValuePtr> data; |
| 268 leveldb_->GetAll(get_all_request_id_, &status, &data); | 278 leveldb_->GetAll(get_all_request_id_, &status, &data); |
| 269 | 279 |
| 270 DOMStorageValuesMap values; | 280 DOMStorageValuesMap values; |
| 271 for (size_t i = 0; i < data.size(); ++i) { | 281 for (size_t i = 0; i < data.size(); ++i) { |
| 272 values[data[i]->key.To<base::string16>()] = | 282 values[Uint8VectorToString16(data[i]->key)] = |
| 273 base::NullableString16(data[i]->value.To<base::string16>(), false); | 283 base::NullableString16(Uint8VectorToString16(data[i]->value), false); |
| 274 } | 284 } |
| 275 | 285 |
| 276 map_ = new DOMStorageMap(kPerStorageAreaQuota); | 286 map_ = new DOMStorageMap(kPerStorageAreaQuota); |
| 277 map_->SwapValues(&values); | 287 map_->SwapValues(&values); |
| 278 | 288 |
| 279 base::TimeDelta time_to_prime = base::TimeTicks::Now() - before; | 289 base::TimeDelta time_to_prime = base::TimeTicks::Now() - before; |
| 280 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrime", time_to_prime); | 290 UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrime", time_to_prime); |
| 281 | 291 |
| 282 size_t local_storage_size_kb = map_->bytes_used() / 1024; | 292 size_t local_storage_size_kb = map_->bytes_used() / 1024; |
| 283 // Track localStorage size, from 0-6MB. Note that the maximum size should be | 293 // Track localStorage size, from 0-6MB. Note that the maximum size should be |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 } | 337 } |
| 328 | 338 |
| 329 void LocalStorageCachedArea::Reset() { | 339 void LocalStorageCachedArea::Reset() { |
| 330 map_ = NULL; | 340 map_ = NULL; |
| 331 ignore_key_mutations_.clear(); | 341 ignore_key_mutations_.clear(); |
| 332 ignore_all_mutations_ = false; | 342 ignore_all_mutations_ = false; |
| 333 weak_factory_.InvalidateWeakPtrs(); | 343 weak_factory_.InvalidateWeakPtrs(); |
| 334 } | 344 } |
| 335 | 345 |
| 336 } // namespace content | 346 } // namespace content |
| OLD | NEW |