yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 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 "InspectorConsoleAgent.h" |
| 28 | |
| 29 | #if ENABLE(INSPECTOR) |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 30 | #include "InstrumentingAgents.h" |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 31 | #include "Console.h" |
| 32 | #include "ConsoleMessage.h" |
| 33 | #include "InjectedScriptHost.h" |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 34 | #include "InjectedScriptManager.h" |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 35 | #include "InspectorAgent.h" |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 36 | #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.org | 8814672 | 2011-01-17 10:44:50 +0000 | [diff] [blame] | 42 | #include "ScriptCallFrame.h" |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 43 | #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 | |
| 49 | namespace WebCore { |
| 50 | |
| 51 | static const unsigned maximumConsoleMessages = 1000; |
| 52 | static const unsigned expireConsoleMessagesStep = 100; |
| 53 | |
caseq@chromium.org | 0b55a5b | 2011-02-08 13:42:10 +0000 | [diff] [blame] | 54 | namespace ConsoleAgentState { |
| 55 | static const char monitoringXHR[] = "monitoringXHR"; |
| 56 | static const char consoleMessagesEnabled[] = "consoleMessagesEnabled"; |
| 57 | } |
| 58 | |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 59 | InspectorConsoleAgent::InspectorConsoleAgent(InstrumentingAgents* instrumentingAgents, InspectorAgent* inspectorAgent, InspectorState* state, InjectedScriptManager* injectedScriptManager, InspectorDOMAgent* domAgent) |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 60 | : m_instrumentingAgents(instrumentingAgents) |
| 61 | , m_inspectorAgent(inspectorAgent) |
| 62 | , m_inspectorState(state) |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 63 | , m_injectedScriptManager(injectedScriptManager) |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 64 | , m_inspectorDOMAgent(domAgent) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 65 | , m_frontend(0) |
| 66 | , m_previousMessage(0) |
| 67 | , m_expiredConsoleMessageCount(0) |
| 68 | { |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 69 | m_instrumentingAgents->setInspectorConsoleAgent(this); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | InspectorConsoleAgent::~InspectorConsoleAgent() |
| 73 | { |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 74 | m_instrumentingAgents->setInspectorConsoleAgent(0); |
| 75 | m_instrumentingAgents = 0; |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 76 | m_inspectorAgent = 0; |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 77 | m_inspectorState = 0; |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 78 | m_injectedScriptManager = 0; |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 79 | m_inspectorDOMAgent = 0; |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 80 | } |
| 81 | |
loislo@chromium.org | df5982d | 2011-02-24 11:43:39 +0000 | [diff] [blame] | 82 | void InspectorConsoleAgent::setConsoleMessagesEnabled(ErrorString*, bool enabled, bool* newState) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 83 | { |
| 84 | *newState = enabled; |
| 85 | setConsoleMessagesEnabled(enabled); |
| 86 | } |
| 87 | |
loislo@chromium.org | df5982d | 2011-02-24 11:43:39 +0000 | [diff] [blame] | 88 | void InspectorConsoleAgent::clearConsoleMessages(ErrorString*) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 89 | { |
| 90 | m_consoleMessages.clear(); |
| 91 | m_expiredConsoleMessageCount = 0; |
| 92 | m_previousMessage = 0; |
pfeldman@chromium.org | 7827856 | 2011-03-21 07:42:31 +0000 | [diff] [blame] | 93 | m_injectedScriptManager->releaseObjectGroup("console"); |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 94 | m_inspectorDOMAgent->releaseDanglingNodes(); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 95 | if (m_frontend) |
| 96 | m_frontend->consoleMessagesCleared(); |
| 97 | } |
| 98 | |
| 99 | void InspectorConsoleAgent::reset() |
| 100 | { |
loislo@chromium.org | df5982d | 2011-02-24 11:43:39 +0000 | [diff] [blame] | 101 | ErrorString error; |
| 102 | clearConsoleMessages(&error); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 103 | m_times.clear(); |
| 104 | m_counts.clear(); |
| 105 | } |
| 106 | |
| 107 | void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend) |
| 108 | { |
yurys@chromium.org | 3fb1663 | 2011-03-03 05:43:34 +0000 | [diff] [blame] | 109 | m_frontend = frontend->console(); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 110 | } |
| 111 | |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 112 | void InspectorConsoleAgent::clearFrontend() |
| 113 | { |
| 114 | m_frontend = 0; |
| 115 | } |
| 116 | |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 117 | void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack) |
| 118 | { |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 119 | if (!m_inspectorAgent->enabled()) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 120 | return; |
| 121 | addConsoleMessage(new ConsoleMessage(source, type, level, message, arguments, callStack)); |
| 122 | } |
| 123 | |
| 124 | void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID) |
| 125 | { |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 126 | if (!m_inspectorAgent->enabled()) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 127 | return; |
| 128 | addConsoleMessage(new ConsoleMessage(source, type, level, message, lineNumber, sourceID)); |
| 129 | } |
| 130 | |
| 131 | void 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.org | 8814672 | 2011-01-17 10:44:50 +0000 | [diff] [blame] | 141 | void InspectorConsoleAgent::stopTiming(const String& title, PassRefPtr<ScriptCallStack> callStack) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 142 | { |
| 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.org | 8814672 | 2011-01-17 10:44:50 +0000 | [diff] [blame] | 157 | const ScriptCallFrame& lastCaller = callStack->at(0); |
| 158 | addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL()); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 159 | } |
| 160 | |
pfeldman@chromium.org | 8814672 | 2011-01-17 10:44:50 +0000 | [diff] [blame] | 161 | void InspectorConsoleAgent::count(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 162 | { |
pfeldman@chromium.org | 8814672 | 2011-01-17 10:44:50 +0000 | [diff] [blame] | 163 | 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.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 170 | 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.org | 8814672 | 2011-01-17 10:44:50 +0000 | [diff] [blame] | 182 | addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL()); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | void InspectorConsoleAgent::resourceRetrievedByXMLHttpRequest(const String& url, const String& sendURL, unsigned sendLineNumber) |
| 186 | { |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 187 | if (!m_inspectorAgent->enabled()) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 188 | return; |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 189 | if (m_inspectorState->getBoolean(ConsoleAgentState::monitoringXHR)) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 190 | addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL); |
| 191 | } |
| 192 | |
| 193 | void InspectorConsoleAgent::didReceiveResponse(unsigned long identifier, const ResourceResponse& response) |
| 194 | { |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 195 | if (!m_inspectorAgent->enabled()) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 196 | 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 | |
| 204 | void InspectorConsoleAgent::didFailLoading(unsigned long identifier, const ResourceError& error) |
| 205 | { |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 206 | if (!m_inspectorAgent->enabled()) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 207 | return; |
caseq@chromium.org | 9746e95 | 2011-03-11 09:28:38 +0000 | [diff] [blame] | 208 | if (error.isCancellation()) // Report failures only. |
| 209 | return; |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 210 | 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.org | df5982d | 2011-02-24 11:43:39 +0000 | [diff] [blame] | 216 | void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled) |
pfeldman@chromium.org | 631b2ce | 2011-01-20 12:49:27 +0000 | [diff] [blame] | 217 | { |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 218 | m_inspectorState->setBoolean(ConsoleAgentState::monitoringXHR, enabled); |
pfeldman@chromium.org | 631b2ce | 2011-01-20 12:49:27 +0000 | [diff] [blame] | 219 | } |
| 220 | |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 221 | void 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.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 229 | void InspectorConsoleAgent::setConsoleMessagesEnabled(bool enabled) |
| 230 | { |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 231 | m_inspectorState->setBoolean(ConsoleAgentState::consoleMessagesEnabled, enabled); |
pfeldman@chromium.org | 631b2ce | 2011-01-20 12:49:27 +0000 | [diff] [blame] | 232 | if (!enabled || !m_frontend) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 233 | return; |
pfeldman@chromium.org | 631b2ce | 2011-01-20 12:49:27 +0000 | [diff] [blame] | 234 | |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 235 | if (m_expiredConsoleMessageCount) |
loislo@chromium.org | 1dd114ba | 2011-03-18 19:49:09 +0000 | [diff] [blame] | 236 | m_frontend->consoleMessageExpiredCountUpdate(m_expiredConsoleMessageCount); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 237 | unsigned messageCount = m_consoleMessages.size(); |
| 238 | for (unsigned i = 0; i < messageCount; ++i) |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 239 | m_consoleMessages[i]->addToFrontend(m_frontend, m_injectedScriptManager); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<ConsoleMessage> consoleMessage) |
| 243 | { |
pfeldman@chromium.org | f73e2772 | 2011-01-23 09:36:21 +0000 | [diff] [blame] | 244 | ASSERT(m_inspectorAgent->enabled()); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 245 | ASSERT_ARG(consoleMessage, consoleMessage); |
| 246 | |
yurys@chromium.org | 6ac7582d | 2011-03-15 13:08:54 +0000 | [diff] [blame] | 247 | if (m_previousMessage && m_previousMessage->type() != EndGroupMessageType && m_previousMessage->isEqual(consoleMessage.get())) { |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 248 | m_previousMessage->incrementCount(); |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 249 | if (m_inspectorState->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend) |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 250 | m_previousMessage->updateRepeatCountInConsole(m_frontend); |
| 251 | } else { |
| 252 | m_previousMessage = consoleMessage.get(); |
| 253 | m_consoleMessages.append(consoleMessage); |
yurys@chromium.org | d8e367c | 2011-02-21 14:38:24 +0000 | [diff] [blame] | 254 | if (m_inspectorState->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend) |
yurys@chromium.org | 8eee659 | 2011-03-11 13:26:56 +0000 | [diff] [blame] | 255 | m_previousMessage->addToFrontend(m_frontend, m_injectedScriptManager); |
yurys@chromium.org | 7382e72 | 2011-01-14 14:57:21 +0000 | [diff] [blame] | 256 | } |
| 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) |