OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/v8_value_converter_impl.h" | 5 #include "content/renderer/v8_value_converter_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
47 v8::Context::Scope context_scope(context); | 47 v8::Context::Scope context_scope(context); |
48 v8::HandleScope handle_scope; | 48 v8::HandleScope handle_scope; |
49 return handle_scope.Close(ToV8ValueImpl(value)); | 49 return handle_scope.Close(ToV8ValueImpl(value)); |
50 } | 50 } |
51 | 51 |
52 Value* V8ValueConverterImpl::FromV8Value( | 52 Value* V8ValueConverterImpl::FromV8Value( |
53 v8::Handle<v8::Value> val, | 53 v8::Handle<v8::Value> val, |
54 v8::Handle<v8::Context> context) const { | 54 v8::Handle<v8::Context> context) const { |
55 v8::Context::Scope context_scope(context); | 55 v8::Context::Scope context_scope(context); |
56 v8::HandleScope handle_scope; | 56 v8::HandleScope handle_scope; |
57 std::set<int> unique_set; | 57 HashToHandleMap unique_map; |
58 return FromV8ValueImpl(val, &unique_set); | 58 return FromV8ValueImpl(val, &unique_map); |
59 } | 59 } |
60 | 60 |
61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( | 61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( |
62 const base::Value* value) const { | 62 const base::Value* value) const { |
63 CHECK(value); | 63 CHECK(value); |
64 switch (value->GetType()) { | 64 switch (value->GetType()) { |
65 case base::Value::TYPE_NULL: | 65 case base::Value::TYPE_NULL: |
66 return v8::Null(); | 66 return v8::Null(); |
67 | 67 |
68 case base::Value::TYPE_BOOLEAN: { | 68 case base::Value::TYPE_BOOLEAN: { |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
147 | 147 |
148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( | 148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( |
149 const base::BinaryValue* value) const { | 149 const base::BinaryValue* value) const { |
150 WebKit::WebArrayBuffer buffer = | 150 WebKit::WebArrayBuffer buffer = |
151 WebKit::WebArrayBuffer::create(value->GetSize(), 1); | 151 WebKit::WebArrayBuffer::create(value->GetSize(), 1); |
152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); | 152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); |
153 return buffer.toV8Value(); | 153 return buffer.toV8Value(); |
154 } | 154 } |
155 | 155 |
156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, | 156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, |
157 std::set<int>* unique_set) const { | 157 HashToHandleMap* unique_map) const { |
158 CHECK(!val.IsEmpty()); | 158 CHECK(!val.IsEmpty()); |
159 | 159 |
160 if (val->IsNull()) | 160 if (val->IsNull()) |
161 return base::Value::CreateNullValue(); | 161 return base::Value::CreateNullValue(); |
162 | 162 |
163 if (val->IsBoolean()) | 163 if (val->IsBoolean()) |
164 return new base::FundamentalValue(val->ToBoolean()->Value()); | 164 return new base::FundamentalValue(val->ToBoolean()->Value()); |
165 | 165 |
166 if (val->IsInt32()) | 166 if (val->IsInt32()) |
167 return new base::FundamentalValue(val->ToInt32()->Value()); | 167 return new base::FundamentalValue(val->ToInt32()->Value()); |
168 | 168 |
169 if (val->IsNumber()) | 169 if (val->IsNumber()) |
170 return new base::FundamentalValue(val->ToNumber()->Value()); | 170 return new base::FundamentalValue(val->ToNumber()->Value()); |
171 | 171 |
172 if (val->IsString()) { | 172 if (val->IsString()) { |
173 v8::String::Utf8Value utf8(val->ToString()); | 173 v8::String::Utf8Value utf8(val->ToString()); |
174 return new base::StringValue(std::string(*utf8, utf8.length())); | 174 return new base::StringValue(std::string(*utf8, utf8.length())); |
175 } | 175 } |
176 | 176 |
177 if (val->IsUndefined()) | 177 if (val->IsUndefined()) |
178 // JSON.stringify ignores undefined. | 178 // JSON.stringify ignores undefined. |
179 return NULL; | 179 return NULL; |
180 | 180 |
181 if (val->IsDate()) { | 181 if (val->IsDate()) { |
182 if (!date_allowed_) | 182 if (!date_allowed_) |
183 // JSON.stringify would convert this to a string, but an object is more | 183 // JSON.stringify would convert this to a string, but an object is more |
184 // consistent within this class. | 184 // consistent within this class. |
185 return FromV8Object(val->ToObject(), unique_set); | 185 return FromV8Object(val->ToObject(), unique_map); |
186 v8::Date* date = v8::Date::Cast(*val); | 186 v8::Date* date = v8::Date::Cast(*val); |
187 return new base::FundamentalValue(date->NumberValue() / 1000.0); | 187 return new base::FundamentalValue(date->NumberValue() / 1000.0); |
188 } | 188 } |
189 | 189 |
190 if (val->IsRegExp()) { | 190 if (val->IsRegExp()) { |
191 if (!reg_exp_allowed_) | 191 if (!reg_exp_allowed_) |
192 // JSON.stringify converts to an object. | 192 // JSON.stringify converts to an object. |
193 return FromV8Object(val->ToObject(), unique_set); | 193 return FromV8Object(val->ToObject(), unique_map); |
194 return new base::StringValue(*v8::String::Utf8Value(val->ToString())); | 194 return new base::StringValue(*v8::String::Utf8Value(val->ToString())); |
195 } | 195 } |
196 | 196 |
197 // v8::Value doesn't have a ToArray() method for some reason. | 197 // v8::Value doesn't have a ToArray() method for some reason. |
198 if (val->IsArray()) | 198 if (val->IsArray()) |
199 return FromV8Array(val.As<v8::Array>(), unique_set); | 199 return FromV8Array(val.As<v8::Array>(), unique_map); |
200 | 200 |
201 if (val->IsFunction()) { | 201 if (val->IsFunction()) { |
202 if (!function_allowed_) | 202 if (!function_allowed_) |
203 // JSON.stringify refuses to convert function(){}. | 203 // JSON.stringify refuses to convert function(){}. |
204 return NULL; | 204 return NULL; |
205 return FromV8Object(val->ToObject(), unique_set); | 205 return FromV8Object(val->ToObject(), unique_map); |
206 } | 206 } |
207 | 207 |
208 if (val->IsObject()) { | 208 if (val->IsObject()) { |
209 base::BinaryValue* binary_value = FromV8Buffer(val); | 209 base::BinaryValue* binary_value = FromV8Buffer(val); |
210 if (binary_value) { | 210 if (binary_value) { |
211 return binary_value; | 211 return binary_value; |
212 } else { | 212 } else { |
213 return FromV8Object(val->ToObject(), unique_set); | 213 return FromV8Object(val->ToObject(), unique_map); |
214 } | 214 } |
215 } | 215 } |
216 | 216 |
217 LOG(ERROR) << "Unexpected v8 value type encountered."; | 217 LOG(ERROR) << "Unexpected v8 value type encountered."; |
218 return NULL; | 218 return NULL; |
219 } | 219 } |
220 | 220 |
221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, | 221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, |
222 std::set<int>* unique_set) const { | 222 HashToHandleMap* unique_map) const { |
223 if (unique_set && unique_set->count(val->GetIdentityHash())) | 223 if (!UpdateAndCheckUniqueness(unique_map, v8::Handle<v8::Array>::Cast(val))) |
eaugusti
2013/03/14 17:21:09
Why the cast? Is it necessary?
vabr (Chromium)
2013/03/14 17:59:37
It was not! Thanks. :)
| |
224 return base::Value::CreateNullValue(); | 224 return base::Value::CreateNullValue(); |
225 | 225 |
226 scoped_ptr<v8::Context::Scope> scope; | 226 scoped_ptr<v8::Context::Scope> scope; |
227 // If val was created in a different context than our current one, change to | 227 // If val was created in a different context than our current one, change to |
228 // that context, but change back after val is converted. | 228 // that context, but change back after val is converted. |
229 if (!val->CreationContext().IsEmpty() && | 229 if (!val->CreationContext().IsEmpty() && |
230 val->CreationContext() != v8::Context::GetCurrent()) | 230 val->CreationContext() != v8::Context::GetCurrent()) |
231 scope.reset(new v8::Context::Scope(val->CreationContext())); | 231 scope.reset(new v8::Context::Scope(val->CreationContext())); |
232 | 232 |
233 base::ListValue* result = new base::ListValue(); | 233 base::ListValue* result = new base::ListValue(); |
234 | 234 |
235 if (unique_set) | |
236 unique_set->insert(val->GetIdentityHash()); | |
237 // Only fields with integer keys are carried over to the ListValue. | 235 // Only fields with integer keys are carried over to the ListValue. |
238 for (uint32 i = 0; i < val->Length(); ++i) { | 236 for (uint32 i = 0; i < val->Length(); ++i) { |
239 v8::TryCatch try_catch; | 237 v8::TryCatch try_catch; |
240 v8::Handle<v8::Value> child_v8 = val->Get(i); | 238 v8::Handle<v8::Value> child_v8 = val->Get(i); |
241 if (try_catch.HasCaught()) { | 239 if (try_catch.HasCaught()) { |
242 LOG(ERROR) << "Getter for index " << i << " threw an exception."; | 240 LOG(ERROR) << "Getter for index " << i << " threw an exception."; |
243 child_v8 = v8::Null(); | 241 child_v8 = v8::Null(); |
244 } | 242 } |
245 | 243 |
246 if (!val->HasRealIndexedProperty(i)) | 244 if (!val->HasRealIndexedProperty(i)) |
247 continue; | 245 continue; |
248 | 246 |
249 base::Value* child = FromV8ValueImpl(child_v8, unique_set); | 247 base::Value* child = FromV8ValueImpl(child_v8, unique_map); |
250 if (child) | 248 if (child) |
251 result->Append(child); | 249 result->Append(child); |
252 else | 250 else |
253 // JSON.stringify puts null in places where values don't serialize, for | 251 // JSON.stringify puts null in places where values don't serialize, for |
254 // example undefined and functions. Emulate that behavior. | 252 // example undefined and functions. Emulate that behavior. |
255 result->Append(base::Value::CreateNullValue()); | 253 result->Append(base::Value::CreateNullValue()); |
256 } | 254 } |
257 return result; | 255 return result; |
258 } | 256 } |
259 | 257 |
(...skipping 17 matching lines...) Expand all Loading... | |
277 } | 275 } |
278 | 276 |
279 if (data) | 277 if (data) |
280 return base::BinaryValue::CreateWithCopiedBuffer(data, length); | 278 return base::BinaryValue::CreateWithCopiedBuffer(data, length); |
281 else | 279 else |
282 return NULL; | 280 return NULL; |
283 } | 281 } |
284 | 282 |
285 Value* V8ValueConverterImpl::FromV8Object( | 283 Value* V8ValueConverterImpl::FromV8Object( |
286 v8::Handle<v8::Object> val, | 284 v8::Handle<v8::Object> val, |
287 std::set<int>* unique_set) const { | 285 HashToHandleMap* unique_map) const { |
288 if (unique_set && unique_set->count(val->GetIdentityHash())) | 286 if (!UpdateAndCheckUniqueness(unique_map, val)) |
289 return base::Value::CreateNullValue(); | 287 return base::Value::CreateNullValue(); |
290 scoped_ptr<v8::Context::Scope> scope; | 288 scoped_ptr<v8::Context::Scope> scope; |
291 // If val was created in a different context than our current one, change to | 289 // If val was created in a different context than our current one, change to |
292 // that context, but change back after val is converted. | 290 // that context, but change back after val is converted. |
293 if (!val->CreationContext().IsEmpty() && | 291 if (!val->CreationContext().IsEmpty() && |
294 val->CreationContext() != v8::Context::GetCurrent()) | 292 val->CreationContext() != v8::Context::GetCurrent()) |
295 scope.reset(new v8::Context::Scope(val->CreationContext())); | 293 scope.reset(new v8::Context::Scope(val->CreationContext())); |
296 | 294 |
297 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 295 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
298 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); | 296 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); |
299 | 297 |
300 if (unique_set) | |
301 unique_set->insert(val->GetIdentityHash()); | |
302 | |
303 for (uint32 i = 0; i < property_names->Length(); ++i) { | 298 for (uint32 i = 0; i < property_names->Length(); ++i) { |
304 v8::Handle<v8::Value> key(property_names->Get(i)); | 299 v8::Handle<v8::Value> key(property_names->Get(i)); |
305 | 300 |
306 // Extend this test to cover more types as necessary and if sensible. | 301 // Extend this test to cover more types as necessary and if sensible. |
307 if (!key->IsString() && | 302 if (!key->IsString() && |
308 !key->IsNumber()) { | 303 !key->IsNumber()) { |
309 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" " | 304 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" " |
310 "is neither a string nor a number"; | 305 "is neither a string nor a number"; |
311 continue; | 306 continue; |
312 } | 307 } |
313 | 308 |
314 // Skip all callbacks: crbug.com/139933 | 309 // Skip all callbacks: crbug.com/139933 |
315 if (val->HasRealNamedCallbackProperty(key->ToString())) | 310 if (val->HasRealNamedCallbackProperty(key->ToString())) |
316 continue; | 311 continue; |
317 | 312 |
318 v8::String::Utf8Value name_utf8(key->ToString()); | 313 v8::String::Utf8Value name_utf8(key->ToString()); |
319 | 314 |
320 v8::TryCatch try_catch; | 315 v8::TryCatch try_catch; |
321 v8::Handle<v8::Value> child_v8 = val->Get(key); | 316 v8::Handle<v8::Value> child_v8 = val->Get(key); |
322 | 317 |
323 if (try_catch.HasCaught()) { | 318 if (try_catch.HasCaught()) { |
324 LOG(ERROR) << "Getter for property " << *name_utf8 | 319 LOG(ERROR) << "Getter for property " << *name_utf8 |
325 << " threw an exception."; | 320 << " threw an exception."; |
326 child_v8 = v8::Null(); | 321 child_v8 = v8::Null(); |
327 } | 322 } |
328 | 323 |
329 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_set)); | 324 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map)); |
330 if (!child.get()) | 325 if (!child.get()) |
331 // JSON.stringify skips properties whose values don't serialize, for | 326 // JSON.stringify skips properties whose values don't serialize, for |
332 // example undefined and functions. Emulate that behavior. | 327 // example undefined and functions. Emulate that behavior. |
333 continue; | 328 continue; |
334 | 329 |
335 // Strip null if asked (and since undefined is turned into null, undefined | 330 // Strip null if asked (and since undefined is turned into null, undefined |
336 // too). The use case for supporting this is JSON-schema support, | 331 // too). The use case for supporting this is JSON-schema support, |
337 // specifically for extensions, where "optional" JSON properties may be | 332 // specifically for extensions, where "optional" JSON properties may be |
338 // represented as null, yet due to buggy legacy code elsewhere isn't | 333 // represented as null, yet due to buggy legacy code elsewhere isn't |
339 // treated as such (potentially causing crashes). For example, the | 334 // treated as such (potentially causing crashes). For example, the |
(...skipping 15 matching lines...) Expand all Loading... | |
355 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) | 350 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) |
356 continue; | 351 continue; |
357 | 352 |
358 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), | 353 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), |
359 child.release()); | 354 child.release()); |
360 } | 355 } |
361 | 356 |
362 return result.release(); | 357 return result.release(); |
363 } | 358 } |
364 | 359 |
360 // static | |
361 bool V8ValueConverterImpl::UpdateAndCheckUniqueness( | |
eaugusti
2013/03/14 17:21:09
Maybe add a comment about how uniqueness is define
vabr (Chromium)
2013/03/14 17:59:37
Done.
I added a comment about the uniqueness to th
| |
362 HashToHandleMap* map, | |
363 v8::Handle<v8::Object> handle) { | |
364 typedef HashToHandleMap::const_iterator Iterator; | |
365 | |
366 int hash = handle->GetIdentityHash(); | |
367 std::pair<Iterator, Iterator> range = map->equal_range(hash); | |
368 bool found = false; | |
369 for (Iterator it = range.first; !false && it != range.second; ++it) { | |
eaugusti
2013/03/14 17:21:09
Why the "!false"?
vabr (Chromium)
2013/03/14 17:59:37
Thanks for catching that, was meant to be !found.
| |
370 found |= it->second == handle; | |
371 } | |
eaugusti
2013/03/14 17:21:09
nit: drop the braces on the for.
vabr (Chromium)
2013/03/14 17:59:37
No longer can due to the added comment.
| |
372 | |
373 if (found) | |
374 return false; | |
375 | |
376 map->insert(std::pair<int, v8::Handle<v8::Object> >(hash, handle)); | |
377 return true; | |
378 } | |
379 | |
365 } // namespace content | 380 } // namespace content |
OLD | NEW |