1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/dom_storage/dom_storage_host.h" 6 7 #include "content/browser/dom_storage/dom_storage_area.h" 8 #include "content/browser/dom_storage/dom_storage_context_impl.h" 9 #include "content/browser/dom_storage/dom_storage_namespace.h" 10 #include "content/common/dom_storage/dom_storage_types.h" 11 #include "url/gurl.h" 12 13 namespace content { 14 15 DOMStorageHost::DOMStorageHost(DOMStorageContextImpl* context, 16 int render_process_id) 17 : context_(context), 18 render_process_id_(render_process_id) { 19 } 20 21 DOMStorageHost::~DOMStorageHost() { 22 AreaMap::const_iterator it = connections_.begin(); 23 for (; it != connections_.end(); ++it) 24 it->second.namespace_->CloseStorageArea(it->second.area_.get()); 25 connections_.clear(); // Clear prior to releasing the context_ 26 } 27 28 bool DOMStorageHost::OpenStorageArea(int connection_id, int namespace_id, 29 const GURL& origin) { 30 DCHECK(!GetOpenArea(connection_id)); 31 if (GetOpenArea(connection_id)) 32 return false; // Indicates the renderer gave us very bad data. 33 NamespaceAndArea references; 34 references.namespace_ = context_->GetStorageNamespace(namespace_id); 35 if (!references.namespace_.get()) 36 return false; 37 references.area_ = references.namespace_->OpenStorageArea(origin); 38 DCHECK(references.area_.get()); 39 connections_[connection_id] = references; 40 return true; 41 } 42 43 void DOMStorageHost::CloseStorageArea(int connection_id) { 44 AreaMap::iterator found = connections_.find(connection_id); 45 if (found == connections_.end()) 46 return; 47 found->second.namespace_->CloseStorageArea(found->second.area_.get()); 48 connections_.erase(found); 49 } 50 51 bool DOMStorageHost::ExtractAreaValues( 52 int connection_id, DOMStorageValuesMap* map, bool* send_log_get_messages) { 53 map->clear(); 54 DOMStorageArea* area = GetOpenArea(connection_id); 55 if (!area) 56 return false; 57 if (!area->IsLoadedInMemory()) { 58 DOMStorageNamespace* ns = GetNamespace(connection_id); 59 DCHECK(ns); 60 if (ns->CountInMemoryAreas() > kMaxInMemoryStorageAreas) { 61 ns->PurgeMemory(DOMStorageNamespace::PURGE_UNOPENED); 62 if (ns->CountInMemoryAreas() > kMaxInMemoryStorageAreas) 63 ns->PurgeMemory(DOMStorageNamespace::PURGE_AGGRESSIVE); 64 } 65 } 66 area->ExtractValues(map); 67 *send_log_get_messages = false; 68 DOMStorageNamespace* ns = GetNamespace(connection_id); 69 DCHECK(ns); 70 *send_log_get_messages = ns->IsLoggingRenderer(render_process_id_); 71 return true; 72 } 73 74 unsigned DOMStorageHost::GetAreaLength(int connection_id) { 75 DOMStorageArea* area = GetOpenArea(connection_id); 76 if (!area) 77 return 0; 78 return area->Length(); 79 } 80 81 base::NullableString16 DOMStorageHost::GetAreaKey(int connection_id, 82 unsigned index) { 83 DOMStorageArea* area = GetOpenArea(connection_id); 84 if (!area) 85 return base::NullableString16(); 86 return area->Key(index); 87 } 88 89 base::NullableString16 DOMStorageHost::GetAreaItem(int connection_id, 90 const base::string16& key) { 91 DOMStorageArea* area = GetOpenArea(connection_id); 92 if (!area) 93 return base::NullableString16(); 94 return area->GetItem(key); 95 } 96 97 bool DOMStorageHost::SetAreaItem( 98 int connection_id, const base::string16& key, 99 const base::string16& value, const GURL& page_url, 100 base::NullableString16* old_value) { 101 DOMStorageArea* area = GetOpenArea(connection_id); 102 if (!area) 103 return false; 104 if (!area->SetItem(key, value, old_value)) 105 return false; 106 if (old_value->is_null() || old_value->string() != value) 107 context_->NotifyItemSet(area, key, value, *old_value, page_url); 108 MaybeLogTransaction(connection_id, 109 DOMStorageNamespace::TRANSACTION_WRITE, 110 area->origin(), page_url, key, 111 base::NullableString16(value, false)); 112 return true; 113 } 114 115 void DOMStorageHost::LogGetAreaItem( 116 int connection_id, const base::string16& key, 117 const base::NullableString16& value) { 118 DOMStorageArea* area = GetOpenArea(connection_id); 119 if (!area) 120 return; 121 MaybeLogTransaction(connection_id, 122 DOMStorageNamespace::TRANSACTION_READ, 123 area->origin(), GURL(), key, value); 124 } 125 126 bool DOMStorageHost::RemoveAreaItem( 127 int connection_id, const base::string16& key, const GURL& page_url, 128 base::string16* old_value) { 129 DOMStorageArea* area = GetOpenArea(connection_id); 130 if (!area) 131 return false; 132 if (!area->RemoveItem(key, old_value)) 133 return false; 134 context_->NotifyItemRemoved(area, key, *old_value, page_url); 135 MaybeLogTransaction(connection_id, 136 DOMStorageNamespace::TRANSACTION_REMOVE, 137 area->origin(), page_url, key, base::NullableString16()); 138 return true; 139 } 140 141 bool DOMStorageHost::ClearArea(int connection_id, const GURL& page_url) { 142 DOMStorageArea* area = GetOpenArea(connection_id); 143 if (!area) 144 return false; 145 if (!area->Clear()) 146 return false; 147 context_->NotifyAreaCleared(area, page_url); 148 MaybeLogTransaction(connection_id, 149 DOMStorageNamespace::TRANSACTION_CLEAR, 150 area->origin(), page_url, base::string16(), 151 base::NullableString16()); 152 return true; 153 } 154 155 bool DOMStorageHost::HasAreaOpen( 156 int64 namespace_id, const GURL& origin, int64* alias_namespace_id) const { 157 AreaMap::const_iterator it = connections_.begin(); 158 for (; it != connections_.end(); ++it) { 159 if (namespace_id == it->second.area_->namespace_id() && 160 origin == it->second.area_->origin()) { 161 *alias_namespace_id = it->second.namespace_->namespace_id(); 162 return true; 163 } 164 } 165 return false; 166 } 167 168 bool DOMStorageHost::ResetOpenAreasForNamespace(int64 namespace_id) { 169 bool result = false; 170 AreaMap::iterator it = connections_.begin(); 171 for (; it != connections_.end(); ++it) { 172 if (namespace_id == it->second.namespace_->namespace_id()) { 173 GURL origin = it->second.area_->origin(); 174 it->second.namespace_->CloseStorageArea(it->second.area_.get()); 175 it->second.area_ = it->second.namespace_->OpenStorageArea(origin); 176 result = true; 177 } 178 } 179 return result; 180 } 181 182 DOMStorageArea* DOMStorageHost::GetOpenArea(int connection_id) { 183 AreaMap::iterator found = connections_.find(connection_id); 184 if (found == connections_.end()) 185 return NULL; 186 return found->second.area_.get(); 187 } 188 189 DOMStorageNamespace* DOMStorageHost::GetNamespace(int connection_id) { 190 AreaMap::iterator found = connections_.find(connection_id); 191 if (found == connections_.end()) 192 return NULL; 193 return found->second.namespace_.get(); 194 } 195 196 void DOMStorageHost::MaybeLogTransaction( 197 int connection_id, 198 DOMStorageNamespace::LogType transaction_type, 199 const GURL& origin, 200 const GURL& page_url, 201 const base::string16& key, 202 const base::NullableString16& value) { 203 DOMStorageNamespace* ns = GetNamespace(connection_id); 204 DCHECK(ns); 205 if (!ns->IsLoggingRenderer(render_process_id_)) 206 return; 207 DOMStorageNamespace::TransactionRecord transaction; 208 transaction.transaction_type = transaction_type; 209 transaction.origin = origin; 210 transaction.page_url = page_url; 211 transaction.key = key; 212 transaction.value = value; 213 ns->AddTransaction(render_process_id_, transaction); 214 } 215 216 // NamespaceAndArea 217 218 DOMStorageHost::NamespaceAndArea::NamespaceAndArea() {} 219 DOMStorageHost::NamespaceAndArea::~NamespaceAndArea() {} 220 221 } // namespace content 222