blob: 990ba53c562dca7a921d20f8f79e691f4fb9841d [file] [log] [blame] [edit]
/*
* Copyright (C) 2018 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"
#include "WebKitBrowserWindow.h"
#include "Common.h"
#include "Common2.h"
#include "MiniBrowserLibResource.h"
#include <WebCore/GDIUtilities.h>
#include <WebKit/WKAuthenticationChallenge.h>
#include <WebKit/WKAuthenticationDecisionListener.h>
#include <WebKit/WKCertificateInfoCurl.h>
#include <WebKit/WKContextConfigurationRef.h>
#include <WebKit/WKCredential.h>
#include <WebKit/WKDownloadClient.h>
#include <WebKit/WKDownloadRef.h>
#include <WebKit/WKFrameInfoRef.h>
#include <WebKit/WKHTTPCookieStoreRef.h>
#include <WebKit/WKInspector.h>
#include <WebKit/WKNavigationResponseRef.h>
#include <WebKit/WKPagePrivate.h>
#include <WebKit/WKPreferencesRefPrivate.h>
#include <WebKit/WKProtectionSpace.h>
#include <WebKit/WKProtectionSpaceCurl.h>
#include <WebKit/WKSecurityOriginRef.h>
#include <WebKit/WKURLResponse.h>
#include <WebKit/WKWebsiteDataStoreConfigurationRef.h>
#include <WebKit/WKWebsiteDataStoreRef.h>
#include <WebKit/WKWebsiteDataStoreRefCurl.h>
#include <filesystem>
#include <sstream>
#include <vector>
std::wstring createString(WKURLRef wkURL)
{
if (!wkURL)
return { };
WKRetainPtr<WKStringRef> url = adoptWK(WKURLCopyString(wkURL));
return createString(url.get());
}
std::string createUTF8String(const wchar_t* src, size_t srcLength)
{
int length = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, 0, 0, nullptr, nullptr);
std::vector<char> buffer(length);
size_t actualLength = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, buffer.data(), length, nullptr, nullptr);
return { buffer.data(), actualLength };
}
std::wstring createPEMString(WKProtectionSpaceRef protectionSpace)
{
auto chain = adoptWK(WKProtectionSpaceCopyCertificateChain(protectionSpace));
std::wstring pems;
for (size_t i = 0; i < WKArrayGetSize(chain.get()); i++) {
auto item = WKArrayGetItemAtIndex(chain.get(), i);
assert(WKGetTypeID(item) == WKDataGetTypeID());
auto certificate = static_cast<WKDataRef>(item);
auto size = WKDataGetSize(certificate);
auto data = WKDataGetBytes(certificate);
for (size_t i = 0; i < size; i++)
pems.push_back(data[i]);
}
return replaceString(pems, L"\n", L"\r\n");
}
WKRetainPtr<WKStringRef> createWKString(_bstr_t str)
{
auto utf8 = createUTF8String(str, str.length());
return adoptWK(WKStringCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKStringRef> createWKString(const std::wstring& str)
{
auto utf8 = createUTF8String(str.c_str(), str.length());
return adoptWK(WKStringCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKStringRef> createWKString(const wchar_t* str)
{
return createWKString(std::wstring(str));
}
WKRetainPtr<WKURLRef> createWKURL(_bstr_t str)
{
auto utf8 = createUTF8String(str, str.length());
return adoptWK(WKURLCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKURLRef> createWKURL(const std::wstring& str)
{
auto utf8 = createUTF8String(str.c_str(), str.length());
return adoptWK(WKURLCreateWithUTF8CString(utf8.data()));
}
WKRetainPtr<WKStringRef> injectedBundlePath()
{
auto module = GetModuleHandle(nullptr);
std::wstring path;
for (;;) {
path.resize(path.size() + MAX_PATH);
auto copied = GetModuleFileName(module, path.data(), path.size());
if (copied < path.size()) {
path.resize(copied);
break;
}
}
path = std::filesystem::path(path).replace_filename("MiniBrowserInjectedBundle.dll");
return createWKString(path);
}
Ref<BrowserWindow> WebKitBrowserWindow::create(BrowserWindowClient& client, HWND mainWnd, bool)
{
auto websiteDataStoreConf = adoptWK(WKWebsiteDataStoreConfigurationCreate());
auto websiteDataStore = adoptWK(WKWebsiteDataStoreCreateWithConfiguration(websiteDataStoreConf.get()));
auto contextConf = adoptWK(WKContextConfigurationCreate());
WKContextConfigurationSetInjectedBundlePath(contextConf.get(), injectedBundlePath().get());
auto context = adoptWK(WKContextCreateWithConfiguration(contextConf.get()));
auto preferences = adoptWK(WKPreferencesCreate());
WKPreferencesSetMediaCapabilitiesEnabled(preferences.get(), false);
WKPreferencesSetDeveloperExtrasEnabled(preferences.get(), true);
auto pageConf = adoptWK(WKPageConfigurationCreate());
WKPageConfigurationSetWebsiteDataStore(pageConf.get(), websiteDataStore.get());
WKPageConfigurationSetContext(pageConf.get(), context.get());
WKPageConfigurationSetPreferences(pageConf.get(), preferences.get());
return adoptRef(*new WebKitBrowserWindow(client, pageConf.get(), mainWnd));
}
WebKitBrowserWindow::WebKitBrowserWindow(BrowserWindowClient& client, WKPageConfigurationRef pageConf, HWND mainWnd)
: m_client(client)
, m_hMainWnd(mainWnd)
{
RECT rect = { };
m_view = adoptWK(WKViewCreate(rect, pageConf, mainWnd));
WKViewSetIsInWindow(m_view.get(), true);
auto page = WKViewGetPage(m_view.get());
m_isControlledByAutomation = WKPageGetIsControlledByAutomation(page);
WKPageNavigationClientV3 navigationClient = { };
navigationClient.base.version = 3;
navigationClient.base.clientInfo = this;
navigationClient.decidePolicyForNavigationResponse = decidePolicyForNavigationResponse;
navigationClient.didFailProvisionalNavigation = didFailProvisionalNavigation;
navigationClient.didReceiveAuthenticationChallenge = didReceiveAuthenticationChallenge;
navigationClient.navigationActionDidBecomeDownload = navigationActionDidBecomeDownload;
navigationClient.navigationResponseDidBecomeDownload = navigationResponseDidBecomeDownload;
navigationClient.contextMenuDidCreateDownload = contextMenuDidCreateDownload;
WKPageSetPageNavigationClient(page, &navigationClient.base);
WKPageUIClientV13 uiClient = { };
uiClient.base.version = 13;
uiClient.base.clientInfo = this;
uiClient.createNewPage = createNewPage;
uiClient.close = close;
uiClient.didNotHandleKeyEvent = didNotHandleKeyEvent;
uiClient.getWindowFrame = getWindowFrame;
uiClient.runJavaScriptAlert = runJavaScriptAlert;
uiClient.runJavaScriptConfirm = runJavaScriptConfirm;
uiClient.runJavaScriptPrompt = runJavaScriptPrompt;
WKPageSetPageUIClient(page, &uiClient.base);
WKPageStateClientV0 stateClient = { };
stateClient.base.version = 0;
stateClient.base.clientInfo = this;
stateClient.didChangeTitle = didChangeTitle;
stateClient.didChangeIsLoading = didChangeIsLoading;
stateClient.didChangeEstimatedProgress = didChangeEstimatedProgress;
stateClient.didChangeActiveURL = didChangeActiveURL;
WKPageSetPageStateClient(page, &stateClient.base);
updateProxySettings();
adjustScaleFactors();
}
void WebKitBrowserWindow::updateProxySettings()
{
auto page = WKViewGetPage(m_view.get());
auto websiteDataStore = WKPageGetWebsiteDataStore(page);
if (!m_proxy.enable) {
WKWebsiteDataStoreDisableNetworkProxySettings(websiteDataStore);
return;
}
if (!m_proxy.custom) {
WKWebsiteDataStoreEnableDefaultNetworkProxySettings(websiteDataStore);
return;
}
auto url = createWKURL(m_proxy.url);
auto excludeHosts = createWKString(m_proxy.excludeHosts);
WKWebsiteDataStoreEnableCustomNetworkProxySettings(websiteDataStore, url.get(), excludeHosts.get());
}
// FIXME: The current design of WebKit produces too many noises on fractional device scale factor.
// This rounds device scale factor for tantative workarond.
void WebKitBrowserWindow::adjustScaleFactors()
{
WKPageRef page = WKViewGetPage(m_view.get());
WKPageSetCustomBackingScaleFactor(page, std::round(WebCore::deviceScaleFactorForWindow(hwnd())));
}
HRESULT WebKitBrowserWindow::init()
{
return S_OK;
}
void WebKitBrowserWindow::resetFeatureMenu(FeatureType featureType, HMENU menu, bool resetsSettingsToDefaults)
{
auto page = WKViewGetPage(m_view.get());
auto configuration = adoptWK(WKPageCopyPageConfiguration(page));
auto pref = WKPageConfigurationGetPreferences(configuration.get());
switch (featureType) {
case FeatureType::Experimental: {
auto features = adoptWK(WKPreferencesCopyExperimentalFeatures(pref));
auto size = WKArrayGetSize(features.get());
for (size_t i = 0; i < size; i++) {
auto item = WKArrayGetItemAtIndex(features.get(), i);
assert(WKGetTypeID(item) == WKFeatureGetTypeID());
auto feature = static_cast<WKFeatureRef>(item);
auto name = createString(adoptWK(WKFeatureCopyName(feature)).get());
auto key = adoptWK(WKFeatureCopyKey(feature));
bool defaultValue = WKFeatureDefaultValue(feature);
if (resetsSettingsToDefaults) {
auto flag = MF_BYCOMMAND | (defaultValue ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(menu, IDM_EXPERIMENTAL_FEATURES_BEGIN + i, flag);
WKPreferencesSetExperimentalFeatureForKey(pref, defaultValue, key.get());
} else {
auto flag = MF_STRING | (defaultValue ? MF_CHECKED : MF_UNCHECKED);
AppendMenu(menu, flag, IDM_EXPERIMENTAL_FEATURES_BEGIN + i, name.c_str());
m_experimentalFeatureKeys.push_back(std::move(key));
}
}
break;
}
case FeatureType::InternalDebug: {
auto features = adoptWK(WKPreferencesCopyInternalDebugFeatures(pref));
auto size = WKArrayGetSize(features.get());
for (size_t i = 0; i < size; i++) {
auto item = WKArrayGetItemAtIndex(features.get(), i);
assert(WKGetTypeID(item) == WKFeatureGetTypeID());
auto feature = static_cast<WKFeatureRef>(item);
auto name = createString(adoptWK(WKFeatureCopyName(feature)).get());
auto key = adoptWK(WKFeatureCopyKey(feature));
bool defaultValue = WKFeatureDefaultValue(feature);
if (resetsSettingsToDefaults) {
auto flag = MF_BYCOMMAND | (defaultValue ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(menu, IDM_INTERNAL_DEBUG_FEATURES_BEGIN + i, flag);
WKPreferencesSetInternalDebugFeatureForKey(pref, defaultValue, key.get());
} else {
auto flag = MF_STRING | (defaultValue ? MF_CHECKED : MF_UNCHECKED);
AppendMenu(menu, flag, IDM_INTERNAL_DEBUG_FEATURES_BEGIN + i, name.c_str());
m_internalDebugFeatureKeys.push_back(std::move(key));
}
}
break;
}
}
}
HWND WebKitBrowserWindow::hwnd()
{
return WKViewGetWindow(m_view.get());
}
HRESULT WebKitBrowserWindow::loadURL(const BSTR& url)
{
auto page = WKViewGetPage(m_view.get());
WKPageLoadURL(page, createWKURL(_bstr_t(url)).get());
return true;
}
void WebKitBrowserWindow::reload()
{
auto page = WKViewGetPage(m_view.get());
WKPageReload(page);
}
void WebKitBrowserWindow::navigateForwardOrBackward(bool forward)
{
auto page = WKViewGetPage(m_view.get());
if (forward)
WKPageGoForward(page);
else
WKPageGoBack(page);
}
void WebKitBrowserWindow::navigateToHistory(UINT)
{
// Not implemented
}
void WebKitBrowserWindow::setPreference(UINT menuID, bool enable)
{
auto page = WKViewGetPage(m_view.get());
auto configuration = adoptWK(WKPageCopyPageConfiguration(page));
auto pref = WKPageConfigurationGetPreferences(configuration.get());
if (IDM_EXPERIMENTAL_FEATURES_BEGIN <= menuID && menuID <= IDM_EXPERIMENTAL_FEATURES_END) {
int index = menuID - IDM_EXPERIMENTAL_FEATURES_BEGIN;
WKPreferencesSetExperimentalFeatureForKey(pref, enable, m_experimentalFeatureKeys[index].get());
return;
}
if (IDM_INTERNAL_DEBUG_FEATURES_BEGIN <= menuID && menuID <= IDM_INTERNAL_DEBUG_FEATURES_END) {
int index = menuID - IDM_INTERNAL_DEBUG_FEATURES_BEGIN;
WKPreferencesSetInternalDebugFeatureForKey(pref, enable, m_internalDebugFeatureKeys[index].get());
return;
}
switch (menuID) {
case IDM_ACC_COMPOSITING:
WKPreferencesSetAcceleratedCompositingEnabled(pref, enable);
break;
case IDM_COMPOSITING_BORDERS:
WKPreferencesSetCompositingBordersVisible(pref, enable);
WKPreferencesSetCompositingRepaintCountersVisible(pref, enable);
break;
case IDM_DEBUG_INFO_LAYER:
WKPreferencesSetTiledScrollingIndicatorVisible(pref, enable);
break;
case IDM_DISABLE_IMAGES:
WKPreferencesSetLoadsImagesAutomatically(pref, !enable);
break;
case IDM_DISABLE_JAVASCRIPT:
WKPreferencesSetJavaScriptEnabled(pref, !enable);
break;
}
}
void WebKitBrowserWindow::print()
{
// Not implemented
}
void WebKitBrowserWindow::launchInspector()
{
auto page = WKViewGetPage(m_view.get());
auto inspector = WKPageGetInspector(page);
WKInspectorShow(inspector);
}
void WebKitBrowserWindow::openProxySettings()
{
if (askProxySettings(m_hMainWnd, m_proxy))
updateProxySettings();
}
void WebKitBrowserWindow::setUserAgent(_bstr_t& customUAString)
{
auto page = WKViewGetPage(m_view.get());
auto ua = createWKString(customUAString);
WKPageSetCustomUserAgent(page, ua.get());
}
_bstr_t WebKitBrowserWindow::userAgent()
{
auto page = WKViewGetPage(m_view.get());
auto ua = adoptWK(WKPageCopyUserAgent(page));
return createString(ua.get()).c_str();
}
void WebKitBrowserWindow::showLayerTree()
{
auto page = WKViewGetPage(m_view.get());
auto name = createWKString("DumpLayerTree");
WKPagePostMessageToInjectedBundle(page, name.get(), nullptr);
}
void WebKitBrowserWindow::updateStatistics(HWND)
{
// Not implemented
}
void WebKitBrowserWindow::resetZoom()
{
auto page = WKViewGetPage(m_view.get());
WKPageSetPageZoomFactor(page, 1);
}
void WebKitBrowserWindow::zoomIn()
{
auto page = WKViewGetPage(m_view.get());
double s = WKPageGetPageZoomFactor(page);
WKPageSetPageZoomFactor(page, s * 1.25);
}
void WebKitBrowserWindow::zoomOut()
{
auto page = WKViewGetPage(m_view.get());
double s = WKPageGetPageZoomFactor(page);
WKPageSetPageZoomFactor(page, s * 0.8);
}
static void deleteAllCookiesCallback(void*)
{
}
void WebKitBrowserWindow::clearCookies()
{
auto page = WKViewGetPage(m_view.get());
auto websiteDataStore = WKPageGetWebsiteDataStore(page);
WKHTTPCookieStoreRef cookieStore = WKWebsiteDataStoreGetHTTPCookieStore(websiteDataStore);
if (cookieStore)
WKHTTPCookieStoreDeleteAllCookies(cookieStore, this, deleteAllCookiesCallback);
}
static void removeAllFetchCachesCallback(void*)
{
}
static void removeNetworkCacheCallback(void*)
{
}
static void removeMemoryCachesCallback(void*)
{
}
static void removeAllServiceWorkerRegistrationsCallback(void*)
{
}
static void removeAllIndexedDatabasesCallback(void*)
{
}
static void removeLocalStorageCallback(void*)
{
}
void WebKitBrowserWindow::clearWebsiteData()
{
auto page = WKViewGetPage(m_view.get());
auto websiteDataStore = WKPageGetWebsiteDataStore(page);
WKWebsiteDataStoreRemoveAllFetchCaches(websiteDataStore, this, removeAllFetchCachesCallback);
WKWebsiteDataStoreRemoveNetworkCache(websiteDataStore, this, removeNetworkCacheCallback);
WKWebsiteDataStoreRemoveMemoryCaches(websiteDataStore, this, removeMemoryCachesCallback);
WKWebsiteDataStoreRemoveAllServiceWorkerRegistrations(websiteDataStore, this, removeAllServiceWorkerRegistrationsCallback);
WKWebsiteDataStoreRemoveAllIndexedDatabases(websiteDataStore, this, removeAllIndexedDatabasesCallback);
WKWebsiteDataStoreRemoveLocalStorage(websiteDataStore, this, removeLocalStorageCallback);
}
static WebKitBrowserWindow& toWebKitBrowserWindow(const void *clientInfo)
{
return *const_cast<WebKitBrowserWindow*>(static_cast<const WebKitBrowserWindow*>(clientInfo));
}
void WebKitBrowserWindow::didChangeTitle(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto page = WKViewGetPage(thisWindow.m_view.get());
WKRetainPtr<WKStringRef> title = adoptWK(WKPageCopyTitle(page));
std::wstring titleString = createString(title.get()) + L" [WebKit]";
SetWindowText(thisWindow.m_hMainWnd, titleString.c_str());
}
void WebKitBrowserWindow::didChangeIsLoading(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
thisWindow.m_client.progressFinished();
}
void WebKitBrowserWindow::didChangeEstimatedProgress(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto page = WKViewGetPage(thisWindow.m_view.get());
thisWindow.m_client.progressChanged(WKPageGetEstimatedProgress(page));
}
void WebKitBrowserWindow::didChangeActiveURL(const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto page = WKViewGetPage(thisWindow.m_view.get());
WKRetainPtr<WKURLRef> url = adoptWK(WKPageCopyActiveURL(page));
thisWindow.m_client.activeURLChanged(createString(url.get()));
}
void WebKitBrowserWindow::decidePolicyForNavigationResponse(WKPageRef, WKNavigationResponseRef navigationResponse, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto response = adoptWK(WKNavigationResponseCopyResponse(navigationResponse));
auto code = WKURLResponseHTTPStatusCode(response.get());
auto expectedContentLength = WKURLResponseGetExpectedContentLength(response.get());
if (code > 300 && !expectedContentLength) {
std::wstringstream text;
text << L"Error Code: " << code << std::endl;
text << L"MIME type: " << createString(adoptWK(WKURLResponseCopyMIMEType(response.get())).get()) << std::endl;
text << L"URL: " << createString(adoptWK(WKURLResponseCopyURL(response.get())).get());
MessageBox(thisWindow.m_hMainWnd, text.str().c_str(), L"No Content", MB_OK | MB_ICONWARNING);
}
auto isMainFrame = WKFrameInfoGetIsMainFrame(adoptWK(WKNavigationResponseCopyFrameInfo(navigationResponse)).get());
if (WKNavigationResponseCanShowMIMEType(navigationResponse) || !isMainFrame)
WKFramePolicyListenerUse(listener);
else {
std::wstringstream text;
text << L"Do you want to save this file?" << std::endl;
text << std::endl;
text << L"MIME type: " << createString(adoptWK(WKURLResponseCopyMIMEType(response.get())).get()) << std::endl;
text << L"URL: " << createString(adoptWK(WKURLResponseCopyURL(response.get())).get());
if (MessageBox(thisWindow.hwnd(), text.str().c_str(), L"Unsupported MIME type", MB_OKCANCEL | MB_ICONWARNING) == IDOK)
WKFramePolicyListenerDownload(listener);
else
WKFramePolicyListenerIgnore(listener);
}
}
void WebKitBrowserWindow::didFailProvisionalNavigation(WKPageRef, WKNavigationRef, WKErrorRef error, WKTypeRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstringstream text;
text << createString(adoptWK(WKErrorCopyLocalizedDescription(error)).get()) << std::endl;
text << L"Error Code: " << WKErrorGetErrorCode(error) << std::endl;
text << L"Domain: " << createString(adoptWK(WKErrorCopyDomain(error)).get()) << std::endl;
text << L"Failing URL: " << createString(adoptWK(WKErrorCopyFailingURL(error)).get());
MessageBox(thisWindow.m_hMainWnd, text.str().c_str(), L"Provisional Navigation Failure", MB_OK | MB_ICONWARNING);
}
std::wstring toAuthText(WKProtectionSpaceRef protectionSpace)
{
auto scheme = [&] {
switch (WKProtectionSpaceGetAuthenticationScheme(protectionSpace)) {
case kWKProtectionSpaceAuthenticationSchemeDefault:
return L"Default";
case kWKProtectionSpaceAuthenticationSchemeHTTPBasic:
return L"HTTPBasic";
case kWKProtectionSpaceAuthenticationSchemeHTTPDigest:
return L"HTTPDigest";
case kWKProtectionSpaceAuthenticationSchemeHTMLForm:
return L"HTMLForm";
case kWKProtectionSpaceAuthenticationSchemeNTLM:
return L"NTLM";
case kWKProtectionSpaceAuthenticationSchemeNegotiate:
return L"Negotiate";
case kWKProtectionSpaceAuthenticationSchemeClientCertificateRequested:
return L"ClientCertificateRequested";
case kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
return L"ServerTrustEvaluationRequested";
case kWKProtectionSpaceAuthenticationSchemeOAuth:
return L"OAuth";
case kWKProtectionSpaceAuthenticationSchemeUnknown:
return L"Unknown";
}
return L"Invalid Value";
}();
auto serverType = [&] {
switch (WKProtectionSpaceGetServerType(protectionSpace)) {
case kWKProtectionSpaceServerTypeHTTP:
return L"ServerTypeHTTP";
case kWKProtectionSpaceServerTypeHTTPS:
return L"ServerTypeHTTPS";
case kWKProtectionSpaceServerTypeFTP:
return L"ServerTypeFTP";
case kWKProtectionSpaceServerTypeFTPS:
return L"ServerTypeFTPS";
case kWKProtectionSpaceProxyTypeHTTP:
return L"ProxyTypeHTTP";
case kWKProtectionSpaceProxyTypeHTTPS:
return L"ProxyTypeHTTPS";
case kWKProtectionSpaceProxyTypeFTP:
return L"ProxyTypeFTP";
case kWKProtectionSpaceProxyTypeSOCKS:
return L"ProxyTypeSOCKS";
}
return L"Invalid Value";
}();
auto host = createString(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
auto realm = createString(adoptWK(WKProtectionSpaceCopyRealm(protectionSpace)).get());
auto isProxy = WKProtectionSpaceGetIsProxy(protectionSpace);
std::wstringstream text;
text << L"Scheme: " << scheme << L"\r\n";
text << L"Host: " << host << L"\r\n";
text << L"Port: " << WKProtectionSpaceGetPort(protectionSpace) << L"\r\n";
text << L"Server Type: " << serverType << L"\r\n";
text << L"isProxy: " << isProxy << L"\r\n";
text << L"Realm: " << realm << L"\r\n";
return text.str();
}
void WebKitBrowserWindow::didReceiveAuthenticationChallenge(WKPageRef, WKAuthenticationChallengeRef challenge, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto protectionSpace = WKAuthenticationChallengeGetProtectionSpace(challenge);
auto decisionListener = WKAuthenticationChallengeGetDecisionListener(challenge);
auto authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
if (thisWindow.m_isControlledByAutomation) {
WKRetainPtr<WKStringRef> username = createWKString("accept server trust");
WKRetainPtr<WKStringRef> password = createWKString("");
WKRetainPtr<WKCredentialRef> wkCredential = adoptWK(WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
WKAuthenticationDecisionListenerUseCredential(decisionListener, wkCredential.get());
return;
}
if (authenticationScheme == kWKProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested) {
if (thisWindow.canTrustServerCertificate(protectionSpace)) {
WKRetainPtr<WKStringRef> username = createWKString("accept server trust");
WKRetainPtr<WKStringRef> password = createWKString("");
WKRetainPtr<WKCredentialRef> wkCredential = adoptWK(WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
WKAuthenticationDecisionListenerUseCredential(decisionListener, wkCredential.get());
return;
}
} else {
if (auto credential = askCredential(thisWindow.hwnd(), toAuthText(protectionSpace))) {
WKRetainPtr<WKStringRef> username = createWKString(credential->username);
WKRetainPtr<WKStringRef> password = createWKString(credential->password);
WKRetainPtr<WKCredentialRef> wkCredential = adoptWK(WKCredentialCreate(username.get(), password.get(), kWKCredentialPersistenceForSession));
WKAuthenticationDecisionListenerUseCredential(decisionListener, wkCredential.get());
return;
}
}
WKAuthenticationDecisionListenerUseCredential(decisionListener, nullptr);
}
bool WebKitBrowserWindow::canTrustServerCertificate(WKProtectionSpaceRef protectionSpace)
{
auto host = createString(adoptWK(WKProtectionSpaceCopyHost(protectionSpace)).get());
auto verificationError = WKProtectionSpaceGetCertificateVerificationError(protectionSpace);
auto description = createString(adoptWK(WKProtectionSpaceCopyCertificateVerificationErrorDescription(protectionSpace)).get());
auto pem = createPEMString(protectionSpace);
auto it = m_acceptedServerTrustCerts.find(host);
if (it != m_acceptedServerTrustCerts.end() && it->second == pem)
return true;
std::wstring textString = L"[HOST] " + host + L"\r\n";
textString.append(L"[ERROR] " + std::to_wstring(verificationError) + L"\r\n");
textString.append(L"[DESCRIPTION] " + description + L"\r\n");
textString.append(pem);
if (askServerTrustEvaluation(hwnd(), textString)) {
m_acceptedServerTrustCerts.emplace(host, pem);
return true;
}
return false;
}
void WebKitBrowserWindow::navigationActionDidBecomeDownload(WKPageRef, WKNavigationActionRef, WKDownloadRef download, const void* clientInfo)
{
setDownloadClient(download, clientInfo);
}
void WebKitBrowserWindow::navigationResponseDidBecomeDownload(WKPageRef, WKNavigationResponseRef, WKDownloadRef download, const void* clientInfo)
{
setDownloadClient(download, clientInfo);
}
void WebKitBrowserWindow::contextMenuDidCreateDownload(WKPageRef, WKDownloadRef download, const void* clientInfo)
{
setDownloadClient(download, clientInfo);
}
void WebKitBrowserWindow::setDownloadClient(WKDownloadRef download, const void* clientInfo)
{
WKDownloadClientV0 client = { };
client.base = { 0, clientInfo };
client.decideDestinationWithResponse = downloadDecideDestinationWithResponse;
client.didFinish = downloadDidFinish;
client.didFailWithError = downloadDidFailWithError;
WKDownloadSetClient(download, &client.base);
}
WKStringRef WebKitBrowserWindow::downloadDecideDestinationWithResponse(WKDownloadRef, WKURLResponseRef response, WKStringRef suggestedFilename, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto filename = createString(suggestedFilename);
if (filename.empty()) {
auto urlRef = adoptWK(WKURLResponseCopyURL(response));
auto hostRef = adoptWK(WKURLCopyHostName(urlRef.get()));
filename = createString(hostRef.get());
}
std::wstring folderPath;
if (!getKnownFolderPath(FOLDERID_Downloads, folderPath)) {
MessageBox(thisWindow.hwnd(), L"Could not get Downloads folder path.", L"Download Failure", MB_OK | MB_ICONWARNING);
return nullptr;
}
return createWKString(folderPath + L"\\" + filename).leakRef();
}
void WebKitBrowserWindow::downloadDidFinish(WKDownloadRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
MessageBox(thisWindow.hwnd(), L"File has been downloaded successfully.", L"Download", MB_OK);
}
void WebKitBrowserWindow::downloadDidFailWithError(WKDownloadRef, WKErrorRef error, WKDataRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstringstream text;
text << createString(adoptWK(WKErrorCopyLocalizedDescription(error)).get()) << std::endl;
text << L"Error Code: " << WKErrorGetErrorCode(error) << std::endl;
text << L"Domain: " << createString(adoptWK(WKErrorCopyDomain(error)).get()) << std::endl;
text << L"Failing URL: " << createString(adoptWK(WKErrorCopyFailingURL(error)).get());
MessageBox(thisWindow.hwnd(), text.str().c_str(), L"Download Failure", MB_OK | MB_ICONWARNING);
}
void WebKitBrowserWindow::close(WKPageRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
PostMessage(thisWindow.m_hMainWnd, WM_CLOSE, 0, 0);
}
WKPageRef WebKitBrowserWindow::createNewPage(WKPageRef, WKPageConfigurationRef pageConf, WKNavigationActionRef, WKWindowFeaturesRef, const void*)
{
auto& newWindow = MainWindow::create().leakRef();
auto factory = [pageConf](BrowserWindowClient& client, HWND mainWnd, bool) -> auto {
return adoptRef(*new WebKitBrowserWindow(client, pageConf, mainWnd));
};
bool ok = newWindow.init(factory, hInst);
if (!ok)
return nullptr;
ShowWindow(newWindow.hwnd(), SW_SHOW);
auto& newBrowserWindow = *static_cast<WebKitBrowserWindow*>(newWindow.browserWindow());
WKRetainPtr<WKPageRef> newPage = WKViewGetPage(newBrowserWindow.m_view.get());
return newPage.leakRef();
}
void WebKitBrowserWindow::didNotHandleKeyEvent(WKPageRef, WKNativeEventPtr event, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
PostMessage(thisWindow.m_hMainWnd, event->message, event->wParam, event->lParam);
}
WKRect WebKitBrowserWindow::getWindowFrame(WKPageRef, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
RECT rect;
GetWindowRect(thisWindow.hwnd(), &rect);
return WKRectMake(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}
void WebKitBrowserWindow::runJavaScriptAlert(WKPageRef, WKStringRef alertText, WKFrameRef, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstring title = L"Alert: ";
title += createString(adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get());
auto text = createString(alertText);
MessageBox(thisWindow.m_hMainWnd, text.c_str(), title.c_str(), MB_OK);
WKPageRunJavaScriptAlertResultListenerCall(listener);
}
void WebKitBrowserWindow::runJavaScriptConfirm(WKPageRef, WKStringRef message, WKFrameRef, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstring title = L"Confirm: ";
title += createString(adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get());
auto text = createString(message);
bool result = MessageBox(thisWindow.m_hMainWnd, text.c_str(), title.c_str(), MB_OKCANCEL) == IDOK;
WKPageRunJavaScriptConfirmResultListenerCall(listener, result);
}
void WebKitBrowserWindow::runJavaScriptPrompt(WKPageRef, WKStringRef message, WKStringRef defaultValue, WKFrameRef, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
std::wstring title = L"Prompt: ";
title += createString(adoptWK(WKSecurityOriginCopyToString(securityOrigin)).get());
auto text = createString(message);
text += L"\nDefault Value: " + createString(defaultValue);
MessageBox(thisWindow.m_hMainWnd, text.c_str(), title.c_str(), MB_OK);
WKPageRunJavaScriptPromptResultListenerCall(listener, defaultValue);
}