blob: 38d7aeb912be106730868d98f2ae3ec25ba9d9ce [file] [log] [blame]
yurys@chromium.org7382e722011-01-14 14:57:21 +00001/*
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 "InspectorConsoleAgent.h"
28
29#if ENABLE(INSPECTOR)
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000030#include "InstrumentingAgents.h"
yurys@chromium.org7382e722011-01-14 14:57:21 +000031#include "Console.h"
32#include "ConsoleMessage.h"
33#include "InjectedScriptHost.h"
yurys@chromium.org8eee6592011-03-11 13:26:56 +000034#include "InjectedScriptManager.h"
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +000035#include "InspectorAgent.h"
yurys@chromium.org7382e722011-01-14 14:57:21 +000036#include "InspectorDOMAgent.h"
37#include "InspectorFrontend.h"
38#include "InspectorState.h"
39#include "ResourceError.h"
40#include "ResourceResponse.h"
41#include "ScriptArguments.h"
pfeldman@chromium.org88146722011-01-17 10:44:50 +000042#include "ScriptCallFrame.h"
yurys@chromium.org7382e722011-01-14 14:57:21 +000043#include "ScriptCallStack.h"
44#include <wtf/CurrentTime.h>
45#include <wtf/OwnPtr.h>
46#include <wtf/PassOwnPtr.h>
47#include <wtf/text/StringConcatenate.h>
48
49namespace WebCore {
50
51static const unsigned maximumConsoleMessages = 1000;
52static const unsigned expireConsoleMessagesStep = 100;
53
caseq@chromium.org0b55a5b2011-02-08 13:42:10 +000054namespace ConsoleAgentState {
55static const char monitoringXHR[] = "monitoringXHR";
56static const char consoleMessagesEnabled[] = "consoleMessagesEnabled";
57}
58
yurys@chromium.org8eee6592011-03-11 13:26:56 +000059InspectorConsoleAgent::InspectorConsoleAgent(InstrumentingAgents* instrumentingAgents, InspectorAgent* inspectorAgent, InspectorState* state, InjectedScriptManager* injectedScriptManager, InspectorDOMAgent* domAgent)
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000060 : m_instrumentingAgents(instrumentingAgents)
61 , m_inspectorAgent(inspectorAgent)
62 , m_inspectorState(state)
yurys@chromium.org8eee6592011-03-11 13:26:56 +000063 , m_injectedScriptManager(injectedScriptManager)
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000064 , m_inspectorDOMAgent(domAgent)
yurys@chromium.org7382e722011-01-14 14:57:21 +000065 , m_frontend(0)
66 , m_previousMessage(0)
67 , m_expiredConsoleMessageCount(0)
68{
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000069 m_instrumentingAgents->setInspectorConsoleAgent(this);
yurys@chromium.org7382e722011-01-14 14:57:21 +000070}
71
72InspectorConsoleAgent::~InspectorConsoleAgent()
73{
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000074 m_instrumentingAgents->setInspectorConsoleAgent(0);
75 m_instrumentingAgents = 0;
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +000076 m_inspectorAgent = 0;
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000077 m_inspectorState = 0;
yurys@chromium.org8eee6592011-03-11 13:26:56 +000078 m_injectedScriptManager = 0;
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +000079 m_inspectorDOMAgent = 0;
yurys@chromium.org7382e722011-01-14 14:57:21 +000080}
81
loislo@chromium.orgdf5982d2011-02-24 11:43:39 +000082void InspectorConsoleAgent::setConsoleMessagesEnabled(ErrorString*, bool enabled, bool* newState)
yurys@chromium.org7382e722011-01-14 14:57:21 +000083{
84 *newState = enabled;
85 setConsoleMessagesEnabled(enabled);
86}
87
loislo@chromium.orgdf5982d2011-02-24 11:43:39 +000088void InspectorConsoleAgent::clearConsoleMessages(ErrorString*)
yurys@chromium.org7382e722011-01-14 14:57:21 +000089{
90 m_consoleMessages.clear();
91 m_expiredConsoleMessageCount = 0;
92 m_previousMessage = 0;
pfeldman@chromium.org78278562011-03-21 07:42:31 +000093 m_injectedScriptManager->releaseObjectGroup("console");
yurys@chromium.org8eee6592011-03-11 13:26:56 +000094 m_inspectorDOMAgent->releaseDanglingNodes();
yurys@chromium.org7382e722011-01-14 14:57:21 +000095 if (m_frontend)
96 m_frontend->consoleMessagesCleared();
97}
98
99void InspectorConsoleAgent::reset()
100{
loislo@chromium.orgdf5982d2011-02-24 11:43:39 +0000101 ErrorString error;
102 clearConsoleMessages(&error);
yurys@chromium.org7382e722011-01-14 14:57:21 +0000103 m_times.clear();
104 m_counts.clear();
105}
106
107void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
108{
yurys@chromium.org3fb16632011-03-03 05:43:34 +0000109 m_frontend = frontend->console();
yurys@chromium.org7382e722011-01-14 14:57:21 +0000110}
111
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000112void InspectorConsoleAgent::clearFrontend()
113{
114 m_frontend = 0;
115}
116
yurys@chromium.org7382e722011-01-14 14:57:21 +0000117void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
118{
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +0000119 if (!m_inspectorAgent->enabled())
yurys@chromium.org7382e722011-01-14 14:57:21 +0000120 return;
121 addConsoleMessage(new ConsoleMessage(source, type, level, message, arguments, callStack));
122}
123
124void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
125{
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +0000126 if (!m_inspectorAgent->enabled())
yurys@chromium.org7382e722011-01-14 14:57:21 +0000127 return;
128 addConsoleMessage(new ConsoleMessage(source, type, level, message, lineNumber, sourceID));
129}
130
131void InspectorConsoleAgent::startTiming(const String& title)
132{
133 // Follow Firebug's behavior of requiring a title that is not null or
134 // undefined for timing functions
135 if (title.isNull())
136 return;
137
138 m_times.add(title, currentTime() * 1000);
139}
140
pfeldman@chromium.org88146722011-01-17 10:44:50 +0000141void InspectorConsoleAgent::stopTiming(const String& title, PassRefPtr<ScriptCallStack> callStack)
yurys@chromium.org7382e722011-01-14 14:57:21 +0000142{
143 // Follow Firebug's behavior of requiring a title that is not null or
144 // undefined for timing functions
145 if (title.isNull())
146 return;
147
148 HashMap<String, double>::iterator it = m_times.find(title);
149 if (it == m_times.end())
150 return;
151
152 double startTime = it->second;
153 m_times.remove(it);
154
155 double elapsed = currentTime() * 1000 - startTime;
156 String message = title + String::format(": %.0fms", elapsed);
pfeldman@chromium.org88146722011-01-17 10:44:50 +0000157 const ScriptCallFrame& lastCaller = callStack->at(0);
158 addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL());
yurys@chromium.org7382e722011-01-14 14:57:21 +0000159}
160
pfeldman@chromium.org88146722011-01-17 10:44:50 +0000161void InspectorConsoleAgent::count(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
yurys@chromium.org7382e722011-01-14 14:57:21 +0000162{
pfeldman@chromium.org88146722011-01-17 10:44:50 +0000163 const ScriptCallFrame& lastCaller = callStack->at(0);
164 // Follow Firebug's behavior of counting with null and undefined title in
165 // the same bucket as no argument
166 String title;
167 arguments->getFirstArgumentAsString(title);
168 String identifier = makeString(title, '@', lastCaller.sourceURL(), ':', String::number(lastCaller.lineNumber()));
169
yurys@chromium.org7382e722011-01-14 14:57:21 +0000170 HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
171 int count;
172 if (it == m_counts.end())
173 count = 1;
174 else {
175 count = it->second + 1;
176 m_counts.remove(it);
177 }
178
179 m_counts.add(identifier, count);
180
181 String message = makeString(title, ": ", String::number(count));
pfeldman@chromium.org88146722011-01-17 10:44:50 +0000182 addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL());
yurys@chromium.org7382e722011-01-14 14:57:21 +0000183}
184
185void InspectorConsoleAgent::resourceRetrievedByXMLHttpRequest(const String& url, const String& sendURL, unsigned sendLineNumber)
186{
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +0000187 if (!m_inspectorAgent->enabled())
yurys@chromium.org7382e722011-01-14 14:57:21 +0000188 return;
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000189 if (m_inspectorState->getBoolean(ConsoleAgentState::monitoringXHR))
yurys@chromium.org7382e722011-01-14 14:57:21 +0000190 addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL);
191}
192
193void InspectorConsoleAgent::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
194{
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +0000195 if (!m_inspectorAgent->enabled())
yurys@chromium.org7382e722011-01-14 14:57:21 +0000196 return;
197
198 if (response.httpStatusCode() >= 400) {
199 String message = makeString("Failed to load resource: the server responded with a status of ", String::number(response.httpStatusCode()), " (", response.httpStatusText(), ')');
200 addConsoleMessage(new ConsoleMessage(OtherMessageSource, NetworkErrorMessageType, ErrorMessageLevel, message, response.url().string(), identifier));
201 }
202}
203
204void InspectorConsoleAgent::didFailLoading(unsigned long identifier, const ResourceError& error)
205{
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +0000206 if (!m_inspectorAgent->enabled())
yurys@chromium.org7382e722011-01-14 14:57:21 +0000207 return;
caseq@chromium.org9746e952011-03-11 09:28:38 +0000208 if (error.isCancellation()) // Report failures only.
209 return;
yurys@chromium.org7382e722011-01-14 14:57:21 +0000210 String message = "Failed to load resource";
211 if (!error.localizedDescription().isEmpty())
212 message += ": " + error.localizedDescription();
213 addConsoleMessage(new ConsoleMessage(OtherMessageSource, NetworkErrorMessageType, ErrorMessageLevel, message, error.failingURL(), identifier));
214}
215
loislo@chromium.orgdf5982d2011-02-24 11:43:39 +0000216void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
pfeldman@chromium.org631b2ce2011-01-20 12:49:27 +0000217{
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000218 m_inspectorState->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
pfeldman@chromium.org631b2ce2011-01-20 12:49:27 +0000219}
220
yurys@chromium.org8eee6592011-03-11 13:26:56 +0000221void InspectorConsoleAgent::addInspectedNode(ErrorString*, long nodeId)
222{
223 Node* node = m_inspectorDOMAgent->nodeForId(nodeId);
224 if (!node)
225 return;
226 m_injectedScriptManager->injectedScriptHost()->addInspectedNode(node);
227}
228
yurys@chromium.org7382e722011-01-14 14:57:21 +0000229void InspectorConsoleAgent::setConsoleMessagesEnabled(bool enabled)
230{
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000231 m_inspectorState->setBoolean(ConsoleAgentState::consoleMessagesEnabled, enabled);
pfeldman@chromium.org631b2ce2011-01-20 12:49:27 +0000232 if (!enabled || !m_frontend)
yurys@chromium.org7382e722011-01-14 14:57:21 +0000233 return;
pfeldman@chromium.org631b2ce2011-01-20 12:49:27 +0000234
yurys@chromium.org7382e722011-01-14 14:57:21 +0000235 if (m_expiredConsoleMessageCount)
loislo@chromium.org1dd114ba2011-03-18 19:49:09 +0000236 m_frontend->consoleMessageExpiredCountUpdate(m_expiredConsoleMessageCount);
yurys@chromium.org7382e722011-01-14 14:57:21 +0000237 unsigned messageCount = m_consoleMessages.size();
238 for (unsigned i = 0; i < messageCount; ++i)
yurys@chromium.org8eee6592011-03-11 13:26:56 +0000239 m_consoleMessages[i]->addToFrontend(m_frontend, m_injectedScriptManager);
yurys@chromium.org7382e722011-01-14 14:57:21 +0000240}
241
242void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<ConsoleMessage> consoleMessage)
243{
pfeldman@chromium.orgf73e27722011-01-23 09:36:21 +0000244 ASSERT(m_inspectorAgent->enabled());
yurys@chromium.org7382e722011-01-14 14:57:21 +0000245 ASSERT_ARG(consoleMessage, consoleMessage);
246
yurys@chromium.org6ac7582d2011-03-15 13:08:54 +0000247 if (m_previousMessage && m_previousMessage->type() != EndGroupMessageType && m_previousMessage->isEqual(consoleMessage.get())) {
yurys@chromium.org7382e722011-01-14 14:57:21 +0000248 m_previousMessage->incrementCount();
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000249 if (m_inspectorState->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend)
yurys@chromium.org7382e722011-01-14 14:57:21 +0000250 m_previousMessage->updateRepeatCountInConsole(m_frontend);
251 } else {
252 m_previousMessage = consoleMessage.get();
253 m_consoleMessages.append(consoleMessage);
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000254 if (m_inspectorState->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend)
yurys@chromium.org8eee6592011-03-11 13:26:56 +0000255 m_previousMessage->addToFrontend(m_frontend, m_injectedScriptManager);
yurys@chromium.org7382e722011-01-14 14:57:21 +0000256 }
257
258 if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) {
259 m_expiredConsoleMessageCount += expireConsoleMessagesStep;
260 m_consoleMessages.remove(0, expireConsoleMessagesStep);
261 }
262}
263
264} // namespace WebCore
265
266#endif // ENABLE(INSPECTOR)