8a7df20ac04c7e02fb9accb98979ed3564150f7d
[WebKit-https.git] / Source / WebCore / inspector / InspectorController.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2014 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 "InspectorController.h"
34
35 #include "CommandLineAPIHost.h"
36 #include "DOMWrapperWorld.h"
37 #include "GraphicsContext.h"
38 #include "InspectorApplicationCacheAgent.h"
39 #include "InspectorCSSAgent.h"
40 #include "InspectorClient.h"
41 #include "InspectorDOMAgent.h"
42 #include "InspectorDOMDebuggerAgent.h"
43 #include "InspectorDOMStorageAgent.h"
44 #include "InspectorDatabaseAgent.h"
45 #include "InspectorFrontendClient.h"
46 #include "InspectorIndexedDBAgent.h"
47 #include "InspectorInstrumentation.h"
48 #include "InspectorLayerTreeAgent.h"
49 #include "InspectorPageAgent.h"
50 #include "InspectorReplayAgent.h"
51 #include "InspectorResourceAgent.h"
52 #include "InspectorTimelineAgent.h"
53 #include "InspectorWorkerAgent.h"
54 #include "InstrumentingAgents.h"
55 #include "JSDOMWindow.h"
56 #include "JSDOMWindowCustom.h"
57 #include "JSMainThreadExecState.h"
58 #include "MainFrame.h"
59 #include "Page.h"
60 #include "PageConsoleAgent.h"
61 #include "PageDebuggerAgent.h"
62 #include "PageRuntimeAgent.h"
63 #include "PageScriptDebugServer.h"
64 #include "Settings.h"
65 #include "WebInjectedScriptHost.h"
66 #include "WebInjectedScriptManager.h"
67 #include <inspector/IdentifiersFactory.h>
68 #include <inspector/InspectorBackendDispatcher.h>
69 #include <inspector/InspectorBackendDispatchers.h>
70 #include <inspector/InspectorFrontendDispatchers.h>
71 #include <inspector/InspectorFrontendRouter.h>
72 #include <inspector/agents/InspectorAgent.h>
73 #include <profiler/LegacyProfiler.h>
74 #include <runtime/JSLock.h>
75 #include <wtf/Stopwatch.h>
76
77 #if ENABLE(REMOTE_INSPECTOR)
78 #include "PageDebuggable.h"
79 #endif
80
81 using namespace JSC;
82 using namespace Inspector;
83
84 namespace WebCore {
85
86 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
87     : m_instrumentingAgents(InstrumentingAgents::create(*this))
88     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
89     , m_frontendRouter(FrontendRouter::create())
90     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
91     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
92     , m_executionStopwatch(Stopwatch::create())
93     , m_page(page)
94     , m_inspectorClient(inspectorClient)
95 {
96     ASSERT_ARG(inspectorClient, inspectorClient);
97
98     auto inspectorAgentPtr = std::make_unique<InspectorAgent>(*this);
99     m_inspectorAgent = inspectorAgentPtr.get();
100     m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
101     m_agents.append(WTF::move(inspectorAgentPtr));
102
103     auto pageAgentPtr = std::make_unique<InspectorPageAgent>(m_instrumentingAgents.get(), &page, inspectorClient, m_overlay.get());
104     InspectorPageAgent* pageAgent = pageAgentPtr.get();
105     m_pageAgent = pageAgentPtr.get();
106     m_agents.append(WTF::move(pageAgentPtr));
107
108     auto runtimeAgentPtr = std::make_unique<PageRuntimeAgent>(*m_injectedScriptManager, &page, pageAgent);
109     PageRuntimeAgent* runtimeAgent = runtimeAgentPtr.get();
110     m_instrumentingAgents->setPageRuntimeAgent(runtimeAgent);
111     m_agents.append(WTF::move(runtimeAgentPtr));
112
113     auto domAgentPtr = std::make_unique<InspectorDOMAgent>(m_instrumentingAgents.get(), pageAgent, *m_injectedScriptManager, m_overlay.get());
114     m_domAgent = domAgentPtr.get();
115     m_agents.append(WTF::move(domAgentPtr));
116
117     m_agents.append(std::make_unique<InspectorCSSAgent>(m_instrumentingAgents.get(), m_domAgent));
118
119     auto databaseAgentPtr = std::make_unique<InspectorDatabaseAgent>(m_instrumentingAgents.get());
120     InspectorDatabaseAgent* databaseAgent = databaseAgentPtr.get();
121     m_agents.append(WTF::move(databaseAgentPtr));
122
123 #if ENABLE(INDEXED_DATABASE)
124     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(m_instrumentingAgents.get(), *m_injectedScriptManager, pageAgent));
125 #endif
126
127 #if ENABLE(WEB_REPLAY)
128     m_agents.append(std::make_unique<InspectorReplayAgent>(m_instrumentingAgents.get(), pageAgent));
129 #endif
130
131     auto domStorageAgentPtr = std::make_unique<InspectorDOMStorageAgent>(m_instrumentingAgents.get(), m_pageAgent);
132     InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
133     m_agents.append(WTF::move(domStorageAgentPtr));
134
135     auto timelineAgentPtr = std::make_unique<InspectorTimelineAgent>(m_instrumentingAgents.get(), pageAgent, InspectorTimelineAgent::PageInspector, inspectorClient);
136     m_timelineAgent = timelineAgentPtr.get();
137     m_agents.append(WTF::move(timelineAgentPtr));
138
139     auto resourceAgentPtr = std::make_unique<InspectorResourceAgent>(m_instrumentingAgents.get(), pageAgent, inspectorClient);
140     m_resourceAgent = resourceAgentPtr.get();
141     m_agents.append(WTF::move(resourceAgentPtr));
142
143     auto consoleAgentPtr = std::make_unique<PageConsoleAgent>(*m_injectedScriptManager, m_domAgent);
144     WebConsoleAgent* consoleAgent = consoleAgentPtr.get();
145     m_instrumentingAgents->setWebConsoleAgent(consoleAgentPtr.get());
146     m_agents.append(WTF::move(consoleAgentPtr));
147
148     auto debuggerAgentPtr = std::make_unique<PageDebuggerAgent>(*m_injectedScriptManager, m_instrumentingAgents.get(), pageAgent, m_overlay.get());
149     m_debuggerAgent = debuggerAgentPtr.get();
150     m_agents.append(WTF::move(debuggerAgentPtr));
151
152     auto domDebuggerAgentPtr = std::make_unique<InspectorDOMDebuggerAgent>(m_instrumentingAgents.get(), m_domAgent, m_debuggerAgent);
153     m_domDebuggerAgent = domDebuggerAgentPtr.get();
154     m_agents.append(WTF::move(domDebuggerAgentPtr));
155
156     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(m_instrumentingAgents.get(), pageAgent));
157     m_agents.append(std::make_unique<InspectorWorkerAgent>(m_instrumentingAgents.get()));
158     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(m_instrumentingAgents.get()));
159
160     ASSERT(m_injectedScriptManager->commandLineAPIHost());
161     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost()) {
162         commandLineAPIHost->init(m_inspectorAgent
163             , consoleAgent
164             , m_domAgent
165             , domStorageAgent
166             , databaseAgent
167         );
168     }
169
170     runtimeAgent->setScriptDebugServer(&m_debuggerAgent->scriptDebugServer());
171     m_timelineAgent->setPageScriptDebugServer(&m_debuggerAgent->scriptDebugServer());
172 }
173
174 InspectorController::~InspectorController()
175 {
176     m_instrumentingAgents->reset();
177     m_agents.discardAgents();
178     ASSERT(!m_inspectorClient);
179 }
180
181 void InspectorController::inspectedPageDestroyed()
182 {
183     disconnectAllFrontends();
184
185     m_injectedScriptManager->disconnect();
186     m_inspectorClient->inspectorDestroyed();
187     m_inspectorClient = nullptr;
188 }
189
190 void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
191 {
192     m_inspectorFrontendClient = inspectorFrontendClient;
193 }
194
195 bool InspectorController::hasLocalFrontend() const
196 {
197     return m_frontendRouter->hasLocalFrontend();
198 }
199
200 bool InspectorController::hasRemoteFrontend() const
201 {
202     return m_frontendRouter->hasRemoteFrontend();
203 }
204
205 bool InspectorController::hasInspectorFrontendClient() const
206 {
207     return m_inspectorFrontendClient;
208 }
209
210 void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
211 {
212     if (&world != &mainThreadNormalWorld())
213         return;
214
215     if (frame.isMainFrame())
216         m_injectedScriptManager->discardInjectedScripts();
217
218     // If the page is supposed to serve as InspectorFrontend notify inspector frontend
219     // client that it's cleared so that the client can expose inspector bindings.
220     if (m_inspectorFrontendClient && frame.isMainFrame())
221         m_inspectorFrontendClient->windowObjectCleared();
222 }
223
224 void InspectorController::connectFrontend(Inspector::FrontendChannel* frontendChannel, bool isAutomaticInspection)
225 {
226     ASSERT_ARG(frontendChannel, frontendChannel);
227     ASSERT(m_inspectorClient);
228
229     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
230     m_isAutomaticInspection = isAutomaticInspection;
231
232     m_frontendRouter->connectFrontend(frontendChannel);
233
234     InspectorInstrumentation::frontendCreated();
235
236     if (connectedFirstFrontend) {
237         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
238         m_agents.didCreateFrontendAndBackend(frontendChannel, &m_backendDispatcher.get());
239     }
240
241 #if ENABLE(REMOTE_INSPECTOR)
242     if (!m_frontendRouter->hasRemoteFrontend())
243         m_page.remoteInspectorInformationDidChange();
244 #endif
245 }
246
247 void InspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
248 {
249     // The local frontend client should be disconnected first so it stops sending messages.
250     ASSERT(!m_frontendRouter->hasLocalFrontend() || !m_inspectorFrontendClient);
251
252     m_frontendRouter->disconnectFrontend(frontendChannel);
253     m_isAutomaticInspection = false;
254
255     InspectorInstrumentation::frontendDeleted();
256
257     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
258     if (disconnectedLastFrontend) {
259         // Release overlay page resources.
260         m_overlay->freePage();
261         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
262         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
263     }
264
265 #if ENABLE(REMOTE_INSPECTOR)
266     if (!m_frontendRouter->hasFrontends())
267         m_page.remoteInspectorInformationDidChange();
268 #endif
269 }
270
271 void InspectorController::disconnectAllFrontends()
272 {
273     // The local frontend client should be disconnected first so it stops sending messages.
274     ASSERT(!m_frontendRouter->hasLocalFrontend() || !m_inspectorFrontendClient);
275
276     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
277
278     m_frontendRouter->disconnectAllFrontends();
279     m_isAutomaticInspection = false;
280
281     // Release overlay page resources.
282     m_overlay->freePage();
283
284     while (InspectorInstrumentation::hasFrontends())
285         InspectorInstrumentation::frontendDeleted();
286
287     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
288     
289 #if ENABLE(REMOTE_INSPECTOR)
290     m_page.remoteInspectorInformationDidChange();
291 #endif
292 }
293
294 void InspectorController::show()
295 {
296     ASSERT(!m_frontendRouter->hasRemoteFrontend());
297
298     // The local frontend client should be disconnected if there's no local frontend.
299     ASSERT(m_frontendRouter->hasLocalFrontend() || !m_inspectorFrontendClient);
300
301     if (!enabled())
302         return;
303
304     if (m_frontendRouter->hasLocalFrontend())
305         m_inspectorClient->bringFrontendToFront();
306     else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openInspectorFrontend(this))
307         connectFrontend(frontendChannel);
308 }
309
310 void InspectorController::close()
311 {
312     if (m_frontendRouter->hasLocalFrontend())
313         m_inspectorClient->closeInspectorFrontend();
314
315     ASSERT(!m_frontendRouter->hasLocalFrontend());
316 }
317
318 void InspectorController::setProcessId(long processId)
319 {
320     IdentifiersFactory::setProcessId(processId);
321 }
322
323 void InspectorController::evaluateForTestInFrontend(const String& script)
324 {
325     m_inspectorAgent->evaluateForTestInFrontend(script);
326 }
327
328 void InspectorController::drawHighlight(GraphicsContext& context) const
329 {
330     m_overlay->paint(context);
331 }
332
333 void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
334 {
335     m_overlay->getHighlight(highlight, coordinateSystem);
336 }
337
338 Ref<Inspector::Protocol::Array<Inspector::Protocol::OverlayTypes::NodeHighlightData>> InspectorController::buildObjectForHighlightedNodes() const
339 {
340     return m_overlay->buildObjectForHighlightedNodes();
341 }
342
343 void InspectorController::inspect(Node* node)
344 {
345     if (!enabled())
346         return;
347
348     if (!hasRemoteFrontend())
349         show();
350
351     m_domAgent->inspect(node);
352 }
353
354 bool InspectorController::enabled() const
355 {
356     return developerExtrasEnabled();
357 }
358
359 Page& InspectorController::inspectedPage() const
360 {
361     return m_page;
362 }
363
364 void InspectorController::dispatchMessageFromFrontend(const String& message)
365 {
366     m_backendDispatcher->dispatch(message);
367 }
368
369 void InspectorController::hideHighlight()
370 {
371     ErrorString unused;
372     m_domAgent->hideHighlight(unused);
373 }
374
375 Node* InspectorController::highlightedNode() const
376 {
377     return m_overlay->highlightedNode();
378 }
379
380 void InspectorController::setIndicating(bool indicating)
381 {
382 #if !PLATFORM(IOS)
383     m_overlay->setIndicating(indicating);
384 #else
385     if (indicating)
386         m_inspectorClient->showInspectorIndication();
387     else
388         m_inspectorClient->hideInspectorIndication();
389 #endif
390 }
391
392 bool InspectorController::profilerEnabled() const
393 {
394     return m_instrumentingAgents->persistentInspectorTimelineAgent();
395 }
396
397 void InspectorController::setProfilerEnabled(bool enable)
398 {
399     ErrorString unused;
400
401     if (enable) {
402         m_instrumentingAgents->setPersistentInspectorTimelineAgent(m_timelineAgent);
403         m_timelineAgent->start(unused);
404     } else {
405         m_instrumentingAgents->setPersistentInspectorTimelineAgent(nullptr);
406         m_timelineAgent->stop(unused);
407     }
408 }
409
410 void InspectorController::resume()
411 {
412     if (m_debuggerAgent) {
413         ErrorString unused;
414         m_debuggerAgent->resume(unused);
415     }
416 }
417
418 bool InspectorController::developerExtrasEnabled() const
419 {
420     return m_page.settings().developerExtrasEnabled();
421 }
422
423 bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
424 {
425     JSLockHolder lock(scriptState);
426     JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->lexicalGlobalObject());
427     if (!inspectedWindow)
428         return false;
429
430     return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->impl(), DoNotReportSecurityError);
431 }
432
433 InspectorFunctionCallHandler InspectorController::functionCallHandler() const
434 {
435     return WebCore::functionCallHandlerFromAnyThread;
436 }
437
438 InspectorEvaluateHandler InspectorController::evaluateHandler() const
439 {
440     return WebCore::evaluateHandlerFromAnyThread;
441 }
442
443 void InspectorController::willCallInjectedScriptFunction(JSC::ExecState* scriptState, const String&, int)
444 {
445     LegacyProfiler::profiler()->suspendProfiling(scriptState);
446 }
447
448 void InspectorController::didCallInjectedScriptFunction(JSC::ExecState* scriptState)
449 {
450     LegacyProfiler::profiler()->unsuspendProfiling(scriptState);
451 }
452
453 void InspectorController::frontendInitialized()
454 {
455 #if ENABLE(REMOTE_INSPECTOR)
456     if (m_isAutomaticInspection)
457         m_page.inspectorDebuggable().unpauseForInitializedInspector();
458 #endif
459 }
460
461 Ref<Stopwatch> InspectorController::executionStopwatch()
462 {
463     return m_executionStopwatch.copyRef();
464 }
465
466 void InspectorController::didComposite(Frame& frame)
467 {
468     InspectorInstrumentation::didComposite(frame);
469 }
470
471 } // namespace WebCore