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
DOMStorageHost(DOMStorageContextImpl * context,int render_process_id)15 DOMStorageHost::DOMStorageHost(DOMStorageContextImpl* context,
16 int render_process_id)
17 : context_(context),
18 render_process_id_(render_process_id) {
19 }
20
~DOMStorageHost()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
OpenStorageArea(int connection_id,int namespace_id,const GURL & origin)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
CloseStorageArea(int connection_id)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
ExtractAreaValues(int connection_id,DOMStorageValuesMap * map,bool * send_log_get_messages)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
GetAreaLength(int connection_id)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
GetAreaKey(int connection_id,unsigned index)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
GetAreaItem(int connection_id,const base::string16 & key)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
SetAreaItem(int connection_id,const base::string16 & key,const base::string16 & value,const GURL & page_url,base::NullableString16 * old_value)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
LogGetAreaItem(int connection_id,const base::string16 & key,const base::NullableString16 & value)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
RemoveAreaItem(int connection_id,const base::string16 & key,const GURL & page_url,base::string16 * old_value)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
ClearArea(int connection_id,const GURL & page_url)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
HasAreaOpen(int64 namespace_id,const GURL & origin,int64 * alias_namespace_id) const155 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
ResetOpenAreasForNamespace(int64 namespace_id)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
GetOpenArea(int connection_id)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
GetNamespace(int connection_id)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
MaybeLogTransaction(int connection_id,DOMStorageNamespace::LogType transaction_type,const GURL & origin,const GURL & page_url,const base::string16 & key,const base::NullableString16 & value)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
NamespaceAndArea()218 DOMStorageHost::NamespaceAndArea::NamespaceAndArea() {}
~NamespaceAndArea()219 DOMStorageHost::NamespaceAndArea::~NamespaceAndArea() {}
220
221 } // namespace content
222