• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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