Home | History | Annotate | Download | only in inspector
      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 
     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 
     77 InspectorConsoleAgent::~InspectorConsoleAgent()
     78 {
     79 #if !ENABLE(OILPAN)
     80     m_instrumentingAgents->setInspectorConsoleAgent(0);
     81 #endif
     82 }
     83 
     84 void InspectorConsoleAgent::trace(Visitor* visitor)
     85 {
     86     visitor->trace(m_timelineAgent);
     87     visitor->trace(m_injectedScriptManager);
     88     InspectorBaseAgent::trace(visitor);
     89 }
     90 
     91 void InspectorConsoleAgent::init()
     92 {
     93     m_instrumentingAgents->setInspectorConsoleAgent(this);
     94 }
     95 
     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 
    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 
    130 void InspectorConsoleAgent::clearMessages(ErrorString*)
    131 {
    132     messageStorage()->clear();
    133 }
    134 
    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 
    144 void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
    145 {
    146     m_frontend = frontend->console();
    147 }
    148 
    149 void InspectorConsoleAgent::clearFrontend()
    150 {
    151     m_frontend = 0;
    152     String errorString;
    153     disable(&errorString);
    154 }
    155 
    156 void InspectorConsoleAgent::addMessageToConsole(ConsoleMessage* consoleMessage)
    157 {
    158     if (m_frontend && m_enabled)
    159         sendConsoleMessageToFrontend(consoleMessage, true);
    160 }
    161 
    162 void InspectorConsoleAgent::consoleMessagesCleared()
    163 {
    164     m_injectedScriptManager->releaseObjectGroup("console");
    165     if (m_frontend && m_enabled)
    166         m_frontend->messagesCleared();
    167 }
    168 
    169 void InspectorConsoleAgent::setTracingBasedTimeline(ErrorString*, bool enabled)
    170 {
    171     m_state->setBoolean(ConsoleAgentState::tracingBasedTimeline, enabled);
    172 }
    173 
    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 
    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 
    187 void InspectorConsoleAgent::frameWindowDiscarded(LocalDOMWindow* window)
    188 {
    189     m_injectedScriptManager->discardInjectedScriptsFor(window);
    190 }
    191 
    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 
    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 
    217 void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
    218 {
    219     m_state->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
    220 }
    221 
    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 
    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 
    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 
    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:
    333     explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { }
    334     virtual ScriptValue get(ScriptState*) OVERRIDE
    335     {
    336         return ScriptProfiler::objectByHeapObjectId(m_heapObjectId);
    337     }
    338 private:
    339     int m_heapObjectId;
    340 };
    341 
    342 void InspectorConsoleAgent::addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId)
    343 {
    344     m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableHeapObject(inspectedHeapObjectId)));
    345 }
    346 
    347 } // namespace blink
    348