| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "platform/v8_inspector/V8ConsoleMessage.h" |
| 6 |
| 7 #include "platform/v8_inspector/InspectedContext.h" |
| 8 #include "platform/v8_inspector/V8ConsoleAgentImpl.h" |
| 9 #include "platform/v8_inspector/V8DebuggerImpl.h" |
| 10 #include "platform/v8_inspector/V8InspectorSessionImpl.h" |
| 11 #include "platform/v8_inspector/V8StackTraceImpl.h" |
| 12 #include "platform/v8_inspector/V8StringUtil.h" |
| 13 #include "platform/v8_inspector/public/V8DebuggerClient.h" |
| 14 |
| 15 namespace blink { |
| 16 |
| 17 namespace { |
| 18 |
| 19 String messageSourceValue(MessageSource source) |
| 20 { |
| 21 switch (source) { |
| 22 case XMLMessageSource: return protocol::Console::ConsoleMessage::SourceEnum:
:Xml; |
| 23 case JSMessageSource: return protocol::Console::ConsoleMessage::SourceEnum::
Javascript; |
| 24 case NetworkMessageSource: return protocol::Console::ConsoleMessage::SourceE
num::Network; |
| 25 case ConsoleAPIMessageSource: return protocol::Console::ConsoleMessage::Sour
ceEnum::ConsoleApi; |
| 26 case StorageMessageSource: return protocol::Console::ConsoleMessage::SourceE
num::Storage; |
| 27 case AppCacheMessageSource: return protocol::Console::ConsoleMessage::Source
Enum::Appcache; |
| 28 case RenderingMessageSource: return protocol::Console::ConsoleMessage::Sourc
eEnum::Rendering; |
| 29 case SecurityMessageSource: return protocol::Console::ConsoleMessage::Source
Enum::Security; |
| 30 case OtherMessageSource: return protocol::Console::ConsoleMessage::SourceEnu
m::Other; |
| 31 case DeprecationMessageSource: return protocol::Console::ConsoleMessage::Sou
rceEnum::Deprecation; |
| 32 } |
| 33 return protocol::Console::ConsoleMessage::SourceEnum::Other; |
| 34 } |
| 35 |
| 36 |
| 37 String messageTypeValue(MessageType type) |
| 38 { |
| 39 switch (type) { |
| 40 case LogMessageType: return protocol::Console::ConsoleMessage::TypeEnum::Log
; |
| 41 case ClearMessageType: return protocol::Console::ConsoleMessage::TypeEnum::C
lear; |
| 42 case DirMessageType: return protocol::Console::ConsoleMessage::TypeEnum::Dir
; |
| 43 case DirXMLMessageType: return protocol::Console::ConsoleMessage::TypeEnum::
Dirxml; |
| 44 case TableMessageType: return protocol::Console::ConsoleMessage::TypeEnum::T
able; |
| 45 case TraceMessageType: return protocol::Console::ConsoleMessage::TypeEnum::T
race; |
| 46 case StartGroupMessageType: return protocol::Console::ConsoleMessage::TypeEn
um::StartGroup; |
| 47 case StartGroupCollapsedMessageType: return protocol::Console::ConsoleMessag
e::TypeEnum::StartGroupCollapsed; |
| 48 case EndGroupMessageType: return protocol::Console::ConsoleMessage::TypeEnum
::EndGroup; |
| 49 case AssertMessageType: return protocol::Console::ConsoleMessage::TypeEnum::
Assert; |
| 50 case TimeEndMessageType: return protocol::Console::ConsoleMessage::TypeEnum:
:Log; |
| 51 case CountMessageType: return protocol::Console::ConsoleMessage::TypeEnum::L
og; |
| 52 } |
| 53 return protocol::Console::ConsoleMessage::TypeEnum::Log; |
| 54 } |
| 55 |
| 56 String messageLevelValue(MessageLevel level) |
| 57 { |
| 58 switch (level) { |
| 59 case DebugMessageLevel: return protocol::Console::ConsoleMessage::LevelEnum:
:Debug; |
| 60 case LogMessageLevel: return protocol::Console::ConsoleMessage::LevelEnum::L
og; |
| 61 case WarningMessageLevel: return protocol::Console::ConsoleMessage::LevelEnu
m::Warning; |
| 62 case ErrorMessageLevel: return protocol::Console::ConsoleMessage::LevelEnum:
:Error; |
| 63 case InfoMessageLevel: return protocol::Console::ConsoleMessage::LevelEnum::
Info; |
| 64 case RevokedErrorMessageLevel: return protocol::Console::ConsoleMessage::Lev
elEnum::RevokedError; |
| 65 } |
| 66 return protocol::Console::ConsoleMessage::LevelEnum::Log; |
| 67 } |
| 68 |
| 69 const unsigned maxConsoleMessageCount = 1000; |
| 70 const unsigned maxArrayItemsLimit = 10000; |
| 71 const unsigned maxStackDepthLimit = 32; |
| 72 |
| 73 class V8ValueStringBuilder { |
| 74 public: |
| 75 static String16 toString(v8::Local<v8::Value> value, v8::Isolate* isolate) |
| 76 { |
| 77 V8ValueStringBuilder builder(isolate); |
| 78 if (!builder.append(value)) |
| 79 return String16(); |
| 80 return builder.toString(); |
| 81 } |
| 82 |
| 83 private: |
| 84 enum { |
| 85 IgnoreNull = 1 << 0, |
| 86 IgnoreUndefined = 1 << 1, |
| 87 }; |
| 88 |
| 89 V8ValueStringBuilder(v8::Isolate* isolate) |
| 90 : m_arrayLimit(maxArrayItemsLimit) |
| 91 , m_isolate(isolate) |
| 92 , m_tryCatch(isolate) |
| 93 { |
| 94 } |
| 95 |
| 96 bool append(v8::Local<v8::Value> value, unsigned ignoreOptions = 0) |
| 97 { |
| 98 if (value.IsEmpty()) |
| 99 return true; |
| 100 if ((ignoreOptions & IgnoreNull) && value->IsNull()) |
| 101 return true; |
| 102 if ((ignoreOptions & IgnoreUndefined) && value->IsUndefined()) |
| 103 return true; |
| 104 if (value->IsString()) |
| 105 return append(v8::Local<v8::String>::Cast(value)); |
| 106 if (value->IsStringObject()) |
| 107 return append(v8::Local<v8::StringObject>::Cast(value)->ValueOf()); |
| 108 if (value->IsSymbol()) |
| 109 return append(v8::Local<v8::Symbol>::Cast(value)); |
| 110 if (value->IsSymbolObject()) |
| 111 return append(v8::Local<v8::SymbolObject>::Cast(value)->ValueOf()); |
| 112 if (value->IsNumberObject()) { |
| 113 m_builder.appendNumber(v8::Local<v8::NumberObject>::Cast(value)->Val
ueOf()); |
| 114 return true; |
| 115 } |
| 116 if (value->IsBooleanObject()) { |
| 117 m_builder.append(v8::Local<v8::BooleanObject>::Cast(value)->ValueOf(
) ? "true" : "false"); |
| 118 return true; |
| 119 } |
| 120 if (value->IsArray()) |
| 121 return append(v8::Local<v8::Array>::Cast(value)); |
| 122 if (value->IsProxy()) { |
| 123 m_builder.append("[object Proxy]"); |
| 124 return true; |
| 125 } |
| 126 if (value->IsObject() |
| 127 && !value->IsDate() |
| 128 && !value->IsFunction() |
| 129 && !value->IsNativeError() |
| 130 && !value->IsRegExp()) { |
| 131 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value); |
| 132 v8::Local<v8::String> stringValue; |
| 133 if (object->ObjectProtoToString(m_isolate->GetCurrentContext()).ToLo
cal(&stringValue)) |
| 134 return append(stringValue); |
| 135 } |
| 136 v8::Local<v8::String> stringValue; |
| 137 if (!value->ToString(m_isolate->GetCurrentContext()).ToLocal(&stringValu
e)) |
| 138 return false; |
| 139 return append(stringValue); |
| 140 } |
| 141 |
| 142 bool append(v8::Local<v8::Array> array) |
| 143 { |
| 144 if (m_visitedArrays.contains(array)) |
| 145 return true; |
| 146 uint32_t length = array->Length(); |
| 147 if (length > m_arrayLimit) |
| 148 return false; |
| 149 if (m_visitedArrays.size() > maxStackDepthLimit) |
| 150 return false; |
| 151 |
| 152 bool result = true; |
| 153 m_arrayLimit -= length; |
| 154 m_visitedArrays.append(array); |
| 155 for (uint32_t i = 0; i < length; ++i) { |
| 156 if (i) |
| 157 m_builder.append(','); |
| 158 if (!append(array->Get(i), IgnoreNull | IgnoreUndefined)) { |
| 159 result = false; |
| 160 break; |
| 161 } |
| 162 } |
| 163 m_visitedArrays.removeLast(); |
| 164 return result; |
| 165 } |
| 166 |
| 167 bool append(v8::Local<v8::Symbol> symbol) |
| 168 { |
| 169 m_builder.append("Symbol("); |
| 170 bool result = append(symbol->Name(), IgnoreUndefined); |
| 171 m_builder.append(')'); |
| 172 return result; |
| 173 } |
| 174 |
| 175 bool append(v8::Local<v8::String> string) |
| 176 { |
| 177 if (m_tryCatch.HasCaught()) |
| 178 return false; |
| 179 if (!string.IsEmpty()) |
| 180 m_builder.append(toProtocolString(string)); |
| 181 return true; |
| 182 } |
| 183 |
| 184 String16 toString() |
| 185 { |
| 186 if (m_tryCatch.HasCaught()) |
| 187 return String16(); |
| 188 return m_builder.toString(); |
| 189 } |
| 190 |
| 191 uint32_t m_arrayLimit; |
| 192 v8::Isolate* m_isolate; |
| 193 String16Builder m_builder; |
| 194 Vector<v8::Local<v8::Array>> m_visitedArrays; |
| 195 v8::TryCatch m_tryCatch; |
| 196 }; |
| 197 |
| 198 } // namespace |
| 199 |
| 200 V8ConsoleMessage::V8ConsoleMessage( |
| 201 double timestampMS, |
| 202 MessageSource source, |
| 203 MessageLevel level, |
| 204 const String16& message, |
| 205 const String16& url, |
| 206 unsigned lineNumber, |
| 207 unsigned columnNumber, |
| 208 std::unique_ptr<V8StackTrace> stackTrace, |
| 209 int scriptId, |
| 210 const String16& requestIdentifier) |
| 211 : m_timestamp(timestampMS / 1000.0) |
| 212 , m_source(source) |
| 213 , m_level(level) |
| 214 , m_message(message) |
| 215 , m_url(url) |
| 216 , m_lineNumber(lineNumber) |
| 217 , m_columnNumber(columnNumber) |
| 218 , m_stackTrace(std::move(stackTrace)) |
| 219 , m_scriptId(scriptId) |
| 220 , m_requestIdentifier(requestIdentifier) |
| 221 , m_contextId(0) |
| 222 , m_type(LogMessageType) |
| 223 , m_messageId(0) |
| 224 , m_relatedMessageId(0) |
| 225 { |
| 226 } |
| 227 |
| 228 V8ConsoleMessage::~V8ConsoleMessage() |
| 229 { |
| 230 } |
| 231 |
| 232 std::unique_ptr<protocol::Console::ConsoleMessage> V8ConsoleMessage::buildInspec
torObject(V8InspectorSessionImpl* session, bool generatePreview) const |
| 233 { |
| 234 std::unique_ptr<protocol::Console::ConsoleMessage> result = |
| 235 protocol::Console::ConsoleMessage::create() |
| 236 .setSource(messageSourceValue(m_source)) |
| 237 .setLevel(messageLevelValue(m_level)) |
| 238 .setText(m_message) |
| 239 .setTimestamp(m_timestamp) |
| 240 .build(); |
| 241 result->setType(messageTypeValue(m_type)); |
| 242 result->setLine(static_cast<int>(m_lineNumber)); |
| 243 result->setColumn(static_cast<int>(m_columnNumber)); |
| 244 if (m_scriptId) |
| 245 result->setScriptId(String::number(m_scriptId)); |
| 246 result->setUrl(m_url); |
| 247 if (m_source == NetworkMessageSource && !m_requestIdentifier.isEmpty()) |
| 248 result->setNetworkRequestId(m_requestIdentifier); |
| 249 if (m_contextId) |
| 250 result->setExecutionContextId(m_contextId); |
| 251 appendArguments(result.get(), session, generatePreview); |
| 252 if (m_stackTrace) |
| 253 result->setStack(m_stackTrace->buildInspectorObject()); |
| 254 if (m_messageId) |
| 255 result->setMessageId(m_messageId); |
| 256 if (m_relatedMessageId) |
| 257 result->setRelatedMessageId(m_relatedMessageId); |
| 258 return result; |
| 259 } |
| 260 |
| 261 void V8ConsoleMessage::appendArguments(protocol::Console::ConsoleMessage* result
, V8InspectorSessionImpl* session, bool generatePreview) const |
| 262 { |
| 263 if (!m_arguments.size() || !m_contextId) |
| 264 return; |
| 265 InspectedContext* inspectedContext = session->debugger()->getContext(session
->contextGroupId(), m_contextId); |
| 266 if (!inspectedContext) |
| 267 return; |
| 268 |
| 269 v8::Isolate* isolate = inspectedContext->isolate(); |
| 270 v8::HandleScope handles(isolate); |
| 271 v8::Local<v8::Context> context = inspectedContext->context(); |
| 272 |
| 273 std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>> args = pro
tocol::Array<protocol::Runtime::RemoteObject>::create(); |
| 274 if (m_type == TableMessageType && generatePreview) { |
| 275 v8::Local<v8::Value> table = m_arguments[0]->Get(isolate); |
| 276 v8::Local<v8::Value> columns = m_arguments.size() > 1 ? m_arguments[1]->
Get(isolate) : v8::Local<v8::Value>(); |
| 277 std::unique_ptr<protocol::Runtime::RemoteObject> wrapped = session->wrap
Table(context, table, columns); |
| 278 if (wrapped) |
| 279 args->addItem(std::move(wrapped)); |
| 280 else |
| 281 args = nullptr; |
| 282 } else { |
| 283 for (size_t i = 0; i < m_arguments.size(); ++i) { |
| 284 std::unique_ptr<protocol::Runtime::RemoteObject> wrapped = session->
wrapObject(context, m_arguments[i]->Get(isolate), "console", generatePreview); |
| 285 if (!wrapped) { |
| 286 args = nullptr; |
| 287 break; |
| 288 } |
| 289 args->addItem(std::move(wrapped)); |
| 290 } |
| 291 } |
| 292 if (args) |
| 293 result->setParameters(std::move(args)); |
| 294 } |
| 295 |
| 296 unsigned V8ConsoleMessage::argumentCount() const |
| 297 { |
| 298 return m_arguments.size(); |
| 299 } |
| 300 |
| 301 MessageType V8ConsoleMessage::type() const |
| 302 { |
| 303 return m_type; |
| 304 } |
| 305 |
| 306 // static |
| 307 std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForConsoleAPI(double t
imestampMS, MessageType type, MessageLevel level, const String16& messageText, s
td::vector<v8::Local<v8::Value>>* arguments, std::unique_ptr<V8StackTrace> stack
Trace, InspectedContext* context) |
| 308 { |
| 309 String16 url; |
| 310 unsigned lineNumber = 0; |
| 311 unsigned columnNumber = 0; |
| 312 if (stackTrace && !stackTrace->isEmpty()) { |
| 313 url = stackTrace->topSourceURL(); |
| 314 lineNumber = stackTrace->topLineNumber(); |
| 315 columnNumber = stackTrace->topColumnNumber(); |
| 316 } |
| 317 |
| 318 String16 actualMessage = messageText; |
| 319 |
| 320 Arguments messageArguments; |
| 321 if (arguments && arguments->size()) { |
| 322 for (size_t i = 0; i < arguments->size(); ++i) |
| 323 messageArguments.push_back(wrapUnique(new v8::Global<v8::Value>(cont
ext->isolate(), arguments->at(i)))); |
| 324 if (actualMessage.isEmpty()) |
| 325 actualMessage = V8ValueStringBuilder::toString(messageArguments.at(0
)->Get(context->isolate()), context->isolate()); |
| 326 } |
| 327 |
| 328 std::unique_ptr<V8ConsoleMessage> message = wrapUnique(new V8ConsoleMessage(
timestampMS, ConsoleAPIMessageSource, level, actualMessage, url, lineNumber, col
umnNumber, std::move(stackTrace), 0 /* scriptId */, String16() /* requestIdentif
ier */)); |
| 329 message->m_type = type; |
| 330 if (messageArguments.size()) { |
| 331 message->m_contextId = context->contextId(); |
| 332 message->m_arguments.swap(messageArguments); |
| 333 } |
| 334 |
| 335 context->debugger()->client()->messageAddedToConsole(context->contextGroupId
(), message->m_source, message->m_level, message->m_message, message->m_url, mes
sage->m_lineNumber, message->m_columnNumber, message->m_stackTrace.get()); |
| 336 return message; |
| 337 } |
| 338 |
| 339 void V8ConsoleMessage::contextDestroyed(int contextId) |
| 340 { |
| 341 if (contextId != m_contextId) |
| 342 return; |
| 343 m_contextId = 0; |
| 344 if (m_message.isEmpty()) |
| 345 m_message = "<message collected>"; |
| 346 Arguments empty; |
| 347 m_arguments.swap(empty); |
| 348 } |
| 349 |
| 350 void V8ConsoleMessage::assignId(unsigned id) |
| 351 { |
| 352 m_messageId = id; |
| 353 } |
| 354 |
| 355 void V8ConsoleMessage::assignRelatedId(unsigned id) |
| 356 { |
| 357 m_relatedMessageId = id; |
| 358 } |
| 359 |
| 360 void V8ConsoleMessage::addArguments(v8::Isolate* isolate, int contextId, std::ve
ctor<v8::Local<v8::Value>>* arguments) |
| 361 { |
| 362 if (!arguments || !contextId) |
| 363 return; |
| 364 m_contextId = contextId; |
| 365 for (size_t i = 0; i < arguments->size(); ++i) |
| 366 m_arguments.push_back(wrapUnique(new v8::Global<v8::Value>(isolate, argu
ments->at(i)))); |
| 367 } |
| 368 |
| 369 // ------------------------ V8ConsoleMessageStorage ---------------------------- |
| 370 |
| 371 V8ConsoleMessageStorage::V8ConsoleMessageStorage(V8DebuggerImpl* debugger, int c
ontextGroupId) |
| 372 : m_debugger(debugger) |
| 373 , m_contextGroupId(contextGroupId) |
| 374 , m_expiredCount(0) |
| 375 { |
| 376 } |
| 377 |
| 378 V8ConsoleMessageStorage::~V8ConsoleMessageStorage() |
| 379 { |
| 380 clear(); |
| 381 } |
| 382 |
| 383 void V8ConsoleMessageStorage::addMessage(std::unique_ptr<V8ConsoleMessage> messa
ge) |
| 384 { |
| 385 if (message->type() == ClearMessageType) |
| 386 clear(); |
| 387 |
| 388 V8InspectorSessionImpl* session = m_debugger->sessionForContextGroup(m_conte
xtGroupId); |
| 389 if (session) |
| 390 session->consoleAgent()->messageAdded(message.get()); |
| 391 |
| 392 DCHECK(m_messages.size() <= maxConsoleMessageCount); |
| 393 if (m_messages.size() == maxConsoleMessageCount) { |
| 394 ++m_expiredCount; |
| 395 m_messages.pop_front(); |
| 396 } |
| 397 m_messages.push_back(std::move(message)); |
| 398 } |
| 399 |
| 400 void V8ConsoleMessageStorage::clear() |
| 401 { |
| 402 m_messages.clear(); |
| 403 m_expiredCount = 0; |
| 404 V8InspectorSessionImpl* session = m_debugger->sessionForContextGroup(m_conte
xtGroupId); |
| 405 if (session) { |
| 406 session->consoleAgent()->reset(); |
| 407 session->releaseObjectGroup("console"); |
| 408 session->client()->consoleCleared(); |
| 409 } |
| 410 } |
| 411 |
| 412 void V8ConsoleMessageStorage::contextDestroyed(int contextId) |
| 413 { |
| 414 for (size_t i = 0; i < m_messages.size(); ++i) |
| 415 m_messages[i]->contextDestroyed(contextId); |
| 416 } |
| 417 |
| 418 } // namespace blink |
| OLD | NEW |