blob: cf1337fa4bbe42625dc24a0e9d5fa1a664df2f15 [file] [log] [blame]
/*
* Copyright (C) 2019 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"
#import "PlatformUtilities.h"
#import "TestWKWebView.h"
#import "UIKitSPI.h"
#import <CoreServices/CoreServices.h>
#import <WebCore/LegacyNSPasteboardTypes.h>
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/_WKExperimentalFeature.h>
@interface TestWKWebView (ClipboardTests)
- (void)readClipboard;
@end
@implementation TestWKWebView (ClipboardTests)
- (void)readClipboard
{
__block bool done = false;
[self performAfterReceivingMessage:@"readClipboard" action:^{
done = true;
}];
[self evaluateJavaScript:@"readClipboard()" completionHandler:nil];
TestWebKitAPI::Util::run(&done);
}
- (void)writeString:(NSString *)string toClipboardWithType:(NSString *)type
{
__block bool done = false;
[self performAfterReceivingMessage:@"wroteStringToClipboard" action:^{
done = true;
}];
[self evaluateJavaScript:[NSString stringWithFormat:@"writeStringToClipboard(`%@`, `%@`)", type, string] completionHandler:nil];
TestWebKitAPI::Util::run(&done);
}
@end
static RetainPtr<TestWKWebView> createWebViewForClipboardTests()
{
#if PLATFORM(IOS_FAMILY)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// UIPasteboard's type coercion codepaths only take effect when the UIApplication has been initialized.
UIApplicationInitialize();
});
#endif // PLATFORM(IOS_FAMILY)
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
[[configuration preferences] _setDOMPasteAllowed:YES];
[[configuration preferences] _setJavaScriptCanAccessClipboard:YES];
for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) {
if ([feature.key isEqualToString:@"AsyncClipboardAPIEnabled"]) {
[[configuration preferences] _setEnabled:YES forExperimentalFeature:feature];
break;
}
}
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]);
[webView synchronouslyLoadTestPageNamed:@"clipboard"];
return webView;
}
static void writeMultipleObjectsToPlatformPasteboard()
{
#if PLATFORM(MAC)
auto firstItem = adoptNS([[NSPasteboardItem alloc] init]);
[firstItem setString:@"Hello" forType:NSPasteboardTypeString];
auto secondItem = adoptNS([[NSPasteboardItem alloc] init]);
[secondItem setString:@"https://apple.com/" forType:NSPasteboardTypeURL];
auto thirdItem = adoptNS([[NSPasteboardItem alloc] init]);
[thirdItem setString:@"<strong style='color: rgb(0, 255, 0);'>Hello world</strong>" forType:NSPasteboardTypeHTML];
auto fourthItem = adoptNS([[NSPasteboardItem alloc] init]);
[fourthItem setString:@"WebKit" forType:NSPasteboardTypeString];
[fourthItem setString:@"https://webkit.org/" forType:NSPasteboardTypeURL];
[fourthItem setString:@"<a href='https://webkit.org/'>Hello world</a>" forType:NSPasteboardTypeHTML];
NSPasteboard *pasteboard = NSPasteboard.generalPasteboard;
[pasteboard clearContents];
[pasteboard writeObjects:@[firstItem.get(), secondItem.get(), thirdItem.get(), fourthItem.get()]];
#elif PLATFORM(IOS_FAMILY) && !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
auto firstItem = adoptNS([[NSItemProvider alloc] initWithObject:@"Hello"]);
auto secondItem = adoptNS([[NSItemProvider alloc] initWithObject:[NSURL URLWithString:@"https://apple.com/"]]);
auto thirdItem = adoptNS([[NSItemProvider alloc] init]);
[thirdItem registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeHTML visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[&] (void (^completionHandler)(NSData *, NSError *)) -> NSProgress * {
completionHandler([@"<strong style='color: rgb(0, 255, 0);'>Hello world</strong>" dataUsingEncoding:NSUTF8StringEncoding], nil);
return nil;
}];
auto fourthItem = adoptNS([[NSItemProvider alloc] init]);
[fourthItem registerObject:@"WebKit" visibility:NSItemProviderRepresentationVisibilityAll];
[fourthItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:NSItemProviderRepresentationVisibilityAll];
[fourthItem registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeHTML visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[&] (void (^completionHandler)(NSData *, NSError *)) -> NSProgress * {
completionHandler([@"<a href='https://webkit.org/'>Hello world</a>" dataUsingEncoding:NSUTF8StringEncoding], nil);
return nil;
}];
UIPasteboard.generalPasteboard.itemProviders = @[ firstItem.get(), secondItem.get(), thirdItem.get(), fourthItem.get() ];
#endif
}
static NSString *readMarkupFromPasteboard()
{
#if PLATFORM(MAC)
NSData *rawData = [NSPasteboard.generalPasteboard dataForType:WebCore::legacyHTMLPasteboardType()];
#else
NSData *rawData = [UIPasteboard.generalPasteboard dataForPasteboardType:(__bridge NSString *)kUTTypeHTML];
#endif
return [[[NSString alloc] initWithData:rawData encoding:NSUTF8StringEncoding] autorelease];
}
TEST(ClipboardTests, ReadMultipleItems)
{
auto webView = createWebViewForClipboardTests();
writeMultipleObjectsToPlatformPasteboard();
[webView readClipboard];
EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"exception ? exception.message : ''"]);
EXPECT_EQ(4U, [[webView objectByEvaluatingJavaScript:@"clipboardData.length"] unsignedIntValue]);
EXPECT_WK_STREQ("Hello", [webView stringByEvaluatingJavaScript:@"clipboardData[0]['text/plain']"]);
EXPECT_WK_STREQ("https://apple.com/", [webView stringByEvaluatingJavaScript:@"clipboardData[1]['text/uri-list']"]);
EXPECT_WK_STREQ("rgb(0, 255, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(clipboardData[2]['text/html'].querySelector('strong')).color"]);
EXPECT_WK_STREQ("WebKit", [webView stringByEvaluatingJavaScript:@"clipboardData[3]['text/plain']"]);
EXPECT_WK_STREQ("https://webkit.org/", [webView objectByEvaluatingJavaScript:@"clipboardData[3]['text/uri-list']"]);
EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"clipboardData[3]['text/html'].querySelector('a').href"]);
}
TEST(ClipboardTests, WriteSanitizedMarkup)
{
auto webView = createWebViewForClipboardTests();
[webView writeString:@"<script>/* super secret */</script>This is a test." toClipboardWithType:@"text/html"];
NSString *writtenMarkup = readMarkupFromPasteboard();
EXPECT_TRUE([writtenMarkup containsString:@"This is a test."]);
EXPECT_FALSE([writtenMarkup containsString:@"super secret"]);
EXPECT_FALSE([writtenMarkup containsString:@"<script>"]);
}