1
1
mirror of https://github.com/microsoft/playwright.git synced 2024-12-23 19:26:16 +03:00
playwright/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.cpp
Andrey Lushnikov a3f34fb4b7
chore: export juggler as a standalone folder for browser build ()
This leaves our firefox diff to gecko instrumentation changes only.

Drive-by: rename webkit "src" folder into "embedder".
2020-06-02 16:51:13 -07:00

380 lines
14 KiB
C++

/*
* 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 "Common.h"
#include "MainWindow.h"
#include "PlaywrightLibResource.h"
#include "WebKitBrowserWindow.h"
#include <WebCore/GDIUtilities.h>
#include <WebKit/WKAuthenticationChallenge.h>
#include <WebKit/WKAuthenticationDecisionListener.h>
#include <WebKit/WKCertificateInfoCurl.h>
#include <WebKit/WKCredential.h>
#include <WebKit/WKFramePolicyListener.h>
#include <WebKit/WKInspector.h>
#include <WebKit/WKProtectionSpace.h>
#include <WebKit/WKProtectionSpaceCurl.h>
#include <WebKit/WKWebsiteDataStoreRef.h>
#include <WebKit/WKWebsiteDataStoreRefCurl.h>
#include <vector>
std::wstring createPEMString(WKCertificateInfoRef certificateInfo)
{
auto chainSize = WKCertificateInfoGetCertificateChainSize(certificateInfo);
std::wstring pems;
for (auto i = 0; i < chainSize; i++) {
auto certificate = adoptWK(WKCertificateInfoCopyCertificateAtIndex(certificateInfo, i));
auto size = WKDataGetSize(certificate.get());
auto data = WKDataGetBytes(certificate.get());
for (size_t i = 0; i < size; i++)
pems.push_back(data[i]);
}
return replaceString(pems, L"\n", L"\r\n");
}
WebKitBrowserWindow::WebKitBrowserWindow(BrowserWindowClient& client, HWND mainWnd, WKPageConfigurationRef conf)
: m_client(client)
, m_hMainWnd(mainWnd)
{
RECT rect = { };
m_view = adoptWK(WKViewCreate(rect, conf, mainWnd));
WKViewSetIsInWindow(m_view.get(), true);
auto page = WKViewGetPage(m_view.get());
WKPageNavigationClientV0 navigationClient = { };
navigationClient.base.version = 0;
navigationClient.base.clientInfo = this;
navigationClient.didReceiveAuthenticationChallenge = didReceiveAuthenticationChallenge;
WKPageSetPageNavigationClient(page, &navigationClient.base);
WKPageUIClientV14 uiClient = { };
uiClient.base.version = 14;
uiClient.base.clientInfo = this;
uiClient.createNewPage = createNewPage;
uiClient.didNotHandleKeyEvent = didNotHandleKeyEvent;
uiClient.close = closeWindow;
uiClient.runJavaScriptAlert = runJavaScriptAlert;
uiClient.runJavaScriptConfirm = runJavaScriptConfirm;
uiClient.runJavaScriptPrompt = runJavaScriptPrompt;
uiClient.runBeforeUnloadConfirmPanel = runBeforeUnloadConfirmPanel;
uiClient.handleJavaScriptDialog = handleJavaScriptDialog;
WKPageSetPageUIClient(page, &uiClient.base);
WKPageStateClientV0 stateClient = { };
stateClient.base.version = 0;
stateClient.base.clientInfo = this;
stateClient.didChangeTitle = didChangeTitle;
stateClient.didChangeIsLoading = didChangeIsLoading;
stateClient.didChangeActiveURL = didChangeActiveURL;
WKPageSetPageStateClient(page, &stateClient.base);
WKPagePolicyClientV1 policyClient = { };
policyClient.base.version = 1;
policyClient.base.clientInfo = this;
policyClient.decidePolicyForResponse_deprecatedForUseWithV0 = decidePolicyForResponse;
WKPageSetPagePolicyClient(page, &policyClient.base);
resetZoom();
}
WebKitBrowserWindow::~WebKitBrowserWindow()
{
if (m_alertDialog) {
WKRelease(m_alertDialog);
m_alertDialog = NULL;
}
if (m_confirmDialog) {
WKRelease(m_confirmDialog);
m_confirmDialog = NULL;
}
if (m_promptDialog) {
WKRelease(m_promptDialog);
m_promptDialog = NULL;
}
if (m_beforeUnloadDialog) {
WKRelease(m_beforeUnloadDialog);
m_beforeUnloadDialog = NULL;
}
}
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::launchInspector()
{
auto page = WKViewGetPage(m_view.get());
auto inspector = WKPageGetInspector(page);
WKInspectorShow(inspector);
}
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::resetZoom()
{
auto page = WKViewGetPage(m_view.get());
WKPageSetPageZoomFactor(page, WebCore::deviceScaleFactorForWindow(hwnd()));
}
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 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);
}
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::didReceiveAuthenticationChallenge(WKPageRef page, WKAuthenticationChallengeRef challenge, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
auto protectionSpace = WKAuthenticationChallengeGetProtectionSpace(challenge);
auto decisionListener = WKAuthenticationChallengeGetDecisionListener(challenge);
auto authenticationScheme = WKProtectionSpaceGetAuthenticationScheme(protectionSpace);
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 {
WKRetainPtr<WKStringRef> realm(WKProtectionSpaceCopyRealm(protectionSpace));
if (auto credential = askCredential(thisWindow.hwnd(), createString(realm.get()))) {
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 certificateInfo = adoptWK(WKProtectionSpaceCopyCertificateInfo(protectionSpace));
auto verificationError = WKCertificateInfoGetVerificationError(certificateInfo.get());
auto description = createString(adoptWK(WKCertificateInfoCopyVerificationErrorDescription(certificateInfo.get())).get());
auto pem = createPEMString(certificateInfo.get());
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::closeWindow(WKPageRef page, const void* clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
PostMessage(thisWindow.m_hMainWnd, WM_CLOSE, 0, 0);
}
void WebKitBrowserWindow::runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void *clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
WKRetain(listener);
thisWindow.m_alertDialog = listener;
}
void WebKitBrowserWindow::runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void *clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
WKRetain(listener);
thisWindow.m_confirmDialog = listener;
}
void WebKitBrowserWindow::runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void *clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
WKRetain(listener);
thisWindow.m_promptDialog = listener;
}
void WebKitBrowserWindow::runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, WKPageRunBeforeUnloadConfirmPanelResultListenerRef listener, const void *clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
WKRetain(listener);
thisWindow.m_beforeUnloadDialog = listener;
}
void WebKitBrowserWindow::handleJavaScriptDialog(WKPageRef page, bool accept, WKStringRef value, const void *clientInfo)
{
auto& thisWindow = toWebKitBrowserWindow(clientInfo);
if (thisWindow.m_alertDialog) {
WKPageRunJavaScriptAlertResultListenerCall(thisWindow.m_alertDialog);
WKRelease(thisWindow.m_alertDialog);
thisWindow.m_alertDialog = NULL;
}
if (thisWindow.m_confirmDialog) {
WKPageRunJavaScriptConfirmResultListenerCall(thisWindow.m_confirmDialog, accept);
WKRelease(thisWindow.m_confirmDialog);
thisWindow.m_confirmDialog = NULL;
}
if (thisWindow.m_promptDialog) {
WKPageRunJavaScriptPromptResultListenerCall(thisWindow.m_promptDialog, accept ? value : NULL);
WKRelease(thisWindow.m_promptDialog);
thisWindow.m_promptDialog = NULL;
}
if (thisWindow.m_beforeUnloadDialog) {
WKPageRunBeforeUnloadConfirmPanelResultListenerCall(thisWindow.m_beforeUnloadDialog, accept);
WKRelease(thisWindow.m_beforeUnloadDialog);
thisWindow.m_beforeUnloadDialog = NULL;
}
}
WKPageRef WebKitBrowserWindow::createPageCallback(WKPageConfigurationRef configuration)
{
// This comes from the Playwright agent, configuration is a pool+data pair.
return WebKitBrowserWindow::createViewCallback(configuration, true);
}
WKPageRef WebKitBrowserWindow::createViewCallback(WKPageConfigurationRef configuration, bool navigate)
{
auto* newWindow = new MainWindow();
bool ok = newWindow->init(hInst, configuration);
if (navigate)
newWindow->browserWindow()->loadURL(_bstr_t("about:blank").GetBSTR());
auto* newBrowserWindow = newWindow->browserWindow();
return WKViewGetPage(newBrowserWindow->m_view.get());
}
WKPageRef WebKitBrowserWindow::createNewPage(WKPageRef, WKPageConfigurationRef configuration, WKNavigationActionRef, WKWindowFeaturesRef, const void*)
{
// This comes from the client for popups, configuration is inherited from main page.
// Retain popups as per API contract.
WKRetainPtr<WKPageRef> newPage = createViewCallback(configuration, false);
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);
}
void WebKitBrowserWindow::decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
if (WKURLResponseIsAttachment(response))
WKFramePolicyListenerDownload(listener);
else
WKFramePolicyListenerUse(listener);
}