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