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