WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
WIP
wip181616.patch (text/plain), 19.47 KB, created by
Ryosuke Niwa
on 2018-01-20 02:05:01 PST
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Ryosuke Niwa
Created:
2018-01-20 02:05:01 PST
Size:
19.47 KB
patch
obsolete
>diff --git a/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm b/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm >index 80488a92289..f4daf19982c 100644 >--- a/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm >+++ b/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm >@@ -528,7 +528,15 @@ bool WebContentReader::readHTML(const String& string) > if (stringOmittingMicrosoftPrefix.isEmpty()) > return false; > >- addFragment(createFragmentFromMarkup(document, stringOmittingMicrosoftPrefix, emptyString(), DisallowScriptingAndPluginContent)); >+ String markup; >+ if (DeprecatedGlobalSettings::customPasteboardDataEnabled() && shouldSanitize()) { >+ markup = sanitizeMarkup(stringOmittingMicrosoftPrefix, std::function<void (DocumentFragment&)> { [] (DocumentFragment& fragment) { >+ removeSubresourceURLAttributes(fragment, [] (const URL& url ) { return shouldReplaceSubresourceURL(url); }); >+ } }); >+ } else >+ markup = stringOmittingMicrosoftPrefix; >+ >+ addFragment(createFragmentFromMarkup(document, markup, emptyString(), DisallowScriptingAndPluginContent)); > return true; > } > >@@ -538,9 +546,11 @@ bool WebContentMarkupReader::readHTML(const String& string) > return false; > > String rawHTML = stripMicrosoftPrefix(string); >- if (shouldSanitize()) >- markup = sanitizeMarkup(rawHTML); >- else >+ if (shouldSanitize()) { >+ markup = sanitizeMarkup(rawHTML, std::function<void (DocumentFragment&)> { [] (DocumentFragment& fragment) { >+ removeSubresourceURLAttributes(fragment, [] (const URL& url ) { return shouldReplaceSubresourceURL(url); }); >+ } }); >+ } else > markup = rawHTML; > > return !markup.isEmpty(); >diff --git a/Source/WebCore/editing/markup.cpp b/Source/WebCore/editing/markup.cpp >index 7b3b1931e40..ba175514ced 100644 >--- a/Source/WebCore/editing/markup.cpp >+++ b/Source/WebCore/editing/markup.cpp >@@ -72,6 +72,7 @@ > #include "TextIterator.h" > #include "TypedElementDescendantIterator.h" > #include "URL.h" >+#include "URLParser.h" > #include "VisibleSelection.h" > #include "VisibleUnits.h" > #include <wtf/StdLibExtras.h> >@@ -144,6 +145,30 @@ void replaceSubresourceURLs(Ref<DocumentFragment>&& fragment, HashMap<AtomicStri > change.apply(); > } > >+struct ElementAttribute { >+ Ref<Element> element; >+ QualifiedName attributeName; >+}; >+ >+void removeSubresourceURLAttributes(Ref<DocumentFragment>&& fragment, std::function<bool (const URL&)> shouldRemoveURL) >+{ >+ Vector<ElementAttribute> attributesToRemove; >+ for (auto& element : descendantsOfType<Element>(fragment)) { >+ if (!element.hasAttributes()) >+ continue; >+ for (const Attribute& attribute : element.attributesIterator()) { >+ // FIXME: This won't work for srcset. >+ if (element.attributeContainsURL(attribute) && !attribute.value().isEmpty()) { >+ URL url = URLParser { attribute.value() }.result(); >+ if (shouldRemoveURL(url)) >+ attributesToRemove.append({ element, attribute.name() }); >+ } >+ } >+ } >+ for (auto& item : attributesToRemove) >+ item.element->removeAttribute(item.attributeName); >+} >+ > std::unique_ptr<Page> createPageForSanitizingWebContent() > { > PageConfiguration pageConfiguration(createEmptyEditorClient(), SocketProvider::create(), LibWebRTCProvider::create(), CacheStorageProvider::create()); >@@ -172,7 +197,7 @@ std::unique_ptr<Page> createPageForSanitizingWebContent() > } > > >-String sanitizeMarkup(const String& rawHTML) >+String sanitizeMarkup(const String& rawHTML, std::optional<std::function<void (DocumentFragment&)>> fragmentSanitizer) > { > auto page = createPageForSanitizingWebContent(); > Document* stagingDocument = page->mainFrame().document(); >@@ -181,6 +206,10 @@ String sanitizeMarkup(const String& rawHTML) > ASSERT(bodyElement); > > auto fragment = createFragmentFromMarkup(*stagingDocument, rawHTML, emptyString(), DisallowScriptingAndPluginContent); >+ >+ if (fragmentSanitizer) >+ (*fragmentSanitizer)(fragment); >+ > bodyElement->appendChild(fragment.get()); > > auto range = Range::create(*stagingDocument); >diff --git a/Source/WebCore/editing/markup.h b/Source/WebCore/editing/markup.h >index 6a7f6fff2be..3b9e97db999 100644 >--- a/Source/WebCore/editing/markup.h >+++ b/Source/WebCore/editing/markup.h >@@ -29,6 +29,7 @@ > #include "FragmentScriptingPermission.h" > #include "HTMLInterchange.h" > #include <wtf/Forward.h> >+#include <wtf/Function.h> > #include <wtf/HashMap.h> > > namespace WebCore { >@@ -47,8 +48,10 @@ class QualifiedName; > class Range; > > void replaceSubresourceURLs(Ref<DocumentFragment>&&, HashMap<AtomicString, AtomicString>&&); >+void removeSubresourceURLAttributes(Ref<DocumentFragment>&&, std::function<bool (const URL&)> shouldRemoveURL); >+ > std::unique_ptr<Page> createPageForSanitizingWebContent(); >-String sanitizeMarkup(const String&); >+String sanitizeMarkup(const String&, std::optional<std::function<void (DocumentFragment&)>> fragmentSanitizer = std::nullopt); > > enum EChildrenOnly { IncludeNode, ChildrenOnly }; > enum EAbsoluteURLs { DoNotResolveURLs, ResolveAllURLs, ResolveNonLocalURLs }; >diff --git a/Source/WebCore/page/DeprecatedGlobalSettings.cpp b/Source/WebCore/page/DeprecatedGlobalSettings.cpp >index 05bb11df5b1..4bf20e7a2d0 100644 >--- a/Source/WebCore/page/DeprecatedGlobalSettings.cpp >+++ b/Source/WebCore/page/DeprecatedGlobalSettings.cpp >@@ -84,10 +84,16 @@ bool DeprecatedGlobalSettings::gShouldOptOutOfNetworkStateObservation = false; > bool DeprecatedGlobalSettings::gManageAudioSession = false; > bool DeprecatedGlobalSettings::gCustomPasteboardDataEnabled = false; > >+// FIXME: Replace these with a runtime enabled flag. > bool DeprecatedGlobalSettings::defaultCustomPasteboardDataEnabled() > { > if (!isInWebProcess()) > return false; >+ return defaultCustomPasteboardDataEnabledInWebKit(); >+} >+ >+bool DeprecatedGlobalSettings::defaultCustomPasteboardDataEnabledInWebKit() >+{ > #if PLATFORM(IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110300 > return IOSApplication::isMobileSafari() || dyld_get_program_sdk_version() >= DYLD_IOS_VERSION_11_3; > #elif PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 >diff --git a/Source/WebCore/page/DeprecatedGlobalSettings.h b/Source/WebCore/page/DeprecatedGlobalSettings.h >index 11ec7ec3456..1df1b36537c 100644 >--- a/Source/WebCore/page/DeprecatedGlobalSettings.h >+++ b/Source/WebCore/page/DeprecatedGlobalSettings.h >@@ -112,6 +112,7 @@ public: > static void setCustomPasteboardDataEnabled(bool enabled) { gCustomPasteboardDataEnabled = enabled; } > static bool customPasteboardDataEnabled() { return gCustomPasteboardDataEnabled; } > WEBCORE_EXPORT static bool defaultCustomPasteboardDataEnabled(); >+ WEBCORE_EXPORT static bool defaultCustomPasteboardDataEnabledInWebKit(); > > #if ENABLE(MEDIA_STREAM) > static bool mockCaptureDevicesEnabled(); >diff --git a/Source/WebKit/Shared/WebPreferences.yaml b/Source/WebKit/Shared/WebPreferences.yaml >index e8560ab2ae0..2600f5bdf30 100644 >--- a/Source/WebKit/Shared/WebPreferences.yaml >+++ b/Source/WebKit/Shared/WebPreferences.yaml >@@ -779,7 +779,7 @@ DataTransferItemsEnabled: > > CustomPasteboardDataEnabled: > type: bool >- defaultValue: WebCore::DeprecatedGlobalSettings::defaultCustomPasteboardDataEnabled() >+ defaultValue: WebCore::DeprecatedGlobalSettings::defaultCustomPasteboardDataEnabledInWebKit() > humanReadableName: "Custom pateboard data" > humanReadableDescription: "Enable custom clipboard types and better security model for clipboard API." > webcoreBinding: DeprecatedGlobalSettings >diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >index 3707e87854c..f722714bb3d 100644 >--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >@@ -575,6 +575,7 @@ > 9B62630C1F8C25C8007EE29B /* copy-url.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B62630B1F8C2510007EE29B /* copy-url.html */; }; > 9B7A37C41F8AEBA5004AA228 /* CopyURL.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */; }; > 9B7D740F1F8378770006C432 /* paste-rtfd.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B7D740E1F8377E60006C432 /* paste-rtfd.html */; }; >+ 9BCB7C2820130600003E7C0C /* PasteHTML.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BCB7C2620130600003E7C0C /* PasteHTML.mm */; }; > 9BD4239A1E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BD423991E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm */; }; > 9BD4239C1E04C01C00200395 /* chinese-character-with-image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9BD4239B1E04BFD000200395 /* chinese-character-with-image.html */; }; > 9BD5111C1FE8E11600D2B630 /* AccessingPastedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BD5111B1FE8E11600D2B630 /* AccessingPastedImage.mm */; }; >@@ -1585,6 +1586,7 @@ > 9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderScrollingPosition.mm; sourceTree = "<group>"; }; > 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CopyURL.mm; sourceTree = "<group>"; }; > 9B7D740E1F8377E60006C432 /* paste-rtfd.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "paste-rtfd.html"; sourceTree = "<group>"; }; >+ 9BCB7C2620130600003E7C0C /* PasteHTML.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PasteHTML.mm; sourceTree = "<group>"; }; > 9BD423991E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AttributedSubstringForProposedRangeWithImage.mm; sourceTree = "<group>"; }; > 9BD4239B1E04BFD000200395 /* chinese-character-with-image.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "chinese-character-with-image.html"; sourceTree = "<group>"; }; > 9BD5111B1FE8E11600D2B630 /* AccessingPastedImage.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AccessingPastedImage.mm; sourceTree = "<group>"; }; >@@ -2110,6 +2112,7 @@ > CEBCA12E1E3A660100C73293 /* OverrideContentSecurityPolicy.mm */, > 9BDCCD851F7D0B0700009A18 /* PasteImage.mm */, > 9BDD95561F83683600D20C60 /* PasteRTFD.mm */, >+ 9BCB7C2620130600003E7C0C /* PasteHTML.mm */, > 9B2346411F943A2400DB1D23 /* PasteWebArchive.mm */, > 3FCC4FE41EC4E8520076E37C /* PictureInPictureDelegate.mm */, > 83BAEE8C1EF4625500DDE894 /* PluginLoadClientPolicies.mm */, >@@ -3389,6 +3392,7 @@ > 7CCE7EBB1A411A7E00447C4C /* DOMHTMLTableCellCellAbove.mm in Sources */, > 2D51A0C71C8BF00C00765C45 /* DOMHTMLVideoElementWrapper.mm in Sources */, > 46397B951DC2C850009A78AE /* DOMNode.mm in Sources */, >+ 9BCB7C2820130600003E7C0C /* PasteHTML.mm in Sources */, > 7CCE7EBC1A411A7E00447C4C /* DOMNodeFromJSObject.mm in Sources */, > 7CCE7EBD1A411A7E00447C4C /* DOMRangeOfString.mm in Sources */, > 7CCE7EEC1A411AE600447C4C /* DOMWindowExtensionBasic.cpp in Sources */, >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteHTML.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteHTML.mm >new file mode 100644 >index 00000000000..44523edad40 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteHTML.mm >@@ -0,0 +1,159 @@ >+/* >+ * Copyright (C) 2017-2018 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. >+ */ >+ >+#include "config.h" >+ >+#if WK_API_ENABLED && PLATFORM(COCOA) >+ >+#import "PlatformUtilities.h" >+#import "TestWKWebView.h" >+#import <WebCore/LegacyNSPasteboardTypes.h> >+#import <WebKit/WKPreferencesPrivate.h> >+#import <WebKit/WKPreferencesRefPrivate.h> >+#import <WebKit/WKWebViewConfigurationPrivate.h> >+#import <wtf/RetainPtr.h> >+#import <wtf/text/WTFString.h> >+ >+#if PLATFORM(IOS) >+#include <MobileCoreServices/MobileCoreServices.h> >+#endif >+ >+@interface WKWebView () >+- (void)paste:(id)sender; >+@end >+ >+#if PLATFORM(MAC) >+void writeHTMLToPasteboard(NSString *html) >+{ >+ [[NSPasteboard generalPasteboard] declareTypes:@[WebCore::legacyHTMLPasteboardType()] owner:nil]; >+ [[NSPasteboard generalPasteboard] setString:html forType:WebCore::legacyHTMLPasteboardType()]; >+} >+#else >+void writeHTMLToPasteboard(NSString *html) >+{ >+ [[UIPasteboard generalPasteboard] setItems:@[@{ (NSString *)kUTTypeHTML : html}]]; >+} >+#endif >+ >+static RetainPtr<TestWKWebView> createWebViewWithCustomPasteboardDataSetting(bool enabled) >+{ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]); >+ auto preferences = (WKPreferencesRef)[[webView configuration] preferences]; >+ WKPreferencesSetDataTransferItemsEnabled(preferences, true); >+ WKPreferencesSetCustomPasteboardDataEnabled(preferences, enabled); >+ return webView; >+} >+ >+TEST(PasteHTML, ExposesHTMLTypeInDataTransfer) >+{ >+ auto webView = createWebViewWithCustomPasteboardDataSetting(true); >+ [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; >+ >+ writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><p><u>hello</u>, world</p></body></html>"); >+ [webView paste:nil]; >+ >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"]); >+ [webView stringByEvaluatingJavaScript:@"editor.innerHTML = clipboardData.values[0]; editor.focus()"]; >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue); >+ [webView stringByEvaluatingJavaScript:@"getSelection().modify('move', 'forward', 'lineboundary')"]; >+ EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue); >+ EXPECT_WK_STREQ("hello, world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]); >+} >+ >+TEST(PasteHTML, SanitizesHTML) >+{ >+ auto webView = createWebViewWithCustomPasteboardDataSetting(true); >+ [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; >+ >+ writeHTMLToPasteboard(@"<!DOCTYPE html><meta content=\"secret\"><b onmouseover=\"dangerousCode()\">hello</b>" >+ "<!-- secret-->, world<script>dangerousCode()</script>';"); >+ [webView paste:nil]; >+ >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue); >+ EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue); >+ EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('dangerousCode')"].boolValue); >+} >+ >+TEST(PasteHTML, DoesNotSanitizeHTMLWhenCustomPasteboardDataIsDisabled) >+{ >+ auto webView = createWebViewWithCustomPasteboardDataSetting(false); >+ [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; >+ >+ writeHTMLToPasteboard(@"<!DOCTYPE html><meta content=\"secret\"><b onmouseover=\"dangerousCode()\">hello</b>" >+ "<!-- secret-->, world<script>dangerousCode()</script>';"); >+ [webView paste:nil]; >+ >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('dangerousCode')"].boolValue); >+} >+ >+TEST(PasteHTML, StripsHTTPURLs) >+{ >+ auto webView = createWebViewWithCustomPasteboardDataSetting(true); >+ [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; >+ >+ writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><a alt='hello' href='file:///private/var/folders/secret/files/'>world</a>"); >+ [webView paste:nil]; >+ >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue); >+ EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue); >+} >+ >+TEST(PasteHTML, DoesNotStripHTTPURLsWhenCustomPasteboardDataIsDisabled) >+{ >+ auto webView = createWebViewWithCustomPasteboardDataSetting(false); >+ [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; >+ >+ writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><a alt='hello' href='file:///private/var/folders/secret/files/'>world</a>"); >+ [webView paste:nil]; >+ >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('secret')"].boolValue); >+} >+ >+TEST(PasteHTML, KeepsHTTPURLs) >+{ >+ auto webView = createWebViewWithCustomPasteboardDataSetting(true); >+ [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; >+ >+ writeHTMLToPasteboard(@"<!DOCTYPE html><html><body><a title='hello' href='https://svn.webkit.org/repository/webkit/trunk/LayoutTests/editing/resources/abe.png'>world</a>"); >+ [webView paste:nil]; >+ >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('hello')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('world')"].boolValue); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.values[0].includes('abe.png')"].boolValue); >+} >+ >+#endif // WK_API_ENABLED && PLATFORM(COCOA)
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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 181616
:
331838
|
331895
|
331897
|
331940
|
331949