https://bugs.webkit.org/show_bug.cgi?id=174082
<rdar://problem/
33046992>
Reviewed by Tim Horton.
Source/WebCore:
Currently, our heuristics for coercing plain text to URLs when reading URLs off of the UIPasteboard allows URLs
to be created as long as -[UIPasteboard valuesForPasteboardType:inItemSet:] returns a non-null NSURL. However,
UIPasteboard automatically coerces any NSString into an NSURL if it initializes an NSURL via +URLWithString:.
Thus, single-word strings such as "hello" that are written to the pasteboard as "public.utf8-plain-text" can
be read back as NSURLs for "public.url". This currently causes bugs in shipping software: e.g. copying and
pasting a single word from an editable input or textarea and pasting into a rich contenteditable area using
WebKit1 inserts a link. However, when combined with another change in WebKit that attempts to read "public.url"
before "public.text" when reading plain text from the pasteboard, this now also affects pasting in plain text
areas, where pasted plain-text strings that are not URLs will paste as URL-encoded strings anyways (for
instance, replacing "[hello]" with "%5Bhello%5D").
To fix this, and existing issues with pasting single words in contenteditables, we make
PlatformPasteboard::readString and PlatformPasteboard::readURL only accept a coerced NSURL as an URL if it also
parses as a valid URL in WebKit (otherwise, we return an empty string).
Tests:
UIPasteboardTests.DoNotPastePlainTextAsURL
UIPasteboardTests.PastePlainTextAsURL
UIPasteboardTests.PasteURLWithPlainTextAsURL
* platform/PlatformPasteboard.h:
* platform/ios/AbstractPasteboard.h:
* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::PlatformPasteboard::allowReadingURLAtIndex):
Allow an URL to be read if either (1) an URL was explicitly specified in the UIPasteboard, or (2) the "proposed"
URL returned from -valuesForPasteboardType: is valid.
(WebCore::PlatformPasteboard::readString):
(WebCore::PlatformPasteboard::readURL):
Consult allowReadingURLAtIndex here (in the case of ::readString, only if the given pasteboard type is
"public.url").
* platform/ios/WebItemProviderPasteboard.h:
* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderPasteboard itemProviders]):
(-[WebItemProviderPasteboard setItemProviders:]):
Source/WebKit2:
Add a hook to WKPreferences to allow programatic pasting.
* UIProcess/API/Cocoa/WKPreferences.mm:
(-[WKPreferences _setDOMPasteAllowed:]):
(-[WKPreferences _domPasteAllowed]):
* UIProcess/API/Cocoa/WKPreferencesPrivate.h:
Tools:
Adds 3 new unit tests to UIPasteboardTests to test cases of pasting plain text and URLs.
* TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:
(TestWebKitAPI::setUpWebViewForPasteboardTests):
(TestWebKitAPI::TEST):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219070
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-07-03 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ Pasting single words copied to UIPasteboard inserts URLs in editable areas
+ https://bugs.webkit.org/show_bug.cgi?id=174082
+ <rdar://problem/33046992>
+
+ Reviewed by Tim Horton.
+
+ Currently, our heuristics for coercing plain text to URLs when reading URLs off of the UIPasteboard allows URLs
+ to be created as long as -[UIPasteboard valuesForPasteboardType:inItemSet:] returns a non-null NSURL. However,
+ UIPasteboard automatically coerces any NSString into an NSURL if it initializes an NSURL via +URLWithString:.
+ Thus, single-word strings such as "hello" that are written to the pasteboard as "public.utf8-plain-text" can
+ be read back as NSURLs for "public.url". This currently causes bugs in shipping software: e.g. copying and
+ pasting a single word from an editable input or textarea and pasting into a rich contenteditable area using
+ WebKit1 inserts a link. However, when combined with another change in WebKit that attempts to read "public.url"
+ before "public.text" when reading plain text from the pasteboard, this now also affects pasting in plain text
+ areas, where pasted plain-text strings that are not URLs will paste as URL-encoded strings anyways (for
+ instance, replacing "[hello]" with "%5Bhello%5D").
+
+ To fix this, and existing issues with pasting single words in contenteditables, we make
+ PlatformPasteboard::readString and PlatformPasteboard::readURL only accept a coerced NSURL as an URL if it also
+ parses as a valid URL in WebKit (otherwise, we return an empty string).
+
+ Tests:
+ UIPasteboardTests.DoNotPastePlainTextAsURL
+ UIPasteboardTests.PastePlainTextAsURL
+ UIPasteboardTests.PasteURLWithPlainTextAsURL
+
+ * platform/PlatformPasteboard.h:
+ * platform/ios/AbstractPasteboard.h:
+ * platform/ios/PlatformPasteboardIOS.mm:
+ (WebCore::PlatformPasteboard::allowReadingURLAtIndex):
+
+ Allow an URL to be read if either (1) an URL was explicitly specified in the UIPasteboard, or (2) the "proposed"
+ URL returned from -valuesForPasteboardType: is valid.
+
+ (WebCore::PlatformPasteboard::readString):
+ (WebCore::PlatformPasteboard::readURL):
+
+ Consult allowReadingURLAtIndex here (in the case of ::readString, only if the given pasteboard type is
+ "public.url").
+
+ * platform/ios/WebItemProviderPasteboard.h:
+ * platform/ios/WebItemProviderPasteboard.mm:
+ (-[WebItemProviderPasteboard itemProviders]):
+ (-[WebItemProviderPasteboard setItemProviders:]):
+
2017-07-03 Zan Dobersek <zdobersek@igalia.com>
[GCrypt] Implement CryptoKeyEC SPKI exports
WEBCORE_EXPORT void writeObjectRepresentations(const PasteboardImage&);
WEBCORE_EXPORT void writeObjectRepresentations(const String& pasteboardType, const String& text);
WEBCORE_EXPORT void writeObjectRepresentations(const PasteboardURL&);
+ bool allowReadingURLAtIndex(const URL&, int index) const;
#endif
#if PLATFORM(MAC)
@property (readonly, nonatomic) NSInteger numberOfItems;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+@property (nonatomic, copy, nullable) NSArray<__kindof NSItemProvider *> *itemProviders;
+#endif
+
- (NSArray<NSString *> *)pasteboardTypes;
- (NSArray *)dataForPasteboardType:(NSString *)pasteboardType inItemSet:(NSIndexSet *)itemSet;
- (NSArray *)valuesForPasteboardType:(NSString *)pasteboardType inItemSet:(NSIndexSet *)itemSet;
[itemsToRegister addData:[(NSString *)plainText dataUsingEncoding:NSUTF8StringEncoding] forType:(NSString *)kUTTypeUTF8PlainText];
}
+bool PlatformPasteboard::allowReadingURLAtIndex(const URL& url, int index) const
+{
+ NSItemProvider *itemProvider = (NSUInteger)index < [m_pasteboard itemProviders].count ? [[m_pasteboard itemProviders] objectAtIndex:index] : nil;
+ for (NSString *type in itemProvider.registeredTypeIdentifiers) {
+ if (UTTypeConformsTo((CFStringRef)type, kUTTypeURL))
+ return true;
+ }
+
+ return url.isValid();
+}
+
+#else
+
+bool PlatformPasteboard::allowReadingURLAtIndex(const URL&, int) const
+{
+ return true;
+}
+
#endif
void PlatformPasteboard::writeObjectRepresentations(const PasteboardWebContent& content)
return [(NSAttributedString *)value string];
} else if (type == String(kUTTypeURL)) {
ASSERT([value isKindOfClass:[NSURL class]]);
- if ([value isKindOfClass:[NSURL class]])
+ if ([value isKindOfClass:[NSURL class]] && allowReadingURLAtIndex((NSURL *)value, index))
return [(NSURL *)value absoluteString];
}
if (![value isKindOfClass:[NSURL class]])
return URL();
+ if (!allowReadingURLAtIndex((NSURL *)value, index))
+ return { };
+
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
title = [value _title];
#else
- (WebItemProviderRegistrationInfoList *)registrationInfoAtIndex:(NSUInteger)index;
- (UIItemProvider *)itemProviderAtIndex:(NSUInteger)index;
-@property (copy, nonatomic, nullable) NSArray<UIItemProvider *> *itemProviders;
+@property (copy, nonatomic, nullable) NSArray<__kindof NSItemProvider *> *itemProviders;
@property (readonly, nonatomic) NSInteger numberOfItems;
@property (readonly, nonatomic) NSInteger changeCount;
return _cachedTypeIdentifiers.get();
}
-- (NSArray<UIItemProvider *> *)itemProviders
+- (NSArray<__kindof NSItemProvider *> *)itemProviders
{
return _itemProviders.get();
}
-- (void)setItemProviders:(NSArray<UIItemProvider *> *)itemProviders
+- (void)setItemProviders:(NSArray<__kindof NSItemProvider *> *)itemProviders
{
itemProviders = itemProviders ?: [NSArray array];
if (_itemProviders == itemProviders || [_itemProviders isEqualToArray:itemProviders])
+2017-07-03 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ Pasting single words copied to UIPasteboard inserts URLs in editable areas
+ https://bugs.webkit.org/show_bug.cgi?id=174082
+ <rdar://problem/33046992>
+
+ Reviewed by Tim Horton.
+
+ Add a hook to WKPreferences to allow programatic pasting.
+
+ * UIProcess/API/Cocoa/WKPreferences.mm:
+ (-[WKPreferences _setDOMPasteAllowed:]):
+ (-[WKPreferences _domPasteAllowed]):
+ * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+
2017-07-03 Zan Dobersek <zdobersek@igalia.com>
Unreviewed GTK+ and WPE build fix when building with GCC 4.9.
return _preferences->javaScriptCanAccessClipboard();
}
+- (void)_setDOMPasteAllowed:(BOOL)domPasteAllowed
+{
+ _preferences->setDOMPasteAllowed(domPasteAllowed);
+}
+
+- (BOOL)_domPasteAllowed
+{
+ return _preferences->domPasteAllowed();
+}
+
- (void)_setMediaDocumentEntersFullscreenAutomatically:(BOOL)mediaDocumentEntersFullscreenAutomatically
{
_preferences->setMediaDocumentEntersFullscreenAutomatically(mediaDocumentEntersFullscreenAutomatically);
@property (nonatomic, setter=_setWebRTCLegacyAPIEnabled:) BOOL _webRTCLegacyAPIEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic, setter=_setJavaScriptCanAccessClipboard:) BOOL _javaScriptCanAccessClipboard WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic, setter=_setDOMPasteAllowed:) BOOL _domPasteAllowed WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic, setter=_setMediaDocumentEntersFullscreenAutomatically:) BOOL _mediaDocumentEntersFullscreenAutomatically WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+2017-07-03 Wenson Hsieh <wenson_hsieh@apple.com>
+
+ Pasting single words copied to UIPasteboard inserts URLs in editable areas
+ https://bugs.webkit.org/show_bug.cgi?id=174082
+ <rdar://problem/33046992>
+
+ Reviewed by Tim Horton.
+
+ Adds 3 new unit tests to UIPasteboardTests to test cases of pasting plain text and URLs.
+
+ * TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:
+ (TestWebKitAPI::setUpWebViewForPasteboardTests):
+ (TestWebKitAPI::TEST):
+
2017-07-02 Brady Eidson <beidson@apple.com>
Add API test for all parts of WebKit1 API related to favicons.
#import "TestWKWebView.h"
#import <MobileCoreServices/MobileCoreServices.h>
#import <UIKit/UIPasteboard.h>
+#import <WebCore/SoftLinking.h>
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/WKWebViewPrivate.h>
+SOFT_LINK_FRAMEWORK(UIKit)
+SOFT_LINK(UIKit, UIApplicationInitialize, void, (void), ())
+
namespace TestWebKitAPI {
NSData *dataForPasteboardType(CFStringRef type)
RetainPtr<TestWKWebView> setUpWebViewForPasteboardTests()
{
+ // UIPasteboard's type coercion codepaths only take effect when the UIApplication has been initialized.
+ UIApplicationInitialize();
+
[UIPasteboard generalPasteboard].items = @[];
EXPECT_TRUE(!dataForPasteboardType(kUTTypeUTF8PlainText).length);
EXPECT_TRUE(!dataForPasteboardType(kUTTypeUTF16PlainText).length);
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
- [webView configuration].preferences._javaScriptCanAccessClipboard = YES;
+ WKPreferences *preferences = [webView configuration].preferences;
+ preferences._javaScriptCanAccessClipboard = YES;
+ preferences._domPasteAllowed = YES;
[webView synchronouslyLoadTestPageNamed:@"rich-and-plain-text"];
return webView;
}
EXPECT_WK_STREQ("Hello world", [utf16Result UTF8String]);
}
+TEST(UIPasteboardTests, DoNotPastePlainTextAsURL)
+{
+ auto webView = setUpWebViewForPasteboardTests();
+
+ NSString *testString = @"[helloworld]";
+ [UIPasteboard generalPasteboard].string = testString;
+
+ [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
+ [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
+ EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"plain.value"]);
+
+ [webView stringByEvaluatingJavaScript:@"selectRichText()"];
+ [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
+ EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"rich.textContent"]);
+ EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"!!rich.querySelector('a')"].boolValue);
+}
+
+TEST(UIPasteboardTests, PastePlainTextAsURL)
+{
+ auto webView = setUpWebViewForPasteboardTests();
+
+ NSString *testString = @"https://www.apple.com/iphone";
+ [UIPasteboard generalPasteboard].string = testString;
+
+ [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
+ [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
+ EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"plain.value"]);
+
+ [webView stringByEvaluatingJavaScript:@"selectRichText()"];
+ [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
+ EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"rich.textContent"]);
+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!rich.querySelector('a')"].boolValue);
+}
+
+TEST(UIPasteboardTests, PasteURLWithPlainTextAsURL)
+{
+ auto webView = setUpWebViewForPasteboardTests();
+
+ NSString *testString = @"thisisdefinitelyaurl";
+ [UIPasteboard generalPasteboard].URL = [NSURL URLWithString:testString];
+
+ [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
+ [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
+ EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"plain.value"]);
+
+ [webView stringByEvaluatingJavaScript:@"selectRichText()"];
+ [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
+ EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"rich.textContent"]);
+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!rich.querySelector('a')"].boolValue);
+}
+
} // namespace TestWebKitAPI
#endif