Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / inspector / ConsoleMessage.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2014, 2015 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4  * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "ConsoleMessage.h"
33
34 #include "IdentifiersFactory.h"
35 #include "InjectedScript.h"
36 #include "InjectedScriptManager.h"
37 #include "InspectorFrontendDispatchers.h"
38 #include "InspectorValues.h"
39 #include "ScriptArguments.h"
40 #include "ScriptCallFrame.h"
41 #include "ScriptCallStack.h"
42 #include "ScriptCallStackFactory.h"
43 #include "ScriptValue.h"
44
45 namespace Inspector {
46
47 ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned long requestIdentifier)
48     : m_source(source)
49     , m_type(type)
50     , m_level(level)
51     , m_message(message)
52     , m_url()
53     , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
54 {
55 }
56
57 ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned line, unsigned column, JSC::ExecState* state, unsigned long requestIdentifier)
58     : m_source(source)
59     , m_type(type)
60     , m_level(level)
61     , m_message(message)
62     , m_url(url)
63     , m_line(line)
64     , m_column(column)
65     , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
66 {
67     autogenerateMetadata(state);
68 }
69
70 ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, Ref<ScriptCallStack>&& callStack, unsigned long requestIdentifier)
71     : m_source(source)
72     , m_type(type)
73     , m_level(level)
74     , m_message(message)
75     , m_callStack(WTFMove(callStack))
76     , m_url()
77     , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
78 {
79     const ScriptCallFrame* frame = m_callStack ? m_callStack->firstNonNativeCallFrame() : nullptr;
80     if (frame) {
81         m_url = frame->sourceURL();
82         m_line = frame->lineNumber();
83         m_column = frame->columnNumber();
84     }
85 }
86
87 ConsoleMessage::ConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, Ref<ScriptArguments>&& arguments, JSC::ExecState* state, unsigned long requestIdentifier)
88     : m_source(source)
89     , m_type(type)
90     , m_level(level)
91     , m_message(message)
92     , m_arguments(WTFMove(arguments))
93     , m_url()
94     , m_requestId(IdentifiersFactory::requestId(requestIdentifier))
95 {
96     autogenerateMetadata(state);
97 }
98
99 ConsoleMessage::~ConsoleMessage()
100 {
101 }
102
103 void ConsoleMessage::autogenerateMetadata(JSC::ExecState* state)
104 {
105     if (!state)
106         return;
107
108     if (m_type == MessageType::EndGroup)
109         return;
110
111     // FIXME: Should this really be using "for console" in the generic ConsoleMessage autogeneration? This can skip the first frame.
112     m_callStack = createScriptCallStackForConsole(state, ScriptCallStack::maxCallStackSizeToCapture);
113
114     if (const ScriptCallFrame* frame = m_callStack->firstNonNativeCallFrame()) {
115         m_url = frame->sourceURL();
116         m_line = frame->lineNumber();
117         m_column = frame->columnNumber();
118         return;
119     }
120 }
121
122 static Inspector::Protocol::Console::ConsoleMessage::Source messageSourceValue(MessageSource source)
123 {
124     switch (source) {
125     case MessageSource::XML: return Inspector::Protocol::Console::ConsoleMessage::Source::XML;
126     case MessageSource::JS: return Inspector::Protocol::Console::ConsoleMessage::Source::Javascript;
127     case MessageSource::Network: return Inspector::Protocol::Console::ConsoleMessage::Source::Network;
128     case MessageSource::ConsoleAPI: return Inspector::Protocol::Console::ConsoleMessage::Source::ConsoleAPI;
129     case MessageSource::Storage: return Inspector::Protocol::Console::ConsoleMessage::Source::Storage;
130     case MessageSource::AppCache: return Inspector::Protocol::Console::ConsoleMessage::Source::Appcache;
131     case MessageSource::Rendering: return Inspector::Protocol::Console::ConsoleMessage::Source::Rendering;
132     case MessageSource::CSS: return Inspector::Protocol::Console::ConsoleMessage::Source::CSS;
133     case MessageSource::Security: return Inspector::Protocol::Console::ConsoleMessage::Source::Security;
134     case MessageSource::ContentBlocker: return Inspector::Protocol::Console::ConsoleMessage::Source::ContentBlocker;
135     case MessageSource::Other: return Inspector::Protocol::Console::ConsoleMessage::Source::Other;
136     }
137     return Inspector::Protocol::Console::ConsoleMessage::Source::Other;
138 }
139
140 static Inspector::Protocol::Console::ConsoleMessage::Type messageTypeValue(MessageType type)
141 {
142     switch (type) {
143     case MessageType::Log: return Inspector::Protocol::Console::ConsoleMessage::Type::Log;
144     case MessageType::Clear: return Inspector::Protocol::Console::ConsoleMessage::Type::Clear;
145     case MessageType::Dir: return Inspector::Protocol::Console::ConsoleMessage::Type::Dir;
146     case MessageType::DirXML: return Inspector::Protocol::Console::ConsoleMessage::Type::DirXML;
147     case MessageType::Table: return Inspector::Protocol::Console::ConsoleMessage::Type::Table;
148     case MessageType::Trace: return Inspector::Protocol::Console::ConsoleMessage::Type::Trace;
149     case MessageType::StartGroup: return Inspector::Protocol::Console::ConsoleMessage::Type::StartGroup;
150     case MessageType::StartGroupCollapsed: return Inspector::Protocol::Console::ConsoleMessage::Type::StartGroupCollapsed;
151     case MessageType::EndGroup: return Inspector::Protocol::Console::ConsoleMessage::Type::EndGroup;
152     case MessageType::Assert: return Inspector::Protocol::Console::ConsoleMessage::Type::Assert;
153     case MessageType::Timing: return Inspector::Protocol::Console::ConsoleMessage::Type::Timing;
154     case MessageType::Profile: return Inspector::Protocol::Console::ConsoleMessage::Type::Profile;
155     case MessageType::ProfileEnd: return Inspector::Protocol::Console::ConsoleMessage::Type::ProfileEnd;
156     }
157     return Inspector::Protocol::Console::ConsoleMessage::Type::Log;
158 }
159
160 static Inspector::Protocol::Console::ConsoleMessage::Level messageLevelValue(MessageLevel level)
161 {
162     switch (level) {
163     case MessageLevel::Log: return Inspector::Protocol::Console::ConsoleMessage::Level::Log;
164     case MessageLevel::Info: return Inspector::Protocol::Console::ConsoleMessage::Level::Info;
165     case MessageLevel::Warning: return Inspector::Protocol::Console::ConsoleMessage::Level::Warning;
166     case MessageLevel::Error: return Inspector::Protocol::Console::ConsoleMessage::Level::Error;
167     case MessageLevel::Debug: return Inspector::Protocol::Console::ConsoleMessage::Level::Debug;
168     }
169     return Inspector::Protocol::Console::ConsoleMessage::Level::Log;
170 }
171
172 void ConsoleMessage::addToFrontend(ConsoleFrontendDispatcher& consoleFrontendDispatcher, InjectedScriptManager& injectedScriptManager, bool generatePreview)
173 {
174     Ref<Inspector::Protocol::Console::ConsoleMessage> jsonObj = Inspector::Protocol::Console::ConsoleMessage::create()
175         .setSource(messageSourceValue(m_source))
176         .setLevel(messageLevelValue(m_level))
177         .setText(m_message)
178         .release();
179
180     // FIXME: only send out type for ConsoleAPI source messages.
181     jsonObj->setType(messageTypeValue(m_type));
182     jsonObj->setLine(static_cast<int>(m_line));
183     jsonObj->setColumn(static_cast<int>(m_column));
184     jsonObj->setUrl(m_url);
185     jsonObj->setRepeatCount(static_cast<int>(m_repeatCount));
186
187     if (m_source == MessageSource::Network && !m_requestId.isEmpty())
188         jsonObj->setNetworkRequestId(m_requestId);
189
190     if (m_arguments && m_arguments->argumentCount()) {
191         InjectedScript injectedScript = injectedScriptManager.injectedScriptFor(m_arguments->globalState());
192         if (!injectedScript.hasNoValue()) {
193             Ref<Inspector::Protocol::Array<Inspector::Protocol::Runtime::RemoteObject>> jsonArgs = Inspector::Protocol::Array<Inspector::Protocol::Runtime::RemoteObject>::create();
194             if (m_type == MessageType::Table && generatePreview && m_arguments->argumentCount()) {
195                 Deprecated::ScriptValue table = m_arguments->argumentAt(0);
196                 Deprecated::ScriptValue columns = m_arguments->argumentCount() > 1 ? m_arguments->argumentAt(1) : Deprecated::ScriptValue();
197                 RefPtr<Inspector::Protocol::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns);
198                 if (!inspectorValue) {
199                     ASSERT_NOT_REACHED();
200                     return;
201                 }
202                 jsonArgs->addItem(inspectorValue.copyRef());
203                 if (m_arguments->argumentCount() > 1)
204                     jsonArgs->addItem(injectedScript.wrapObject(columns, ASCIILiteral("console"), true));
205             } else {
206                 for (unsigned i = 0; i < m_arguments->argumentCount(); ++i) {
207                     RefPtr<Inspector::Protocol::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), ASCIILiteral("console"), generatePreview);
208                     if (!inspectorValue) {
209                         ASSERT_NOT_REACHED();
210                         return;
211                     }
212                     jsonArgs->addItem(inspectorValue.copyRef());
213                 }
214             }
215             jsonObj->setParameters(WTFMove(jsonArgs));
216         }
217     }
218
219     if (m_callStack)
220         jsonObj->setStackTrace(m_callStack->buildInspectorArray());
221
222     consoleFrontendDispatcher.messageAdded(WTFMove(jsonObj));
223 }
224
225 void ConsoleMessage::updateRepeatCountInConsole(ConsoleFrontendDispatcher& consoleFrontendDispatcher)
226 {
227     consoleFrontendDispatcher.messageRepeatCountUpdated(m_repeatCount);
228 }
229
230 bool ConsoleMessage::isEqual(ConsoleMessage* msg) const
231 {
232     if (m_arguments) {
233         if (!m_arguments->isEqual(msg->m_arguments.get()))
234             return false;
235
236         // Never treat objects as equal - their properties might change over time.
237         for (size_t i = 0; i < m_arguments->argumentCount(); ++i) {
238             if (m_arguments->argumentAt(i).isObject())
239                 return false;
240         }
241     } else if (msg->m_arguments)
242         return false;
243
244     if (m_callStack) {
245         if (!m_callStack->isEqual(msg->m_callStack.get()))
246             return false;
247     } else if (msg->m_callStack)
248         return false;
249
250     return msg->m_source == m_source
251         && msg->m_type == m_type
252         && msg->m_level == m_level
253         && msg->m_message == m_message
254         && msg->m_line == m_line
255         && msg->m_column == m_column
256         && msg->m_url == m_url
257         && msg->m_requestId == m_requestId;
258 }
259
260 void ConsoleMessage::clear()
261 {
262     if (!m_message)
263         m_message = ASCIILiteral("<message collected>");
264
265     if (m_arguments)
266         m_arguments = nullptr;
267 }
268
269 JSC::ExecState* ConsoleMessage::scriptState() const
270 {
271     if (m_arguments)
272         return m_arguments->globalState();
273
274     return nullptr;
275 }
276
277 unsigned ConsoleMessage::argumentCount() const
278 {
279     if (m_arguments)
280         return m_arguments->argumentCount();
281
282     return 0;
283 }
284
285 } // namespace Inspector