Index: Source/core/inspector/ScriptArguments.cpp |
diff --git a/Source/core/inspector/ScriptArguments.cpp b/Source/core/inspector/ScriptArguments.cpp |
index bbb163955a990dd38748ab91cda43b70f7445ae1..76349f1529fb7f5a3ee94a52497d7992c9f4d071 100644 |
--- a/Source/core/inspector/ScriptArguments.cpp |
+++ b/Source/core/inspector/ScriptArguments.cpp |
@@ -33,10 +33,127 @@ |
#include "bindings/core/v8/ScriptValue.h" |
#include "bindings/core/v8/V8Binding.h" |
+#include "wtf/Vector.h" |
+#include "wtf/text/StringBuilder.h" |
#include <v8.h> |
namespace WebCore { |
+namespace { |
+ |
+static const int maxArrayItemsLimit = 10000; |
+static const int maxStackDepthLimit = 32; |
+ |
+class V8ValueStringBuilder { |
+public: |
+ static String toString(v8::Handle<v8::Value> value) |
+ { |
+ V8ValueStringBuilder builder; |
+ if (!builder.append(value)) |
yurys
2014/07/14 16:36:09
This check seems redundant.
aandrey
2014/07/18 08:54:47
Nope, builder can also fail w/o throwing an except
|
+ return String(); |
+ return builder.toString(); |
+ } |
+ |
+private: |
+ enum { |
+ IgnoreNull = 1 << 0, |
+ IgnoreUndefined = 1 << 1, |
+ }; |
+ |
+ V8ValueStringBuilder() : m_arrayLimit(maxArrayItemsLimit) { } |
+ |
+ bool append(v8::Handle<v8::Value> value, unsigned ignoreOptions = 0) |
+ { |
+ if (value.IsEmpty()) |
+ return true; |
+ if ((ignoreOptions & IgnoreNull) && value->IsNull()) |
+ return true; |
+ if ((ignoreOptions & IgnoreUndefined) && value->IsUndefined()) |
+ return true; |
+ if (value->IsString()) |
+ return append(v8::Handle<v8::String>::Cast(value)); |
+ if (value->IsStringObject()) |
+ return append(v8::Handle<v8::StringObject>::Cast(value)->ValueOf()); |
+ if (value->IsSymbol()) |
+ return append(v8::Handle<v8::Symbol>::Cast(value)); |
+ if (value->IsSymbolObject()) |
+ return append(v8::Handle<v8::SymbolObject>::Cast(value)->ValueOf()); |
+ if (value->IsNumberObject()) { |
+ m_builder.appendNumber(v8::Handle<v8::NumberObject>::Cast(value)->ValueOf()); |
+ return true; |
+ } |
+ if (value->IsBooleanObject()) { |
+ m_builder.append(v8::Handle<v8::BooleanObject>::Cast(value)->ValueOf() ? "true" : "false"); |
+ return true; |
+ } |
+ if (value->IsArray()) |
+ return append(v8::Handle<v8::Array>::Cast(value)); |
+ if (value->IsObject() |
+ && !value->IsDate() |
+ && !value->IsFunction() |
+ && !value->IsNativeError() |
+ && !value->IsRegExp()) |
+ return append(v8::Handle<v8::Object>::Cast(value)->ObjectProtoToString()); |
+ return append(value->ToString()); |
+ } |
+ |
+ bool append(v8::Handle<v8::Array> array) |
+ { |
+ if (m_visitedArrays.contains(array)) |
+ return true; |
+ uint32_t length = array->Length(); |
+ if (length > m_arrayLimit) |
+ return false; |
+ if (m_visitedArrays.size() > maxStackDepthLimit) |
+ return false; |
+ |
+ bool result = true; |
+ m_arrayLimit -= length; |
+ m_visitedArrays.append(array); |
+ for (uint32_t i = 0; i < length; ++i) { |
+ if (i) |
+ m_builder.append(','); |
+ if (!append(array->Get(i), IgnoreNull | IgnoreUndefined)) { |
+ result = false; |
+ break; |
+ } |
+ } |
+ m_visitedArrays.removeLast(); |
+ return result; |
+ } |
+ |
+ bool append(v8::Handle<v8::Symbol> symbol) |
+ { |
+ m_builder.append("Symbol("); |
+ bool result = append(symbol->Name(), IgnoreUndefined); |
+ m_builder.append(')'); |
+ return result; |
+ } |
+ |
+ bool append(v8::Handle<v8::String> string) |
+ { |
+ if (m_tryCatch.HasCaught()) |
+ return false; |
+ if (!string.IsEmpty()) |
+ m_builder.append(toCoreString(string)); |
+ return true; |
+ } |
+ |
+ String toString() |
+ { |
+ if (m_tryCatch.HasCaught()) |
+ return String(); |
+ return m_builder.toString(); |
+ } |
+ |
+ uint32_t m_arrayLimit; |
+ StringBuilder m_builder; |
+ Vector<v8::Handle<v8::Array> > m_visitedArrays; |
+ v8::TryCatch m_tryCatch; |
+}; |
+ |
+} // namespace |
+ |
DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(ScriptArguments) |
PassRefPtrWillBeRawPtr<ScriptArguments> ScriptArguments::create(ScriptState* scriptState, Vector<ScriptValue>& arguments) |
@@ -66,10 +183,7 @@ bool ScriptArguments::getFirstArgumentAsString(String& result, bool checkForNull |
if (checkForNullOrUndefined && (value.isNull() || value.isUndefined())) |
return false; |
- // We intentionally ignore an exception that can be thrown in ToString(). |
- v8::TryCatch block; |
- v8::Handle<v8::String> string = value.v8Value()->ToString(); |
- result = string.IsEmpty() ? String() : toCoreString(string); |
+ result = V8ValueStringBuilder::toString(value.v8Value()); |
return true; |
} |