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