1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Matt Lilek <webkit (at) 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 Computer, 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 33 34 #include "core/inspector/ConsoleMessage.h" 35 36 #include "bindings/v8/ScriptCallStackFactory.h" 37 #include "bindings/v8/ScriptValue.h" 38 #include "core/inspector/IdentifiersFactory.h" 39 #include "core/inspector/InjectedScript.h" 40 #include "core/inspector/InjectedScriptManager.h" 41 #include "core/inspector/ScriptArguments.h" 42 #include "core/inspector/ScriptCallFrame.h" 43 #include "core/inspector/ScriptCallStack.h" 44 #include "wtf/CurrentTime.h" 45 46 namespace WebCore { 47 48 ConsoleMessage::ConsoleMessage(bool canGenerateCallStack, MessageSource source, MessageType type, MessageLevel level, const String& message) 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(0)) 58 , m_timestamp(WTF::currentTime()) 59 { 60 autogenerateMetadata(canGenerateCallStack); 61 } 62 63 ConsoleMessage::ConsoleMessage(bool canGenerateCallStack, MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned line, unsigned column, ScriptState* state, unsigned long requestIdentifier) 64 : m_source(source) 65 , m_type(type) 66 , m_level(level) 67 , m_message(message) 68 , m_url(url) 69 , m_line(line) 70 , m_column(column) 71 , m_repeatCount(1) 72 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 73 , m_timestamp(WTF::currentTime()) 74 { 75 autogenerateMetadata(canGenerateCallStack, state); 76 } 77 78 ConsoleMessage::ConsoleMessage(bool, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier) 79 : m_source(source) 80 , m_type(type) 81 , m_level(level) 82 , m_message(message) 83 , m_arguments(0) 84 , m_line(0) 85 , m_column(0) 86 , m_repeatCount(1) 87 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 88 , m_timestamp(WTF::currentTime()) 89 { 90 if (callStack && callStack->size()) { 91 const ScriptCallFrame& frame = callStack->at(0); 92 m_url = frame.sourceURL(); 93 m_line = frame.lineNumber(); 94 m_column = frame.columnNumber(); 95 } 96 m_callStack = callStack; 97 } 98 99 ConsoleMessage::ConsoleMessage(bool canGenerateCallStack, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, ScriptState* state, unsigned long requestIdentifier) 100 : m_source(source) 101 , m_type(type) 102 , m_level(level) 103 , m_message(message) 104 , m_arguments(arguments) 105 , m_url() 106 , m_line(0) 107 , m_column(0) 108 , m_repeatCount(1) 109 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 110 , m_timestamp(WTF::currentTime()) 111 { 112 autogenerateMetadata(canGenerateCallStack, state); 113 } 114 115 ConsoleMessage::~ConsoleMessage() 116 { 117 } 118 119 void ConsoleMessage::autogenerateMetadata(bool canGenerateCallStack, ScriptState* state) 120 { 121 if (m_type == EndGroupMessageType) 122 return; 123 124 if (state) 125 m_callStack = createScriptCallStackForConsole(); 126 else if (canGenerateCallStack) 127 m_callStack = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true); 128 else 129 return; 130 131 if (m_callStack && m_callStack->size()) { 132 const ScriptCallFrame& frame = m_callStack->at(0); 133 m_url = frame.sourceURL(); 134 m_line = frame.lineNumber(); 135 m_column = frame.columnNumber(); 136 return; 137 } 138 139 m_callStack.clear(); 140 } 141 142 static TypeBuilder::Console::ConsoleMessage::Source::Enum messageSourceValue(MessageSource source) 143 { 144 switch (source) { 145 case XMLMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Xml; 146 case JSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Javascript; 147 case NetworkMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Network; 148 case ConsoleAPIMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Console_api; 149 case StorageMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Storage; 150 case AppCacheMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Appcache; 151 case RenderingMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Rendering; 152 case CSSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Css; 153 case SecurityMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Security; 154 case OtherMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Other; 155 case DeprecationMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Deprecation; 156 } 157 return TypeBuilder::Console::ConsoleMessage::Source::Other; 158 } 159 160 static TypeBuilder::Console::ConsoleMessage::Type::Enum messageTypeValue(MessageType type) 161 { 162 switch (type) { 163 case LogMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log; 164 case ClearMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Clear; 165 case DirMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dir; 166 case DirXMLMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dirxml; 167 case TableMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Table; 168 case TraceMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Trace; 169 case StartGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroup; 170 case StartGroupCollapsedMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroupCollapsed; 171 case EndGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::EndGroup; 172 case AssertMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Assert; 173 } 174 return TypeBuilder::Console::ConsoleMessage::Type::Log; 175 } 176 177 static TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level) 178 { 179 switch (level) { 180 case DebugMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Debug; 181 case LogMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Log; 182 case WarningMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Warning; 183 case ErrorMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Error; 184 case InfoMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Info; 185 } 186 return TypeBuilder::Console::ConsoleMessage::Level::Log; 187 } 188 189 void ConsoleMessage::addToFrontend(InspectorFrontend::Console* frontend, InjectedScriptManager* injectedScriptManager, bool generatePreview) 190 { 191 RefPtr<TypeBuilder::Console::ConsoleMessage> jsonObj = TypeBuilder::Console::ConsoleMessage::create() 192 .setSource(messageSourceValue(m_source)) 193 .setLevel(messageLevelValue(m_level)) 194 .setText(m_message) 195 .setTimestamp(m_timestamp); 196 // FIXME: only send out type for ConsoleAPI source messages. 197 jsonObj->setType(messageTypeValue(m_type)); 198 jsonObj->setLine(static_cast<int>(m_line)); 199 jsonObj->setColumn(static_cast<int>(m_column)); 200 jsonObj->setUrl(m_url); 201 jsonObj->setRepeatCount(static_cast<int>(m_repeatCount)); 202 if (m_source == NetworkMessageSource && !m_requestId.isEmpty()) 203 jsonObj->setNetworkRequestId(m_requestId); 204 if (m_arguments && m_arguments->argumentCount()) { 205 InjectedScript injectedScript = injectedScriptManager->injectedScriptFor(m_arguments->globalState()); 206 if (!injectedScript.hasNoValue()) { 207 RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject> > jsonArgs = TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject>::create(); 208 if (m_type == TableMessageType && generatePreview && m_arguments->argumentCount()) { 209 ScriptValue table = m_arguments->argumentAt(0); 210 ScriptValue columns = m_arguments->argumentCount() > 1 ? m_arguments->argumentAt(1) : ScriptValue(); 211 RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns); 212 if (!inspectorValue) { 213 ASSERT_NOT_REACHED(); 214 return; 215 } 216 jsonArgs->addItem(inspectorValue); 217 } else { 218 for (unsigned i = 0; i < m_arguments->argumentCount(); ++i) { 219 RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), "console", generatePreview); 220 if (!inspectorValue) { 221 ASSERT_NOT_REACHED(); 222 return; 223 } 224 jsonArgs->addItem(inspectorValue); 225 } 226 } 227 jsonObj->setParameters(jsonArgs); 228 } 229 } 230 if (m_callStack) 231 jsonObj->setStackTrace(m_callStack->buildInspectorArray()); 232 frontend->messageAdded(jsonObj); 233 } 234 235 void ConsoleMessage::incrementCount() 236 { 237 m_timestamp = WTF::currentTime(); 238 ++m_repeatCount; 239 } 240 241 void ConsoleMessage::updateRepeatCountInConsole(InspectorFrontend::Console* frontend) 242 { 243 frontend->messageRepeatCountUpdated(m_repeatCount, m_timestamp); 244 } 245 246 bool ConsoleMessage::isEqual(ConsoleMessage* msg) const 247 { 248 if (m_arguments) { 249 if (!m_arguments->isEqual(msg->m_arguments.get())) 250 return false; 251 // Never treat objects as equal - their properties might change over time. 252 for (size_t i = 0; i < m_arguments->argumentCount(); ++i) { 253 if (m_arguments->argumentAt(i).isObject()) 254 return false; 255 } 256 } else if (msg->m_arguments) 257 return false; 258 259 if (m_callStack) { 260 if (!m_callStack->isEqual(msg->m_callStack.get())) 261 return false; 262 } else if (msg->m_callStack) 263 return false; 264 265 return msg->m_source == m_source 266 && msg->m_type == m_type 267 && msg->m_level == m_level 268 && msg->m_message == m_message 269 && msg->m_line == m_line 270 && msg->m_column == m_column 271 && msg->m_url == m_url 272 && msg->m_requestId == m_requestId; 273 } 274 275 void ConsoleMessage::windowCleared(DOMWindow* window) 276 { 277 if (!m_arguments) 278 return; 279 if (m_arguments->globalState()->domWindow() != window) 280 return; 281 if (!m_message) 282 m_message = "<message collected>"; 283 m_arguments.clear(); 284 } 285 286 unsigned ConsoleMessage::argumentCount() 287 { 288 if (m_arguments) 289 return m_arguments->argumentCount(); 290 return 0; 291 } 292 293 } // namespace WebCore 294 295