1/* 2 * Copyright (C) 2007, 2008, 2014 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> 4 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "ConsoleMessage.h" 33 34#if ENABLE(INSPECTOR) 35 36#include "IdentifiersFactory.h" 37#include "InjectedScript.h" 38#include "InjectedScriptManager.h" 39#include "InspectorValues.h" 40#include "ScriptArguments.h" 41#include "ScriptCallFrame.h" 42#include "ScriptCallStack.h" 43#include "ScriptCallStackFactory.h" 44#include "ScriptValue.h" 45 46namespace Inspector { 47 48ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned long requestIdentifier) 49 : m_source(source) 50 , m_type(type) 51 , m_level(level) 52 , m_message(message) 53 , m_url() 54 , m_line(0) 55 , m_column(0) 56 , m_repeatCount(1) 57 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 58{ 59} 60 61ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned line, unsigned column, JSC::ExecState* state, unsigned long requestIdentifier) 62 : m_source(source) 63 , m_type(type) 64 , m_level(level) 65 , m_message(message) 66 , m_url(url) 67 , m_line(line) 68 , m_column(column) 69 , m_repeatCount(1) 70 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 71{ 72 autogenerateMetadata(state); 73} 74 75ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier) 76 : m_source(source) 77 , m_type(type) 78 , m_level(level) 79 , m_message(message) 80 , m_url() 81 , m_line(0) 82 , m_column(0) 83 , m_repeatCount(1) 84 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 85{ 86 m_callStack = callStack; 87 88 const ScriptCallFrame* frame = m_callStack ? m_callStack->firstNonNativeCallFrame() : nullptr; 89 if (frame) { 90 m_url = frame->sourceURL(); 91 m_line = frame->lineNumber(); 92 m_column = frame->columnNumber(); 93 } 94} 95 96ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, JSC::ExecState* state, unsigned long requestIdentifier) 97 : m_source(source) 98 , m_type(type) 99 , m_level(level) 100 , m_message(message) 101 , m_arguments(arguments) 102 , m_url() 103 , m_line(0) 104 , m_column(0) 105 , m_repeatCount(1) 106 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 107{ 108 autogenerateMetadata(state); 109} 110 111ConsoleMessage::~ConsoleMessage() 112{ 113} 114 115void ConsoleMessage::autogenerateMetadata(JSC::ExecState* state) 116{ 117 if (!state) 118 return; 119 120 if (m_type == MessageType::EndGroup) 121 return; 122 123 // FIXME: Should this really be using "for console" in the generic ConsoleMessage autogeneration? This can skip the first frame. 124 m_callStack = createScriptCallStackForConsole(state, ScriptCallStack::maxCallStackSizeToCapture); 125 126 if (const ScriptCallFrame* frame = m_callStack->firstNonNativeCallFrame()) { 127 m_url = frame->sourceURL(); 128 m_line = frame->lineNumber(); 129 m_column = frame->columnNumber(); 130 return; 131 } 132} 133 134static Inspector::TypeBuilder::Console::ConsoleMessage::Source::Enum messageSourceValue(MessageSource source) 135{ 136 switch (source) { 137 case MessageSource::XML: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::XML; 138 case MessageSource::JS: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Javascript; 139 case MessageSource::Network: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Network; 140 case MessageSource::ConsoleAPI: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::ConsoleAPI; 141 case MessageSource::Storage: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Storage; 142 case MessageSource::AppCache: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Appcache; 143 case MessageSource::Rendering: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Rendering; 144 case MessageSource::CSS: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::CSS; 145 case MessageSource::Security: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Security; 146 case MessageSource::Other: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Other; 147 } 148 return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Other; 149} 150 151static Inspector::TypeBuilder::Console::ConsoleMessage::Type::Enum messageTypeValue(MessageType type) 152{ 153 switch (type) { 154 case MessageType::Log: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Log; 155 case MessageType::Clear: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Clear; 156 case MessageType::Dir: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Dir; 157 case MessageType::DirXML: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::DirXML; 158 case MessageType::Table: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Table; 159 case MessageType::Trace: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Trace; 160 case MessageType::StartGroup: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::StartGroup; 161 case MessageType::StartGroupCollapsed: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::StartGroupCollapsed; 162 case MessageType::EndGroup: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::EndGroup; 163 case MessageType::Assert: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Assert; 164 case MessageType::Timing: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Timing; 165 case MessageType::Profile: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Profile; 166 case MessageType::ProfileEnd: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::ProfileEnd; 167 } 168 return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Log; 169} 170 171static Inspector::TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level) 172{ 173 switch (level) { 174 case MessageLevel::Log: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Log; 175 case MessageLevel::Warning: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Warning; 176 case MessageLevel::Error: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Error; 177 case MessageLevel::Debug: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Debug; 178 } 179 return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Log; 180} 181 182void ConsoleMessage::addToFrontend(InspectorConsoleFrontendDispatcher* consoleFrontendDispatcher, Inspector::InjectedScriptManager* injectedScriptManager, bool generatePreview) 183{ 184 RefPtr<Inspector::TypeBuilder::Console::ConsoleMessage> jsonObj = Inspector::TypeBuilder::Console::ConsoleMessage::create() 185 .setSource(messageSourceValue(m_source)) 186 .setLevel(messageLevelValue(m_level)) 187 .setText(m_message); 188 189 // FIXME: only send out type for ConsoleAPI source messages. 190 jsonObj->setType(messageTypeValue(m_type)); 191 jsonObj->setLine(static_cast<int>(m_line)); 192 jsonObj->setColumn(static_cast<int>(m_column)); 193 jsonObj->setUrl(m_url); 194 jsonObj->setRepeatCount(static_cast<int>(m_repeatCount)); 195 196 if (m_source == MessageSource::Network && !m_requestId.isEmpty()) 197 jsonObj->setNetworkRequestId(m_requestId); 198 199 if (m_arguments && m_arguments->argumentCount()) { 200 InjectedScript injectedScript = injectedScriptManager->injectedScriptFor(m_arguments->globalState()); 201 if (!injectedScript.hasNoValue()) { 202 RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::RemoteObject>> jsonArgs = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::RemoteObject>::create(); 203 if (m_type == MessageType::Table && generatePreview && m_arguments->argumentCount()) { 204 Deprecated::ScriptValue table = m_arguments->argumentAt(0); 205 Deprecated::ScriptValue columns = m_arguments->argumentCount() > 1 ? m_arguments->argumentAt(1) : Deprecated::ScriptValue(); 206 RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns); 207 if (!inspectorValue) { 208 ASSERT_NOT_REACHED(); 209 return; 210 } 211 jsonArgs->addItem(inspectorValue); 212 } else { 213 for (unsigned i = 0; i < m_arguments->argumentCount(); ++i) { 214 RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), "console", generatePreview); 215 if (!inspectorValue) { 216 ASSERT_NOT_REACHED(); 217 return; 218 } 219 jsonArgs->addItem(inspectorValue); 220 } 221 } 222 jsonObj->setParameters(jsonArgs); 223 } 224 } 225 226 if (m_callStack) 227 jsonObj->setStackTrace(m_callStack->buildInspectorArray()); 228 229 consoleFrontendDispatcher->messageAdded(jsonObj); 230} 231 232void ConsoleMessage::updateRepeatCountInConsole(InspectorConsoleFrontendDispatcher* consoleFrontendDispatcher) 233{ 234 consoleFrontendDispatcher->messageRepeatCountUpdated(m_repeatCount); 235} 236 237bool ConsoleMessage::isEqual(ConsoleMessage* msg) const 238{ 239 if (m_arguments) { 240 if (!m_arguments->isEqual(msg->m_arguments.get())) 241 return false; 242 243 // Never treat objects as equal - their properties might change over time. 244 for (size_t i = 0; i < m_arguments->argumentCount(); ++i) { 245 if (m_arguments->argumentAt(i).isObject()) 246 return false; 247 } 248 } else if (msg->m_arguments) 249 return false; 250 251 if (m_callStack) { 252 if (!m_callStack->isEqual(msg->m_callStack.get())) 253 return false; 254 } else if (msg->m_callStack) 255 return false; 256 257 return msg->m_source == m_source 258 && msg->m_type == m_type 259 && msg->m_level == m_level 260 && msg->m_message == m_message 261 && msg->m_line == m_line 262 && msg->m_column == m_column 263 && msg->m_url == m_url 264 && msg->m_requestId == m_requestId; 265} 266 267void ConsoleMessage::clear() 268{ 269 if (!m_message) 270 m_message = ASCIILiteral("<message collected>"); 271 272 if (m_arguments) 273 m_arguments.clear(); 274} 275 276JSC::ExecState* ConsoleMessage::scriptState() const 277{ 278 if (m_arguments) 279 return m_arguments->globalState(); 280 281 return nullptr; 282} 283 284unsigned ConsoleMessage::argumentCount() const 285{ 286 if (m_arguments) 287 return m_arguments->argumentCount(); 288 289 return 0; 290} 291 292} // namespace Inspector 293 294#endif // ENABLE(INSPECTOR) 295