be94652efd3ed099b77c2c0ca4eb0956738bd761
[WebKit.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     InspectorScriptProfilerAgent* scriptProfilerAgent = 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     m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext, scriptProfilerAgent, heapAgent, pageAgent));
148
149     auto canvasAgentPtr = std::make_unique<InspectorCanvasAgent>(pageContext);
150     m_instrumentingAgents->setInspectorCanvasAgent(canvasAgentPtr.get());
151     m_agents.append(WTFMove(canvasAgentPtr));
152
153     ASSERT(m_injectedScriptManager->commandLineAPIHost());
154     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
155         commandLineAPIHost->init(m_inspectorAgent, consoleAgent, m_domAgent, domStorageAgent, databaseAgent);
156 }
157
158 InspectorController::~InspectorController()
159 {
160     m_instrumentingAgents->reset();
161     ASSERT(!m_inspectorClient);
162 }
163
164 PageAgentContext InspectorController::pageAgentContext()
165 {
166     AgentContext baseContext = {
167         *this,
168         *m_injectedScriptManager,
169         m_frontendRouter.get(),
170         m_backendDispatcher.get()
171     };
172
173     WebAgentContext webContext = {
174         baseContext,
175         m_instrumentingAgents.get()
176     };
177
178     PageAgentContext pageContext = {
179         webContext,
180         m_page
181     };
182
183     return pageContext;
184 }
185
186 void InspectorController::createLazyAgents()
187 {
188     if (m_didCreateLazyAgents)
189         return;
190
191     m_didCreateLazyAgents = true;
192
193     auto pageContext = pageAgentContext();
194
195     auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext, m_pageAgent, m_overlay.get());
196     auto debuggerAgentPtr = debuggerAgent.get();
197
198     m_agents.append(WTFMove(debuggerAgent));
199     m_agents.append(std::make_unique<PageNetworkAgent>(pageContext, m_pageAgent));
200     m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext, m_domAgent));
201     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, m_domAgent, debuggerAgentPtr));
202     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, m_pageAgent));
203     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
204     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
205 #if ENABLE(INDEXED_DATABASE)
206     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext, m_pageAgent));
207 #endif
208 #if ENABLE(RESOURCE_USAGE)
209     m_agents.append(std::make_unique<InspectorCPUProfilerAgent>(pageContext));
210     m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
211 #endif
212     m_agents.append(std::make_unique<PageAuditAgent>(pageContext));
213 }
214
215 void InspectorController::inspectedPageDestroyed()
216 {
217     // Clean up resources and disconnect local and remote frontends.
218     disconnectAllFrontends();
219
220     // Disconnect the client.
221     m_inspectorClient->inspectedPageDestroyed();
222     m_inspectorClient = nullptr;
223
224     m_agents.discardValues();
225 }
226
227 void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
228 {
229     m_inspectorFrontendClient = inspectorFrontendClient;
230 }
231
232 bool InspectorController::hasLocalFrontend() const
233 {
234     return m_frontendRouter->hasLocalFrontend();
235 }
236
237 bool InspectorController::hasRemoteFrontend() const
238 {
239     return m_frontendRouter->hasRemoteFrontend();
240 }
241
242 unsigned InspectorController::inspectionLevel() const
243 {
244     return m_inspectorFrontendClient ? m_inspectorFrontendClient->inspectionLevel() : 0;
245 }
246
247 void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
248 {
249     if (&world != &mainThreadNormalWorld())
250         return;
251
252     if (frame.isMainFrame())
253         m_injectedScriptManager->discardInjectedScripts();
254
255     // If the page is supposed to serve as InspectorFrontend notify inspector frontend
256     // client that it's cleared so that the client can expose inspector bindings.
257     if (m_inspectorFrontendClient && frame.isMainFrame())
258         m_inspectorFrontendClient->windowObjectCleared();
259 }
260
261 void InspectorController::connectFrontend(Inspector::FrontendChannel& frontendChannel, bool isAutomaticInspection, bool immediatelyPause)
262 {
263     ASSERT(m_inspectorClient);
264
265     // If a frontend has connected enable the developer extras and keep them enabled.
266     m_page.settings().setDeveloperExtrasEnabled(true);
267
268     createLazyAgents();
269
270     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
271     m_isAutomaticInspection = isAutomaticInspection;
272     m_pauseAfterInitialization = immediatelyPause;
273
274     m_frontendRouter->connectFrontend(frontendChannel);
275
276     InspectorInstrumentation::frontendCreated();
277
278     if (connectedFirstFrontend) {
279         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
280         m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
281     }
282
283     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
284
285 #if ENABLE(REMOTE_INSPECTOR)
286     if (hasLocalFrontend())
287         m_page.remoteInspectorInformationDidChange();
288 #endif
289 }
290
291 void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
292 {
293     m_frontendRouter->disconnectFrontend(frontendChannel);
294
295     m_isAutomaticInspection = false;
296     m_pauseAfterInitialization = false;
297
298     InspectorInstrumentation::frontendDeleted();
299
300     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
301     if (disconnectedLastFrontend) {
302         // Notify agents first.
303         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
304
305         // Clean up inspector resources.
306         m_overlay->freePage();
307         m_injectedScriptManager->discardInjectedScripts();
308
309         // Unplug all instrumentations since they aren't needed now.
310         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
311     }
312
313     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
314
315 #if ENABLE(REMOTE_INSPECTOR)
316     if (disconnectedLastFrontend)
317         m_page.remoteInspectorInformationDidChange();
318 #endif
319 }
320
321 void InspectorController::disconnectAllFrontends()
322 {
323     // If the local frontend page was destroyed, close the window.
324     if (m_inspectorFrontendClient)
325         m_inspectorFrontendClient->closeWindow();
326
327     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
328     ASSERT(!m_inspectorFrontendClient);
329
330     if (!m_frontendRouter->hasFrontends())
331         return;
332
333     for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
334         InspectorInstrumentation::frontendDeleted();
335
336     // Unplug all instrumentations to prevent further agent callbacks.
337     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
338
339     // Notify agents first, since they may need to use InspectorClient.
340     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
341
342     // Clean up inspector resources.
343     m_overlay->freePage();
344     m_injectedScriptManager->disconnect();
345
346     // Disconnect any remaining remote frontends.
347     m_frontendRouter->disconnectAllFrontends();
348     m_isAutomaticInspection = false;
349     m_pauseAfterInitialization = false;
350
351     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
352
353 #if ENABLE(REMOTE_INSPECTOR)
354     m_page.remoteInspectorInformationDidChange();
355 #endif
356 }
357
358 void InspectorController::show()
359 {
360     ASSERT(!hasRemoteFrontend());
361
362     if (!enabled())
363         return;
364
365     if (m_frontendRouter->hasLocalFrontend())
366         m_inspectorClient->bringFrontendToFront();
367     else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openLocalFrontend(this))
368         connectFrontend(*frontendChannel);
369 }
370
371 void InspectorController::setIsUnderTest(bool value)
372 {
373     if (value == m_isUnderTest)
374         return;
375
376     m_isUnderTest = value;
377
378     // <rdar://problem/26768628> Try to catch suspicious scenarios where we may have a dangling frontend while running tests.
379     RELEASE_ASSERT(!m_isUnderTest || !m_frontendRouter->hasFrontends());
380 }
381
382 void InspectorController::evaluateForTestInFrontend(const String& script)
383 {
384     m_inspectorAgent->evaluateForTestInFrontend(script);
385 }
386
387 void InspectorController::drawHighlight(GraphicsContext& context) const
388 {
389     m_overlay->paint(context);
390 }
391
392 void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
393 {
394     m_overlay->getHighlight(highlight, coordinateSystem);
395 }
396
397 Ref<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::NodeHighlightData>> InspectorController::buildObjectForHighlightedNodes() const
398 {
399     return m_overlay->buildObjectForHighlightedNodes();
400 }
401
402 void InspectorController::inspect(Node* node)
403 {
404     if (!enabled())
405         return;
406
407     if (!hasRemoteFrontend())
408         show();
409
410     m_domAgent->inspect(node);
411 }
412
413 bool InspectorController::enabled() const
414 {
415     return developerExtrasEnabled();
416 }
417
418 Page& InspectorController::inspectedPage() const
419 {
420     return m_page;
421 }
422
423 void InspectorController::dispatchMessageFromFrontend(const String& message)
424 {
425     m_backendDispatcher->dispatch(message);
426 }
427
428 void InspectorController::hideHighlight()
429 {
430     ErrorString unused;
431     m_domAgent->hideHighlight(unused);
432 }
433
434 Node* InspectorController::highlightedNode() const
435 {
436     return m_overlay->highlightedNode();
437 }
438
439 void InspectorController::setIndicating(bool indicating)
440 {
441 #if !PLATFORM(IOS_FAMILY)
442     m_overlay->setIndicating(indicating);
443 #else
444     if (indicating)
445         m_inspectorClient->showInspectorIndication();
446     else
447         m_inspectorClient->hideInspectorIndication();
448 #endif
449 }
450
451 bool InspectorController::developerExtrasEnabled() const
452 {
453     return m_page.settings().developerExtrasEnabled();
454 }
455
456 bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
457 {
458     JSLockHolder lock(scriptState);
459
460     JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->vm(), scriptState->lexicalGlobalObject());
461     if (!inspectedWindow)
462         return false;
463
464     return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->wrapped(), DoNotReportSecurityError);
465 }
466
467 InspectorFunctionCallHandler InspectorController::functionCallHandler() const
468 {
469     return WebCore::functionCallHandlerFromAnyThread;
470 }
471
472 InspectorEvaluateHandler InspectorController::evaluateHandler() const
473 {
474     return WebCore::evaluateHandlerFromAnyThread;
475 }
476
477 void InspectorController::frontendInitialized()
478 {
479     if (m_pauseAfterInitialization) {
480         m_pauseAfterInitialization = false;
481         if (PageDebuggerAgent* debuggerAgent = m_instrumentingAgents->pageDebuggerAgent()) {
482             ErrorString ignored;
483             debuggerAgent->pause(ignored);
484         }
485     }
486
487 #if ENABLE(REMOTE_INSPECTOR)
488     if (m_isAutomaticInspection)
489         m_page.inspectorDebuggable().unpauseForInitializedInspector();
490 #endif
491 }
492
493 Ref<Stopwatch> InspectorController::executionStopwatch()
494 {
495     return m_executionStopwatch.copyRef();
496 }
497
498 PageScriptDebugServer& InspectorController::scriptDebugServer()
499 {
500     return m_scriptDebugServer;
501 }
502
503 JSC::VM& InspectorController::vm()
504 {
505     return commonVM();
506 }
507
508 void InspectorController::didComposite(Frame& frame)
509 {
510     InspectorInstrumentation::didComposite(frame);
511 }
512
513 } // namespace WebCore