Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(496)

Side by Side Diff: content/renderer/v8_value_converter_impl.cc

Issue 10890002: Make V8ValueConverter.FromV8Value behave similarly to JSON.stringify (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ignore -> omit Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 : undefined_value_behavior_(TREAT_AS_ERROR),
31 date_allowed_(false), 31 date_allowed_(false),
32 regexp_allowed_(false), 32 regexp_allowed_(false),
33 strip_null_from_objects_(false) { 33 strip_null_from_objects_(false) {
34 } 34 }
35 35
36 bool V8ValueConverterImpl::GetUndefinedAllowed() const { 36 content::V8ValueConverter::UndefinedValueBehavior
37 return undefined_allowed_; 37 V8ValueConverterImpl::GetUndefinedValueBehavior() const {
38 return undefined_value_behavior_;
38 } 39 }
39 40
40 void V8ValueConverterImpl::SetUndefinedAllowed(bool val) { 41 void V8ValueConverterImpl::SetUndefinedValueBehavior(
41 undefined_allowed_ = val; 42 UndefinedValueBehavior val) {
43 undefined_value_behavior_ = val;
42 } 44 }
43 45
44 bool V8ValueConverterImpl::GetDateAllowed() const { 46 bool V8ValueConverterImpl::GetDateAllowed() const {
45 return date_allowed_; 47 return date_allowed_;
46 } 48 }
47 49
48 void V8ValueConverterImpl::SetDateAllowed(bool val) { 50 void V8ValueConverterImpl::SetDateAllowed(bool val) {
49 date_allowed_ = val; 51 date_allowed_ = val;
50 } 52 }
51 53
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 return Value::CreateIntegerValue(val->ToInt32()->Value()); 195 return Value::CreateIntegerValue(val->ToInt32()->Value());
194 196
195 if (val->IsNumber()) 197 if (val->IsNumber())
196 return Value::CreateDoubleValue(val->ToNumber()->Value()); 198 return Value::CreateDoubleValue(val->ToNumber()->Value());
197 199
198 if (val->IsString()) { 200 if (val->IsString()) {
199 v8::String::Utf8Value utf8(val->ToString()); 201 v8::String::Utf8Value utf8(val->ToString());
200 return Value::CreateStringValue(std::string(*utf8, utf8.length())); 202 return Value::CreateStringValue(std::string(*utf8, utf8.length()));
201 } 203 }
202 204
203 if (undefined_allowed_ && val->IsUndefined()) 205 if (val->IsUndefined()) {
204 return Value::CreateNullValue(); 206 switch (undefined_value_behavior_) {
207 case TREAT_AS_ERROR:
208 LOG(ERROR) << "Unexpected 'undefined' v8 value encountered.";
209 return NULL;
210 case OMIT:
211 return NULL;
212 case CONVERT_TO_NULL:
213 return Value::CreateNullValue();
214 }
215 NOTREACHED();
216 }
205 217
206 if (date_allowed_ && val->IsDate()) { 218 if (val->IsDate()) {
219 if (!date_allowed_)
220 // JSON.stringify would convert this to a string, but {} is more
221 // consistent within this class.
222 return new DictionaryValue();
207 v8::Date* date = v8::Date::Cast(*val); 223 v8::Date* date = v8::Date::Cast(*val);
208 return Value::CreateDoubleValue(date->NumberValue() / 1000.0); 224 return Value::CreateDoubleValue(date->NumberValue() / 1000.0);
209 } 225 }
210 226
211 if (regexp_allowed_ && val->IsRegExp()) { 227 if (val->IsRegExp()) {
212 return Value::CreateStringValue( 228 if (!regexp_allowed_)
213 *v8::String::Utf8Value(val->ToString())); 229 // JSON.stringify converts to {}.
230 return new DictionaryValue();
231 return Value::CreateStringValue(*v8::String::Utf8Value(val->ToString()));
214 } 232 }
215 233
216 // v8::Value doesn't have a ToArray() method for some reason. 234 // v8::Value doesn't have a ToArray() method for some reason.
217 if (val->IsArray()) 235 if (val->IsArray())
218 return FromV8Array(val.As<v8::Array>(), unique_set); 236 return FromV8Array(val.As<v8::Array>(), unique_set);
219 237
238 if (val->IsFunction())
239 // JSON.stringify refuses to convert function(){}.
240 return NULL;
241
220 if (val->IsObject()) { 242 if (val->IsObject()) {
221 BinaryValue* binary_value = FromV8Buffer(val); 243 BinaryValue* binary_value = FromV8Buffer(val);
222 if (binary_value) { 244 if (binary_value) {
223 return binary_value; 245 return binary_value;
224 } else { 246 } else {
225 return FromV8Object(val->ToObject(), unique_set); 247 return FromV8Object(val->ToObject(), unique_set);
226 } 248 }
227 } 249 }
250
228 LOG(ERROR) << "Unexpected v8 value type encountered."; 251 LOG(ERROR) << "Unexpected v8 value type encountered.";
229 return Value::CreateNullValue(); 252 return NULL;
230 } 253 }
231 254
232 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, 255 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val,
233 std::set<int>* unique_set) const { 256 std::set<int>* unique_set) const {
234 if (unique_set && unique_set->count(val->GetIdentityHash())) 257 if (unique_set && unique_set->count(val->GetIdentityHash()))
235 return Value::CreateNullValue(); 258 return Value::CreateNullValue();
236 259
237 scoped_ptr<v8::Context::Scope> scope; 260 scoped_ptr<v8::Context::Scope> scope;
238 // If val was created in a different context than our current one, change to 261 // If val was created in a different context than our current one, change to
239 // that context, but change back after val is converted. 262 // that context, but change back after val is converted.
(...skipping 11 matching lines...) Expand all
251 v8::Handle<v8::Value> child_v8 = val->Get(i); 274 v8::Handle<v8::Value> child_v8 = val->Get(i);
252 if (try_catch.HasCaught()) { 275 if (try_catch.HasCaught()) {
253 LOG(ERROR) << "Getter for index " << i << " threw an exception."; 276 LOG(ERROR) << "Getter for index " << i << " threw an exception.";
254 child_v8 = v8::Null(); 277 child_v8 = v8::Null();
255 } 278 }
256 279
257 if (!val->HasRealIndexedProperty(i)) 280 if (!val->HasRealIndexedProperty(i))
258 continue; 281 continue;
259 282
260 Value* child = FromV8ValueImpl(child_v8, unique_set); 283 Value* child = FromV8ValueImpl(child_v8, unique_set);
261 CHECK(child); 284 if (child)
262 285 result->Append(child);
263 result->Append(child); 286 else
287 // JSON.stringify puts null in places where values don't serialize, for
288 // example undefined and functions. Emulate that behavior.
289 result->Append(Value::CreateNullValue());
264 } 290 }
265 return result; 291 return result;
266 } 292 }
267 293
268 base::BinaryValue* V8ValueConverterImpl::FromV8Buffer( 294 base::BinaryValue* V8ValueConverterImpl::FromV8Buffer(
269 v8::Handle<v8::Value> val) const { 295 v8::Handle<v8::Value> val) const {
270 char* data = NULL; 296 char* data = NULL;
271 size_t length = 0; 297 size_t length = 0;
272 298
273 scoped_ptr<WebKit::WebArrayBuffer> array_buffer( 299 scoped_ptr<WebKit::WebArrayBuffer> array_buffer(
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 v8::TryCatch try_catch; 354 v8::TryCatch try_catch;
329 v8::Handle<v8::Value> child_v8 = val->Get(key); 355 v8::Handle<v8::Value> child_v8 = val->Get(key);
330 356
331 if (try_catch.HasCaught()) { 357 if (try_catch.HasCaught()) {
332 LOG(ERROR) << "Getter for property " << *name_utf8 358 LOG(ERROR) << "Getter for property " << *name_utf8
333 << " threw an exception."; 359 << " threw an exception.";
334 child_v8 = v8::Null(); 360 child_v8 = v8::Null();
335 } 361 }
336 362
337 scoped_ptr<Value> child(FromV8ValueImpl(child_v8, unique_set)); 363 scoped_ptr<Value> child(FromV8ValueImpl(child_v8, unique_set));
338 CHECK(child.get()); 364 if (!child.get())
365 // JSON.stringify skips properties whose values don't serialize, for
366 // example undefined and functions. Emulate that behavior.
367 continue;
339 368
340 // Strip null if asked (and since undefined is turned into null, undefined 369 // Strip null if asked (and since undefined is turned into null, undefined
341 // too). The use case for supporting this is JSON-schema support, 370 // too). The use case for supporting this is JSON-schema support,
342 // specifically for extensions, where "optional" JSON properties may be 371 // specifically for extensions, where "optional" JSON properties may be
343 // represented as null, yet due to buggy legacy code elsewhere isn't 372 // represented as null, yet due to buggy legacy code elsewhere isn't
344 // treated as such (potentially causing crashes). For example, the 373 // treated as such (potentially causing crashes). For example, the
345 // "tabs.create" function takes an object as its first argument with an 374 // "tabs.create" function takes an object as its first argument with an
346 // optional "windowId" property. 375 // optional "windowId" property.
347 // 376 //
348 // Given just 377 // Given just
(...skipping 10 matching lines...) Expand all
359 // We can avoid all bugs related to this by stripping null. 388 // We can avoid all bugs related to this by stripping null.
360 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) 389 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL))
361 continue; 390 continue;
362 391
363 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), 392 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
364 child.release()); 393 child.release());
365 } 394 }
366 395
367 return result.release(); 396 return result.release();
368 } 397 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698