e8cf48fd6d044f72e67975717dd34c110fac1aaf
[WebKit-https.git] / Source / WebCore / inspector / agents / page / PageDebuggerAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "PageDebuggerAgent.h"
34
35 #include "CachedResource.h"
36 #include "Document.h"
37 #include "EventListener.h"
38 #include "EventTarget.h"
39 #include "Frame.h"
40 #include "InspectorPageAgent.h"
41 #include "InstrumentingAgents.h"
42 #include "Page.h"
43 #include "PageConsoleClient.h"
44 #include "PageScriptDebugServer.h"
45 #include "ScriptExecutionContext.h"
46 #include "ScriptState.h"
47 #include "Timer.h"
48 #include <JavaScriptCore/InjectedScript.h>
49 #include <JavaScriptCore/InjectedScriptManager.h>
50 #include <JavaScriptCore/ScriptCallStack.h>
51 #include <JavaScriptCore/ScriptCallStackFactory.h>
52 #include <wtf/NeverDestroyed.h>
53
54
55 namespace WebCore {
56
57 using namespace Inspector;
58
59 PageDebuggerAgent::PageDebuggerAgent(PageAgentContext& context)
60     : WebDebuggerAgent(context)
61     , m_inspectedPage(context.inspectedPage)
62 {
63 }
64
65 void PageDebuggerAgent::enable()
66 {
67     WebDebuggerAgent::enable();
68     m_instrumentingAgents.setPageDebuggerAgent(this);
69 }
70
71 void PageDebuggerAgent::disable(bool isBeingDestroyed)
72 {
73     WebDebuggerAgent::disable(isBeingDestroyed);
74     m_instrumentingAgents.setPageDebuggerAgent(nullptr);
75 }
76
77 String PageDebuggerAgent::sourceMapURLForScript(const Script& script)
78 {
79     static NeverDestroyed<String> sourceMapHTTPHeader(MAKE_STATIC_STRING_IMPL("SourceMap"));
80     static NeverDestroyed<String> sourceMapHTTPHeaderDeprecated(MAKE_STATIC_STRING_IMPL("X-SourceMap"));
81
82     if (!script.url.isEmpty()) {
83         CachedResource* resource = InspectorPageAgent::cachedResource(&m_inspectedPage.mainFrame(), URL({ }, script.url));
84         if (resource) {
85             String sourceMapHeader = resource->response().httpHeaderField(sourceMapHTTPHeader);
86             if (!sourceMapHeader.isEmpty())
87                 return sourceMapHeader;
88
89             sourceMapHeader = resource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
90             if (!sourceMapHeader.isEmpty())
91                 return sourceMapHeader;
92         }
93     }
94
95     return InspectorDebuggerAgent::sourceMapURLForScript(script);
96 }
97
98 void PageDebuggerAgent::didClearAsyncStackTraceData()
99 {
100     m_registeredEventListeners.clear();
101     m_postMessageTimers.clear();
102     m_nextEventListenerIdentifier = 1;
103     m_nextPostMessageIdentifier = 1;
104 }
105
106 void PageDebuggerAgent::muteConsole()
107 {
108     PageConsoleClient::mute();
109 }
110
111 void PageDebuggerAgent::unmuteConsole()
112 {
113     PageConsoleClient::unmute();
114 }
115
116 void PageDebuggerAgent::breakpointActionLog(JSC::ExecState& state, const String& message)
117 {
118     m_inspectedPage.console().addMessage(MessageSource::JS, MessageLevel::Log, message, createScriptCallStack(&state));
119 }
120
121 InjectedScript PageDebuggerAgent::injectedScriptForEval(ErrorString& errorString, const int* executionContextId)
122 {
123     if (!executionContextId) {
124         JSC::ExecState* scriptState = mainWorldExecState(&m_inspectedPage.mainFrame());
125         return injectedScriptManager().injectedScriptFor(scriptState);
126     }
127
128     InjectedScript injectedScript = injectedScriptManager().injectedScriptForId(*executionContextId);
129     if (injectedScript.hasNoValue())
130         errorString = "Execution context with given id not found."_s;
131
132     return injectedScript;
133 }
134
135 void PageDebuggerAgent::didClearMainFrameWindowObject()
136 {
137     didClearGlobalObject();
138 }
139
140 void PageDebuggerAgent::mainFrameStartedLoading()
141 {
142     if (isPaused()) {
143         setSuppressAllPauses(true);
144         ErrorString unused;
145         resume(unused);
146     }
147 }
148
149 void PageDebuggerAgent::mainFrameStoppedLoading()
150 {
151     setSuppressAllPauses(false);
152 }
153
154 void PageDebuggerAgent::mainFrameNavigated()
155 {
156     setSuppressAllPauses(false);
157 }
158
159 void PageDebuggerAgent::didAddEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
160 {
161     if (!breakpointsActive())
162         return;
163
164     auto& eventListeners = target.eventListeners(eventType);
165     auto position = eventListeners.findMatching([&](auto& registeredListener) {
166         return &registeredListener->callback() == &listener && registeredListener->useCapture() == capture;
167     });
168     if (position == notFound)
169         return;
170
171     auto& registeredListener = eventListeners.at(position);
172     if (m_registeredEventListeners.contains(registeredListener.get()))
173         return;
174
175     JSC::ExecState* scriptState = target.scriptExecutionContext()->execState();
176     if (!scriptState)
177         return;
178
179     int identifier = m_nextEventListenerIdentifier++;
180     m_registeredEventListeners.set(registeredListener.get(), identifier);
181
182     didScheduleAsyncCall(scriptState, InspectorDebuggerAgent::AsyncCallType::EventListener, identifier, registeredListener->isOnce());
183 }
184
185 void PageDebuggerAgent::willRemoveEventListener(EventTarget& target, const AtomicString& eventType, EventListener& listener, bool capture)
186 {
187     auto& eventListeners = target.eventListeners(eventType);
188     size_t listenerIndex = eventListeners.findMatching([&](auto& registeredListener) {
189         return &registeredListener->callback() == &listener && registeredListener->useCapture() == capture;
190     });
191
192     if (listenerIndex == notFound)
193         return;
194
195     int identifier = m_registeredEventListeners.take(eventListeners[listenerIndex].get());
196     didCancelAsyncCall(InspectorDebuggerAgent::AsyncCallType::EventListener, identifier);
197 }
198
199 void PageDebuggerAgent::willHandleEvent(const RegisteredEventListener& listener)
200 {
201     auto it = m_registeredEventListeners.find(&listener);
202     if (it == m_registeredEventListeners.end())
203         return;
204
205     willDispatchAsyncCall(InspectorDebuggerAgent::AsyncCallType::EventListener, it->value);
206 }
207
208 void PageDebuggerAgent::didRequestAnimationFrame(int callbackId, Document& document)
209 {
210     if (!breakpointsActive())
211         return;
212
213     JSC::ExecState* scriptState = document.execState();
214     if (!scriptState)
215         return;
216
217     didScheduleAsyncCall(scriptState, InspectorDebuggerAgent::AsyncCallType::RequestAnimationFrame, callbackId, true);
218 }
219
220 void PageDebuggerAgent::willFireAnimationFrame(int callbackId)
221 {
222     willDispatchAsyncCall(InspectorDebuggerAgent::AsyncCallType::RequestAnimationFrame, callbackId);
223 }
224
225 void PageDebuggerAgent::didCancelAnimationFrame(int callbackId)
226 {
227     didCancelAsyncCall(InspectorDebuggerAgent::AsyncCallType::RequestAnimationFrame, callbackId);
228 }
229
230 void PageDebuggerAgent::didPostMessage(const TimerBase& timer, JSC::ExecState& state)
231 {
232     if (!breakpointsActive())
233         return;
234
235     if (m_postMessageTimers.contains(&timer))
236         return;
237
238     int postMessageIdentifier = m_nextPostMessageIdentifier++;
239     m_postMessageTimers.set(&timer, postMessageIdentifier);
240
241     didScheduleAsyncCall(&state, InspectorDebuggerAgent::AsyncCallType::PostMessage, postMessageIdentifier, true);
242 }
243
244 void PageDebuggerAgent::didFailPostMessage(const TimerBase& timer)
245 {
246     auto it = m_postMessageTimers.find(&timer);
247     if (it == m_postMessageTimers.end())
248         return;
249
250     didCancelAsyncCall(InspectorDebuggerAgent::AsyncCallType::PostMessage, it->value);
251
252     m_postMessageTimers.remove(it);
253 }
254
255 void PageDebuggerAgent::willDispatchPostMessage(const TimerBase& timer)
256 {
257     auto it = m_postMessageTimers.find(&timer);
258     if (it == m_postMessageTimers.end())
259         return;
260
261     willDispatchAsyncCall(InspectorDebuggerAgent::AsyncCallType::PostMessage, it->value);
262 }
263
264 void PageDebuggerAgent::didDispatchPostMessage(const TimerBase& timer)
265 {
266     auto it = m_postMessageTimers.find(&timer);
267     if (it == m_postMessageTimers.end())
268         return;
269
270     didDispatchAsyncCall();
271
272     m_postMessageTimers.remove(it);
273 }
274
275 } // namespace WebCore