Delay WebProcess launch until a load is triggered in a Web view
[WebKit-https.git] / Source / WebKit / UIProcess / WebInspectorProxy.cpp
1 /*
2  * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2011 Motorola Mobility, 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
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebInspectorProxy.h"
29
30 #include "APINavigation.h"
31 #include "APIProcessPoolConfiguration.h"
32 #include "WebAutomationSession.h"
33 #include "WebFrameProxy.h"
34 #include "WebInspectorInterruptDispatcherMessages.h"
35 #include "WebInspectorMessages.h"
36 #include "WebInspectorProxyMessages.h"
37 #include "WebInspectorUIMessages.h"
38 #include "WebPageGroup.h"
39 #include "WebPageInspectorController.h"
40 #include "WebPageProxy.h"
41 #include "WebPreferences.h"
42 #include "WebProcessPool.h"
43 #include "WebProcessProxy.h"
44 #include <WebCore/CertificateInfo.h>
45 #include <WebCore/NotImplemented.h>
46 #include <WebCore/TextEncoding.h>
47 #include <wtf/SetForScope.h>
48
49 #if PLATFORM(GTK)
50 #include "WebInspectorProxyClient.h"
51 #endif
52
53 namespace WebKit {
54 using namespace WebCore;
55
56 const unsigned WebInspectorProxy::minimumWindowWidth = 500;
57 const unsigned WebInspectorProxy::minimumWindowHeight = 400;
58
59 const unsigned WebInspectorProxy::initialWindowWidth = 1000;
60 const unsigned WebInspectorProxy::initialWindowHeight = 650;
61
62 WebInspectorProxy::WebInspectorProxy(WebPageProxy* inspectedPage)
63 #if PLATFORM(MAC)
64     : m_closeFrontendAfterInactivityTimer(RunLoop::main(), this, &WebInspectorProxy::closeFrontendAfterInactivityTimerFired)
65 #endif
66 {
67     if (inspectedPage && inspectedPage->hasRunningProcess()) {
68         m_inspectedPage = inspectedPage;
69         m_inspectedPage->process().addMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID(), *this);
70     }
71 }
72
73 WebInspectorProxy::~WebInspectorProxy()
74 {
75 }
76
77 unsigned WebInspectorProxy::inspectionLevel() const
78 {
79     return inspectorLevelForPage(inspectedPage());
80 }
81
82 WebPreferences& WebInspectorProxy::inspectorPagePreferences() const
83 {
84     ASSERT(m_inspectorPage);
85     return m_inspectorPage->pageGroup().preferences();
86 }
87
88 void WebInspectorProxy::invalidate()
89 {
90     if (m_inspectedPage)
91         m_inspectedPage->process().removeMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID());
92
93     closeFrontendPageAndWindow();
94     platformInvalidate();
95
96     m_inspectedPage = nullptr;
97 }
98
99 void WebInspectorProxy::sendMessageToFrontend(const String& message)
100 {
101     if (!m_inspectorPage)
102         return;
103
104     m_inspectorPage->process().send(Messages::WebInspectorUI::SendMessageToFrontend(message), m_inspectorPage->pageID());
105 }
106
107 // Public APIs
108 bool WebInspectorProxy::isFront()
109 {
110     if (!m_inspectedPage)
111         return false;
112
113     return platformIsFront();
114 }
115
116 void WebInspectorProxy::connect()
117 {
118     if (!m_inspectedPage)
119         return;
120
121     if (m_showMessageSent)
122         return;
123
124     m_showMessageSent = true;
125     m_ignoreFirstBringToFront = true;
126
127     createFrontendPage();
128
129     m_inspectedPage->process().send(Messages::WebInspectorInterruptDispatcher::NotifyNeedDebuggerBreak(), 0);
130     m_inspectedPage->process().send(Messages::WebInspector::Show(), m_inspectedPage->pageID());
131 }
132
133 void WebInspectorProxy::show()
134 {
135     if (!m_inspectedPage)
136         return;
137
138     if (isConnected()) {
139         bringToFront();
140         return;
141     }
142
143     connect();
144
145     // Don't ignore the first bringToFront so it opens the Inspector.
146     m_ignoreFirstBringToFront = false;
147 }
148
149 void WebInspectorProxy::hide()
150 {
151     if (!m_inspectedPage)
152         return;
153
154     m_isVisible = false;
155
156     platformHide();
157 }
158
159 void WebInspectorProxy::close()
160 {
161     if (!m_inspectedPage)
162         return;
163
164     m_inspectedPage->process().send(Messages::WebInspector::Close(), m_inspectedPage->pageID());
165
166     closeFrontendPageAndWindow();
167 }
168
169 void WebInspectorProxy::closeForCrash()
170 {
171     close();
172
173     platformDidCloseForCrash();
174 }
175
176 void WebInspectorProxy::reopen()
177 {
178     if (!m_inspectedPage)
179         return;
180
181     close();
182     show();
183 }
184
185 void WebInspectorProxy::reset()
186 {
187     if (m_inspectedPage) {
188         m_inspectedPage->process().removeMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID());
189         m_inspectedPage = nullptr;
190     }
191 }
192
193 void WebInspectorProxy::updateForNewPageProcess(WebPageProxy* inspectedPage)
194 {
195     ASSERT(!m_inspectedPage);
196     ASSERT(inspectedPage);
197
198     m_inspectedPage = inspectedPage;
199     m_inspectedPage->process().addMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID(), *this);
200
201     if (m_inspectorPage)
202         m_inspectorPage->process().send(Messages::WebInspectorUI::UpdateConnection(), m_inspectorPage->pageID());
203 }
204
205 void WebInspectorProxy::setFrontendConnection(IPC::Attachment connectionIdentifier)
206 {
207     if (!m_inspectedPage)
208         return;
209
210     m_inspectedPage->process().send(Messages::WebInspector::SetFrontendConnection(connectionIdentifier), m_inspectedPage->pageID());
211 }
212
213 void WebInspectorProxy::showConsole()
214 {
215     if (!m_inspectedPage)
216         return;
217
218     createFrontendPage();
219
220     m_inspectedPage->process().send(Messages::WebInspector::ShowConsole(), m_inspectedPage->pageID());
221 }
222
223 void WebInspectorProxy::showResources()
224 {
225     if (!m_inspectedPage)
226         return;
227
228     createFrontendPage();
229
230     m_inspectedPage->process().send(Messages::WebInspector::ShowResources(), m_inspectedPage->pageID());
231 }
232
233 void WebInspectorProxy::showTimelines()
234 {
235     if (!m_inspectedPage)
236         return;
237
238     createFrontendPage();
239
240     m_inspectedPage->process().send(Messages::WebInspector::ShowTimelines(), m_inspectedPage->pageID());
241 }
242
243 void WebInspectorProxy::showMainResourceForFrame(WebFrameProxy* frame)
244 {
245     if (!m_inspectedPage)
246         return;
247
248     createFrontendPage();
249
250     m_inspectedPage->process().send(Messages::WebInspector::ShowMainResourceForFrame(frame->frameID()), m_inspectedPage->pageID());
251 }
252
253 void WebInspectorProxy::attachBottom()
254 {
255     attach(AttachmentSide::Bottom);
256 }
257
258 void WebInspectorProxy::attachRight()
259 {
260     attach(AttachmentSide::Right);
261 }
262
263 void WebInspectorProxy::attachLeft()
264 {
265     attach(AttachmentSide::Left);
266 }
267
268 void WebInspectorProxy::attach(AttachmentSide side)
269 {
270     if (!m_inspectedPage || !canAttach())
271         return;
272
273     m_isAttached = true;
274     m_attachmentSide = side;
275
276     inspectorPagePreferences().setInspectorAttachmentSide(static_cast<uint32_t>(side));
277
278     if (m_isVisible)
279         inspectorPagePreferences().setInspectorStartsAttached(true);
280
281     m_inspectedPage->process().send(Messages::WebInspector::SetAttached(true), m_inspectedPage->pageID());
282
283     switch (m_attachmentSide) {
284     case AttachmentSide::Bottom:
285         m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedBottom(), m_inspectorPage->pageID());
286         break;
287
288     case AttachmentSide::Right:
289         m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedRight(), m_inspectorPage->pageID());
290         break;
291
292     case AttachmentSide::Left:
293         m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedLeft(), m_inspectorPage->pageID());
294         break;
295     }
296
297     platformAttach();
298 }
299
300 void WebInspectorProxy::detach()
301 {
302     if (!m_inspectedPage)
303         return;
304
305     m_isAttached = false;
306
307     if (m_isVisible)
308         inspectorPagePreferences().setInspectorStartsAttached(false);
309
310     m_inspectedPage->process().send(Messages::WebInspector::SetAttached(false), m_inspectedPage->pageID());
311     m_inspectorPage->process().send(Messages::WebInspectorUI::Detached(), m_inspectorPage->pageID());
312
313     platformDetach();
314 }
315
316 void WebInspectorProxy::setAttachedWindowHeight(unsigned height)
317 {
318     inspectorPagePreferences().setInspectorAttachedHeight(height);
319     platformSetAttachedWindowHeight(height);
320 }
321
322 void WebInspectorProxy::setAttachedWindowWidth(unsigned width)
323 {
324     inspectorPagePreferences().setInspectorAttachedWidth(width);
325     platformSetAttachedWindowWidth(width);
326 }
327
328 void WebInspectorProxy::startWindowDrag()
329 {
330     platformStartWindowDrag();
331 }
332
333 void WebInspectorProxy::togglePageProfiling()
334 {
335     if (!m_inspectedPage)
336         return;
337
338     if (m_isProfilingPage)
339         m_inspectedPage->process().send(Messages::WebInspector::StopPageProfiling(), m_inspectedPage->pageID());
340     else
341         m_inspectedPage->process().send(Messages::WebInspector::StartPageProfiling(), m_inspectedPage->pageID());
342
343     // FIXME: have the WebProcess notify us on state changes.
344     m_isProfilingPage = !m_isProfilingPage;
345 }
346
347 void WebInspectorProxy::toggleElementSelection()
348 {
349     if (!m_inspectedPage)
350         return;
351
352     if (m_elementSelectionActive) {
353         m_ignoreElementSelectionChange = true;
354         m_inspectedPage->process().send(Messages::WebInspector::StopElementSelection(), m_inspectedPage->pageID());
355     } else {
356         connect();
357         m_inspectedPage->process().send(Messages::WebInspector::StartElementSelection(), m_inspectedPage->pageID());
358     }
359 }
360
361 bool WebInspectorProxy::isMainOrTestInspectorPage(const URL& url)
362 {
363     // Use URL so we can compare the paths and protocols.
364     URL mainPageURL(URL(), WebInspectorProxy::inspectorPageURL());
365     if (url.protocol() == mainPageURL.protocol() && decodeURLEscapeSequences(url.path()) == decodeURLEscapeSequences(mainPageURL.path()))
366         return true;
367
368     // We might not have a Test URL in Production builds.
369     String testPageURLString = WebInspectorProxy::inspectorTestPageURL();
370     if (testPageURLString.isNull())
371         return false;
372
373     URL testPageURL(URL(), testPageURLString);
374     return url.protocol() == testPageURL.protocol() && decodeURLEscapeSequences(url.path()) == decodeURLEscapeSequences(testPageURL.path());
375 }
376
377 void WebInspectorProxy::createFrontendPage()
378 {
379     if (m_inspectorPage)
380         return;
381
382     m_inspectorPage = platformCreateFrontendPage();
383     ASSERT(m_inspectorPage);
384     if (!m_inspectorPage)
385         return;
386
387     trackInspectorPage(m_inspectorPage);
388
389     m_inspectorPage->process().addMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID(), *this);
390     m_inspectorPage->process().assumeReadAccessToBaseURL(*m_inspectorPage, WebInspectorProxy::inspectorBaseURL());
391 }
392
393 void WebInspectorProxy::openLocalInspectorFrontend(bool canAttach, bool underTest)
394 {
395     if (!m_inspectedPage)
396         return;
397
398     if (m_inspectedPage->inspectorController().hasLocalFrontend()) {
399         show();
400         return;
401     }
402
403     m_underTest = underTest;
404     createFrontendPage();
405
406     ASSERT(m_inspectorPage);
407     if (!m_inspectorPage)
408         return;
409
410     m_inspectorPage->process().send(Messages::WebInspectorUI::EstablishConnection(m_inspectedPage->pageID(), m_underTest, inspectionLevel()), m_inspectorPage->pageID());
411
412     ASSERT(!m_isActiveFrontend);
413     m_isActiveFrontend = true;
414     m_inspectedPage->inspectorController().connectFrontend(*this);
415
416     if (!m_underTest) {
417         m_canAttach = platformCanAttach(canAttach);
418         m_isAttached = shouldOpenAttached();
419         m_attachmentSide = static_cast<AttachmentSide>(inspectorPagePreferences().inspectorAttachmentSide());
420
421         m_inspectedPage->process().send(Messages::WebInspector::SetAttached(m_isAttached), m_inspectedPage->pageID());
422
423         if (m_isAttached) {
424             switch (m_attachmentSide) {
425             case AttachmentSide::Bottom:
426                 m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedBottom(), m_inspectorPage->pageID());
427                 break;
428
429             case AttachmentSide::Right:
430                 m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedRight(), m_inspectorPage->pageID());
431                 break;
432
433             case AttachmentSide::Left:
434                 m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedLeft(), m_inspectorPage->pageID());
435                 break;
436             }
437         } else
438             m_inspectorPage->process().send(Messages::WebInspectorUI::Detached(), m_inspectorPage->pageID());
439
440         m_inspectorPage->process().send(Messages::WebInspectorUI::SetDockingUnavailable(!m_canAttach), m_inspectorPage->pageID());
441     }
442
443     m_inspectorPage->loadRequest(URL(URL(), m_underTest ? WebInspectorProxy::inspectorTestPageURL() : WebInspectorProxy::inspectorPageURL()));
444 }
445
446 void WebInspectorProxy::open()
447 {
448     if (m_underTest)
449         return;
450
451     if (!m_inspectorPage)
452         return;
453
454     SetForScope<bool> isOpening(m_isOpening, true);
455     m_isVisible = true;
456     m_inspectorPage->process().send(Messages::WebInspectorUI::SetIsVisible(m_isVisible), m_inspectorPage->pageID());
457
458     if (m_isAttached)
459         platformAttach();
460     else
461         platformCreateFrontendWindow();
462
463     platformBringToFront();
464 }
465
466 void WebInspectorProxy::didClose()
467 {
468     closeFrontendPageAndWindow();
469 }
470
471 void WebInspectorProxy::closeFrontendPageAndWindow()
472 {
473     if (!m_inspectorPage)
474         return;
475
476     m_isVisible = false;
477     m_isProfilingPage = false;
478     m_showMessageSent = false;
479     m_ignoreFirstBringToFront = false;
480
481     untrackInspectorPage(m_inspectorPage);
482
483     m_inspectorPage->process().send(Messages::WebInspectorUI::SetIsVisible(m_isVisible), m_inspectorPage->pageID());
484     m_inspectorPage->process().removeMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID());
485
486     if (m_isActiveFrontend) {
487         m_isActiveFrontend = false;
488         m_inspectedPage->inspectorController().disconnectFrontend(*this);
489     }
490
491     if (m_isAttached)
492         platformDetach();
493
494     // Null out m_inspectorPage after platformDetach(), so the views can be cleaned up correctly.
495     m_inspectorPage = nullptr;
496
497     m_isAttached = false;
498     m_canAttach = false;
499     m_underTest = false;
500
501     platformCloseFrontendPageAndWindow();
502 }
503
504 void WebInspectorProxy::sendMessageToBackend(const String& message)
505 {
506     if (!m_inspectedPage)
507         return;
508
509     m_inspectedPage->inspectorController().dispatchMessageFromFrontend(message);
510 }
511
512 void WebInspectorProxy::frontendLoaded()
513 {
514     if (!m_inspectedPage)
515         return;
516
517     if (auto* automationSession = m_inspectedPage->process().processPool().automationSession())
518         automationSession->inspectorFrontendLoaded(*m_inspectedPage);
519 }
520
521 void WebInspectorProxy::bringToFront()
522 {
523     // WebCore::InspectorFrontendClientLocal tells us to do this on load. We want to
524     // ignore it once if we only wanted to connect. This allows the Inspector to later
525     // request to be brought to the front when a breakpoint is hit or some other action.
526     if (m_ignoreFirstBringToFront) {
527         m_ignoreFirstBringToFront = false;
528         return;
529     }
530
531     if (m_isVisible)
532         platformBringToFront();
533     else
534         open();
535 }
536
537 void WebInspectorProxy::attachAvailabilityChanged(bool available)
538 {
539     bool previousCanAttach = m_canAttach;
540
541     m_canAttach = platformCanAttach(available);
542
543     if (previousCanAttach == m_canAttach)
544         return;
545
546     if (m_inspectorPage && !m_underTest)
547         m_inspectorPage->process().send(Messages::WebInspectorUI::SetDockingUnavailable(!m_canAttach), m_inspectorPage->pageID());
548
549     platformAttachAvailabilityChanged(m_canAttach);
550 }
551
552 void WebInspectorProxy::inspectedURLChanged(const String& urlString)
553 {
554     platformInspectedURLChanged(urlString);
555 }
556
557 void WebInspectorProxy::showCertificate(const CertificateInfo& certificateInfo)
558 {
559     platformShowCertificate(certificateInfo);
560 }
561
562 void WebInspectorProxy::elementSelectionChanged(bool active)
563 {
564     m_elementSelectionActive = active;
565
566     if (m_ignoreElementSelectionChange) {
567         m_ignoreElementSelectionChange = false;
568         if (!m_isVisible)
569             close();
570         return;
571     }
572
573     if (active)
574         platformBringInspectedPageToFront();
575     else if (isConnected())
576         bringToFront();
577 }
578
579 void WebInspectorProxy::save(const String& filename, const String& content, bool base64Encoded, bool forceSaveAs)
580 {
581     platformSave(filename, content, base64Encoded, forceSaveAs);
582 }
583
584 void WebInspectorProxy::append(const String& filename, const String& content)
585 {
586     platformAppend(filename, content);
587 }
588
589 bool WebInspectorProxy::shouldOpenAttached()
590 {
591     return inspectorPagePreferences().inspectorStartsAttached() && canAttach();
592 }
593
594 // Unsupported configurations can use the stubs provided here.
595
596 #if PLATFORM(IOS_FAMILY)
597
598 WebPageProxy* WebInspectorProxy::platformCreateFrontendPage()
599 {
600     notImplemented();
601     return nullptr;
602 }
603
604 void WebInspectorProxy::platformCreateFrontendWindow()
605 {
606     notImplemented();
607 }
608
609 void WebInspectorProxy::platformCloseFrontendPageAndWindow()
610 {
611     notImplemented();
612 }
613
614 void WebInspectorProxy::platformDidCloseForCrash()
615 {
616     notImplemented();
617 }
618
619 void WebInspectorProxy::platformInvalidate()
620 {
621     notImplemented();
622 }
623
624 void WebInspectorProxy::platformBringToFront()
625 {
626     notImplemented();
627 }
628
629 void WebInspectorProxy::platformBringInspectedPageToFront()
630 {
631     notImplemented();
632 }
633
634 void WebInspectorProxy::platformHide()
635 {
636     notImplemented();
637 }
638
639 bool WebInspectorProxy::platformIsFront()
640 {
641     notImplemented();
642     return false;
643 }
644
645 void WebInspectorProxy::platformInspectedURLChanged(const String&)
646 {
647     notImplemented();
648 }
649
650 void WebInspectorProxy::platformShowCertificate(const CertificateInfo&)
651 {
652     notImplemented();
653 }
654
655 void WebInspectorProxy::platformSave(const String& suggestedURL, const String& content, bool base64Encoded, bool forceSaveDialog)
656 {
657     notImplemented();
658 }
659
660 void WebInspectorProxy::platformAppend(const String& suggestedURL, const String& content)
661 {
662     notImplemented();
663 }
664
665 unsigned WebInspectorProxy::platformInspectedWindowHeight()
666 {
667     notImplemented();
668     return 0;
669 }
670
671 unsigned WebInspectorProxy::platformInspectedWindowWidth()
672 {
673     notImplemented();
674     return 0;
675 }
676
677 void WebInspectorProxy::platformAttach()
678 {
679     notImplemented();
680 }
681
682 void WebInspectorProxy::platformDetach()
683 {
684     notImplemented();
685 }
686
687 void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned)
688 {
689     notImplemented();
690 }
691
692 void WebInspectorProxy::platformStartWindowDrag()
693 {
694     notImplemented();
695 }
696
697 String WebInspectorProxy::inspectorPageURL()
698 {
699     notImplemented();
700     return String();
701 }
702
703 String WebInspectorProxy::inspectorTestPageURL()
704 {
705     notImplemented();
706     return String();
707 }
708
709 String WebInspectorProxy::inspectorBaseURL()
710 {
711     notImplemented();
712     return String();
713 }
714
715 void WebInspectorProxy::platformSetAttachedWindowWidth(unsigned)
716 {
717     notImplemented();
718 }
719
720 void WebInspectorProxy::platformAttachAvailabilityChanged(bool)
721 {
722     notImplemented();
723 }
724
725 #endif // PLATFORM(IOS_FAMILY)
726
727 } // namespace WebKit