Web Inspector: opt out of process swap on navigation if a Web Inspector frontend...
[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 "InspectorCSSAgent.h"
43 #include "InspectorCanvasAgent.h"
44 #include "InspectorClient.h"
45 #include "InspectorDOMAgent.h"
46 #include "InspectorDOMDebuggerAgent.h"
47 #include "InspectorDOMStorageAgent.h"
48 #include "InspectorDatabaseAgent.h"
49 #include "InspectorFrontendClient.h"
50 #include "InspectorIndexedDBAgent.h"
51 #include "InspectorInstrumentation.h"
52 #include "InspectorLayerTreeAgent.h"
53 #include "InspectorMemoryAgent.h"
54 #include "InspectorPageAgent.h"
55 #include "InspectorTimelineAgent.h"
56 #include "InspectorWorkerAgent.h"
57 #include "InstrumentingAgents.h"
58 #include "JSDOMBindingSecurity.h"
59 #include "JSDOMWindow.h"
60 #include "JSDOMWindowCustom.h"
61 #include "JSMainThreadExecState.h"
62 #include "Page.h"
63 #include "PageConsoleAgent.h"
64 #include "PageDebuggerAgent.h"
65 #include "PageHeapAgent.h"
66 #include "PageNetworkAgent.h"
67 #include "PageRuntimeAgent.h"
68 #include "PageScriptDebugServer.h"
69 #include "Settings.h"
70 #include "WebInjectedScriptHost.h"
71 #include "WebInjectedScriptManager.h"
72 #include <JavaScriptCore/IdentifiersFactory.h>
73 #include <JavaScriptCore/InspectorAgent.h>
74 #include <JavaScriptCore/InspectorBackendDispatcher.h>
75 #include <JavaScriptCore/InspectorBackendDispatchers.h>
76 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
77 #include <JavaScriptCore/InspectorFrontendRouter.h>
78 #include <JavaScriptCore/InspectorScriptProfilerAgent.h>
79 #include <JavaScriptCore/JSLock.h>
80 #include <wtf/Stopwatch.h>
81
82 #if ENABLE(REMOTE_INSPECTOR)
83 #include "PageDebuggable.h"
84 #endif
85
86 namespace WebCore {
87
88 using namespace JSC;
89 using namespace Inspector;
90
91 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
92     : m_instrumentingAgents(InstrumentingAgents::create(*this))
93     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
94     , m_frontendRouter(FrontendRouter::create())
95     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
96     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
97     , m_executionStopwatch(Stopwatch::create())
98     , m_scriptDebugServer(page)
99     , m_page(page)
100     , m_inspectorClient(inspectorClient)
101 {
102     ASSERT_ARG(inspectorClient, inspectorClient);
103
104     auto pageContext = pageAgentContext();
105
106     auto inspectorAgentPtr = std::make_unique<InspectorAgent>(pageContext);
107     m_inspectorAgent = inspectorAgentPtr.get();
108     m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
109     m_agents.append(WTFMove(inspectorAgentPtr));
110
111     auto pageAgentPtr = std::make_unique<InspectorPageAgent>(pageContext, inspectorClient, m_overlay.get());
112     InspectorPageAgent* pageAgent = pageAgentPtr.get();
113     m_pageAgent = pageAgentPtr.get();
114     m_agents.append(WTFMove(pageAgentPtr));
115
116     auto runtimeAgent = std::make_unique<PageRuntimeAgent>(pageContext, pageAgent);
117     m_instrumentingAgents->setPageRuntimeAgent(runtimeAgent.get());
118     m_agents.append(WTFMove(runtimeAgent));
119
120     auto domAgentPtr = std::make_unique<InspectorDOMAgent>(pageContext, pageAgent, m_overlay.get());
121     m_domAgent = domAgentPtr.get();
122     m_agents.append(WTFMove(domAgentPtr));
123
124     auto databaseAgentPtr = std::make_unique<InspectorDatabaseAgent>(pageContext);
125     InspectorDatabaseAgent* databaseAgent = databaseAgentPtr.get();
126     m_agents.append(WTFMove(databaseAgentPtr));
127
128     auto domStorageAgentPtr = std::make_unique<InspectorDOMStorageAgent>(pageContext, m_pageAgent);
129     InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
130     m_agents.append(WTFMove(domStorageAgentPtr));
131
132     auto heapAgentPtr = std::make_unique<PageHeapAgent>(pageContext);
133     InspectorHeapAgent* heapAgent = heapAgentPtr.get();
134     m_agents.append(WTFMove(heapAgentPtr));
135
136     auto scriptProfilerAgentPtr = std::make_unique<InspectorScriptProfilerAgent>(pageContext);
137     InspectorScriptProfilerAgent* scriptProfilerAgent = scriptProfilerAgentPtr.get();
138     m_agents.append(WTFMove(scriptProfilerAgentPtr));
139
140     auto consoleAgentPtr = std::make_unique<PageConsoleAgent>(pageContext, heapAgent, m_domAgent);
141     WebConsoleAgent* consoleAgent = consoleAgentPtr.get();
142     m_instrumentingAgents->setWebConsoleAgent(consoleAgentPtr.get());
143     m_agents.append(WTFMove(consoleAgentPtr));
144
145     m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext, scriptProfilerAgent, heapAgent, pageAgent));
146
147     auto canvasAgentPtr = std::make_unique<InspectorCanvasAgent>(pageContext);
148     m_instrumentingAgents->setInspectorCanvasAgent(canvasAgentPtr.get());
149     m_agents.append(WTFMove(canvasAgentPtr));
150
151     ASSERT(m_injectedScriptManager->commandLineAPIHost());
152     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
153         commandLineAPIHost->init(m_inspectorAgent, consoleAgent, m_domAgent, domStorageAgent, databaseAgent);
154 }
155
156 InspectorController::~InspectorController()
157 {
158     m_instrumentingAgents->reset();
159     ASSERT(!m_inspectorClient);
160 }
161
162 PageAgentContext InspectorController::pageAgentContext()
163 {
164     AgentContext baseContext = {
165         *this,
166         *m_injectedScriptManager,
167         m_frontendRouter.get(),
168         m_backendDispatcher.get()
169     };
170
171     WebAgentContext webContext = {
172         baseContext,
173         m_instrumentingAgents.get()
174     };
175
176     PageAgentContext pageContext = {
177         webContext,
178         m_page
179     };
180
181     return pageContext;
182 }
183
184 void InspectorController::createLazyAgents()
185 {
186     if (m_didCreateLazyAgents)
187         return;
188
189     m_didCreateLazyAgents = true;
190
191     auto pageContext = pageAgentContext();
192
193     auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext, m_pageAgent, m_overlay.get());
194     auto debuggerAgentPtr = debuggerAgent.get();
195
196     m_agents.append(WTFMove(debuggerAgent));
197     m_agents.append(std::make_unique<PageNetworkAgent>(pageContext, m_pageAgent));
198     m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext, m_domAgent));
199     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, m_domAgent, debuggerAgentPtr));
200     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, m_pageAgent));
201     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
202     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
203 #if ENABLE(INDEXED_DATABASE)
204     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext, m_pageAgent));
205 #endif
206 #if ENABLE(RESOURCE_USAGE)
207     m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
208 #endif
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_ARG(frontendChannel, frontendChannel);
260     ASSERT(m_inspectorClient);
261
262     createLazyAgents();
263
264     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
265     m_isAutomaticInspection = isAutomaticInspection;
266     m_pauseAfterInitialization = immediatelyPause;
267
268     m_frontendRouter->connectFrontend(frontendChannel);
269
270     InspectorInstrumentation::frontendCreated();
271
272     if (connectedFirstFrontend) {
273         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
274         m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
275     }
276
277     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
278
279 #if ENABLE(REMOTE_INSPECTOR)
280     if (!m_frontendRouter->hasRemoteFrontend())
281         m_page.remoteInspectorInformationDidChange();
282 #endif
283 }
284
285 void InspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
286 {
287     m_frontendRouter->disconnectFrontend(frontendChannel);
288
289     m_isAutomaticInspection = false;
290     m_pauseAfterInitialization = false;
291
292     InspectorInstrumentation::frontendDeleted();
293
294     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
295     if (disconnectedLastFrontend) {
296         // Notify agents first.
297         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
298
299         // Clean up inspector resources.
300         m_overlay->freePage();
301         m_injectedScriptManager->discardInjectedScripts();
302
303         // Unplug all instrumentations since they aren't needed now.
304         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
305     }
306
307     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
308
309 #if ENABLE(REMOTE_INSPECTOR)
310     if (!m_frontendRouter->hasFrontends())
311         m_page.remoteInspectorInformationDidChange();
312 #endif
313 }
314
315 void InspectorController::disconnectAllFrontends()
316 {
317     // If the local frontend page was destroyed, close the window.
318     if (m_inspectorFrontendClient)
319         m_inspectorFrontendClient->closeWindow();
320
321     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
322     ASSERT(!m_inspectorFrontendClient);
323
324     if (!m_frontendRouter->hasFrontends())
325         return;
326
327     for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
328         InspectorInstrumentation::frontendDeleted();
329
330     // Unplug all instrumentations to prevent further agent callbacks.
331     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
332
333     // Notify agents first, since they may need to use InspectorClient.
334     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
335
336     // Clean up inspector resources.
337     m_overlay->freePage();
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(!m_frontendRouter->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 Ref<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::NodeHighlightData>> InspectorController::buildObjectForHighlightedNodes() const
392 {
393     return m_overlay->buildObjectForHighlightedNodes();
394 }
395
396 void InspectorController::inspect(Node* node)
397 {
398     if (!enabled())
399         return;
400
401     if (!hasRemoteFrontend())
402         show();
403
404     m_domAgent->inspect(node);
405 }
406
407 bool InspectorController::enabled() const
408 {
409     return developerExtrasEnabled();
410 }
411
412 Page& InspectorController::inspectedPage() const
413 {
414     return m_page;
415 }
416
417 void InspectorController::dispatchMessageFromFrontend(const String& message)
418 {
419     m_backendDispatcher->dispatch(message);
420 }
421
422 void InspectorController::hideHighlight()
423 {
424     ErrorString unused;
425     m_domAgent->hideHighlight(unused);
426 }
427
428 Node* InspectorController::highlightedNode() const
429 {
430     return m_overlay->highlightedNode();
431 }
432
433 void InspectorController::setIndicating(bool indicating)
434 {
435 #if !PLATFORM(IOS)
436     m_overlay->setIndicating(indicating);
437 #else
438     if (indicating)
439         m_inspectorClient->showInspectorIndication();
440     else
441         m_inspectorClient->hideInspectorIndication();
442 #endif
443 }
444
445 bool InspectorController::developerExtrasEnabled() const
446 {
447     return m_page.settings().developerExtrasEnabled();
448 }
449
450 bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
451 {
452     JSLockHolder lock(scriptState);
453
454     JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->vm(), scriptState->lexicalGlobalObject());
455     if (!inspectedWindow)
456         return false;
457
458     return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->wrapped(), DoNotReportSecurityError);
459 }
460
461 InspectorFunctionCallHandler InspectorController::functionCallHandler() const
462 {
463     return WebCore::functionCallHandlerFromAnyThread;
464 }
465
466 InspectorEvaluateHandler InspectorController::evaluateHandler() const
467 {
468     return WebCore::evaluateHandlerFromAnyThread;
469 }
470
471 void InspectorController::frontendInitialized()
472 {
473     if (m_pauseAfterInitialization) {
474         m_pauseAfterInitialization = false;
475         if (PageDebuggerAgent* debuggerAgent = m_instrumentingAgents->pageDebuggerAgent()) {
476             ErrorString ignored;
477             debuggerAgent->pause(ignored);
478         }
479     }
480
481 #if ENABLE(REMOTE_INSPECTOR)
482     if (m_isAutomaticInspection)
483         m_page.inspectorDebuggable().unpauseForInitializedInspector();
484 #endif
485 }
486
487 Ref<Stopwatch> InspectorController::executionStopwatch()
488 {
489     return m_executionStopwatch.copyRef();
490 }
491
492 PageScriptDebugServer& InspectorController::scriptDebugServer()
493 {
494     return m_scriptDebugServer;
495 }
496
497 JSC::VM& InspectorController::vm()
498 {
499     return commonVM();
500 }
501
502 void InspectorController::didComposite(Frame& frame)
503 {
504     InspectorInstrumentation::didComposite(frame);
505 }
506
507 } // namespace WebCore