5203706b53b32b0ba4f0ed4d4ba400b6c79b5e15
[WebKit-https.git] / Source / WebCore / inspector / InspectorController.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2014, 2015 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 "CommonVM.h"
37 #include "DOMWindow.h"
38 #include "DOMWrapperWorld.h"
39 #include "Frame.h"
40 #include "GraphicsContext.h"
41 #include "InspectorApplicationCacheAgent.h"
42 #include "InspectorCPUProfilerAgent.h"
43 #include "InspectorCSSAgent.h"
44 #include "InspectorCanvasAgent.h"
45 #include "InspectorClient.h"
46 #include "InspectorDOMAgent.h"
47 #include "InspectorDOMDebuggerAgent.h"
48 #include "InspectorDOMStorageAgent.h"
49 #include "InspectorDatabaseAgent.h"
50 #include "InspectorDatabaseResource.h"
51 #include "InspectorFrontendClient.h"
52 #include "InspectorIndexedDBAgent.h"
53 #include "InspectorInstrumentation.h"
54 #include "InspectorLayerTreeAgent.h"
55 #include "InspectorMemoryAgent.h"
56 #include "InspectorPageAgent.h"
57 #include "InspectorTimelineAgent.h"
58 #include "InspectorWorkerAgent.h"
59 #include "InstrumentingAgents.h"
60 #include "JSDOMBindingSecurity.h"
61 #include "JSDOMWindow.h"
62 #include "JSDOMWindowCustom.h"
63 #include "JSExecState.h"
64 #include "Page.h"
65 #include "PageAuditAgent.h"
66 #include "PageConsoleAgent.h"
67 #include "PageDebuggerAgent.h"
68 #include "PageHeapAgent.h"
69 #include "PageNetworkAgent.h"
70 #include "PageRuntimeAgent.h"
71 #include "PageScriptDebugServer.h"
72 #include "Settings.h"
73 #include "WebInjectedScriptHost.h"
74 #include "WebInjectedScriptManager.h"
75 #include <JavaScriptCore/IdentifiersFactory.h>
76 #include <JavaScriptCore/InspectorAgent.h>
77 #include <JavaScriptCore/InspectorBackendDispatcher.h>
78 #include <JavaScriptCore/InspectorBackendDispatchers.h>
79 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
80 #include <JavaScriptCore/InspectorFrontendRouter.h>
81 #include <JavaScriptCore/InspectorScriptProfilerAgent.h>
82 #include <JavaScriptCore/JSLock.h>
83 #include <wtf/Stopwatch.h>
84
85 #if ENABLE(REMOTE_INSPECTOR)
86 #include "PageDebuggable.h"
87 #endif
88
89 namespace WebCore {
90
91 using namespace JSC;
92 using namespace Inspector;
93
94 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
95     : m_instrumentingAgents(InstrumentingAgents::create(*this))
96     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
97     , m_frontendRouter(FrontendRouter::create())
98     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
99     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
100     , m_executionStopwatch(Stopwatch::create())
101     , m_scriptDebugServer(page)
102     , m_page(page)
103     , m_inspectorClient(inspectorClient)
104 {
105     ASSERT_ARG(inspectorClient, inspectorClient);
106
107     auto pageContext = pageAgentContext();
108
109     auto consoleAgent = std::make_unique<PageConsoleAgent>(pageContext);
110     m_instrumentingAgents->setWebConsoleAgent(consoleAgent.get());
111     m_agents.append(WTFMove(consoleAgent));
112 }
113
114 InspectorController::~InspectorController()
115 {
116     m_instrumentingAgents->reset();
117     ASSERT(!m_inspectorClient);
118 }
119
120 PageAgentContext InspectorController::pageAgentContext()
121 {
122     AgentContext baseContext = {
123         *this,
124         *m_injectedScriptManager,
125         m_frontendRouter.get(),
126         m_backendDispatcher.get()
127     };
128
129     WebAgentContext webContext = {
130         baseContext,
131         m_instrumentingAgents.get()
132     };
133
134     PageAgentContext pageContext = {
135         webContext,
136         m_page
137     };
138
139     return pageContext;
140 }
141
142 void InspectorController::createLazyAgents()
143 {
144     if (m_didCreateLazyAgents)
145         return;
146
147     m_didCreateLazyAgents = true;
148
149     m_injectedScriptManager->connect();
150
151     auto pageContext = pageAgentContext();
152
153     ensureInspectorAgent();
154     ensurePageAgent();
155
156     m_agents.append(std::make_unique<PageRuntimeAgent>(pageContext));
157
158     auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext);
159     auto debuggerAgentPtr = debuggerAgent.get();
160     m_agents.append(WTFMove(debuggerAgent));
161
162     m_agents.append(std::make_unique<PageNetworkAgent>(pageContext));
163     m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext));
164     ensureDOMAgent();
165     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, debuggerAgentPtr));
166     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext));
167     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
168     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
169     m_agents.append(std::make_unique<InspectorDOMStorageAgent>(pageContext));
170     m_agents.append(std::make_unique<InspectorDatabaseAgent>(pageContext));
171 #if ENABLE(INDEXED_DATABASE)
172     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext));
173 #endif
174
175     auto scriptProfilerAgentPtr = std::make_unique<InspectorScriptProfilerAgent>(pageContext);
176     m_instrumentingAgents->setInspectorScriptProfilerAgent(scriptProfilerAgentPtr.get());
177     m_agents.append(WTFMove(scriptProfilerAgentPtr));
178
179 #if ENABLE(RESOURCE_USAGE)
180     m_agents.append(std::make_unique<InspectorCPUProfilerAgent>(pageContext));
181     m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
182 #endif
183     m_agents.append(std::make_unique<PageHeapAgent>(pageContext));
184     m_agents.append(std::make_unique<PageAuditAgent>(pageContext));
185     m_agents.append(std::make_unique<InspectorCanvasAgent>(pageContext));
186     m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext));
187
188     if (auto& commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
189         commandLineAPIHost->init(m_instrumentingAgents.copyRef());
190 }
191
192 void InspectorController::inspectedPageDestroyed()
193 {
194     // Clean up resources and disconnect local and remote frontends.
195     disconnectAllFrontends();
196
197     // Disconnect the client.
198     m_inspectorClient->inspectedPageDestroyed();
199     m_inspectorClient = nullptr;
200
201     m_agents.discardValues();
202 }
203
204 void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
205 {
206     m_inspectorFrontendClient = inspectorFrontendClient;
207 }
208
209 bool InspectorController::hasLocalFrontend() const
210 {
211     return m_frontendRouter->hasLocalFrontend();
212 }
213
214 bool InspectorController::hasRemoteFrontend() const
215 {
216     return m_frontendRouter->hasRemoteFrontend();
217 }
218
219 unsigned InspectorController::inspectionLevel() const
220 {
221     return m_inspectorFrontendClient ? m_inspectorFrontendClient->inspectionLevel() : 0;
222 }
223
224 void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
225 {
226     if (&world != &mainThreadNormalWorld())
227         return;
228
229     if (frame.isMainFrame())
230         m_injectedScriptManager->discardInjectedScripts();
231
232     // If the page is supposed to serve as InspectorFrontend notify inspector frontend
233     // client that it's cleared so that the client can expose inspector bindings.
234     if (m_inspectorFrontendClient && frame.isMainFrame())
235         m_inspectorFrontendClient->windowObjectCleared();
236 }
237
238 void InspectorController::connectFrontend(Inspector::FrontendChannel& frontendChannel, bool isAutomaticInspection, bool immediatelyPause)
239 {
240     ASSERT(m_inspectorClient);
241
242     // If a frontend has connected enable the developer extras and keep them enabled.
243     m_page.settings().setDeveloperExtrasEnabled(true);
244
245     createLazyAgents();
246
247     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
248     m_isAutomaticInspection = isAutomaticInspection;
249     m_pauseAfterInitialization = immediatelyPause;
250
251     m_frontendRouter->connectFrontend(frontendChannel);
252
253     InspectorInstrumentation::frontendCreated();
254
255     if (connectedFirstFrontend) {
256         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
257         m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
258     }
259
260     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
261
262 #if ENABLE(REMOTE_INSPECTOR)
263     if (hasLocalFrontend())
264         m_page.remoteInspectorInformationDidChange();
265 #endif
266 }
267
268 void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
269 {
270     m_frontendRouter->disconnectFrontend(frontendChannel);
271
272     m_isAutomaticInspection = false;
273     m_pauseAfterInitialization = false;
274
275     InspectorInstrumentation::frontendDeleted();
276
277     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
278     if (disconnectedLastFrontend) {
279         // Notify agents first.
280         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
281
282         // Clean up inspector resources.
283         m_injectedScriptManager->discardInjectedScripts();
284
285         // Unplug all instrumentations since they aren't needed now.
286         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
287     }
288
289     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
290
291 #if ENABLE(REMOTE_INSPECTOR)
292     if (disconnectedLastFrontend)
293         m_page.remoteInspectorInformationDidChange();
294 #endif
295 }
296
297 void InspectorController::disconnectAllFrontends()
298 {
299     // If the local frontend page was destroyed, close the window.
300     if (m_inspectorFrontendClient)
301         m_inspectorFrontendClient->closeWindow();
302
303     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
304     ASSERT(!m_inspectorFrontendClient);
305
306     if (!m_frontendRouter->hasFrontends())
307         return;
308
309     for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
310         InspectorInstrumentation::frontendDeleted();
311
312     // Unplug all instrumentations to prevent further agent callbacks.
313     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
314
315     // Notify agents first, since they may need to use InspectorClient.
316     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
317
318     // Clean up inspector resources.
319     m_injectedScriptManager->disconnect();
320
321     // Disconnect any remaining remote frontends.
322     m_frontendRouter->disconnectAllFrontends();
323     m_isAutomaticInspection = false;
324     m_pauseAfterInitialization = false;
325
326     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
327
328 #if ENABLE(REMOTE_INSPECTOR)
329     m_page.remoteInspectorInformationDidChange();
330 #endif
331 }
332
333 void InspectorController::show()
334 {
335     ASSERT(!hasRemoteFrontend());
336
337     if (!enabled())
338         return;
339
340     if (m_frontendRouter->hasLocalFrontend())
341         m_inspectorClient->bringFrontendToFront();
342     else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openLocalFrontend(this))
343         connectFrontend(*frontendChannel);
344 }
345
346 void InspectorController::setIsUnderTest(bool value)
347 {
348     if (value == m_isUnderTest)
349         return;
350
351     m_isUnderTest = value;
352
353     // <rdar://problem/26768628> Try to catch suspicious scenarios where we may have a dangling frontend while running tests.
354     RELEASE_ASSERT(!m_isUnderTest || !m_frontendRouter->hasFrontends());
355 }
356
357 void InspectorController::evaluateForTestInFrontend(const String& script)
358 {
359     ensureInspectorAgent().evaluateForTestInFrontend(script);
360 }
361
362 void InspectorController::drawHighlight(GraphicsContext& context) const
363 {
364     m_overlay->paint(context);
365 }
366
367 void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
368 {
369     m_overlay->getHighlight(highlight, coordinateSystem);
370 }
371
372 void InspectorController::inspect(Node* node)
373 {
374     if (!enabled())
375         return;
376
377     if (!hasRemoteFrontend())
378         show();
379
380     ensureDOMAgent().inspect(node);
381 }
382
383 bool InspectorController::enabled() const
384 {
385     return developerExtrasEnabled();
386 }
387
388 Page& InspectorController::inspectedPage() const
389 {
390     return m_page;
391 }
392
393 void InspectorController::dispatchMessageFromFrontend(const String& message)
394 {
395     m_backendDispatcher->dispatch(message);
396 }
397
398 void InspectorController::hideHighlight()
399 {
400     m_overlay->hideHighlight();
401 }
402
403 Node* InspectorController::highlightedNode() const
404 {
405     return m_overlay->highlightedNode();
406 }
407
408 void InspectorController::setIndicating(bool indicating)
409 {
410 #if !PLATFORM(IOS_FAMILY)
411     m_overlay->setIndicating(indicating);
412 #else
413     if (indicating)
414         m_inspectorClient->showInspectorIndication();
415     else
416         m_inspectorClient->hideInspectorIndication();
417 #endif
418 }
419
420 InspectorAgent& InspectorController::ensureInspectorAgent()
421 {
422     if (!m_inspectorAgent) {
423         auto pageContext = pageAgentContext();
424         auto inspectorAgent = std::make_unique<InspectorAgent>(pageContext);
425         m_inspectorAgent = inspectorAgent.get();
426         m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
427         m_agents.append(WTFMove(inspectorAgent));
428     }
429     return *m_inspectorAgent;
430 }
431
432 InspectorDOMAgent& InspectorController::ensureDOMAgent()
433 {
434     if (!m_inspectorDOMAgent) {
435         auto pageContext = pageAgentContext();
436         auto domAgent = std::make_unique<InspectorDOMAgent>(pageContext, m_overlay.get());
437         m_inspectorDOMAgent = domAgent.get();
438         m_agents.append(WTFMove(domAgent));
439     }
440     return *m_inspectorDOMAgent;
441 }
442
443 InspectorPageAgent& InspectorController::ensurePageAgent()
444 {
445     if (!m_inspectorPageAgent) {
446         auto pageContext = pageAgentContext();
447         auto pageAgent = std::make_unique<InspectorPageAgent>(pageContext, m_inspectorClient, m_overlay.get());
448         m_inspectorPageAgent = pageAgent.get();
449         m_agents.append(WTFMove(pageAgent));
450     }
451     return *m_inspectorPageAgent;
452 }
453
454 bool InspectorController::developerExtrasEnabled() const
455 {
456     return m_page.settings().developerExtrasEnabled();
457 }
458
459 bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
460 {
461     JSLockHolder lock(scriptState);
462
463     JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->vm(), scriptState->lexicalGlobalObject());
464     if (!inspectedWindow)
465         return false;
466
467     return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->wrapped(), DoNotReportSecurityError);
468 }
469
470 InspectorFunctionCallHandler InspectorController::functionCallHandler() const
471 {
472     return WebCore::functionCallHandlerFromAnyThread;
473 }
474
475 InspectorEvaluateHandler InspectorController::evaluateHandler() const
476 {
477     return WebCore::evaluateHandlerFromAnyThread;
478 }
479
480 void InspectorController::frontendInitialized()
481 {
482     if (m_pauseAfterInitialization) {
483         m_pauseAfterInitialization = false;
484         if (PageDebuggerAgent* debuggerAgent = m_instrumentingAgents->pageDebuggerAgent()) {
485             ErrorString ignored;
486             debuggerAgent->pause(ignored);
487         }
488     }
489
490 #if ENABLE(REMOTE_INSPECTOR)
491     if (m_isAutomaticInspection)
492         m_page.inspectorDebuggable().unpauseForInitializedInspector();
493 #endif
494 }
495
496 Ref<Stopwatch> InspectorController::executionStopwatch()
497 {
498     return m_executionStopwatch.copyRef();
499 }
500
501 PageScriptDebugServer& InspectorController::scriptDebugServer()
502 {
503     return m_scriptDebugServer;
504 }
505
506 JSC::VM& InspectorController::vm()
507 {
508     return commonVM();
509 }
510
511 void InspectorController::willComposite(Frame& frame)
512 {
513     InspectorInstrumentation::willComposite(frame);
514 }
515
516 void InspectorController::didComposite(Frame& frame)
517 {
518     InspectorInstrumentation::didComposite(frame);
519 }
520
521 } // namespace WebCore