1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25
26 #include "config.h"
27 #include "core/inspector/InspectorConsoleAgent.h"
28
29 #include "bindings/core/v8/ScriptCallStackFactory.h"
30 #include "bindings/core/v8/ScriptController.h"
31 #include "bindings/core/v8/ScriptProfiler.h"
32 #include "core/frame/LocalFrame.h"
33 #include "core/frame/UseCounter.h"
34 #include "core/inspector/ConsoleMessage.h"
35 #include "core/inspector/ConsoleMessageStorage.h"
36 #include "core/inspector/IdentifiersFactory.h"
37 #include "core/inspector/InjectedScript.h"
38 #include "core/inspector/InjectedScriptHost.h"
39 #include "core/inspector/InjectedScriptManager.h"
40 #include "core/inspector/InspectorState.h"
41 #include "core/inspector/InspectorTimelineAgent.h"
42 #include "core/inspector/InstrumentingAgents.h"
43 #include "core/inspector/ScriptArguments.h"
44 #include "core/inspector/ScriptAsyncCallStack.h"
45 #include "core/inspector/ScriptCallFrame.h"
46 #include "core/inspector/ScriptCallStack.h"
47 #include "core/loader/DocumentLoader.h"
48 #include "core/page/Page.h"
49 #include "core/xml/XMLHttpRequest.h"
50 #include "platform/network/ResourceError.h"
51 #include "platform/network/ResourceResponse.h"
52 #include "wtf/CurrentTime.h"
53 #include "wtf/OwnPtr.h"
54 #include "wtf/PassOwnPtr.h"
55 #include "wtf/text/StringBuilder.h"
56 #include "wtf/text/WTFString.h"
57
58 namespace blink {
59
60 namespace ConsoleAgentState {
61 static const char monitoringXHR[] = "monitoringXHR";
62 static const char consoleMessagesEnabled[] = "consoleMessagesEnabled";
63 static const char tracingBasedTimeline[] = "tracingBasedTimeline";
64 }
65
66 int InspectorConsoleAgent::s_enabledAgentCount = 0;
67
InspectorConsoleAgent(InspectorTimelineAgent * timelineAgent,InjectedScriptManager * injectedScriptManager)68 InspectorConsoleAgent::InspectorConsoleAgent(InspectorTimelineAgent* timelineAgent, InjectedScriptManager* injectedScriptManager)
69 : InspectorBaseAgent<InspectorConsoleAgent>("Console")
70 , m_timelineAgent(timelineAgent)
71 , m_injectedScriptManager(injectedScriptManager)
72 , m_frontend(0)
73 , m_enabled(false)
74 {
75 }
76
~InspectorConsoleAgent()77 InspectorConsoleAgent::~InspectorConsoleAgent()
78 {
79 #if !ENABLE(OILPAN)
80 m_instrumentingAgents->setInspectorConsoleAgent(0);
81 #endif
82 }
83
trace(Visitor * visitor)84 void InspectorConsoleAgent::trace(Visitor* visitor)
85 {
86 visitor->trace(m_timelineAgent);
87 visitor->trace(m_injectedScriptManager);
88 InspectorBaseAgent::trace(visitor);
89 }
90
init()91 void InspectorConsoleAgent::init()
92 {
93 m_instrumentingAgents->setInspectorConsoleAgent(this);
94 }
95
enable(ErrorString *)96 void InspectorConsoleAgent::enable(ErrorString*)
97 {
98 if (m_enabled)
99 return;
100 m_enabled = true;
101 if (!s_enabledAgentCount)
102 ScriptController::setCaptureCallStackForUncaughtExceptions(true);
103 ++s_enabledAgentCount;
104
105 m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, true);
106
107 ConsoleMessageStorage* storage = messageStorage();
108 if (storage->expiredCount()) {
109 RefPtrWillBeRawPtr<ConsoleMessage> expiredMessage = ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String::format("%d console messages are not shown.", storage->expiredCount()));
110 expiredMessage->setTimestamp(0);
111 sendConsoleMessageToFrontend(expiredMessage.get(), false);
112 }
113
114 size_t messageCount = storage->size();
115 for (size_t i = 0; i < messageCount; ++i)
116 sendConsoleMessageToFrontend(storage->at(i), false);
117 }
118
disable(ErrorString *)119 void InspectorConsoleAgent::disable(ErrorString*)
120 {
121 if (!m_enabled)
122 return;
123 m_enabled = false;
124 if (!(--s_enabledAgentCount))
125 ScriptController::setCaptureCallStackForUncaughtExceptions(false);
126 m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, false);
127 m_state->setBoolean(ConsoleAgentState::tracingBasedTimeline, false);
128 }
129
clearMessages(ErrorString *)130 void InspectorConsoleAgent::clearMessages(ErrorString*)
131 {
132 messageStorage()->clear();
133 }
134
restore()135 void InspectorConsoleAgent::restore()
136 {
137 if (m_state->getBoolean(ConsoleAgentState::consoleMessagesEnabled)) {
138 m_frontend->messagesCleared();
139 ErrorString error;
140 enable(&error);
141 }
142 }
143
setFrontend(InspectorFrontend * frontend)144 void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
145 {
146 m_frontend = frontend->console();
147 }
148
clearFrontend()149 void InspectorConsoleAgent::clearFrontend()
150 {
151 m_frontend = 0;
152 String errorString;
153 disable(&errorString);
154 }
155
addMessageToConsole(ConsoleMessage * consoleMessage)156 void InspectorConsoleAgent::addMessageToConsole(ConsoleMessage* consoleMessage)
157 {
158 if (m_frontend && m_enabled)
159 sendConsoleMessageToFrontend(consoleMessage, true);
160 }
161
consoleMessagesCleared()162 void InspectorConsoleAgent::consoleMessagesCleared()
163 {
164 m_injectedScriptManager->releaseObjectGroup("console");
165 if (m_frontend && m_enabled)
166 m_frontend->messagesCleared();
167 }
168
setTracingBasedTimeline(ErrorString *,bool enabled)169 void InspectorConsoleAgent::setTracingBasedTimeline(ErrorString*, bool enabled)
170 {
171 m_state->setBoolean(ConsoleAgentState::tracingBasedTimeline, enabled);
172 }
173
consoleTimeline(ExecutionContext * context,const String & title,ScriptState * scriptState)174 void InspectorConsoleAgent::consoleTimeline(ExecutionContext* context, const String& title, ScriptState* scriptState)
175 {
176 UseCounter::count(context, UseCounter::DevToolsConsoleTimeline);
177 if (!m_state->getBoolean(ConsoleAgentState::tracingBasedTimeline))
178 m_timelineAgent->consoleTimeline(context, title, scriptState);
179 }
180
consoleTimelineEnd(ExecutionContext * context,const String & title,ScriptState * scriptState)181 void InspectorConsoleAgent::consoleTimelineEnd(ExecutionContext* context, const String& title, ScriptState* scriptState)
182 {
183 if (!m_state->getBoolean(ConsoleAgentState::tracingBasedTimeline))
184 m_timelineAgent->consoleTimelineEnd(context, title, scriptState);
185 }
186
frameWindowDiscarded(LocalDOMWindow * window)187 void InspectorConsoleAgent::frameWindowDiscarded(LocalDOMWindow* window)
188 {
189 m_injectedScriptManager->discardInjectedScriptsFor(window);
190 }
191
didFinishXHRLoading(XMLHttpRequest *,ThreadableLoaderClient *,unsigned long requestIdentifier,ScriptString,const AtomicString & method,const String & url,const String & sendURL,unsigned sendLineNumber)192 void InspectorConsoleAgent::didFinishXHRLoading(XMLHttpRequest*, ThreadableLoaderClient*, unsigned long requestIdentifier, ScriptString, const AtomicString& method, const String& url, const String& sendURL, unsigned sendLineNumber)
193 {
194 if (m_frontend && m_state->getBoolean(ConsoleAgentState::monitoringXHR)) {
195 String message = "XHR finished loading: " + method + " \"" + url + "\".";
196 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(NetworkMessageSource, DebugMessageLevel, message, sendURL, sendLineNumber);
197 consoleMessage->setRequestIdentifier(requestIdentifier);
198 messageStorage()->reportMessage(consoleMessage.release());
199 }
200 }
201
didFailLoading(unsigned long requestIdentifier,const ResourceError & error)202 void InspectorConsoleAgent::didFailLoading(unsigned long requestIdentifier, const ResourceError& error)
203 {
204 if (error.isCancellation()) // Report failures only.
205 return;
206 StringBuilder message;
207 message.appendLiteral("Failed to load resource");
208 if (!error.localizedDescription().isEmpty()) {
209 message.appendLiteral(": ");
210 message.append(error.localizedDescription());
211 }
212 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(NetworkMessageSource, ErrorMessageLevel, message.toString(), error.failingURL());
213 consoleMessage->setRequestIdentifier(requestIdentifier);
214 messageStorage()->reportMessage(consoleMessage.release());
215 }
216
setMonitoringXHREnabled(ErrorString *,bool enabled)217 void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
218 {
219 m_state->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
220 }
221
messageSourceValue(MessageSource source)222 static TypeBuilder::Console::ConsoleMessage::Source::Enum messageSourceValue(MessageSource source)
223 {
224 switch (source) {
225 case XMLMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Xml;
226 case JSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Javascript;
227 case NetworkMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Network;
228 case ConsoleAPIMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Console_api;
229 case StorageMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Storage;
230 case AppCacheMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Appcache;
231 case RenderingMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Rendering;
232 case CSSMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Css;
233 case SecurityMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Security;
234 case OtherMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Other;
235 case DeprecationMessageSource: return TypeBuilder::Console::ConsoleMessage::Source::Deprecation;
236 }
237 return TypeBuilder::Console::ConsoleMessage::Source::Other;
238 }
239
240
messageTypeValue(MessageType type)241 static TypeBuilder::Console::ConsoleMessage::Type::Enum messageTypeValue(MessageType type)
242 {
243 switch (type) {
244 case LogMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
245 case ClearMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Clear;
246 case DirMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dir;
247 case DirXMLMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Dirxml;
248 case TableMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Table;
249 case TraceMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Trace;
250 case StartGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroup;
251 case StartGroupCollapsedMessageType: return TypeBuilder::Console::ConsoleMessage::Type::StartGroupCollapsed;
252 case EndGroupMessageType: return TypeBuilder::Console::ConsoleMessage::Type::EndGroup;
253 case AssertMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Assert;
254 case TimeEndMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
255 case CountMessageType: return TypeBuilder::Console::ConsoleMessage::Type::Log;
256 }
257 return TypeBuilder::Console::ConsoleMessage::Type::Log;
258 }
259
messageLevelValue(MessageLevel level)260 static TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level)
261 {
262 switch (level) {
263 case DebugMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Debug;
264 case LogMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Log;
265 case WarningMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Warning;
266 case ErrorMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Error;
267 case InfoMessageLevel: return TypeBuilder::Console::ConsoleMessage::Level::Info;
268 }
269 return TypeBuilder::Console::ConsoleMessage::Level::Log;
270 }
271
sendConsoleMessageToFrontend(ConsoleMessage * consoleMessage,bool generatePreview)272 void InspectorConsoleAgent::sendConsoleMessageToFrontend(ConsoleMessage* consoleMessage, bool generatePreview)
273 {
274 if (consoleMessage->workerGlobalScopeProxy())
275 return;
276
277 RefPtr<TypeBuilder::Console::ConsoleMessage> jsonObj = TypeBuilder::Console::ConsoleMessage::create()
278 .setSource(messageSourceValue(consoleMessage->source()))
279 .setLevel(messageLevelValue(consoleMessage->level()))
280 .setText(consoleMessage->message())
281 .setTimestamp(consoleMessage->timestamp());
282 // FIXME: only send out type for ConsoleAPI source messages.
283 jsonObj->setType(messageTypeValue(consoleMessage->type()));
284 jsonObj->setLine(static_cast<int>(consoleMessage->lineNumber()));
285 jsonObj->setColumn(static_cast<int>(consoleMessage->columnNumber()));
286 if (consoleMessage->scriptId())
287 jsonObj->setScriptId(String::number(consoleMessage->scriptId()));
288 jsonObj->setUrl(consoleMessage->url());
289 ScriptState* scriptState = consoleMessage->scriptState();
290 if (scriptState)
291 jsonObj->setExecutionContextId(m_injectedScriptManager->injectedScriptIdFor(scriptState));
292 if (consoleMessage->source() == NetworkMessageSource && consoleMessage->requestIdentifier())
293 jsonObj->setNetworkRequestId(IdentifiersFactory::requestId(consoleMessage->requestIdentifier()));
294 RefPtrWillBeRawPtr<ScriptArguments> arguments = consoleMessage->scriptArguments();
295 if (arguments && arguments->argumentCount()) {
296 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(arguments->scriptState());
297 if (!injectedScript.isEmpty()) {
298 RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject> > jsonArgs = TypeBuilder::Array<TypeBuilder::Runtime::RemoteObject>::create();
299 if (consoleMessage->type() == TableMessageType && generatePreview && arguments->argumentCount()) {
300 ScriptValue table = arguments->argumentAt(0);
301 ScriptValue columns = arguments->argumentCount() > 1 ? arguments->argumentAt(1) : ScriptValue();
302 RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns);
303 if (!inspectorValue) {
304 ASSERT_NOT_REACHED();
305 return;
306 }
307 jsonArgs->addItem(inspectorValue);
308 } else {
309 for (unsigned i = 0; i < arguments->argumentCount(); ++i) {
310 RefPtr<TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(arguments->argumentAt(i), "console", generatePreview);
311 if (!inspectorValue) {
312 ASSERT_NOT_REACHED();
313 return;
314 }
315 jsonArgs->addItem(inspectorValue);
316 }
317 }
318 jsonObj->setParameters(jsonArgs);
319 }
320 }
321 if (consoleMessage->callStack()) {
322 jsonObj->setStackTrace(consoleMessage->callStack()->buildInspectorArray());
323 RefPtrWillBeRawPtr<ScriptAsyncCallStack> asyncCallStack = consoleMessage->callStack()->asyncCallStack();
324 if (asyncCallStack)
325 jsonObj->setAsyncStackTrace(asyncCallStack->buildInspectorObject());
326 }
327 m_frontend->messageAdded(jsonObj);
328 m_frontend->flush();
329 }
330
331 class InspectableHeapObject FINAL : public InjectedScriptHost::InspectableObject {
332 public:
InspectableHeapObject(int heapObjectId)333 explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { }
get(ScriptState *)334 virtual ScriptValue get(ScriptState*) OVERRIDE
335 {
336 return ScriptProfiler::objectByHeapObjectId(m_heapObjectId);
337 }
338 private:
339 int m_heapObjectId;
340 };
341
addInspectedHeapObject(ErrorString *,int inspectedHeapObjectId)342 void InspectorConsoleAgent::addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId)
343 {
344 m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableHeapObject(inspectedHeapObjectId)));
345 }
346
347 } // namespace blink
348