| 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/WebArrayBufferView.h" | 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBufferView.h" |
| 14 #include "v8/include/v8.h" | 14 #include "v8/include/v8.h" |
| 15 | 15 |
| 16 using base::BinaryValue; | |
| 17 using base::DictionaryValue; | |
| 18 using base::ListValue; | |
| 19 using base::StringValue; | |
| 20 using base::Value; | |
| 21 | |
| 22 namespace content { | 16 namespace content { |
| 23 | 17 |
| 24 V8ValueConverter* V8ValueConverter::create() { | 18 V8ValueConverter* V8ValueConverter::create() { |
| 25 return new V8ValueConverterImpl(); | 19 return new V8ValueConverterImpl(); |
| 26 } | 20 } |
| 27 | 21 |
| 28 V8ValueConverterImpl::V8ValueConverterImpl() | 22 V8ValueConverterImpl::V8ValueConverterImpl() |
| 29 : date_allowed_(false), | 23 : date_allowed_(false), |
| 30 reg_exp_allowed_(false), | 24 reg_exp_allowed_(false), |
| 31 function_allowed_(false), | 25 function_allowed_(false), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 42 | 36 |
| 43 void V8ValueConverterImpl::SetFunctionAllowed(bool val) { | 37 void V8ValueConverterImpl::SetFunctionAllowed(bool val) { |
| 44 function_allowed_ = val; | 38 function_allowed_ = val; |
| 45 } | 39 } |
| 46 | 40 |
| 47 void V8ValueConverterImpl::SetStripNullFromObjects(bool val) { | 41 void V8ValueConverterImpl::SetStripNullFromObjects(bool val) { |
| 48 strip_null_from_objects_ = val; | 42 strip_null_from_objects_ = val; |
| 49 } | 43 } |
| 50 | 44 |
| 51 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Value( | 45 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Value( |
| 52 const Value* value, v8::Handle<v8::Context> context) const { | 46 const base::Value* value, v8::Handle<v8::Context> context) const { |
| 53 v8::Context::Scope context_scope(context); | 47 v8::Context::Scope context_scope(context); |
| 54 v8::HandleScope handle_scope; | 48 v8::HandleScope handle_scope; |
| 55 return handle_scope.Close(ToV8ValueImpl(value)); | 49 return handle_scope.Close(ToV8ValueImpl(value)); |
| 56 } | 50 } |
| 57 | 51 |
| 58 Value* V8ValueConverterImpl::FromV8Value( | 52 Value* V8ValueConverterImpl::FromV8Value( |
| 59 v8::Handle<v8::Value> val, | 53 v8::Handle<v8::Value> val, |
| 60 v8::Handle<v8::Context> context) const { | 54 v8::Handle<v8::Context> context) const { |
| 61 v8::Context::Scope context_scope(context); | 55 v8::Context::Scope context_scope(context); |
| 62 v8::HandleScope handle_scope; | 56 v8::HandleScope handle_scope; |
| 63 std::set<int> unique_set; | 57 std::set<int> unique_set; |
| 64 return FromV8ValueImpl(val, &unique_set); | 58 return FromV8ValueImpl(val, &unique_set); |
| 65 } | 59 } |
| 66 | 60 |
| 67 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( | 61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( |
| 68 const Value* value) const { | 62 const base::Value* value) const { |
| 69 CHECK(value); | 63 CHECK(value); |
| 70 switch (value->GetType()) { | 64 switch (value->GetType()) { |
| 71 case Value::TYPE_NULL: | 65 case base::Value::TYPE_NULL: |
| 72 return v8::Null(); | 66 return v8::Null(); |
| 73 | 67 |
| 74 case Value::TYPE_BOOLEAN: { | 68 case base::Value::TYPE_BOOLEAN: { |
| 75 bool val = false; | 69 bool val = false; |
| 76 CHECK(value->GetAsBoolean(&val)); | 70 CHECK(value->GetAsBoolean(&val)); |
| 77 return v8::Boolean::New(val); | 71 return v8::Boolean::New(val); |
| 78 } | 72 } |
| 79 | 73 |
| 80 case Value::TYPE_INTEGER: { | 74 case base::Value::TYPE_INTEGER: { |
| 81 int val = 0; | 75 int val = 0; |
| 82 CHECK(value->GetAsInteger(&val)); | 76 CHECK(value->GetAsInteger(&val)); |
| 83 return v8::Integer::New(val); | 77 return v8::Integer::New(val); |
| 84 } | 78 } |
| 85 | 79 |
| 86 case Value::TYPE_DOUBLE: { | 80 case base::Value::TYPE_DOUBLE: { |
| 87 double val = 0.0; | 81 double val = 0.0; |
| 88 CHECK(value->GetAsDouble(&val)); | 82 CHECK(value->GetAsDouble(&val)); |
| 89 return v8::Number::New(val); | 83 return v8::Number::New(val); |
| 90 } | 84 } |
| 91 | 85 |
| 92 case Value::TYPE_STRING: { | 86 case base::Value::TYPE_STRING: { |
| 93 std::string val; | 87 std::string val; |
| 94 CHECK(value->GetAsString(&val)); | 88 CHECK(value->GetAsString(&val)); |
| 95 return v8::String::New(val.c_str(), val.length()); | 89 return v8::String::New(val.c_str(), val.length()); |
| 96 } | 90 } |
| 97 | 91 |
| 98 case Value::TYPE_LIST: | 92 case base::Value::TYPE_LIST: |
| 99 return ToV8Array(static_cast<const ListValue*>(value)); | 93 return ToV8Array(static_cast<const base::ListValue*>(value)); |
| 100 | 94 |
| 101 case Value::TYPE_DICTIONARY: | 95 case base::Value::TYPE_DICTIONARY: |
| 102 return ToV8Object(static_cast<const DictionaryValue*>(value)); | 96 return ToV8Object(static_cast<const base::DictionaryValue*>(value)); |
| 103 | 97 |
| 104 case Value::TYPE_BINARY: | 98 case base::Value::TYPE_BINARY: |
| 105 return ToArrayBuffer(static_cast<const BinaryValue*>(value)); | 99 return ToArrayBuffer(static_cast<const base::BinaryValue*>(value)); |
| 106 | 100 |
| 107 default: | 101 default: |
| 108 LOG(ERROR) << "Unexpected value type: " << value->GetType(); | 102 LOG(ERROR) << "Unexpected value type: " << value->GetType(); |
| 109 return v8::Null(); | 103 return v8::Null(); |
| 110 } | 104 } |
| 111 } | 105 } |
| 112 | 106 |
| 113 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Array( | 107 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Array( |
| 114 const ListValue* val) const { | 108 const base::ListValue* val) const { |
| 115 v8::Handle<v8::Array> result(v8::Array::New(val->GetSize())); | 109 v8::Handle<v8::Array> result(v8::Array::New(val->GetSize())); |
| 116 | 110 |
| 117 for (size_t i = 0; i < val->GetSize(); ++i) { | 111 for (size_t i = 0; i < val->GetSize(); ++i) { |
| 118 const Value* child = NULL; | 112 const base::Value* child = NULL; |
| 119 CHECK(val->Get(i, &child)); | 113 CHECK(val->Get(i, &child)); |
| 120 | 114 |
| 121 v8::Handle<v8::Value> child_v8 = ToV8ValueImpl(child); | 115 v8::Handle<v8::Value> child_v8 = ToV8ValueImpl(child); |
| 122 CHECK(!child_v8.IsEmpty()); | 116 CHECK(!child_v8.IsEmpty()); |
| 123 | 117 |
| 124 v8::TryCatch try_catch; | 118 v8::TryCatch try_catch; |
| 125 result->Set(static_cast<uint32>(i), child_v8); | 119 result->Set(static_cast<uint32>(i), child_v8); |
| 126 if (try_catch.HasCaught()) | 120 if (try_catch.HasCaught()) |
| 127 LOG(ERROR) << "Setter for index " << i << " threw an exception."; | 121 LOG(ERROR) << "Setter for index " << i << " threw an exception."; |
| 128 } | 122 } |
| 129 | 123 |
| 130 return result; | 124 return result; |
| 131 } | 125 } |
| 132 | 126 |
| 133 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Object( | 127 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8Object( |
| 134 const DictionaryValue* val) const { | 128 const base::DictionaryValue* val) const { |
| 135 v8::Handle<v8::Object> result(v8::Object::New()); | 129 v8::Handle<v8::Object> result(v8::Object::New()); |
| 136 | 130 |
| 137 for (DictionaryValue::Iterator iter(*val); !iter.IsAtEnd(); iter.Advance()) { | 131 for (base::DictionaryValue::Iterator iter(*val); |
| 132 !iter.IsAtEnd(); iter.Advance()) { |
| 138 const std::string& key = iter.key(); | 133 const std::string& key = iter.key(); |
| 139 v8::Handle<v8::Value> child_v8 = ToV8ValueImpl(&iter.value()); | 134 v8::Handle<v8::Value> child_v8 = ToV8ValueImpl(&iter.value()); |
| 140 CHECK(!child_v8.IsEmpty()); | 135 CHECK(!child_v8.IsEmpty()); |
| 141 | 136 |
| 142 v8::TryCatch try_catch; | 137 v8::TryCatch try_catch; |
| 143 result->Set(v8::String::New(key.c_str(), key.length()), child_v8); | 138 result->Set(v8::String::New(key.c_str(), key.length()), child_v8); |
| 144 if (try_catch.HasCaught()) { | 139 if (try_catch.HasCaught()) { |
| 145 LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " | 140 LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " |
| 146 << "exception."; | 141 << "exception."; |
| 147 } | 142 } |
| 148 } | 143 } |
| 149 | 144 |
| 150 return result; | 145 return result; |
| 151 } | 146 } |
| 152 | 147 |
| 153 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( | 148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( |
| 154 const BinaryValue* value) const { | 149 const base::BinaryValue* value) const { |
| 155 WebKit::WebArrayBuffer buffer = | 150 WebKit::WebArrayBuffer buffer = |
| 156 WebKit::WebArrayBuffer::create(value->GetSize(), 1); | 151 WebKit::WebArrayBuffer::create(value->GetSize(), 1); |
| 157 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); | 152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); |
| 158 return buffer.toV8Value(); | 153 return buffer.toV8Value(); |
| 159 } | 154 } |
| 160 | 155 |
| 161 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, | 156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, |
| 162 std::set<int>* unique_set) const { | 157 std::set<int>* unique_set) const { |
| 163 CHECK(!val.IsEmpty()); | 158 CHECK(!val.IsEmpty()); |
| 164 | 159 |
| 165 if (val->IsNull()) | 160 if (val->IsNull()) |
| 166 return Value::CreateNullValue(); | 161 return base::Value::CreateNullValue(); |
| 167 | 162 |
| 168 if (val->IsBoolean()) | 163 if (val->IsBoolean()) |
| 169 return Value::CreateBooleanValue(val->ToBoolean()->Value()); | 164 return new base::FundamentalValue(val->ToBoolean()->Value()); |
| 170 | 165 |
| 171 if (val->IsInt32()) | 166 if (val->IsInt32()) |
| 172 return Value::CreateIntegerValue(val->ToInt32()->Value()); | 167 return new base::FundamentalValue(val->ToInt32()->Value()); |
| 173 | 168 |
| 174 if (val->IsNumber()) | 169 if (val->IsNumber()) |
| 175 return Value::CreateDoubleValue(val->ToNumber()->Value()); | 170 return new base::FundamentalValue(val->ToNumber()->Value()); |
| 176 | 171 |
| 177 if (val->IsString()) { | 172 if (val->IsString()) { |
| 178 v8::String::Utf8Value utf8(val->ToString()); | 173 v8::String::Utf8Value utf8(val->ToString()); |
| 179 return Value::CreateStringValue(std::string(*utf8, utf8.length())); | 174 return new base::StringValue(std::string(*utf8, utf8.length())); |
| 180 } | 175 } |
| 181 | 176 |
| 182 if (val->IsUndefined()) | 177 if (val->IsUndefined()) |
| 183 // JSON.stringify ignores undefined. | 178 // JSON.stringify ignores undefined. |
| 184 return NULL; | 179 return NULL; |
| 185 | 180 |
| 186 if (val->IsDate()) { | 181 if (val->IsDate()) { |
| 187 if (!date_allowed_) | 182 if (!date_allowed_) |
| 188 // 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 |
| 189 // consistent within this class. | 184 // consistent within this class. |
| 190 return FromV8Object(val->ToObject(), unique_set); | 185 return FromV8Object(val->ToObject(), unique_set); |
| 191 v8::Date* date = v8::Date::Cast(*val); | 186 v8::Date* date = v8::Date::Cast(*val); |
| 192 return Value::CreateDoubleValue(date->NumberValue() / 1000.0); | 187 return new base::FundamentalValue(date->NumberValue() / 1000.0); |
| 193 } | 188 } |
| 194 | 189 |
| 195 if (val->IsRegExp()) { | 190 if (val->IsRegExp()) { |
| 196 if (!reg_exp_allowed_) | 191 if (!reg_exp_allowed_) |
| 197 // JSON.stringify converts to an object. | 192 // JSON.stringify converts to an object. |
| 198 return FromV8Object(val->ToObject(), unique_set); | 193 return FromV8Object(val->ToObject(), unique_set); |
| 199 return Value::CreateStringValue(*v8::String::Utf8Value(val->ToString())); | 194 return new base::StringValue(*v8::String::Utf8Value(val->ToString())); |
| 200 } | 195 } |
| 201 | 196 |
| 202 // v8::Value doesn't have a ToArray() method for some reason. | 197 // v8::Value doesn't have a ToArray() method for some reason. |
| 203 if (val->IsArray()) | 198 if (val->IsArray()) |
| 204 return FromV8Array(val.As<v8::Array>(), unique_set); | 199 return FromV8Array(val.As<v8::Array>(), unique_set); |
| 205 | 200 |
| 206 if (val->IsFunction()) { | 201 if (val->IsFunction()) { |
| 207 if (!function_allowed_) | 202 if (!function_allowed_) |
| 208 // JSON.stringify refuses to convert function(){}. | 203 // JSON.stringify refuses to convert function(){}. |
| 209 return NULL; | 204 return NULL; |
| 210 return FromV8Object(val->ToObject(), unique_set); | 205 return FromV8Object(val->ToObject(), unique_set); |
| 211 } | 206 } |
| 212 | 207 |
| 213 if (val->IsObject()) { | 208 if (val->IsObject()) { |
| 214 BinaryValue* binary_value = FromV8Buffer(val); | 209 base::BinaryValue* binary_value = FromV8Buffer(val); |
| 215 if (binary_value) { | 210 if (binary_value) { |
| 216 return binary_value; | 211 return binary_value; |
| 217 } else { | 212 } else { |
| 218 return FromV8Object(val->ToObject(), unique_set); | 213 return FromV8Object(val->ToObject(), unique_set); |
| 219 } | 214 } |
| 220 } | 215 } |
| 221 | 216 |
| 222 LOG(ERROR) << "Unexpected v8 value type encountered."; | 217 LOG(ERROR) << "Unexpected v8 value type encountered."; |
| 223 return NULL; | 218 return NULL; |
| 224 } | 219 } |
| 225 | 220 |
| 226 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, | 221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, |
| 227 std::set<int>* unique_set) const { | 222 std::set<int>* unique_set) const { |
| 228 if (unique_set && unique_set->count(val->GetIdentityHash())) | 223 if (unique_set && unique_set->count(val->GetIdentityHash())) |
| 229 return Value::CreateNullValue(); | 224 return base::Value::CreateNullValue(); |
| 230 | 225 |
| 231 scoped_ptr<v8::Context::Scope> scope; | 226 scoped_ptr<v8::Context::Scope> scope; |
| 232 // 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 |
| 233 // that context, but change back after val is converted. | 228 // that context, but change back after val is converted. |
| 234 if (!val->CreationContext().IsEmpty() && | 229 if (!val->CreationContext().IsEmpty() && |
| 235 val->CreationContext() != v8::Context::GetCurrent()) | 230 val->CreationContext() != v8::Context::GetCurrent()) |
| 236 scope.reset(new v8::Context::Scope(val->CreationContext())); | 231 scope.reset(new v8::Context::Scope(val->CreationContext())); |
| 237 | 232 |
| 238 ListValue* result = new ListValue(); | 233 base::ListValue* result = new base::ListValue(); |
| 239 | 234 |
| 240 if (unique_set) | 235 if (unique_set) |
| 241 unique_set->insert(val->GetIdentityHash()); | 236 unique_set->insert(val->GetIdentityHash()); |
| 242 // Only fields with integer keys are carried over to the ListValue. | 237 // Only fields with integer keys are carried over to the ListValue. |
| 243 for (uint32 i = 0; i < val->Length(); ++i) { | 238 for (uint32 i = 0; i < val->Length(); ++i) { |
| 244 v8::TryCatch try_catch; | 239 v8::TryCatch try_catch; |
| 245 v8::Handle<v8::Value> child_v8 = val->Get(i); | 240 v8::Handle<v8::Value> child_v8 = val->Get(i); |
| 246 if (try_catch.HasCaught()) { | 241 if (try_catch.HasCaught()) { |
| 247 LOG(ERROR) << "Getter for index " << i << " threw an exception."; | 242 LOG(ERROR) << "Getter for index " << i << " threw an exception."; |
| 248 child_v8 = v8::Null(); | 243 child_v8 = v8::Null(); |
| 249 } | 244 } |
| 250 | 245 |
| 251 if (!val->HasRealIndexedProperty(i)) | 246 if (!val->HasRealIndexedProperty(i)) |
| 252 continue; | 247 continue; |
| 253 | 248 |
| 254 Value* child = FromV8ValueImpl(child_v8, unique_set); | 249 base::Value* child = FromV8ValueImpl(child_v8, unique_set); |
| 255 if (child) | 250 if (child) |
| 256 result->Append(child); | 251 result->Append(child); |
| 257 else | 252 else |
| 258 // JSON.stringify puts null in places where values don't serialize, for | 253 // JSON.stringify puts null in places where values don't serialize, for |
| 259 // example undefined and functions. Emulate that behavior. | 254 // example undefined and functions. Emulate that behavior. |
| 260 result->Append(Value::CreateNullValue()); | 255 result->Append(base::Value::CreateNullValue()); |
| 261 } | 256 } |
| 262 return result; | 257 return result; |
| 263 } | 258 } |
| 264 | 259 |
| 265 base::BinaryValue* V8ValueConverterImpl::FromV8Buffer( | 260 base::BinaryValue* V8ValueConverterImpl::FromV8Buffer( |
| 266 v8::Handle<v8::Value> val) const { | 261 v8::Handle<v8::Value> val) const { |
| 267 char* data = NULL; | 262 char* data = NULL; |
| 268 size_t length = 0; | 263 size_t length = 0; |
| 269 | 264 |
| 270 scoped_ptr<WebKit::WebArrayBuffer> array_buffer( | 265 scoped_ptr<WebKit::WebArrayBuffer> array_buffer( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 284 if (data) | 279 if (data) |
| 285 return base::BinaryValue::CreateWithCopiedBuffer(data, length); | 280 return base::BinaryValue::CreateWithCopiedBuffer(data, length); |
| 286 else | 281 else |
| 287 return NULL; | 282 return NULL; |
| 288 } | 283 } |
| 289 | 284 |
| 290 Value* V8ValueConverterImpl::FromV8Object( | 285 Value* V8ValueConverterImpl::FromV8Object( |
| 291 v8::Handle<v8::Object> val, | 286 v8::Handle<v8::Object> val, |
| 292 std::set<int>* unique_set) const { | 287 std::set<int>* unique_set) const { |
| 293 if (unique_set && unique_set->count(val->GetIdentityHash())) | 288 if (unique_set && unique_set->count(val->GetIdentityHash())) |
| 294 return Value::CreateNullValue(); | 289 return base::Value::CreateNullValue(); |
| 295 scoped_ptr<v8::Context::Scope> scope; | 290 scoped_ptr<v8::Context::Scope> scope; |
| 296 // If val was created in a different context than our current one, change to | 291 // If val was created in a different context than our current one, change to |
| 297 // that context, but change back after val is converted. | 292 // that context, but change back after val is converted. |
| 298 if (!val->CreationContext().IsEmpty() && | 293 if (!val->CreationContext().IsEmpty() && |
| 299 val->CreationContext() != v8::Context::GetCurrent()) | 294 val->CreationContext() != v8::Context::GetCurrent()) |
| 300 scope.reset(new v8::Context::Scope(val->CreationContext())); | 295 scope.reset(new v8::Context::Scope(val->CreationContext())); |
| 301 | 296 |
| 302 scoped_ptr<DictionaryValue> result(new DictionaryValue()); | 297 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| 303 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); | 298 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); |
| 304 | 299 |
| 305 if (unique_set) | 300 if (unique_set) |
| 306 unique_set->insert(val->GetIdentityHash()); | 301 unique_set->insert(val->GetIdentityHash()); |
| 307 | 302 |
| 308 for (uint32 i = 0; i < property_names->Length(); ++i) { | 303 for (uint32 i = 0; i < property_names->Length(); ++i) { |
| 309 v8::Handle<v8::Value> key(property_names->Get(i)); | 304 v8::Handle<v8::Value> key(property_names->Get(i)); |
| 310 | 305 |
| 311 // Extend this test to cover more types as necessary and if sensible. | 306 // Extend this test to cover more types as necessary and if sensible. |
| 312 if (!key->IsString() && | 307 if (!key->IsString() && |
| (...skipping 11 matching lines...) Expand all Loading... |
| 324 | 319 |
| 325 v8::TryCatch try_catch; | 320 v8::TryCatch try_catch; |
| 326 v8::Handle<v8::Value> child_v8 = val->Get(key); | 321 v8::Handle<v8::Value> child_v8 = val->Get(key); |
| 327 | 322 |
| 328 if (try_catch.HasCaught()) { | 323 if (try_catch.HasCaught()) { |
| 329 LOG(ERROR) << "Getter for property " << *name_utf8 | 324 LOG(ERROR) << "Getter for property " << *name_utf8 |
| 330 << " threw an exception."; | 325 << " threw an exception."; |
| 331 child_v8 = v8::Null(); | 326 child_v8 = v8::Null(); |
| 332 } | 327 } |
| 333 | 328 |
| 334 scoped_ptr<Value> child(FromV8ValueImpl(child_v8, unique_set)); | 329 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_set)); |
| 335 if (!child.get()) | 330 if (!child.get()) |
| 336 // JSON.stringify skips properties whose values don't serialize, for | 331 // JSON.stringify skips properties whose values don't serialize, for |
| 337 // example undefined and functions. Emulate that behavior. | 332 // example undefined and functions. Emulate that behavior. |
| 338 continue; | 333 continue; |
| 339 | 334 |
| 340 // Strip null if asked (and since undefined is turned into null, undefined | 335 // Strip null if asked (and since undefined is turned into null, undefined |
| 341 // too). The use case for supporting this is JSON-schema support, | 336 // too). The use case for supporting this is JSON-schema support, |
| 342 // specifically for extensions, where "optional" JSON properties may be | 337 // specifically for extensions, where "optional" JSON properties may be |
| 343 // represented as null, yet due to buggy legacy code elsewhere isn't | 338 // represented as null, yet due to buggy legacy code elsewhere isn't |
| 344 // treated as such (potentially causing crashes). For example, the | 339 // treated as such (potentially causing crashes). For example, the |
| (...skipping 16 matching lines...) Expand all Loading... |
| 361 continue; | 356 continue; |
| 362 | 357 |
| 363 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), | 358 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), |
| 364 child.release()); | 359 child.release()); |
| 365 } | 360 } |
| 366 | 361 |
| 367 return result.release(); | 362 return result.release(); |
| 368 } | 363 } |
| 369 | 364 |
| 370 } // namespace content | 365 } // namespace content |
| OLD | NEW |