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