[Win] MiniBrowser should default to webkit.org
[WebKit-https.git] / Tools / MiniBrowser / win / WebKitBrowserWindow.cpp
1 /*
2  * Copyright (C) 2018 Sony Interactive Entertainment Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "stdafx.h"
26 #include "WebKitBrowserWindow.h"
27
28 #include "MiniBrowserLibResource.h"
29 #include "common.h"
30 #include <WebCore/GDIUtilities.h>
31 #include <WebKit/WKAuthenticationChallenge.h>
32 #include <WebKit/WKAuthenticationDecisionListener.h>
33 #include <WebKit/WKCertificateInfoCurl.h>
34 #include <WebKit/WKCredential.h>
35 #include <WebKit/WKInspector.h>
36 #include <WebKit/WKProtectionSpace.h>
37 #include <WebKit/WKProtectionSpaceCurl.h>
38 #include <WebKit/WKWebsiteDataStoreRefCurl.h>
39 #include <vector>
40
41 std::wstring createString(WKStringRef wkString)
42 {
43     size_t maxSize = WKStringGetLength(wkString);
44
45     std::vector<WKChar> wkCharBuffer(maxSize);
46     size_t actualLength = WKStringGetCharacters(wkString, wkCharBuffer.data(), maxSize);
47     return std::wstring(wkCharBuffer.data(), actualLength);
48 }
49
50 std::wstring createString(WKURLRef wkURL)
51 {
52     WKRetainPtr<WKStringRef> url = adoptWK(WKURLCopyString(wkURL));
53     return createString(url.get());
54 }
55
56 std::string createUTF8String(const wchar_t* src, size_t srcLength)
57 {
58     int length = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, 0, 0, nullptr, nullptr);
59     std::vector<char> buffer(length);
60     size_t actualLength = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, buffer.data(), length, nullptr, nullptr);
61     return { buffer.data(), actualLength };
62 }
63
64 std::wstring createPEMString(WKProtectionSpaceRef protectionSpace)
65 {
66     auto certificateInfo = WKProtectionSpaceCopyCertificateInfo(protectionSpace);
67     auto chainSize = WKCertificateInfoGetCertificateChainSize(certificateInfo);
68
69     std::wstring pems;
70
71     for (auto i = 0; i < chainSize; i++) {
72         auto certificate = adoptWK(WKCertificateInfoCopyCertificateAtIndex(certificateInfo, i));
73         auto size = WKDataGetSize(certificate.get());
74         auto data = WKDataGetBytes(certificate.get());
75
76         for (size_t i = 0; i < size; i++)
77             pems.push_back(data[i]);
78     }
79
80     return replaceString(pems, L"\n", L"\r\n");
81 }
82
83 WKRetainPtr<WKStringRef> createWKString(_bstr_t str)
84 {
85     auto utf8 = createUTF8String(str, str.length());
86     return adoptWK(WKStringCreateWithUTF8CString(utf8.data()));
87 }
88
89 WKRetainPtr<WKStringRef> createWKString(const std::wstring& str)
90 {
91     auto utf8 = createUTF8String(str.c_str(), str.length());
92     return adoptWK(WKStringCreateWithUTF8CString(utf8.data()));
93 }
94
95 WKRetainPtr<WKURLRef> createWKURL(_bstr_t str)
96 {
97     auto utf8 = createUTF8String(str, str.length());
98     return adoptWK(WKURLCreateWithUTF8CString(utf8.data()));
99 }
100
101 WKRetainPtr<WKURLRef> createWKURL(const std::wstring& str)
102 {
103     auto utf8 = createUTF8String(str.c_str(), str.length());
104     return adoptWK(WKURLCreateWithUTF8CString(utf8.data()));
105 }
106
107 Ref<BrowserWindow> WebKitBrowserWindow::create(HWND mainWnd, HWND urlBarWnd, bool, bool)
108 {
109     auto conf = adoptWK(WKPageConfigurationCreate());
110
111     auto prefs = adoptWK(WKPreferencesCreate());
112
113     auto pageGroup = adoptWK(WKPageGroupCreateWithIdentifier(createWKString("WinMiniBrowser").get()));
114     WKPageConfigurationSetPageGroup(conf.get(), pageGroup.get());
115     WKPageGroupSetPreferences(pageGroup.get(), prefs.get());
116
117     WKPreferencesSetMediaCapabilitiesEnabled(prefs.get(), false);
118     WKPreferencesSetDeveloperExtrasEnabled(prefs.get(), true);
119     WKPageConfigurationSetPreferences(conf.get(), prefs.get());
120
121     auto context =adoptWK(WKContextCreateWithConfiguration(nullptr));
122     WKPageConfigurationSetContext(conf.get(), context.get());
123
124     return adoptRef(*new WebKitBrowserWindow(conf.get(), mainWnd, urlBarWnd));
125 }
126
127 WebKitBrowserWindow::WebKitBrowserWindow(WKPageConfigurationRef conf, HWND mainWnd, HWND urlBarWnd)
128     : m_hMainWnd(mainWnd)
129     , m_urlBarWnd(urlBarWnd)
130 {
131     RECT rect = { };
132     m_view = adoptWK(WKViewCreate(rect, conf, mainWnd));
133     WKViewSetIsInWindow(m_view.get(), true);
134
135     auto page = WKViewGetPage(m_view.get());
136
137     WKPageNavigationClientV0 navigationClient = { };
138     navigationClient.base.version = 0;
139     navigationClient.base.clientInfo = this;
140     navigationClient.didFinishNavigation = didFinishNavigation;
141     navigationClient.didCommitNavigation = didCommitNavigation;
142     navigationClient.didReceiveAuthenticationChallenge = didReceiveAuthenticationChallenge;
143     WKPageSetPageNavigationClient(page, &navigationClient.base);
144
145     WKPageUIClientV13 uiClient = { };
146     uiClient.base.version = 13;
147     uiClient.base.clientInfo = this;
148     uiClient.createNewPage = createNewPage;
149     WKPageSetPageUIClient(page, &uiClient.base);
150
151     updateProxySettings();
152     resetZoom();
153 }
154
155 void WebKitBrowserWindow::updateProxySettings()
156 {
157     auto context = WKPageGetContext(WKViewGetPage(m_view.get()));
158     auto store = WKContextGetWebsiteDataStore(context);
159
160     if (!m_proxy.enable) {
161         WKWebsiteDataStoreDisableNetworkProxySettings(store);
162         return;
163     }
164
165     if (!m_proxy.custom) {
166         WKWebsiteDataStoreEnableDefaultNetworkProxySettings(store);
167         return;
168     }
169
170     auto url = createWKURL(m_proxy.url);
171     auto excludeHosts = createWKString(m_proxy.excludeHosts);
172     WKWebsiteDataStoreEnableCustomNetworkProxySettings(store, url.get(), excludeHosts.get());
173 }
174
175 HRESULT WebKitBrowserWindow::init()
176 {
177     return S_OK;
178 }
179
180 HWND WebKitBrowserWindow::hwnd()
181 {
182     return WKViewGetWindow(m_view.get());
183 }
184
185 HRESULT WebKitBrowserWindow::loadURL(const BSTR& url)
186 {
187     auto page = WKViewGetPage(m_view.get());
188     WKPageLoadURL(page, createWKURL(_bstr_t(url)).get());
189     return true;
190 }
191
192 void WebKitBrowserWindow::navigateForwardOrBackward(UINT menuID)
193 {
194     auto page = WKViewGetPage(m_view.get());
195     if (menuID == IDM_HISTORY_FORWARD)
196         WKPageGoForward(page);
197     else
198         WKPageGoBack(page);
199 }
200
201 void WebKitBrowserWindow::navigateToHistory(UINT menuID)
202 {
203     // Not implemented
204 }
205
206 void WebKitBrowserWindow::setPreference(UINT menuID, bool enable)
207 {
208     auto page = WKViewGetPage(m_view.get());
209     auto pgroup = WKPageGetPageGroup(page);
210     auto pref = WKPageGroupGetPreferences(pgroup);
211     switch (menuID) {
212     case IDM_DISABLE_IMAGES:
213         WKPreferencesSetLoadsImagesAutomatically(pref, !enable);
214         break;
215     case IDM_DISABLE_JAVASCRIPT:
216         WKPreferencesSetJavaScriptEnabled(pref, !enable);
217         break;
218     }
219 }
220
221 void WebKitBrowserWindow::print()
222 {
223     // Not implemented
224 }
225
226 void WebKitBrowserWindow::launchInspector()
227 {
228     auto page = WKViewGetPage(m_view.get());
229     auto inspector = WKPageGetInspector(page);
230     WKInspectorShow(inspector);
231 }
232
233 void WebKitBrowserWindow::openProxySettings()
234 {
235     if (askProxySettings(m_hMainWnd, m_proxy))
236         updateProxySettings();
237
238 }
239
240 void WebKitBrowserWindow::setUserAgent(_bstr_t& customUAString)
241 {
242     auto page = WKViewGetPage(m_view.get());
243     auto ua = createWKString(customUAString);
244     WKPageSetCustomUserAgent(page, ua.get());
245 }
246
247 _bstr_t WebKitBrowserWindow::userAgent()
248 {
249     auto page = WKViewGetPage(m_view.get());
250     auto ua = adoptWK(WKPageCopyUserAgent(page));
251     return createString(ua.get()).c_str();
252 }
253
254 void WebKitBrowserWindow::showLayerTree()
255 {
256     // Not implemented
257 }
258
259 void WebKitBrowserWindow::updateStatistics(HWND hDlg)
260 {
261     // Not implemented
262 }
263
264
265 void WebKitBrowserWindow::resetZoom()
266 {
267     auto page = WKViewGetPage(m_view.get());
268     WKPageSetPageZoomFactor(page, WebCore::deviceScaleFactorForWindow(hwnd()));
269 }
270
271 void WebKitBrowserWindow::zoomIn()
272 {
273     auto page = WKViewGetPage(m_view.get());
274     double s = WKPageGetPageZoomFactor(page);
275     WKPageSetPageZoomFactor(page, s * 1.25);
276 }
277
278 void WebKitBrowserWindow::zoomOut()
279 {
280     auto page = WKViewGetPage(m_view.get());
281     double s = WKPageGetPageZoomFactor(page);
282     WKPageSetPageZoomFactor(page, s * 0.8);
283 }
284
285 static WebKitBrowserWindow& toWebKitBrowserWindow(const void *clientInfo)
286 {
287     return *const_cast<WebKitBrowserWindow*>(static_cast<const WebKitBrowserWindow*>(clientInfo));
288 }
289
290 void WebKitBrowserWindow::didFinishNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef userData, const void* clientInfo)
291 {
292     WKRetainPtr<WKStringRef> title = adoptWK(WKPageCopyTitle(page));
293     std::wstring titleString = createString(title.get()) + L" [WebKit]";
294     auto& thisWindow = toWebKitBrowserWindow(clientInfo);
295     SetWindowText(thisWindow.m_hMainWnd, titleString.c_str());
296 }
297
298 void WebKitBrowserWindow::didCommitNavigation(WKPageRef page, WKNavigationRef navigation, WKTypeRef userData, const void* clientInfo)
299 {
300     auto& thisWindow = toWebKitBrowserWindow(clientInfo);
301
302     WKRetainPtr<WKURLRef> wkurl = adoptWK(WKPageCopyCommittedURL(page));
303     std::wstring urlString = createString(wkurl.get());
304     SetWindowText(thisWindow.m_urlBarWnd, urlString.c_str());
305 }
306
307 void WebKitBrowserWindow::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef challenge, const void* clientInfo)
308 {
309     auto& thisWindow = toWebKitBrowserWindow(clientInfo);
310     auto protectionSpace = WKAuthenticationChallengeGetProtectionSpace(challenge);
311     auto decisionListener = WKAuthenticationChallengeGetDecisionListener(challenge);
312     auto authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
313
314     if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
315         if (thisWindow.canTrustServerCertificate(protectionSpace)) {
316             WKRetainPtr<WKStringRef> username = createWKString("accept server trust");
317             WKRetainPtr<WKStringRef> password = createWKString("");
318             WKRetainPtr<WKCredentialRef> wkCredential = adoptWK(WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
319             WKAuthenticationDecisionListenerUseCredential(decisionListener, wkCredential.get());
320             return;
321         }
322     } else {
323         WKRetainPtr<WKStringRef> realm(WKProtectionSpaceCopyRealm(protectionSpace));
324
325         if (auto credential = askCredential(thisWindow.hwnd(), createString(realm.get()))) {
326             WKRetainPtr<WKStringRef> username = createWKString(credential->username);
327             WKRetainPtr<WKStringRef> password = createWKString(credential->password);
328             WKRetainPtr<WKCredentialRef> wkCredential = adoptWK(WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
329             WKAuthenticationDecisionListenerUseCredential(decisionListener, wkCredential.get());
330             return;
331         }
332     }
333
334     WKAuthenticationDecisionListenerUseCredential(decisionListener, nullptr);
335 }
336
337 bool WebKitBrowserWindow::canTrustServerCertificate(WKProtectionSpaceRef protectionSpace)
338 {
339     auto host = createString(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
340     auto pem = createPEMString(protectionSpace);
341
342     auto it = m_acceptedServerTrustCerts.find(host);
343     if (it != m_acceptedServerTrustCerts.end() && it->second == pem)
344         return true;
345
346     if (askServerTrustEvaluation(hwnd(), pem)) {
347         m_acceptedServerTrustCerts.emplace(host, pem);
348         return true;
349     }
350
351     return false;
352 }
353
354 WKPageRef WebKitBrowserWindow::createNewPage(WKPageRef page, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
355 {
356     auto& newWindow = MainWindow::create().leakRef();
357     auto factory = [configuration](HWND mainWnd, HWND urlBarWnd, bool, bool) -> auto {
358         return adoptRef(*new WebKitBrowserWindow(configuration, mainWnd, urlBarWnd));
359     };
360     bool ok = newWindow.init(factory, hInst);
361     if (!ok)
362         return nullptr;
363     ShowWindow(newWindow.hwnd(), SW_SHOW);
364     auto& newBrowserWindow = *static_cast<WebKitBrowserWindow*>(newWindow.browserWindow());
365     WKRetainPtr<WKPageRef> newPage = WKViewGetPage(newBrowserWindow.m_view.get());
366     return newPage.leakRef();
367 }