| 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" |
| 11 #include "base/values.h" | 11 #include "base/values.h" |
| 12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h" | 12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h" |
| 13 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebArrayBuff
erView.h" | 13 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebArrayBuff
erView.h" |
| 14 #include "v8/include/v8.h" | 14 #include "v8/include/v8.h" |
| 15 | 15 |
| 16 using base::BinaryValue; | 16 using base::BinaryValue; |
| 17 using base::DictionaryValue; | 17 using base::DictionaryValue; |
| 18 using base::ListValue; | 18 using base::ListValue; |
| 19 using base::StringValue; | 19 using base::StringValue; |
| 20 using base::Value; | 20 using base::Value; |
| 21 | 21 |
| 22 namespace content { | 22 namespace content { |
| 23 | 23 |
| 24 V8ValueConverter* V8ValueConverter::create() { | 24 V8ValueConverter* V8ValueConverter::create() { |
| 25 return new V8ValueConverterImpl(); | 25 return new V8ValueConverterImpl(); |
| 26 } | 26 } |
| 27 } // namespace content | 27 } // namespace content |
| 28 | 28 |
| 29 V8ValueConverterImpl::V8ValueConverterImpl() | 29 V8ValueConverterImpl::V8ValueConverterImpl() |
| 30 : undefined_allowed_(false), | 30 : date_allowed_(false), |
| 31 date_allowed_(false), | 31 reg_exp_allowed_(false), |
| 32 regexp_allowed_(false), | 32 function_allowed_(false), |
| 33 strip_null_from_objects_(false) { | 33 strip_null_from_objects_(false) { |
| 34 } | 34 } |
| 35 | 35 |
| 36 bool V8ValueConverterImpl::GetUndefinedAllowed() const { | |
| 37 return undefined_allowed_; | |
| 38 } | |
| 39 | |
| 40 void V8ValueConverterImpl::SetUndefinedAllowed(bool val) { | |
| 41 undefined_allowed_ = val; | |
| 42 } | |
| 43 | |
| 44 bool V8ValueConverterImpl::GetDateAllowed() const { | |
| 45 return date_allowed_; | |
| 46 } | |
| 47 | |
| 48 void V8ValueConverterImpl::SetDateAllowed(bool val) { | 36 void V8ValueConverterImpl::SetDateAllowed(bool val) { |
| 49 date_allowed_ = val; | 37 date_allowed_ = val; |
| 50 } | 38 } |
| 51 | 39 |
| 52 bool V8ValueConverterImpl::GetRegexpAllowed() const { | 40 void V8ValueConverterImpl::SetRegExpAllowed(bool val) { |
| 53 return regexp_allowed_; | 41 reg_exp_allowed_ = val; |
| 54 } | 42 } |
| 55 | 43 |
| 56 void V8ValueConverterImpl::SetRegexpAllowed(bool val) { | 44 void V8ValueConverterImpl::SetFunctionAllowed(bool val) { |
| 57 regexp_allowed_ = val; | 45 function_allowed_ = val; |
| 58 } | |
| 59 | |
| 60 bool V8ValueConverterImpl::GetStripNullFromObjects() const { | |
| 61 return strip_null_from_objects_; | |
| 62 } | 46 } |
| 63 | 47 |
| 64 void V8ValueConverterImpl::SetStripNullFromObjects(bool val) { | 48 void V8ValueConverterImpl::SetStripNullFromObjects(bool val) { |
| 65 strip_null_from_objects_ = val; | 49 strip_null_from_objects_ = val; |
| 66 } | 50 } |
| 67 | 51 |
| 68 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Value( | 52 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Value( |
| 69 const Value* value, v8::Handle<v8::Context> context) const { | 53 const Value* value, v8::Handle<v8::Context> context) const { |
| 70 v8::Context::Scope context_scope(context); | 54 v8::Context::Scope context_scope(context); |
| 71 v8::HandleScope handle_scope; | 55 v8::HandleScope handle_scope; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 return Value::CreateIntegerValue(val->ToInt32()->Value()); | 177 return Value::CreateIntegerValue(val->ToInt32()->Value()); |
| 194 | 178 |
| 195 if (val->IsNumber()) | 179 if (val->IsNumber()) |
| 196 return Value::CreateDoubleValue(val->ToNumber()->Value()); | 180 return Value::CreateDoubleValue(val->ToNumber()->Value()); |
| 197 | 181 |
| 198 if (val->IsString()) { | 182 if (val->IsString()) { |
| 199 v8::String::Utf8Value utf8(val->ToString()); | 183 v8::String::Utf8Value utf8(val->ToString()); |
| 200 return Value::CreateStringValue(std::string(*utf8, utf8.length())); | 184 return Value::CreateStringValue(std::string(*utf8, utf8.length())); |
| 201 } | 185 } |
| 202 | 186 |
| 203 if (undefined_allowed_ && val->IsUndefined()) | 187 if (val->IsUndefined()) |
| 204 return Value::CreateNullValue(); | 188 // JSON.stringify ignores undefined. |
| 189 return NULL; |
| 205 | 190 |
| 206 if (date_allowed_ && val->IsDate()) { | 191 if (val->IsDate()) { |
| 192 if (!date_allowed_) |
| 193 // JSON.stringify would convert this to a string, but an object is more |
| 194 // consistent within this class. |
| 195 return FromV8Object(val->ToObject(), unique_set); |
| 207 v8::Date* date = v8::Date::Cast(*val); | 196 v8::Date* date = v8::Date::Cast(*val); |
| 208 return Value::CreateDoubleValue(date->NumberValue() / 1000.0); | 197 return Value::CreateDoubleValue(date->NumberValue() / 1000.0); |
| 209 } | 198 } |
| 210 | 199 |
| 211 if (regexp_allowed_ && val->IsRegExp()) { | 200 if (val->IsRegExp()) { |
| 212 return Value::CreateStringValue( | 201 if (!reg_exp_allowed_) |
| 213 *v8::String::Utf8Value(val->ToString())); | 202 // JSON.stringify converts to an object. |
| 203 return FromV8Object(val->ToObject(), unique_set); |
| 204 return Value::CreateStringValue(*v8::String::Utf8Value(val->ToString())); |
| 214 } | 205 } |
| 215 | 206 |
| 216 // v8::Value doesn't have a ToArray() method for some reason. | 207 // v8::Value doesn't have a ToArray() method for some reason. |
| 217 if (val->IsArray()) | 208 if (val->IsArray()) |
| 218 return FromV8Array(val.As<v8::Array>(), unique_set); | 209 return FromV8Array(val.As<v8::Array>(), unique_set); |
| 219 | 210 |
| 211 if (val->IsFunction()) { |
| 212 if (!function_allowed_) |
| 213 // JSON.stringify refuses to convert function(){}. |
| 214 return NULL; |
| 215 return FromV8Object(val->ToObject(), unique_set); |
| 216 } |
| 217 |
| 220 if (val->IsObject()) { | 218 if (val->IsObject()) { |
| 221 BinaryValue* binary_value = FromV8Buffer(val); | 219 BinaryValue* binary_value = FromV8Buffer(val); |
| 222 if (binary_value) { | 220 if (binary_value) { |
| 223 return binary_value; | 221 return binary_value; |
| 224 } else { | 222 } else { |
| 225 return FromV8Object(val->ToObject(), unique_set); | 223 return FromV8Object(val->ToObject(), unique_set); |
| 226 } | 224 } |
| 227 } | 225 } |
| 226 |
| 228 LOG(ERROR) << "Unexpected v8 value type encountered."; | 227 LOG(ERROR) << "Unexpected v8 value type encountered."; |
| 229 return Value::CreateNullValue(); | 228 return NULL; |
| 230 } | 229 } |
| 231 | 230 |
| 232 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, | 231 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, |
| 233 std::set<int>* unique_set) const { | 232 std::set<int>* unique_set) const { |
| 234 if (unique_set && unique_set->count(val->GetIdentityHash())) | 233 if (unique_set && unique_set->count(val->GetIdentityHash())) |
| 235 return Value::CreateNullValue(); | 234 return Value::CreateNullValue(); |
| 236 | 235 |
| 237 scoped_ptr<v8::Context::Scope> scope; | 236 scoped_ptr<v8::Context::Scope> scope; |
| 238 // If val was created in a different context than our current one, change to | 237 // If val was created in a different context than our current one, change to |
| 239 // that context, but change back after val is converted. | 238 // that context, but change back after val is converted. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 251 v8::Handle<v8::Value> child_v8 = val->Get(i); | 250 v8::Handle<v8::Value> child_v8 = val->Get(i); |
| 252 if (try_catch.HasCaught()) { | 251 if (try_catch.HasCaught()) { |
| 253 LOG(ERROR) << "Getter for index " << i << " threw an exception."; | 252 LOG(ERROR) << "Getter for index " << i << " threw an exception."; |
| 254 child_v8 = v8::Null(); | 253 child_v8 = v8::Null(); |
| 255 } | 254 } |
| 256 | 255 |
| 257 if (!val->HasRealIndexedProperty(i)) | 256 if (!val->HasRealIndexedProperty(i)) |
| 258 continue; | 257 continue; |
| 259 | 258 |
| 260 Value* child = FromV8ValueImpl(child_v8, unique_set); | 259 Value* child = FromV8ValueImpl(child_v8, unique_set); |
| 261 CHECK(child); | 260 if (child) |
| 262 | 261 result->Append(child); |
| 263 result->Append(child); | 262 else |
| 263 // JSON.stringify puts null in places where values don't serialize, for |
| 264 // example undefined and functions. Emulate that behavior. |
| 265 result->Append(Value::CreateNullValue()); |
| 264 } | 266 } |
| 265 return result; | 267 return result; |
| 266 } | 268 } |
| 267 | 269 |
| 268 base::BinaryValue* V8ValueConverterImpl::FromV8Buffer( | 270 base::BinaryValue* V8ValueConverterImpl::FromV8Buffer( |
| 269 v8::Handle<v8::Value> val) const { | 271 v8::Handle<v8::Value> val) const { |
| 270 char* data = NULL; | 272 char* data = NULL; |
| 271 size_t length = 0; | 273 size_t length = 0; |
| 272 | 274 |
| 273 scoped_ptr<WebKit::WebArrayBuffer> array_buffer( | 275 scoped_ptr<WebKit::WebArrayBuffer> array_buffer( |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 v8::TryCatch try_catch; | 330 v8::TryCatch try_catch; |
| 329 v8::Handle<v8::Value> child_v8 = val->Get(key); | 331 v8::Handle<v8::Value> child_v8 = val->Get(key); |
| 330 | 332 |
| 331 if (try_catch.HasCaught()) { | 333 if (try_catch.HasCaught()) { |
| 332 LOG(ERROR) << "Getter for property " << *name_utf8 | 334 LOG(ERROR) << "Getter for property " << *name_utf8 |
| 333 << " threw an exception."; | 335 << " threw an exception."; |
| 334 child_v8 = v8::Null(); | 336 child_v8 = v8::Null(); |
| 335 } | 337 } |
| 336 | 338 |
| 337 scoped_ptr<Value> child(FromV8ValueImpl(child_v8, unique_set)); | 339 scoped_ptr<Value> child(FromV8ValueImpl(child_v8, unique_set)); |
| 338 CHECK(child.get()); | 340 if (!child.get()) |
| 341 // JSON.stringify skips properties whose values don't serialize, for |
| 342 // example undefined and functions. Emulate that behavior. |
| 343 continue; |
| 339 | 344 |
| 340 // Strip null if asked (and since undefined is turned into null, undefined | 345 // Strip null if asked (and since undefined is turned into null, undefined |
| 341 // too). The use case for supporting this is JSON-schema support, | 346 // too). The use case for supporting this is JSON-schema support, |
| 342 // specifically for extensions, where "optional" JSON properties may be | 347 // specifically for extensions, where "optional" JSON properties may be |
| 343 // represented as null, yet due to buggy legacy code elsewhere isn't | 348 // represented as null, yet due to buggy legacy code elsewhere isn't |
| 344 // treated as such (potentially causing crashes). For example, the | 349 // treated as such (potentially causing crashes). For example, the |
| 345 // "tabs.create" function takes an object as its first argument with an | 350 // "tabs.create" function takes an object as its first argument with an |
| 346 // optional "windowId" property. | 351 // optional "windowId" property. |
| 347 // | 352 // |
| 348 // Given just | 353 // Given just |
| (...skipping 10 matching lines...) Expand all Loading... |
| 359 // We can avoid all bugs related to this by stripping null. | 364 // We can avoid all bugs related to this by stripping null. |
| 360 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) | 365 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) |
| 361 continue; | 366 continue; |
| 362 | 367 |
| 363 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), | 368 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), |
| 364 child.release()); | 369 child.release()); |
| 365 } | 370 } |
| 366 | 371 |
| 367 return result.release(); | 372 return result.release(); |
| 368 } | 373 } |
| OLD | NEW |