WebKit Bugzilla
Attachment 356350 Details for
Bug 192283
: [iOSMac] Unable to upload non-image files using drag and drop in WKWebView
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
First pass
bug-192283-20181202160527.patch (text/plain), 20.54 KB, created by
Wenson Hsieh
on 2018-12-02 16:05:27 PST
(
hide
)
Description:
First pass
Filename:
MIME Type:
Creator:
Wenson Hsieh
Created:
2018-12-02 16:05:27 PST
Size:
20.54 KB
patch
obsolete
>Subversion Revision: 238784 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index f72c17beefd11815fd179bfd7843b3d1a36ac349..b1e62910b37bea3d1b25dfe59386d781b83378f9 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,77 @@ >+2018-12-02 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [iOSMac] Unable to upload non-image files using drag and drop in WKWebView >+ https://bugs.webkit.org/show_bug.cgi?id=192283 >+ <rdar://problem/46399461> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Currently on iOS, file URLs aren't generally written to the pasteboard during drag and drop unless the >+ application providing the data explicitly registers "public.file-url" to item providers. As such, our current >+ logic on iOS for handling drops does not attempt to prevent "public.file-url" from being advertised as the >+ "text/uri-list" MIME type in DataTransfer, though we do currently succeed in suppressing access to the file URL. >+ >+ However, on iOSMac, the scenario in which file URLs are registered to item providers becomes pertinent when >+ uploading files from other macOS apps (e.g. Finder) into a WKWebView running in iOSMac. Furthermore, the >+ `preferredPresentationStyle` flag on `NSItemProvider` is unavailable in iOSMac; currently, this flag is our >+ primary cue on iOS that an item should be treated as an attachment rather than inline data. In order to support >+ file uploads in iOSMac, we make several adjustments to drop handling logic in iOS to handle the case where the >+ "public.file-url" type is registered. See below for more details. >+ >+ Tests: DragAndDropTests.DataTransferExposePlainTextWithFileURLAsFile >+ DragAndDropTests.DataTransferGetDataWhenDroppingImageWithFileURL >+ >+ * platform/PasteboardItemInfo.h: >+ (WebCore::PasteboardItemInfo::encode const): >+ (WebCore::PasteboardItemInfo::decode): >+ >+ Add a new flag that is set if and only if the item provider contains the "public.file-url" type, and also >+ contains some non-URL data type that conforms to one of the file types supported for file uploads (i.e. >+ "public.content", zip archives, and folders). >+ >+ * platform/cocoa/PasteboardCocoa.mm: >+ (WebCore::Pasteboard::fileContentState): >+ >+ Consider the pasteboard to contain files in the case where one or more of the items contains a file URL, along >+ with some other pasteboard data that can be represented as a file upload. >+ >+ * platform/ios/PlatformPasteboardIOS.mm: >+ (WebCore::PlatformPasteboard::informationForItemAtIndex): >+ (WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const): >+ >+ If the pasteboard contains "public.file-url", don't consider "text-uri-list" to be one of the data types that's >+ safe to expose to the page. Our currently behavior in this case is that we will advertise "text-uri-list" as a >+ pasteboard type in the DataTransfer, but if the page attempts to request this information, we simply return the >+ empty string. Instead, we shouldn't expose "text/uri-list" as a type in the first place. >+ >+ * platform/ios/WebItemProviderPasteboard.h: >+ * platform/ios/WebItemProviderPasteboard.mm: >+ >+ Add a few more `__bridge`-ing casts where appropriate. >+ >+ (typeConformsToTypes): >+ >+ Move this further up the file so that it can be used in `NSItemProvider (WebCoreExtras)`. >+ >+ (-[NSItemProvider web_containsFileURLAndFileUploadContent]): >+ >+ Add a helper method on NSItemProvider to determine whether an item provider has a file URL, as well as a content >+ type suitable for file uploads. >+ >+ (-[WebItemProviderLoadResult canBeRepresentedAsFileUpload]): >+ >+ This currently always returns `NO` in iOSMac; instead, return `YES` on both iOS and iOSMac in the case where the >+ item provider contains a file URL and content which may be uploaded. >+ >+ (-[WebItemProviderPasteboard preferredFileUploadURLAtIndex:fileType:]): >+ (-[WebItemProviderPasteboard typeIdentifiersToLoad:]): >+ >+ Refactor this to take an `NSItemProvider` instead of a list of type identifiers, and bail out of loading data >+ for "public.url" if the item provider contains a file URL. >+ >+ (-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]): >+ (-[WebItemProviderPasteboard typeIdentifiersToLoadForRegisteredTypeIdentifiers:]): Deleted. >+ > 2018-12-01 Christopher Reid <chris.reid@sony.com> > > Add generic implementations to FileSystemPOSIX.cpp >diff --git a/Source/WebCore/platform/PasteboardItemInfo.h b/Source/WebCore/platform/PasteboardItemInfo.h >index e11743dd2976287c5cbdf4eb7e1614dcef6473b5..bd5996296541061ba766cc144ae6c246875d1087 100644 >--- a/Source/WebCore/platform/PasteboardItemInfo.h >+++ b/Source/WebCore/platform/PasteboardItemInfo.h >@@ -41,6 +41,7 @@ struct PasteboardItemInfo { > String contentTypeForFileUpload; > String suggestedFileName; > bool isNonTextType { false }; >+ bool containsFileURLAndFileUploadContent { false }; > PasteboardItemPresentationStyle preferredPresentationStyle { PasteboardItemPresentationStyle::Unspecified }; > > template<class Encoder> void encode(Encoder&) const; >@@ -50,7 +51,7 @@ struct PasteboardItemInfo { > template<class Encoder> > void PasteboardItemInfo::encode(Encoder& encoder) const > { >- encoder << pathForFileUpload << contentTypeForFileUpload << suggestedFileName << isNonTextType; >+ encoder << pathForFileUpload << contentTypeForFileUpload << suggestedFileName << isNonTextType << containsFileURLAndFileUploadContent; > encoder.encodeEnum(preferredPresentationStyle); > } > >@@ -70,6 +71,9 @@ std::optional<PasteboardItemInfo> PasteboardItemInfo::decode(Decoder& decoder) > if (!decoder.decode(result.isNonTextType)) > return std::nullopt; > >+ if (!decoder.decode(result.containsFileURLAndFileUploadContent)) >+ return std::nullopt; >+ > if (!decoder.decodeEnum(result.preferredPresentationStyle)) > return std::nullopt; > >diff --git a/Source/WebCore/platform/cocoa/PasteboardCocoa.mm b/Source/WebCore/platform/cocoa/PasteboardCocoa.mm >index 3e487ba0fd135aa265fdf522b0e512cec997cec5..250a2afea58e5f18f0e6d25dd0b6181bd4f6d524 100644 >--- a/Source/WebCore/platform/cocoa/PasteboardCocoa.mm >+++ b/Source/WebCore/platform/cocoa/PasteboardCocoa.mm >@@ -162,7 +162,7 @@ Pasteboard::FileContentState Pasteboard::fileContentState() > if (item.preferredPresentationStyle != PasteboardItemPresentationStyle::Unspecified) > return item.preferredPresentationStyle == PasteboardItemPresentationStyle::Attachment; > >- return !item.suggestedFileName.isEmpty() || item.isNonTextType; >+ return !item.suggestedFileName.isEmpty() || item.isNonTextType || item.containsFileURLAndFileUploadContent; > }); > } > #endif >diff --git a/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm b/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm >index b0491476393f03b0800d47099cffc3731b3dbcd4..58f0534abd4cbfae115eb129c53ed80d7af3f033 100644 >--- a/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm >+++ b/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm >@@ -154,6 +154,7 @@ PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index) > #if PASTEBOARD_SUPPORTS_PRESENTATION_STYLE_AND_TEAM_DATA > info.preferredPresentationStyle = pasteboardItemPresentationStyle(itemProvider.preferredPresentationStyle); > #endif >+ info.containsFileURLAndFileUploadContent = itemProvider.web_containsFileURLAndFileUploadContent; > info.suggestedFileName = itemProvider.suggestedName; > for (NSString *typeIdentifier in itemProvider.registeredTypeIdentifiers) { > CFStringRef cfTypeIdentifier = (CFStringRef)typeIdentifier; >@@ -531,6 +532,9 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o > BOOL ableToDetermineProtocolOfPasteboardURL = ![m_pasteboard isKindOfClass:[WebItemProviderPasteboard class]]; > if (ableToDetermineProtocolOfPasteboardURL && stringForType(kUTTypeURL).isEmpty()) > continue; >+ >+ if ([[m_pasteboard pasteboardTypes] containsObject:(__bridge NSString *)kUTTypeFileURL]) >+ continue; > } > domPasteboardTypes.add(WTFMove(domTypeAsString)); > } >diff --git a/Source/WebCore/platform/ios/WebItemProviderPasteboard.h b/Source/WebCore/platform/ios/WebItemProviderPasteboard.h >index 1f1af86fd9b0c86893e9ceef8f6d74f27b51df9f..e2a6c9a49eba6060d753430fd77c9abebf3e7a88 100644 >--- a/Source/WebCore/platform/ios/WebItemProviderPasteboard.h >+++ b/Source/WebCore/platform/ios/WebItemProviderPasteboard.h >@@ -37,6 +37,10 @@ typedef NS_ENUM(NSInteger, WebPreferredPresentationStyle) { > > NS_ASSUME_NONNULL_BEGIN > >+@interface NSItemProvider (WebCoreExtras) >+@property (nonatomic, readonly) BOOL web_containsFileURLAndFileUploadContent; >+@end >+ > /*! A WebItemProviderRegistrar encapsulates a single call to register something to an item provider. > @discussion Classes that implement this protocol each represent a different way of writing data to > an item provider. Some examples include setting a chunk of data corresponding to a type identifier, >diff --git a/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm b/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm >index 9fdf6eb4434a3e016b3e9e8a3988dc73d3a87ea0..c7b75a52d1438c89e5c2ff900893e3588b6eb55d 100644 >--- a/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm >+++ b/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm >@@ -53,6 +53,39 @@ typedef NSMutableDictionary<NSString *, NSURL *> TypeToFileURLMap; > using WebCore::Pasteboard; > using WebCore::PasteboardCustomData; > >+static BOOL typeConformsToTypes(NSString *type, NSArray *conformsToTypes) >+{ >+ for (NSString *conformsToType in conformsToTypes) { >+ if (UTTypeConformsTo((__bridge CFStringRef)type, (__bridge CFStringRef)conformsToType)) >+ return YES; >+ } >+ return NO; >+} >+ >+@implementation NSItemProvider (WebCoreExtras) >+ >+- (BOOL)web_containsFileURLAndFileUploadContent >+{ >+ BOOL containsFileURL = NO; >+ BOOL containsContentForFileUpload = NO; >+ for (NSString *identifier in self.registeredTypeIdentifiers) { >+ if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeFileURL)) { >+ containsFileURL = YES; >+ continue; >+ } >+ >+ if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeURL)) >+ continue; >+ >+ containsContentForFileUpload |= typeConformsToTypes(identifier, Pasteboard::supportedFileUploadPasteboardTypes()); >+ if (containsContentForFileUpload && containsFileURL) >+ return YES; >+ } >+ return NO; >+} >+ >+@end >+ > @interface WebItemProviderDataRegistrar : NSObject <WebItemProviderRegistrar> > - (instancetype)initWithData:(NSData *)data type:(NSString *)utiType; > @property (nonatomic, readonly) NSString *typeIdentifier; >@@ -342,8 +375,11 @@ - (instancetype)initWithItemProvider:(NSItemProvider *)itemProvider typesToLoad: > > - (BOOL)canBeRepresentedAsFileUpload > { >+ if ([_itemProvider web_containsFileURLAndFileUploadContent]) >+ return YES; >+ > #if PLATFORM(IOSMAC) >- return false; >+ return NO; > #else > return [_itemProvider preferredPresentationStyle] != UIPreferredPresentationStyleInline; > #endif >@@ -606,11 +642,11 @@ - (NSURL *)preferredFileUploadURLAtIndex:(NSUInteger)index fileType:(NSString ** > NSItemProvider *itemProvider = [result itemProvider]; > for (NSString *registeredTypeIdentifier in itemProvider.registeredTypeIdentifiers) { > // Search for the highest fidelity non-private type identifier we loaded from the item provider. >- if (!UTTypeIsDeclared((CFStringRef)registeredTypeIdentifier) && !UTTypeIsDynamic((CFStringRef)registeredTypeIdentifier)) >+ if (!UTTypeIsDeclared((__bridge CFStringRef)registeredTypeIdentifier) && !UTTypeIsDynamic((__bridge CFStringRef)registeredTypeIdentifier)) > continue; > > for (NSString *loadedTypeIdentifier in [result loadedTypeIdentifiers]) { >- if (!UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, (CFStringRef)loadedTypeIdentifier)) >+ if (!UTTypeConformsTo((__bridge CFStringRef)registeredTypeIdentifier, (__bridge CFStringRef)loadedTypeIdentifier)) > continue; > > if (outFileType) >@@ -632,16 +668,6 @@ - (NSArray<NSURL *> *)allDroppedFileURLs > return fileURLs; > } > >-static BOOL typeConformsToTypes(NSString *type, NSArray *conformsToTypes) >-{ >- // A type is considered appropriate to load if it conforms to one or more supported types. >- for (NSString *conformsToType in conformsToTypes) { >- if (UTTypeConformsTo((CFStringRef)type, (CFStringRef)conformsToType)) >- return YES; >- } >- return NO; >-} >- > - (NSInteger)numberOfFiles > { > NSArray *supportedFileTypes = Pasteboard::supportedFileUploadPasteboardTypes(); >@@ -688,16 +714,18 @@ static NSURL *linkTemporaryItemProviderFilesToDropStagingDirectory(NSURL *url, N > return [fileManager linkItemAtURL:url toURL:destination error:nil] ? destination : nil; > } > >-- (NSArray<NSString *> *)typeIdentifiersToLoadForRegisteredTypeIdentifiers:(NSArray<NSString *> *)registeredTypeIdentifiers >+- (NSArray<NSString *> *)typeIdentifiersToLoad:(NSItemProvider *)itemProvider > { > auto typesToLoad = adoptNS([[NSMutableOrderedSet alloc] init]); > NSString *highestFidelitySupportedType = nil; > NSString *highestFidelityContentType = nil; > >- BOOL containsFlatRTFD = [registeredTypeIdentifiers containsObject:(NSString *)kUTTypeFlatRTFD]; >+ NSArray<NSString *> *registeredTypeIdentifiers = itemProvider.registeredTypeIdentifiers; >+ BOOL containsFile = itemProvider.web_containsFileURLAndFileUploadContent; >+ BOOL containsFlatRTFD = [registeredTypeIdentifiers containsObject:(__bridge NSString *)kUTTypeFlatRTFD]; > // First, search for the highest fidelity supported type or the highest fidelity generic content type. > for (NSString *registeredTypeIdentifier in registeredTypeIdentifiers) { >- if (containsFlatRTFD && [registeredTypeIdentifier isEqualToString:(NSString *)kUTTypeRTFD]) { >+ if (containsFlatRTFD && [registeredTypeIdentifier isEqualToString:(__bridge NSString *)kUTTypeRTFD]) { > // In the case where attachments are enabled and we're accepting all types of content using attachment > // elements as a fallback representation, if the source writes attributed strings to the pasteboard with > // com.apple.rtfd at a higher fidelity than com.apple.flat-rtfd, we'll end up loading only com.apple.rtfd >@@ -707,6 +735,9 @@ - (NSArray<NSString *> *)typeIdentifiersToLoadForRegisteredTypeIdentifiers:(NSAr > continue; > } > >+ if (containsFile && UTTypeConformsTo((__bridge CFStringRef)registeredTypeIdentifier, kUTTypeURL)) >+ continue; >+ > if (!highestFidelitySupportedType && typeConformsToTypes(registeredTypeIdentifier, _supportedTypeIdentifiers.get())) > highestFidelitySupportedType = registeredTypeIdentifier; > >@@ -721,9 +752,9 @@ - (NSArray<NSString *> *)typeIdentifiersToLoadForRegisteredTypeIdentifiers:(NSAr > if ([registeredTypeIdentifier isEqualToString:highestFidelityContentType] > || [registeredTypeIdentifier isEqualToString:highestFidelitySupportedType] > || [registeredTypeIdentifier isEqualToString:customPasteboardDataUTI] >- || UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, kUTTypeURL) >- || UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, kUTTypeHTML) >- || UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, kUTTypePlainText)) >+ || (!containsFile && UTTypeConformsTo((__bridge CFStringRef)registeredTypeIdentifier, kUTTypeURL)) >+ || UTTypeConformsTo((__bridge CFStringRef)registeredTypeIdentifier, kUTTypeHTML) >+ || UTTypeConformsTo((__bridge CFStringRef)registeredTypeIdentifier, kUTTypePlainText)) > [typesToLoad addObject:registeredTypeIdentifier]; > } > >@@ -746,7 +777,7 @@ - (void)doAfterLoadingProvidedContentIntoFileURLs:(WebItemProviderFileLoadBlock) > BOOL foundAnyDataToLoad = NO; > RetainPtr<WebItemProviderPasteboard> protectedSelf = self; > for (NSItemProvider *itemProvider in _itemProviders.get()) { >- NSArray<NSString *> *typeIdentifiersToLoad = [protectedSelf typeIdentifiersToLoadForRegisteredTypeIdentifiers:itemProvider.registeredTypeIdentifiers]; >+ NSArray<NSString *> *typeIdentifiersToLoad = [protectedSelf typeIdentifiersToLoad:itemProvider]; > foundAnyDataToLoad |= typeIdentifiersToLoad.count; > [loadResults addObject:[WebItemProviderLoadResult loadResultWithItemProvider:itemProvider typesToLoad:typeIdentifiersToLoad]]; > } >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 1f4ad675b8f730f829b0c6fe7bafd81ed3f89a6c..70482b24e02f3c885b7c84cc53ec167d51fea741 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,20 @@ >+2018-12-02 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [iOSMac] Unable to upload non-image files using drag and drop in WKWebView >+ https://bugs.webkit.org/show_bug.cgi?id=192283 >+ <rdar://problem/46399461> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a new API test to check that an item provider which contains plain text data and a file URL (but is not >+ marked as an attachment) is still treated as an attachment upon drop. Furthermore, verify that "text/uri-list" >+ does not expose the actual file URL written to the item provider. >+ >+ Additionally, rebaseline an existing API test to remove an extraneous "text/uri-list" type that appears in >+ `DataTransfer.types`, but whose data is inaccessible via `getData` anyways. >+ >+ * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm: >+ > 2018-12-01 Jonathan Bedard <jbedard@apple.com> > > Unreviewed, rolling out r238764. >diff --git a/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm b/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm >index 29ef6747a3cfaf131c1904a973724bb78b1160c5..2c81e57b8b794dd920fe1e37564ac39ec09c1514 100644 >--- a/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm >+++ b/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm >@@ -1646,8 +1646,8 @@ TEST(DragAndDropTests, DataTransferGetDataWhenDroppingImageWithFileURL) > > // File URLs should never be exposed directly to web content, so DataTransfer.getData should return an empty string here. > checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{ >- @"dragover": @{ @"Files": @"", @"text/uri-list": @"" }, >- @"drop": @{ @"Files": @"", @"text/uri-list": @"" } >+ @"dragover": @{ @"Files": @"" }, >+ @"drop": @{ @"Files": @"" } > }); > } > >@@ -1772,6 +1772,29 @@ TEST(DragAndDropTests, DataTransferSuppressGetDataDueToPresenceOfTextFile) > EXPECT_WK_STREQ("('hello.txt', text/plain)", [webView stringByEvaluatingJavaScript:@"files.textContent"]); > } > >+TEST(DragAndDropTests, DataTransferExposePlainTextWithFileURLAsFile) >+{ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); >+ [webView synchronouslyLoadTestPageNamed:@"DataTransfer"]; >+ auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]); >+ >+ auto itemProvider = adoptNS([[NSItemProvider alloc] init]); >+ NSData *urlAsData = [@"file:///some/file/path.txt" dataUsingEncoding:NSUTF8StringEncoding]; >+ [itemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeFileURL withData:urlAsData]; >+ [itemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeURL withData:urlAsData]; >+ [itemProvider registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll]; >+ >+ [simulator setExternalItemProviders:@[ itemProvider.get() ]]; >+ [simulator runFrom:CGPointZero to:CGPointMake(50, 100)]; >+ >+ EXPECT_WK_STREQ("Files", [webView stringByEvaluatingJavaScript:@"types.textContent"]); >+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"textData.textContent"]); >+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]); >+ EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]); >+ EXPECT_WK_STREQ("(FILE, text/plain)", [webView stringByEvaluatingJavaScript:@"items.textContent"]); >+ EXPECT_WK_STREQ("('text.txt', text/plain)", [webView stringByEvaluatingJavaScript:@"files.textContent"]); >+} >+ > TEST(DragAndDropTests, DataTransferGetDataCannotReadPrivateArbitraryTypes) > { > auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
rniwa
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 192283
: 356350 |
356378