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/dom/ExecutionContext.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_scriptState(0) 55 , m_url() 56 , m_line(0) 57 , m_column(0) 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* scriptState, unsigned long requestIdentifier) 65 : m_source(source) 66 , m_type(type) 67 , m_level(level) 68 , m_message(message) 69 , m_scriptState(scriptState) 70 , m_url(url) 71 , m_line(line) 72 , m_column(column) 73 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 74 , m_timestamp(WTF::currentTime()) 75 { 76 autogenerateMetadata(canGenerateCallStack, scriptState); 77 } 78 79 ConsoleMessage::ConsoleMessage(bool, MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack, unsigned long requestIdentifier) 80 : m_source(source) 81 , m_type(type) 82 , m_level(level) 83 , m_message(message) 84 , m_scriptState(0) 85 , m_arguments(nullptr) 86 , m_line(0) 87 , m_column(0) 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, PassRefPtrWillBeRawPtr<ScriptArguments> arguments, ScriptState* scriptState, unsigned long requestIdentifier) 101 : m_source(source) 102 , m_type(type) 103 , m_level(level) 104 , m_message(message) 105 , m_scriptState(scriptState) 106 , m_arguments(arguments) 107 , m_url() 108 , m_line(0) 109 , m_column(0) 110 , m_requestId(IdentifiersFactory::requestId(requestIdentifier)) 111 , m_timestamp(WTF::currentTime()) 112 { 113 autogenerateMetadata(canGenerateCallStack, scriptState); 114 } 115 116 ConsoleMessage::~ConsoleMessage() 117 { 118 } 119 120 void ConsoleMessage::autogenerateMetadata(bool canGenerateCallStack, ScriptState* scriptState) 121 { 122 if (m_type == EndGroupMessageType) 123 return; 124 125 if (scriptState) 126 m_callStack = createScriptCallStackForConsole(scriptState); 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 } 175 return TypeBuilder::Console::ConsoleMessage::Type::Log; 176 } 177 178 static TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level) 179 { 180 switch (level) { 181 case DebugMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Debug; 182 case LogMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Log; 183 case WarningMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Warning; 184 case ErrorMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Error; 185 case InfoMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Info; 186 } 187 return TypeBuilder::Console::ConsoleMessage::Level::Log; 188 } 189 190 void ConsoleMessage::addToFrontend(InspectorFrontend::Console* frontend, InjectedScriptManager* injectedScriptManager, bool generatePreview) 191 { 192 RefPtr<TypeBuilder::Console::ConsoleMessage> jsonObj = TypeBuilder::Console::ConsoleMessage::create() 193 .setSource(messageSourceValue(m_source)) 194 .setLevel(messageLevelValue(m_level)) 195 .setText(m_message) 196 .setTimestamp(m_timestamp); 197 // FIXME: only send out type for ConsoleAPI source messages. 198 jsonObj->setType(messageTypeValue(m_type)); 199 jsonObj->setLine(static_cast<int>(m_line)); 200 jsonObj->setColumn(static_cast<int>(m_column)); 201 jsonObj->setUrl(m_url); 202 ScriptState* scriptState = m_scriptState.get(); 203 if (scriptState && scriptState->executionContext()->isDocument()) 204 jsonObj->setExecutionContextId(injectedScriptManager->injectedScriptIdFor(scriptState)); 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->scriptState()); 209 if (!injectedScript.isEmpty()) { 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 frontend->flush(); 237 } 238 239 void ConsoleMessage::windowCleared(LocalDOMWindow* window) 240 { 241 if (m_scriptState.get() && m_scriptState.get()->domWindow() == window) 242 m_scriptState.clear(); 243 244 if (!m_arguments) 245 return; 246 if (m_arguments->scriptState()->domWindow() != window) 247 return; 248 if (!m_message) 249 m_message = "<message collected>"; 250 m_arguments.clear(); 251 } 252 253 unsigned ConsoleMessage::argumentCount() 254 { 255 if (m_arguments) 256 return m_arguments->argumentCount(); 257 return 0; 258 } 259 260 } // namespace WebCore 261 262