blob: 10428cb338d7640c26ecfa9f2dfd2a03d9a1609c [file] [log] [blame] [edit]
/*
* Copyright (C) 2020-2025 Apple Inc. All rights reserved.
*
* 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. AND ITS CONTRIBUTORS ``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 ITS 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.
*/
#import "config.h"
#if PLATFORM(MAC) || PLATFORM(IOS_FAMILY)
#import "HTTPServer.h"
#import "PlatformUtilities.h"
#import "Test.h"
#import "TestNavigationDelegate.h"
#import "TestURLSchemeHandler.h"
#import "TestWKWebView.h"
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import <WebKit/_WKArchiveConfiguration.h>
#import <WebKit/_WKArchiveExclusionRule.h>
#if PLATFORM(IOS_FAMILY)
#import <MobileCoreServices/MobileCoreServices.h>
#endif
namespace TestWebKitAPI {
static const char* mainBytes = R"TESTRESOURCE(
<head>
<script src="webarchivetest://host/script.js"></script>
</head>
)TESTRESOURCE";
static const char* scriptBytes = R"TESTRESOURCE(
window.webkit.messageHandlers.testHandler.postMessage("done");
)TESTRESOURCE";
TEST(WebArchive, CreateCustomScheme)
{
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
const char* bytes = nullptr;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"])
bytes = mainBytes;
else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/script.js"])
bytes = scriptBytes;
else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:0 textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:[NSData dataWithBytes:bytes length:strlen(bytes)]];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool done = false;
[webView createWebArchiveDataWithCompletionHandler:^(NSData *result, NSError *error) {
EXPECT_NULL(error);
NSDictionary *expectedDictionary = @{
@"WebMainResource" : @{
@"WebResourceData" : [@"<html><head></head><body></body></html>" dataUsingEncoding:NSUTF8StringEncoding],
@"WebResourceFrameName" : @"",
@"WebResourceMIMEType" : @"text/html",
@"WebResourceTextEncodingName" : @"UTF-8",
@"WebResourceURL" : @""
}
};
NSDictionary* actualDictionary = [NSPropertyListSerialization propertyListWithData:result options:0 format:nullptr error:nullptr];
EXPECT_TRUE([expectedDictionary isEqualToDictionary:actualDictionary]);
done = true;
}];
Util::run(&done);
done = false;
[webView performAfterReceivingMessage:@"done" action:[&] { done = true; }];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&done);
done = false;
static RetainPtr<NSData> archiveData;
[webView createWebArchiveDataWithCompletionHandler:^(NSData *result, NSError *error) {
EXPECT_NULL(error);
EXPECT_TRUE(!!result);
archiveData = result;
done = true;
}];
Util::run(&done);
done = false;
[webView performAfterReceivingMessage:@"done" action:[&] { done = true; }];
[webView loadData:archiveData.get() MIMEType:UTTypeArchive.identifier characterEncodingName:@"utf-8" baseURL:[NSURL URLWithString:@"about:blank"]];
Util::run(&done);
done = false;
}
static RetainPtr<NSData> webArchiveAccessingCookies()
{
HTTPServer server({ { "/"_s, { "<script>document.cookie</script>"_s } } }, HTTPServer::Protocol::HttpsProxy);
auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:server.httpsProxyConfiguration()]);
auto navigationDelegate = adoptNS([TestNavigationDelegate new]);
[navigationDelegate allowAnyTLSCertificate];
webView.get().navigationDelegate = navigationDelegate.get();
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://webkit.org/"]]];
[navigationDelegate waitForDidFinishNavigation];
__block RetainPtr<NSData> webArchive;
[webView createWebArchiveDataWithCompletionHandler:^(NSData *result, NSError *error) {
webArchive = result;
}];
while (!webArchive)
Util::spinRunLoop();
return webArchive;
}
TEST(WebArchive, CookieAccessAfterLoadRequest)
{
auto webArchive = webArchiveAccessingCookies();
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"CookieAccessTest.webarchive"];
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
BOOL success = [webArchive writeToFile:path atomically:YES];
EXPECT_TRUE(success);
auto webView = adoptNS([WKWebView new]);
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path isDirectory:NO]]];
[webView _test_waitForDidFinishNavigation];
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}
TEST(WebArchive, CookieAccessAfterLoadData)
{
auto webArchive = webArchiveAccessingCookies();
auto webView = adoptNS([WKWebView new]);
[webView loadData:webArchive.get() MIMEType:@"application/x-webarchive" characterEncodingName:@"utf-8" baseURL:[NSURL URLWithString:@"http://example.com/"]];
[webView _test_waitForDidFinishNavigation];
}
TEST(WebArchive, ApplicationXWebarchiveMIMETypeDoesNotLoadHTML)
{
HTTPServer server({ { "/"_s, { { { "Content-Type"_s, "application/x-webarchive"_s } }, "Not web archive content, should not load"_s } } });
auto webView = adoptNS([WKWebView new]);
[webView loadRequest:server.request()];
[webView _test_waitForDidFailProvisionalNavigation];
}
TEST(WebArchive, SaveResourcesBasic)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [@"<head><script src=\"script.js\"></script></head><img src=\"image.png\" onload=\"onImageLoad()\"><script>function onImageLoad() { notifyTestRunner(); }</script>" dataUsingEncoding:NSUTF8StringEncoding];
NSData *scriptData = [@"function notifyTestRunner() { window.webkit.messageHandlers.testHandler.postMessage(\"done\"); }" dataUsingEncoding:NSUTF8StringEncoding];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/script.js"]) {
mimeType = @"application/javascript";
data = scriptData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
auto htmlPath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:htmlPath]);
NSData *htmlDataWithReplacedURLs = [@"<html><head><meta charset=\"UTF-8\"><!-- Encoding specified by WebKit --><script src=\"host_files/script.js\"></script></head><body><img src=\"host_files/image.png\" onload=\"onImageLoad()\"><script>function onImageLoad() { notifyTestRunner(); }</script></body></html>" dataUsingEncoding:NSUTF8StringEncoding];
EXPECT_TRUE([[NSData dataWithContentsOfFile:htmlPath] isEqualToData:htmlDataWithReplacedURLs]);
auto scriptPath = [directoryURL URLByAppendingPathComponent:@"host_files/script.js"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:scriptPath]);
EXPECT_TRUE([[NSData dataWithContentsOfFile:scriptPath] isEqualToData:scriptData]);
auto imagePath = [directoryURL URLByAppendingPathComponent:@"host_files/image.png"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:imagePath]);
EXPECT_TRUE([[NSData dataWithContentsOfFile:imagePath] isEqualToData:imageData]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForIframe = R"TESTRESOURCE(
<script>
count = 0;
function onFrameLoaded() {
if (++count == 3) {
frame = document.getElementById("iframe1_id");
if (frame && !frame.contentDocument.body.innerHTML)
frame.contentDocument.body.innerHTML = "<p>iframe1</p><img src='image.png'>";
window.webkit.messageHandlers.testHandler.postMessage("done");
}
}
</script>
<iframe onload="onFrameLoaded();" id="iframe1_id"></iframe>
<iframe onload="onFrameLoaded();" src="iframe.html"></iframe>
<iframe onload="onFrameLoaded();" srcdoc="<p>iframe3</p><img src='image.png'>"></iframe>
)TESTRESOURCE";
static const char* iframeHTMLDataBytes = R"TESTRESOURCE(
<head>
<link rel="stylesheet" href="style.css">
</head>
<p>iframe2</p>
<img src='image.png'>
)TESTRESOURCE";
static const char* cssDataBytesForIframe = R"TESTRESOURCE(
div {
height: 50%;
width: 50%;
}
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesIframe)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForIframe length:strlen(htmlDataBytesForIframe)];
NSData *iframeHTMLData = [NSData dataWithBytes:iframeHTMLDataBytes length:strlen(iframeHTMLDataBytes)];
NSData *cssData = [NSData dataWithBytes:cssDataBytesForIframe length:strlen(cssDataBytesForIframe)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/iframe.html"]) {
mimeType = @"text/html";
data = iframeHTMLData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/style.css"]) {
mimeType = @"text/css";
data = cssData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResourceString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *savedResourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(5llu, savedResourceFileNames.count);
unsigned frameFileCount = 0;
unsigned imageFileCount = 0;
unsigned cssFileCount = 0;
NSMutableSet *frameResourceContentsToFind = [NSMutableSet set];
[frameResourceContentsToFind addObjectsFromArray:[NSArray arrayWithObjects:@"iframe1", @"iframe2", @"iframe3", nil]];
for (NSString *fileName in savedResourceFileNames) {
if ([fileName containsString:@"frame_"]) {
// Ensure urls are replaced with file path.
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResourceString containsString:replacementPath]);
// Ensure all iframes are saved by looking at content.
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedSubframeResourceString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
NSRange range = [savedSubframeResourceString rangeOfString:@"iframe"];
EXPECT_NE(NSNotFound, (long)range.location);
NSString *iframeContent = [savedSubframeResourceString substringWithRange:NSMakeRange(range.location, range.length + 1)];
[frameResourceContentsToFind removeObject:iframeContent];
++frameFileCount;
}
if ([fileName isEqualToString:@"image.png"])
++imageFileCount;
if ([fileName isEqualToString:@"style.css"])
++cssFileCount;
}
EXPECT_EQ(3u, frameFileCount);
EXPECT_EQ(1u, imageFileCount);
EXPECT_EQ(1u, cssFileCount);
EXPECT_EQ(0u, frameResourceContentsToFind.count);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForFrame = R"TESTRESOURCE(
<head>
<script>
count = 0;
function onFramesLoaded() {
frame = document.getElementById("frame1_id");
if (frame && !frame.contentDocument.body.innerHTML)
frame.contentDocument.body.innerHTML = "<p>thisisframe1</p><img src='image.png'>";
window.webkit.messageHandlers.testHandler.postMessage("done");
}
</script>
</head>
<frameset cols="50%, 50%" onload="onFramesLoaded()">
<frame id="frame1_id">
<frame src="frame.html">
</frameset>
)TESTRESOURCE";
static const char* frameHTMLDataBytes = R"TESTRESOURCE(<p>thisisframe2</p><img src='image.png'>)TESTRESOURCE";
TEST(WebArchive, SaveResourcesFrame)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForFrame length:strlen(htmlDataBytesForFrame)];
NSData *frameHTMLData = [NSData dataWithBytes:frameHTMLDataBytes length:strlen(frameHTMLDataBytes)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/frame.html"]) {
mimeType = @"text/html";
data = frameHTMLData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(3llu, resourceFileNames.count);
unsigned frameFileCount = 0;
unsigned imageFileCount = 0;
NSMutableSet *frameResourceContentsToFind = [NSMutableSet set];
[frameResourceContentsToFind addObjectsFromArray:[NSArray arrayWithObjects:@"thisisframe1", @"thisisframe2", nil]];
for (NSString *fileName in resourceFileNames) {
if ([fileName containsString:@"frame_"]) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResource containsString:replacementPath]);
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedSubframeResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
NSRange range = [savedSubframeResource rangeOfString:@"thisisframe"];
EXPECT_NE(NSNotFound, (long)range.location);
NSString *frameContent = [savedSubframeResource substringWithRange:NSMakeRange(range.location, range.length + 1)];
[frameResourceContentsToFind removeObject:frameContent];
++frameFileCount;
}
if ([fileName isEqualToString:@"image.png"])
++imageFileCount;
}
EXPECT_EQ(2u, frameFileCount);
EXPECT_EQ(1u, imageFileCount);
EXPECT_EQ(0u, frameResourceContentsToFind.count);
saved = true;
}];
Util::run(&saved);
}
TEST(WebArchive, SaveResourcesValidFileName)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSMutableString *mutableFileName = [NSMutableString stringWithCapacity:256];
for (unsigned i = 0; i < 256; ++i)
[mutableFileName appendString:@"x"];
NSArray *tests = [NSArray arrayWithObjects:[NSString stringWithString:mutableFileName], @"a/image.png", @"b/image.png", @"c/image.png", @"d/image.png", @"image.png(1)", @"webarchivetest://host/file:image.png", @"image1/", @"image2///", @"image3.png/./", @"image4/content/../", @"image5%20file.png", @"image 6.png", nil];
NSMutableString *mutableHTMLString = [NSMutableString string];
NSString *styleString = @"<link rel='stylesheet' href='imagestyle'><link rel='stylesheet' href='style.css'><link rel='stylesheet' href='style'>";
NSString *scriptString = [NSString stringWithFormat:@"<script>count = 0; function onImageLoad() { if (++count == %d) window.webkit.messageHandlers.testHandler.postMessage('done'); }</script>", (int)tests.count];
[mutableHTMLString appendString:styleString];
[mutableHTMLString appendString:scriptString];
for (NSString *item in tests)
[mutableHTMLString appendString:[NSString stringWithFormat:@"<img src='%@' onload='onImageLoad()'>", item]];
NSData *htmlData = [[NSString stringWithString:mutableHTMLString] dataUsingEncoding:NSUTF8StringEncoding];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
NSString *cssString = @"img { width: 10px; }";
NSData *cssData = [cssString dataUsingEncoding:NSUTF8StringEncoding];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString containsString:@"style"]) {
mimeType = @"text/css";
data = cssData;
} else {
mimeType = @"image/png";
data = imageData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
NSSet *expectedFileNames = [NSSet setWithArray:[NSArray arrayWithObjects:[mutableFileName substringFromIndex:1], @"image.png", @"image.png-1", @"image.png-2", @"image.png-3", @"image.png-1-", @"file-image.png", @"image1", @"file", @"image3.png", @"image4", @"image5-file.png", @"image-6.png", @"imagestyle.css", @"style.css", @"style-1.css", nil]];
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *resourceDirectoryName = @"host_files";
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:[directoryURL URLByAppendingPathComponent:resourceDirectoryName].path error:nil];
NSSet *savedFileNames = [NSSet setWithArray:resourceFileNames];
EXPECT_TRUE([savedFileNames isEqualToSet:expectedFileNames]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForBlobURL = R"TESTRESOURCE(
<body>
<script>
function onImageLoad() {
window.webkit.messageHandlers.testHandler.postMessage("done");
}
async function fetchImage() {
response = await fetch("image.png");
blob = await response.blob();
url = URL.createObjectURL(blob);
frame = document.createElement("iframe");
frame.src = url;
document.body.appendChild(frame);
img = document.createElement('img');
img.onload = onImageLoad;
img.src = url;
document.body.appendChild(img);
}
function createIframe() {
htmlString = "<p>thisisframe</p>";
blob = new Blob([htmlString], { type: 'text/html' });
url = URL.createObjectURL(blob);
frame = document.createElement("iframe");
frame.onload = fetchImage;
frame.src = url;
document.body.appendChild(frame);
}
createIframe();
</script>
</body>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesBlobURL)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForBlobURL length:strlen(htmlDataBytesForBlobURL)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(2llu, resourceFileNames.count);
for (NSString *fileName in resourceFileNames) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
if ([fileName containsString:@"frame_"]) {
// HTML file from the first iframe element.
EXPECT_TRUE([savedMainResource containsString:replacementPath]);
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedSubframeResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedSubframeResource containsString:@"thisisframe"]);
} else {
// Image file from img and the second iframe element.
unsigned replacementPathCount = 0;
NSString *savedMainResourceCopy = [NSString stringWithString:savedMainResource];
NSRange range = [savedMainResourceCopy rangeOfString:replacementPath];
while (range.location != NSNotFound) {
++replacementPathCount;
savedMainResourceCopy = [savedMainResourceCopy substringFromIndex:range.location + 1];
range = [savedMainResourceCopy rangeOfString:replacementPath];
}
EXPECT_EQ(2u, replacementPathCount);
}
}
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForResponsiveImages = R"TESTRESOURCE(
<head>
<script>
const dpr = window.devicePixelRatio;
// Use image-set for div.
style = document.createElement('style');
style.innerHTML = "div { background-image:image-set('div1.png' " + dpr + "x, 'div2.png' " + (dpr + 1) + "x)}";
document.getElementsByTagName("head")[0].appendChild(style);
</script>
</head>
<body>
<div id="div">Hello</div>
<script>
count = 0;
function addSrcsetToImage() {
image = document.getElementById("image");
image.removeAttribute("src");
image.srcset = "image2.png " + dpr + "x, image1.png " + (dpr + 1) + "x";
}
function onImageLoad() {
++count;
if (count == 2) // image1.png and picture2.png are loaded.
addSrcsetToImage();
if (count == 3) // image2.png is loaded.
window.webkit.messageHandlers.testHandler.postMessage("done");
}
</script>
<img id="image" src="image1.png" onload="onImageLoad()">
<picture id="picture">
<source srcset="picture1.png" media="(min-width: 3000px)">
<img src="picture2.png" onload="onImageLoad()">
</picture>
</body>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesResponsiveImages)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForResponsiveImages length:strlen(htmlDataBytesForResponsiveImages)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString containsString:@"png"]) {
mimeType = @"image/png";
data = imageData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResourceString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
NSSet *expectedFileNames = [NSSet setWithArray:[NSArray arrayWithObjects:@"image1.png", @"image2.png", @"picture2.png", @"div1.png", nil]];
NSSet *savedFileNames = [NSSet setWithArray:resourceFileNames];
EXPECT_TRUE([savedFileNames isEqualToSet:expectedFileNames]);
for (NSString *fileName in resourceFileNames) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResourceString containsString:replacementPath]);
}
saved = true;
}];
Util::run(&saved);
}
static const char* hTMLDataBytesForDataURL = R"TESTRESOURCE(
<script>
count = 0;
function onLoad() {
if (++count == 3)
window.webkit.messageHandlers.testHandler.postMessage("done");
}
</script>
<img onload="onLoad()" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QcOEyQ6arfsmQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD5ElEQVR42u3UMQ0AAAgEsQflSEcFA0kr4YarTABeaAkAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIMSwLAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC+DSAp/KA6AWm53xAAAAAElFTkSuQmCC">
<iframe onload="onLoad()" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QcOEyQ6arfsmQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD5ElEQVR42u3UMQ0AAAgEsQflSEcFA0kr4YarTABeaAkAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIMSwLAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC+DSAp/KA6AWm53xAAAAAElFTkSuQmCC"></iframe>
<iframe onload="onLoad()" src="data:text/html,<img src='webarchivetest://host/image.png'>"></iframe>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesDataURL)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:hTMLDataBytesForDataURL length:strlen(hTMLDataBytesForDataURL)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:nil];
EXPECT_EQ(3llu, resourceFileNames.count);
unsigned frameFileCount = 0;
unsigned imageFileCount = 0;
unsigned frameWithDataURLCount = 0;
for (NSString *fileName in resourceFileNames) {
if ([fileName containsString:@"frame_"]) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResource containsString:replacementPath]);
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedSubframeResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
if ([savedSubframeResource containsString:@"data:image/png"])
++frameWithDataURLCount;
++frameFileCount;
}
if ([fileName containsString:@".png"])
++imageFileCount;
}
EXPECT_EQ(2u, frameFileCount);
EXPECT_EQ(1u, imageFileCount);
EXPECT_EQ(1u, frameWithDataURLCount);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForIframeInIframe = R"TESTRESOURCE(
<script>
count = 0;
function frameLoaded() {
if (++count == 2)
window.webkit.messageHandlers.testHandler.postMessage("done");
}
window.addEventListener('message', function(event) {
if (event.data == 'loaded')
frameLoaded();
});
</script>
<iframe onload="frameLoaded();" src="iframe1.html"></iframe>
)TESTRESOURCE";
static const char* iframe1HTMLDataBytes = R"TESTRESOURCE(
<script>
function frameLoaded() {
window.parent.postMessage("loaded", "*");
}
</script>
<p>thisisiframe1</p>
<iframe onload="frameLoaded();" src="iframe2.html"></iframe>
)TESTRESOURCE";
static const char* iframe2HTMLDataBytes = R"TESTRESOURCE(<p>thisisiframe2</p>)TESTRESOURCE";
TEST(WebArchive, SaveResourcesIframeInIframe)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForIframeInIframe length:strlen(htmlDataBytesForIframeInIframe)];
NSData *iframe1HTMLData = [NSData dataWithBytes:iframe1HTMLDataBytes length:strlen(iframe1HTMLDataBytes)];
NSData *iframe2HTMLData = [NSData dataWithBytes:iframe2HTMLDataBytes length:strlen(iframe2HTMLDataBytes)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/iframe1.html"]) {
mimeType = @"text/html";
data = iframe1HTMLData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/iframe2.html"]) {
mimeType = @"text/html";
data = iframe2HTMLData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(2llu, resourceFileNames.count);
NSMutableSet *frameResourceContentsToFind = [NSMutableSet set];
[frameResourceContentsToFind addObjectsFromArray:[NSArray arrayWithObjects:@"thisisiframe1", @"thisisiframe2", nil]];
for (NSString *fileName in resourceFileNames) {
EXPECT_TRUE([fileName containsString:@"frame_"]);
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedSubframeResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
NSRange range = [savedSubframeResource rangeOfString:@"thisisiframe"];
EXPECT_NE(NSNotFound, (long)range.location);
NSString *iframeContent = [savedSubframeResource substringWithRange:NSMakeRange(range.location, range.length + 1)];
if ([iframeContent isEqualToString:@"thisisiframe1"]) {
// Main resources of iframes are stored in the same directory, so replaced url should not contain the directory name.
EXPECT_FALSE([savedSubframeResource containsString:resourceDirectoryName]);
}
[frameResourceContentsToFind removeObject:iframeContent];
}
EXPECT_EQ(0u, frameResourceContentsToFind.count);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForIframesWithSameURL = R"TESTRESOURCE(
<script>
count = 0;
messageCount = 0;
function frameLoaded() {
if (++count == 3) {
const iframes = document.getElementsByTagName("iframe");
for (let i = 0; i < iframes.length; ++i)
iframes[i].contentWindow.postMessage("thisisiframe" + (i + 1), "*");
}
}
window.addEventListener("message", function(event) {
if (++messageCount == 3)
window.webkit.messageHandlers.testHandler.postMessage("done");
});
</script>
<iframe onload="frameLoaded();" src="iframe.html"></iframe>
<iframe onload="frameLoaded();" src="iframe.html"></iframe>
<iframe onload="frameLoaded();" src="iframe.html"></iframe>
)TESTRESOURCE";
static const char* iframeHTMLDataBytesForIframesWithSameURL = R"TESTRESOURCE(
<head>
<script>
window.addEventListener("message", function(event) {
if (!document.body.innerHTML)
document.body.innerHTML = "<p>" + event.data + "</p>";
window.parent.postMessage("done", "*");
});
</script>
</head>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesIframesWithSameURL)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForIframesWithSameURL length:strlen(htmlDataBytesForIframesWithSameURL)];
NSData *iframeHTMLData = [NSData dataWithBytes:iframeHTMLDataBytesForIframesWithSameURL length:strlen(iframeHTMLDataBytesForIframesWithSameURL)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/iframe.html"]) {
mimeType = @"text/html";
data = iframeHTMLData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(3llu, resourceFileNames.count);
NSMutableSet *frameResourceContentsToFind = [NSMutableSet set];
[frameResourceContentsToFind addObjectsFromArray:[NSArray arrayWithObjects:@"thisisiframe1", @"thisisiframe2", @"thisisiframe3", nil]];
for (NSString *fileName in resourceFileNames) {
EXPECT_TRUE([fileName containsString:@"frame_"]);
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedSubframeResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
NSRange range = [savedSubframeResource rangeOfString:@"thisisiframe"];
EXPECT_NE(NSNotFound, (long)range.location);
NSString *iframeContent = [savedSubframeResource substringWithRange:NSMakeRange(range.location, range.length + 1)];
[frameResourceContentsToFind removeObject:iframeContent];
}
EXPECT_EQ(0u, frameResourceContentsToFind.count);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForShadowDOM = R"TESTRESOURCE(
<button id="button" onclick="buttonClicked()"></button>
<script>
function buttonClicked() {
div1 = document.createElement("div");
div1.id = "div1";
root1 = div1.attachShadow({ mode: "open" });
root1.innerHTML = "ShadowRoot1";
div2 = document.createElement("div");
div2.id = "div2";
root2 = div2.attachShadow({ mode: "closed" });
root2.innerHTML = "ShadowRoot2<slot name='text'></slot>";
span = document.createElement("span");
span.slot= "text";
span.innerHTML = "Text";
root2.appendChild(span);
root1.appendChild(div2);
var button = document.getElementById("button");
button.parentNode.removeChild(button);
document.body.appendChild(div1);
window.webkit.messageHandlers.testHandler.postMessage("done");
}
window.webkit.messageHandlers.testHandler.postMessage("start");
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesShadowDOM)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForShadowDOM length:strlen(htmlDataBytesForShadowDOM)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"start" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView evaluateJavaScript:@"document.getElementById('button').click();" completionHandler:nil];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedMainResource containsString:@"<div id=\"div1\"><template shadowrootmode=\"open\">ShadowRoot1<div id=\"div2\"><template shadowrootmode=\"closed\">ShadowRoot2<slot name=\"text\"></slot><span slot=\"text\">Text</span></template></div></template></div>"]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForDeclarativeShadowDOM = R"TESTRESOURCE(
<script>
function loaded() {
window.webkit.messageHandlers.testHandler.postMessage("done");
}
</script>
<body onload="loaded()">
<div>
<template shadowroot="open"><slot></slot></template><p>ShadowDOM</p><button>Button</button>
</div>
</body>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesDeclarativeShadowDOM)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForDeclarativeShadowDOM length:strlen(htmlDataBytesForDeclarativeShadowDOM)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedMainResource containsString:@"<template shadowroot=\"open\"><slot></slot></template><p>ShadowDOM</p><button>Button</button>"]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForStyle = R"TESTRESOURCE(
<style>
@font-face {
font-family: "WebFont";
src: url("Ahem-10000A.ttf");
}
div {
height: 50%;
width: 50%;
font-family: "WebFont";
background-image: url("image.png");
}
</style>
<div id="div">Hello</div>
<script>
div = document.getElementById("div");
imageURL = getComputedStyle(div).backgroundImage;
document.fonts.ready.then(() => { window.webkit.messageHandlers.testHandler.postMessage("done"); });
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesStyle)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForStyle length:strlen(htmlDataBytesForStyle)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
NSData *fontData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"Ahem-10000A" withExtension:@"ttf"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/Ahem-10000A.ttf"]) {
mimeType = @"font/ttf";
data = fontData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(2llu, resourceFileNames.count);
for (NSString *fileName in resourceFileNames) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResource containsString:replacementPath]);
}
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForInlineStyle = R"TESTRESOURCE(
<div id="div" style="background-image:url('image.png');width:50%;height:50%;color:red">Hello</div>
<script>
div = document.getElementById("div");
div.style.color = "fuchsia";
imageURL = getComputedStyle(div).backgroundImage;
window.webkit.messageHandlers.testHandler.postMessage("done");
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesInlineStyle)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForInlineStyle length:strlen(htmlDataBytesForInlineStyle)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else
FAIL();
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedMainResource containsString:@"color: fuchsia"]);
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:0];
EXPECT_EQ(1llu, resourceFileNames.count);
for (NSString *fileName in resourceFileNames) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResource containsString:replacementPath]);
}
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForLink = R"TESTRESOURCE(
<head>
<link rel="manifest" href="manifest.json">
<link rel="preload" href="Ahem-10000A.ttf" as="font" type="font/ttf">
<link rel="stylesheet" href="style.css">
</head>
<div><p id="console">Hello</p></div>
<script>
img = null;
function onImageLoad() {
img = null;
window.webkit.messageHandlers.testHandler.postMessage("done");
}
document.styleSheets[0].insertRule("p { color: fuchsia; }");
console = document.getElementById("console");
computedStyle = getComputedStyle(console);
var img = document.createElement("img");
img.src = "files/image.png";
img.onload = onImageLoad;
</script>
)TESTRESOURCE";
static const char* cssDataBytesForLink = R"TESTRESOURCE(
div {
height: 50%;
width: 50%;
background-image: url("files/image.png");
}
)TESTRESOURCE";
static const char* manifestDataBytesForLink = R"TESTRESOURCE(
{
"name": "webarchivetest",
"short_name": "wat",
"description": "This is a test app."
}
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesLink)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForLink length:strlen(htmlDataBytesForLink)];
NSData *cssData = [NSData dataWithBytes:cssDataBytesForLink length:strlen(cssDataBytesForLink)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
NSData *manifestData = [NSData dataWithBytes:manifestDataBytesForLink length:strlen(manifestDataBytesForLink)];
NSData *fontData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"Ahem-10000A" withExtension:@"ttf"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/files/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/style.css"]) {
mimeType = @"text/css";
data = cssData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/manifest.json"]) {
mimeType = @"application/json";
data = manifestData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/Ahem-10000A.ttf"]) {
mimeType = @"font/ttf";
data = fontData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath =[directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:nil];
NSSet *savedFileNames = [NSSet setWithArray:resourceFileNames];
NSSet *expectedFileNames = [NSSet setWithArray:[NSArray arrayWithObjects:@"image.png", @"style.css", @"manifest.json", @"Ahem-10000A.ttf", nil]];
EXPECT_TRUE([savedFileNames isEqualToSet:expectedFileNames]);
for (NSString *savedFileName in resourceFileNames) {
// image.png is not subresource in main resource file.
if ([savedFileName isEqualToString:@"image.png"])
continue;
NSString *savedFileRelativePath = [resourceDirectoryName stringByAppendingPathComponent:savedFileName];
EXPECT_TRUE([savedMainResource containsString:savedFileRelativePath]);
}
NSString *styleResourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:@"style.css"];
NSString *savedStyleResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:styleResourceFilePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedStyleResource containsString:@"url(\"image.png\")"]);
EXPECT_TRUE([savedStyleResource containsString:@"color: fuchsia"]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForEmptyStyleSheet = R"TESTRESOURCE(
<head>
<link rel="stylesheet" href="empty.css">
</head>
<script>
window.webkit.messageHandlers.testHandler.postMessage("done");
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesEmptyStyleSheet)
{
RetainPtr directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
RetainPtr configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
RetainPtr schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
RetainPtr htmlData = [NSData dataWithBytes:htmlDataBytesForEmptyStyleSheet length:strlen(htmlDataBytesForEmptyStyleSheet)];
RetainPtr cssData = adoptNS([[NSData alloc] init]);
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData.get();
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/empty.css"]) {
mimeType = @"text/css";
data = cssData.get();
}
RetainPtr response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
RetainPtr savedMainResource = adoptNS([[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding]);
NSString *resourceDirectoryName = @"host_files";
NSString *styleReourceName = @"empty.css";
NSString *resourceDirectoryPath = [directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSString *styleResourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:styleReourceName];
EXPECT_TRUE([fileManager fileExistsAtPath:styleResourceFilePath]);
RetainPtr savedStyleResource = adoptNS([[NSString alloc] initWithData:[NSData dataWithContentsOfFile:styleResourceFilePath] encoding:NSUTF8StringEncoding]);
EXPECT_EQ([savedStyleResource length], 0u);
NSString *styleResourceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:styleReourceName];
EXPECT_TRUE([savedMainResource.get() containsString:styleResourceRelativePath]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForLinksWithSameURL = R"TESTRESOURCE(
<head>
<link href="style.css" rel="stylesheet">
<link href="style.css" rel="stylesheet">
</head>
<div>Hello</div>
<p id="console">World</p>
<script>
document.styleSheets[0].deleteRule(0);
document.styleSheets[0].insertRule("p { color: gray; }");
console = document.getElementById("console");
computedStyle = getComputedStyle(console);
window.webkit.messageHandlers.testHandler.postMessage("done");
</script>
)TESTRESOURCE";
static const char* cssDataBytesForLinksWithSameURL = R"TESTRESOURCE(
div {
color: blue;
}
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesLinksWithSameURL)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForLinksWithSameURL length:strlen(htmlDataBytesForLinksWithSameURL)];
NSData *cssData = [NSData dataWithBytes:cssDataBytesForLinksWithSameURL length:strlen(cssDataBytesForLinksWithSameURL)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/style.css"]) {
mimeType = @"text/css";
data = cssData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath =[directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:nil];
EXPECT_EQ(2llu, resourceFileNames.count);
NSMutableSet *styleResourceContentsToFind = [NSMutableSet set];
[styleResourceContentsToFind addObjectsFromArray:[NSArray arrayWithObjects:@"color: blue", @"color: fuchsia", nil]];
for (NSString *fileName in resourceFileNames) {
NSString *replacementPath = [resourceDirectoryName stringByAppendingPathComponent:fileName];
EXPECT_TRUE([savedMainResource containsString:replacementPath]);
NSString *resourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:fileName];
NSString* savedStyleResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:resourceFilePath] encoding:NSUTF8StringEncoding];
NSRange range = [savedStyleResource rangeOfString:@"color: "];
EXPECT_NE(NSNotFound, (long)range.location);
NSString *styleResourceContent = [savedStyleResource substringWithRange:NSMakeRange(range.location, range.length + 4)];
[styleResourceContentsToFind removeObject:styleResourceContent];
}
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForCSSImportRule = R"TESTRESOURCE(
<head>
<style>
@import url("style.css");
</style>
</head>
<div><p id="console">Hello</p></div>
<script>
img = null;
function onImageLoad() {
img = null;
window.webkit.messageHandlers.testHandler.postMessage("done");
}
document.styleSheets[0].cssRules[0].styleSheet.insertRule("p { color: fuchsia; }");
console = document.getElementById("console");
computedStyle = getComputedStyle(console);
var img = document.createElement("img");
img.src = "files/image.png";
img.onload = onImageLoad;
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesCSSImportRule)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForCSSImportRule length:strlen(htmlDataBytesForCSSImportRule)];
NSData *cssData = [NSData dataWithBytes:cssDataBytesForLink length:strlen(cssDataBytesForLink)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/files/image.png"]) {
mimeType = @"image/png";
data = imageData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/style.css"]) {
mimeType = @"text/css";
data = cssData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *resourceDirectoryName = @"host_files";
NSString *resourceDirectoryPath =[directoryURL URLByAppendingPathComponent:resourceDirectoryName].path;
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:resourceDirectoryPath error:nil];
NSSet *savedFileNames = [NSSet setWithArray:resourceFileNames];
NSSet *expectedFileNames = [NSSet setWithArray:[NSArray arrayWithObjects:@"image.png", @"style.css", nil]];
EXPECT_TRUE([savedFileNames isEqualToSet:expectedFileNames]);
NSString *styleResourceFileName = [resourceDirectoryName stringByAppendingPathComponent:@"style.css"];
EXPECT_TRUE([savedMainResource containsString:styleResourceFileName]);
NSString *styleResourceFilePath = [resourceDirectoryPath stringByAppendingPathComponent:@"style.css"];
NSString *savedStyleResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:styleResourceFilePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedStyleResource containsString:@"url(\"image.png\")"]);
EXPECT_TRUE([savedStyleResource containsString:@"color: fuchsia"]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForCSSSupportsRule = R"TESTRESOURCE(
<head>
<style>
@supports (background-image: url()) {
div {
background-image: url("image.png");
}
}
</style>
</head>
<div>Hello</div>
<script>
img = null;
function onImageLoad() {
img = null;
window.webkit.messageHandlers.testHandler.postMessage("done");
}
var img = document.createElement("img");
img.src = "image.png";
img.onload = onImageLoad;
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesCSSSupportsRule)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForCSSSupportsRule length:strlen(htmlDataBytesForCSSSupportsRule)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *imageFile = @"image.png";
NSString *resourceDirectoryName = @"host_files";
NSString *imageResouceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:imageFile];
EXPECT_TRUE([savedMainResource containsString:imageResouceRelativePath]);
NSString *imageResourcePath = [directoryURL URLByAppendingPathComponent:imageResouceRelativePath].path;
EXPECT_TRUE([fileManager fileExistsAtPath:imageResourcePath]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForCSSMediaRule = R"TESTRESOURCE(
<head>
<style>
@media (min-width: 1px) {
div {
background-image: url("image.png");
}
}
</style>
</head>
<div>Hello</div>
<script>
img = null;
function onImageLoad() {
img = null;
window.webkit.messageHandlers.testHandler.postMessage("done");
}
var img = document.createElement("img");
img.src = "image.png";
img.onload = onImageLoad;
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesCSSMediaRule)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
RetainPtr configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
RetainPtr schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
RetainPtr htmlData = [NSData dataWithBytes:htmlDataBytesForCSSMediaRule length:strlen(htmlDataBytesForCSSMediaRule)];
RetainPtr imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData.get();
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/image.png"]) {
mimeType = @"image/png";
data = imageData.get();
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *imageFile = @"image.png";
NSString *resourceDirectoryName = @"host_files";
NSString *imageResouceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:imageFile];
EXPECT_TRUE([savedMainResource containsString:imageResouceRelativePath]);
NSString *imageResourcePath = [directoryURL URLByAppendingPathComponent:imageResouceRelativePath].path;
EXPECT_TRUE([fileManager fileExistsAtPath:imageResourcePath]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForCrossOriginLink = R"TESTRESOURCE(
<head>
<link href="webarchivetest://resource.com/style.css" rel="stylesheet">
</head>
<div id="console">Hello</div>
<script>
console = document.getElementById("console");
computedStyle = getComputedStyle(console);
window.webkit.messageHandlers.testHandler.postMessage("done");
</script>
)TESTRESOURCE";
static const char* cssDataBytesForCrossOriginLink = R"TESTRESOURCE(
div {
height: 50%;
width: 50%;
}
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesCrossOriginLink)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForCrossOriginLink length:strlen(htmlDataBytesForCrossOriginLink)];
NSData *cssData = [NSData dataWithBytes:cssDataBytesForCrossOriginLink length:strlen(cssDataBytesForCrossOriginLink)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host.com/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://resource.com/style.css"]) {
mimeType = @"text/css";
data = cssData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host.com/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *cssFile = @"style.css";
NSString *resourceDirectoryName = @"host_files";
NSString *cssResourceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:cssFile];
EXPECT_TRUE([savedMainResource containsString:cssResourceRelativePath]);
NSString *cssResourcePath = [directoryURL URLByAppendingPathComponent:cssResourceRelativePath].path;
EXPECT_TRUE([fileManager fileExistsAtPath:cssResourcePath]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForExcludeBaseElement = R"TESTRESOURCE(
<head>
<base href="webarchivetest://resource.com" target="_blank">
</head>
<img src="image.png" onload="onImageLoad()">
<a href="/link">Open Link</a>
<script>
function onImageLoad() {
window.webkit.messageHandlers.testHandler.postMessage("done");
}
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesExcludeBaseElement)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForExcludeBaseElement length:strlen(htmlDataBytesForExcludeBaseElement)];
NSData *imageData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"400x400-green" withExtension:@"png"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host.com/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://resource.com/image.png"]) {
mimeType = @"image/png";
data = imageData;
}
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host.com/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
NSString *imageFile = @"image.png";
NSString *resourceDirectoryName = @"host_files";
NSString *imageResourceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:imageFile];
EXPECT_TRUE([savedMainResource containsString:imageResourceRelativePath]);
EXPECT_FALSE([savedMainResource containsString:@"base"]);
// The anchor element's url should be resolved.
EXPECT_TRUE([savedMainResource containsString:@"webarchivetest://resource.com/link"]);
NSString *imageResourcePath = [directoryURL URLByAppendingPathComponent:imageResourceRelativePath].path;
EXPECT_TRUE([fileManager fileExistsAtPath:imageResourcePath]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForExclusionRules = R"TESTRESOURCE(
<a href="foo.html" target="_blank">Blank</a>
<a href="#bar" target="_self">Self</a>
<textarea disabled hidden>Text</textarea>
<button disabled>Button</button>
<script>
window.webkit.messageHandlers.testHandler.postMessage("done");
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesExclusionRules)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForExclusionRules length:strlen(htmlDataBytesForExclusionRules)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
}
EXPECT_TRUE(data);
auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
RetainPtr<_WKArchiveConfiguration> archiveConfiguration = adoptNS([[_WKArchiveConfiguration alloc] init]);
archiveConfiguration.get().directory = directoryURL.get();
archiveConfiguration.get().suggestedFileName = @"host";
archiveConfiguration.get().exclusionRules = @[
adoptNS([[_WKArchiveExclusionRule alloc] initWithElementLocalName:@"script" attributeLocalNames:nil attributeValues:nil]).get(),
adoptNS([[_WKArchiveExclusionRule alloc] initWithElementLocalName:nil attributeLocalNames:@[@"disabled", @"hidden"] attributeValues:@[@"", @""]]).get(),
adoptNS([[_WKArchiveExclusionRule alloc] initWithElementLocalName:@"a" attributeLocalNames:@[@"target"] attributeValues:@[@"_blank"]]).get(),
];
[webView _archiveWithConfiguration:archiveConfiguration.get() completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_FALSE([savedMainResource containsString:@"script"]);
EXPECT_FALSE([savedMainResource containsString:@"hidden"]);
EXPECT_FALSE([savedMainResource containsString:@"target=\"_blank\""]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForExcludeCrossOriginAttribute = R"TESTRESOURCE(
<head>
<link href="webarchivetest://resource.com/style.css" rel="stylesheet" crossorigin="anonymous">
</head>
<div id="console"></div>
<script src="webarchivetest://resource.com/script.js" integrity="sha256-whXcIuErT+KLyiIBuDxrli97oBljDS1fLlyogfljnnM=" crossorigin="anonymous"></script>
<script>
div = document.getElementById("console");
div.innerHTML += getComputedStyle(div).width;
window.webkit.messageHandlers.testHandler.postMessage("done");
</script>
)TESTRESOURCE";
static const char* scriptDataBytesForExcludeCrossOriginAttribute = R"TESTRESOURCE(document.getElementById("console").innerHTML = "ScriptRuns";)TESTRESOURCE";
static const char* cssDataBytesForExcludeCrossOriginAttribute = R"TESTRESOURCE(div { width: 10px; })TESTRESOURCE";
TEST(WebArchive, SaveResourcesExcludeCrossOriginAttribute)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForExcludeCrossOriginAttribute length:strlen(htmlDataBytesForExcludeCrossOriginAttribute)];
NSData *scriptData = [NSData dataWithBytes:scriptDataBytesForExcludeCrossOriginAttribute length:strlen(scriptDataBytesForExcludeCrossOriginAttribute)];
NSData *cssData = [NSData dataWithBytes:cssDataBytesForExcludeCrossOriginAttribute length:strlen(cssDataBytesForExcludeCrossOriginAttribute)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
bool shouldAddAccessControlHeader = false;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://resource.com/script.js"]) {
mimeType = @"application/javascript";
data = scriptData;
shouldAddAccessControlHeader = true;
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://resource.com/style.css"]) {
mimeType = @"text/css";
data = cssData;
shouldAddAccessControlHeader = true;
}
EXPECT_TRUE(data);
RetainPtr<NSMutableDictionary> headerFields = adoptNS(@{
@"Content-Length": [NSString stringWithFormat:@"%zu", (size_t)data.length],
@"Content-Type": mimeType,
}.mutableCopy);
if (shouldAddAccessControlHeader)
[headerFields setObject:@"*" forKey:@"Access-Control-Allow-Origin"];
auto response = adoptNS([[NSHTTPURLResponse alloc] initWithURL:task.request.URL statusCode:200 HTTPVersion:nil headerFields:headerFields.get()]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedMainResource containsString:@"ScriptRuns"]);
EXPECT_TRUE([savedMainResource containsString:@"10px"]);
EXPECT_FALSE([savedMainResource containsString:@"integrity"]);
EXPECT_FALSE([savedMainResource containsString:@"crossorigin"]);
NSString *resourceDirectoryName = @"host_files";
NSString *scriptFile = @"script.js";
NSString *scriptResourceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:scriptFile];
EXPECT_TRUE([savedMainResource containsString:scriptResourceRelativePath]);
NSString *scriptResourcePath = [directoryURL URLByAppendingPathComponent:scriptResourceRelativePath].path;
EXPECT_TRUE([fileManager fileExistsAtPath:scriptResourcePath]);
NSString *cssFile = @"style.css";
NSString *cssResourceRelativePath = [resourceDirectoryName stringByAppendingPathComponent:cssFile];
EXPECT_TRUE([savedMainResource containsString:cssResourceRelativePath]);
NSString *cssResourcePath = [directoryURL URLByAppendingPathComponent:scriptResourceRelativePath].path;
EXPECT_TRUE([fileManager fileExistsAtPath:cssResourcePath]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForUnsavedSubresources = R"TESTRESOURCE(
<style>
@font-face {
font-family: "WebFont";
src: url("Ahem-10000A.ttf") format("truetype"), url("Ahem-10000A-backup.ttf") format("truetype")
}
div {
width: 100%;
font-family: "WebFont";
}
</style>
<div id="div">Hello</div>
<script>
div = document.getElementById("div");
computedFontFamily = getComputedStyle(div).getPropertyValue("font-family");
document.fonts.ready.then(() => { window.webkit.messageHandlers.testHandler.postMessage("done"); });
</script>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesStyleWithUnloadedResources)
{
RetainPtr directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
RetainPtr htmlData = [NSData dataWithBytes:htmlDataBytesForUnsavedSubresources length:strlen(htmlDataBytesForUnsavedSubresources)];
RetainPtr fontData = [NSData dataWithContentsOfURL:[NSBundle.test_resourcesBundle URLForResource:@"Ahem-10000A" withExtension:@"ttf"]];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData.get();
} else if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/Ahem-10000A.ttf"]) {
mimeType = @"font/ttf";
data = fontData.get();
}
RetainPtr response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedMainResource containsString:@"host_files/Ahem-10000A.ttf"]);
EXPECT_FALSE([savedMainResource containsString:@"host_files/Ahem-10000A-backup.ttf"]);
EXPECT_TRUE([savedMainResource containsString:@"webarchivetest://host/Ahem-10000A-backup.ttf"]);
saved = true;
}];
Util::run(&saved);
}
static const char* htmlDataBytesForUTF8Encoding = R"TESTRESOURCE(
<head>
<meta http-equiv="content-type" content="text/html; charset=Windows-1252">
<script>
function loaded() {
window.webkit.messageHandlers.testHandler.postMessage("done");
}
</script>
</head>
<body onload="loaded()">
Hello World!
</body>
)TESTRESOURCE";
TEST(WebArchive, SaveResourcesWithUTF8Encoding)
{
RetainPtr<NSURL> directoryURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"SaveResourcesTest"] isDirectory:YES];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:directoryURL.get() error:nil];
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
[configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webarchivetest"];
NSData *htmlData = [NSData dataWithBytes:htmlDataBytesForUTF8Encoding length:strlen(htmlDataBytesForUTF8Encoding)];
[schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
NSData *data = nil;
NSString *mimeType = nil;
if ([task.request.URL.absoluteString isEqualToString:@"webarchivetest://host/main.html"]) {
mimeType = @"text/html";
data = htmlData;
}
EXPECT_TRUE(data);
RetainPtr response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil]);
[task didReceiveResponse:response.get()];
[task didReceiveData:data];
[task didFinish];
}];
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
static bool messageReceived = false;
[webView performAfterReceivingMessage:@"done" action:[&] {
messageReceived = true;
}];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSString *mainResourcePath = [directoryURL URLByAppendingPathComponent:@"host.html"].path;
EXPECT_TRUE([fileManager fileExistsAtPath:mainResourcePath]);
NSString *savedMainResource = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:mainResourcePath] encoding:NSUTF8StringEncoding];
EXPECT_TRUE([savedMainResource containsString:@"<meta charset=\"UTF-8\">"]);
saved = true;
}];
Util::run(&saved);
}
} // namespace TestWebKitAPI
#endif // PLATFORM(MAC) || PLATFORM(IOS_FAMILY)