Changeset 223440 in webkit
- Timestamp:
- Oct 16, 2017 2:44:28 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 15 added
- 3 deleted
- 37 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r223428 r223440 1 2017-10-15 Ryosuke Niwa <rniwa@webkit.org> 2 3 Cannot access images included in the content pasted from Microsoft Word 4 https://bugs.webkit.org/show_bug.cgi?id=124391 5 <rdar://problem/26862741> 6 7 Reviewed by Antti Koivisto. 8 9 Added tests for copying & pasting and dragging & dropping HTML contents. 10 11 * TestExpectations: 12 * editing/pasteboard/data-transfer-get-data-on-drop-rich-text-expected.txt: Rebaselined. 13 * editing/pasteboard/data-transfer-get-data-on-paste-rich-text-expected.txt: Ditto. 14 * editing/pasteboard/data-transfer-get-data-on-paste-rich-text.html: Modified the test to strip away platform specific 15 inline style properties. 16 * editing/pasteboard/data-transfer-get-data-on-pasting-html-uses-blob-url-expected.txt: Added. 17 * editing/pasteboard/data-transfer-get-data-on-pasting-html-uses-blob-url.html: Added. 18 * editing/pasteboard/data-transfer-set-data-sanitizes-html-when-copying-expected.txt: Added. 19 * editing/pasteboard/data-transfer-set-data-sanitizes-html-when-copying-in-null-origin-expected.txt: Added. 20 * editing/pasteboard/data-transfer-set-data-sanitizes-html-when-copying-in-null-origin.html: Added. 21 * editing/pasteboard/data-transfer-set-data-sanitizes-html-when-copying.html: Added. 22 * editing/pasteboard/data-transfer-set-data-sanitizes-html-when-dragging-in-null-origin-expected.txt: Added. 23 * editing/pasteboard/data-transfer-set-data-sanitizes-html-when-dragging-in-null-origin.html: Added. 24 * editing/pasteboard/data-transfer-set-data-sanitizes-url-when-dragging-in-null-origin.html: Removed the superflous 25 call to setTimeout that was errornously added during debugging. Also updated the test to not claim all URL and 26 HTML values are read in the same origin, and updated the assertion for cross-origin case as it's now sanitized. 27 * editing/pasteboard/onpaste-text-html-expected.txt: Rebaselined. The order of CSS properties have changed. 28 * http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html-expected.txt: Added. 29 * http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html.html: Added. 30 * http/tests/security/clipboard/copy-paste-url-across-origin-sanitizes-url.html: 31 * http/tests/security/clipboard/resources/copy-html.html: Added. 32 * http/tests/security/clipboard/resources/copy-url.html: Renamed from copy.html. 33 * platform/ios-wk2/editing/pasteboard/data-transfer-get-data-on-paste-rich-text-expected.txt: Remoevd. 34 * platform/ios-wk1/editing/pasteboard/data-transfer-get-data-on-paste-rich-text-expected.txt: Remoevd. 35 * platform/mac-wk1/TestExpectations: 36 1 37 2017-10-16 Ross Kirsling <ross.kirsling@sony.com> 2 38 -
trunk/LayoutTests/TestExpectations
r223414 r223440 75 75 editing/pasteboard/data-transfer-get-data-on-drop-url.html [ Skip ] 76 76 editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Skip ] 77 editing/pasteboard/data-transfer-set-data-sanitize-html-when-dragging-in-null-origin.html [ Skip ] 77 78 editing/pasteboard/data-transfer-set-data-sanitize-url-when-dragging-in-null-origin.html [ Skip ] 79 78 80 editing/pasteboard/drag-end-crash-accessing-item-list.html [ Skip ] 79 81 editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Skip ] -
trunk/LayoutTests/editing/pasteboard/data-transfer-get-data-on-drop-rich-text-expected.txt
r222595 r223440 6 6 }, 7 7 "drop": { 8 "text/html": "<strong style=\"font- family: -apple-system; font-size: 150px; font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: nowrap; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; color: purple;\">Rich text</strong>",8 "text/html": "<strong style=\"font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-family: -apple-system; font-size: 150px; white-space: nowrap; color: purple;\">Rich text</strong>", 9 9 "text/plain": "Rich text" 10 10 } -
trunk/LayoutTests/editing/pasteboard/data-transfer-get-data-on-paste-rich-text-expected.txt
r222595 r223440 2 2 { 3 3 "paste": { 4 "text/html": "<span style=\" caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-family: -apple-system; font-size: 150px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: nowrap; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; display: inline !important; float: none;\">Rich text</span>",4 "text/html": "<span style=\"...\"\">Rich text</span>", 5 5 "text/plain": "Rich text" 6 6 } -
trunk/LayoutTests/editing/pasteboard/data-transfer-get-data-on-paste-rich-text.html
r222595 r223440 36 36 const eventData = {}; 37 37 for (const type of event.clipboardData.types) 38 eventData[type] = event.clipboardData.getData(type) ;38 eventData[type] = event.clipboardData.getData(type).replace(/style="[^"]+"/g, 'style="...""'); 39 39 result[event.type] = eventData; 40 40 output.textContent = JSON.stringify(result, null, " "); -
trunk/LayoutTests/editing/pasteboard/data-transfer-set-data-sanitize-url-when-dragging-in-null-origin-expected.txt
r223278 r223440 5 5 6 6 dragstart in the null origin document: 7 PASS url ReadInSameDocumentis "http://webkit.org/b/🤔?x=8 + 6"8 PASS html ReadInSameDocumentis "testing"9 PASS JSON.stringify(types InSameDocument) is "[\"text/uri-list\",\"text/html\"]"10 PASS JSON.stringify(items InSameDocument) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]"7 PASS url is "http://webkit.org/b/🤔?x=8 + 6" 8 PASS html is "testing" 9 PASS JSON.stringify(types) is "[\"text/uri-list\",\"text/html\"]" 10 PASS JSON.stringify(items) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]" 11 11 12 12 dragover in the null origin document: 13 PASS url ReadInSameDocumentis ""14 PASS html ReadInSameDocumentis ""15 PASS JSON.stringify(types InSameDocument) is "[\"text/uri-list\",\"text/html\"]"16 PASS JSON.stringify(items InSameDocument) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]"13 PASS url is "" 14 PASS html is "" 15 PASS JSON.stringify(types) is "[\"text/uri-list\",\"text/html\"]" 16 PASS JSON.stringify(items) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]" 17 17 18 18 drop in the null origin document: 19 PASS url ReadInSameDocumentis "http://webkit.org/b/🤔?x=8 + 6"20 PASS html ReadInSameDocumentis "testing"21 PASS JSON.stringify(types InSameDocument) is "[\"text/uri-list\",\"text/html\"]"22 PASS JSON.stringify(items InSameDocument) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]"19 PASS url is "http://webkit.org/b/🤔?x=8 + 6" 20 PASS html is "testing" 21 PASS JSON.stringify(types) is "[\"text/uri-list\",\"text/html\"]" 22 PASS JSON.stringify(items) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]" 23 23 24 24 dragstart in the null origin document: 25 PASS url ReadInSameDocumentis "http://webkit.org/b/🤔?x=8 + 6"26 PASS html ReadInSameDocumentis "testing"27 PASS JSON.stringify(types InSameDocument) is "[\"text/uri-list\",\"text/html\"]"28 PASS JSON.stringify(items InSameDocument) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]"25 PASS url is "http://webkit.org/b/🤔?x=8 + 6" 26 PASS html is "testing" 27 PASS JSON.stringify(types) is "[\"text/uri-list\",\"text/html\"]" 28 PASS JSON.stringify(items) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]" 29 29 30 30 dragover in the file URL document: 31 PASS url ReadInSameDocumentis ""32 PASS html ReadInSameDocumentis ""33 PASS JSON.stringify(types InSameDocument) is "[\"text/uri-list\",\"text/html\"]"34 PASS JSON.stringify(items InSameDocument) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]"31 PASS url is "" 32 PASS html is "" 33 PASS JSON.stringify(types) is "[\"text/uri-list\",\"text/html\"]" 34 PASS JSON.stringify(items) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]" 35 35 36 36 drop in the file URL document: 37 PASS url ReadInSameDocumentis "http://webkit.org/b/%F0%9F%A4%94?x=8%20+%206"38 PASS html ReadInSameDocument is "testing"39 PASS JSON.stringify(types InSameDocument) is "[\"text/uri-list\",\"text/html\"]"40 PASS JSON.stringify(items InSameDocument) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]"37 PASS url is "http://webkit.org/b/%F0%9F%A4%94?x=8%20+%206" 38 PASS html.includes("testing") is true 39 PASS JSON.stringify(types) is "[\"text/uri-list\",\"text/html\"]" 40 PASS JSON.stringify(items) is "[{\"kind\":\"string\",\"type\":\"text/uri-list\"},{\"kind\":\"string\",\"type\":\"text/html\"}]" 41 41 PASS successfullyParsed is true 42 42 -
trunk/LayoutTests/editing/pasteboard/data-transfer-set-data-sanitize-url-when-dragging-in-null-origin.html
r223278 r223440 84 84 switch (kind) { 85 85 case 'dragstart': 86 url ReadInSameDocument= event.data.url;87 shouldBeEqualToString('url ReadInSameDocument', originalURL);88 html ReadInSameDocument= event.data.html;89 shouldBeEqualToString('html ReadInSameDocument', "testing");90 types InSameDocument= event.data.types;91 shouldBeEqualToString('JSON.stringify(types InSameDocument)', '["text/uri-list","text/html"]');92 items InSameDocument= event.data.items;93 shouldBeEqualToString('JSON.stringify(items InSameDocument)', '[{"kind":"string","type":"text/uri-list"},{"kind":"string","type":"text/html"}]');86 url = event.data.url; 87 shouldBeEqualToString('url', originalURL); 88 html = event.data.html; 89 shouldBeEqualToString('html', "testing"); 90 types = event.data.types; 91 shouldBeEqualToString('JSON.stringify(types)', '["text/uri-list","text/html"]'); 92 items = event.data.items; 93 shouldBeEqualToString('JSON.stringify(items)', '[{"kind":"string","type":"text/uri-list"},{"kind":"string","type":"text/html"}]'); 94 94 break; 95 95 case 'dragover': 96 url ReadInSameDocument= event.data.url;97 shouldBeEqualToString('url ReadInSameDocument', '');98 html ReadInSameDocument= event.data.html;99 shouldBeEqualToString('html ReadInSameDocument', '');100 types InSameDocument= event.data.types;101 shouldBeEqualToString('JSON.stringify(types InSameDocument)', '["text/uri-list","text/html"]');102 items InSameDocument= event.data.items;103 shouldBeEqualToString('JSON.stringify(items InSameDocument)', '[{"kind":"string","type":"text/uri-list"},{"kind":"string","type":"text/html"}]');96 url = event.data.url; 97 shouldBeEqualToString('url', ''); 98 html = event.data.html; 99 shouldBeEqualToString('html', ''); 100 types = event.data.types; 101 shouldBeEqualToString('JSON.stringify(types)', '["text/uri-list","text/html"]'); 102 items = event.data.items; 103 shouldBeEqualToString('JSON.stringify(items)', '[{"kind":"string","type":"text/uri-list"},{"kind":"string","type":"text/html"}]'); 104 104 break; 105 105 case 'drop': 106 urlReadInSameDocument = event.data.url; 107 shouldBeEqualToString('urlReadInSameDocument', event.data.documentLabel.includes('null') ? originalURL : (new URL(originalURL)).href); 108 htmlReadInSameDocument = event.data.html; 109 shouldBeEqualToString('htmlReadInSameDocument', "testing"); 110 typesInSameDocument = event.data.types; 111 shouldBeEqualToString('JSON.stringify(typesInSameDocument)', '["text/uri-list","text/html"]'); 112 itemsInSameDocument = event.data.items; 113 shouldBeEqualToString('JSON.stringify(itemsInSameDocument)', '[{"kind":"string","type":"text/uri-list"},{"kind":"string","type":"text/html"}]'); 106 url = event.data.url; 107 isSameOrigin = event.data.documentLabel.includes('null'); 108 shouldBeEqualToString('url', isSameOrigin ? originalURL : (new URL(originalURL)).href); 109 html = event.data.html; 110 if (isSameOrigin) 111 shouldBeEqualToString('html', 'testing'); 112 else 113 shouldBeTrue('html.includes("testing")'); 114 types = event.data.types; 115 shouldBeEqualToString('JSON.stringify(types)', '["text/uri-list","text/html"]'); 116 items = event.data.items; 117 shouldBeEqualToString('JSON.stringify(items)', '[{"kind":"string","type":"text/uri-list"},{"kind":"string","type":"text/html"}]'); 114 118 if (!event.data.documentLabel.includes('null')) { 115 119 document.getElementById('container').remove(); … … 159 163 } 160 164 161 setTimeout(finishJSTest, 3000);162 163 165 </script> 164 166 <script src="../../resources/js-test-post.js"></script> -
trunk/LayoutTests/editing/pasteboard/onpaste-text-html-expected.txt
r220706 r223440 1 1 CONSOLE MESSAGE: line 21: text/plain: This test verifies that we can get text/html from the clipboard during an onpaste event. 2 CONSOLE MESSAGE: line 23: text/html: <span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-s ize: medium; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; display: inline !important; float: none;">This test verifies that we can get text/html from the clipboard during an onpaste event.<span class="Apple-converted-space"> </span></span>2 CONSOLE MESSAGE: line 23: text/html: <span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; float: none; display: inline !important;">This test verifies that we can get text/html from the clipboard during an onpaste event.<span class="Apple-converted-space"> </span></span> 3 3 This test verifies that we can get text/html from the clipboard during an onpaste event. This test requires DRT. 4 4 Paste content in this div.This test verifies that we can get text/html from the clipboard during an onpaste event. -
trunk/LayoutTests/fast/events/ondrop-text-html-expected.txt
r220706 r223440 1 1 CONSOLE MESSAGE: line 21: text/plain: This test verifies that we can get text/html from the drag object during an ondrop event. 2 CONSOLE MESSAGE: line 23: text/html: <span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-s ize: medium; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; display: inline !important; float: none;">This test verifies that we can get text/html from the drag object during an ondrop event.<span class="Apple-converted-space"> </span></span>2 CONSOLE MESSAGE: line 23: text/html: <span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; float: none; display: inline !important;">This test verifies that we can get text/html from the drag object during an ondrop event.<span class="Apple-converted-space"> </span></span> 3 3 This test verifies that we can get text/html from the drag object during an ondrop event. This test requires DRT. 4 4 PASS -
trunk/LayoutTests/http/tests/security/clipboard/copy-paste-url-across-origin-sanitizes-url.html
r223195 r223440 34 34 35 35 </script> 36 <iframe src="http://localhost:8000/security/clipboard/resources/copy .html"></iframe>36 <iframe src="http://localhost:8000/security/clipboard/resources/copy-url.html"></iframe> 37 37 <div id="destination" onpaste="doPaste(event)" contenteditable>3. Paste here</div> 38 38 <script src="/resources/js-test-post.js"></script> -
trunk/LayoutTests/platform/mac-wk1/TestExpectations
r223413 r223440 13 13 editing/pasteboard/data-transfer-get-data-on-drop-url.html [ Pass ] 14 14 editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Pass ] 15 editing/pasteboard/data-transfer-set-data-sanitize-html-when-dragging-in-null-origin.html [ Pass ] 15 16 editing/pasteboard/data-transfer-set-data-sanitize-url-when-dragging-in-null-origin.html [ Pass ] 16 17 editing/pasteboard/drag-end-crash-accessing-item-list.html [ Pass ] -
trunk/LayoutTests/platform/win/TestExpectations
r223407 r223440 1136 1136 1137 1137 # Custom pasteboard data is not supported on Windows. 1138 http/tests/security/clipboard/copy-paste-url-across-origin-sanitizes-url.html 1138 http/tests/security/clipboard/copy-paste-url-across-origin-sanitizes-url.html [ Skip ] 1139 http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html.html [ Skip ] 1139 1140 1140 1141 webkit.org/b/140783 [ Release ] editing/pasteboard/copy-standalone-image.html [ Failure ImageOnlyFailure ] -
trunk/Source/WebCore/ChangeLog
r223438 r223440 1 2017-10-15 Ryosuke Niwa <rniwa@webkit.org> 2 3 Cannot access images included in the content pasted from Microsoft Word 4 https://bugs.webkit.org/show_bug.cgi?id=124391 5 <rdar://problem/26862741> 6 7 Reviewed by Antti Koivisto. 8 9 The bug is caused by the fact Microsoft Word generates HTML content which references an image using file URL. 10 Because the websites don't have access to arbtirary file URLs, this prevents editors such as TinyMCE to save 11 those images. 12 13 This patch fixes the problem by converting file URLs for images and all other subresources in the web archive 14 generated by Microsoft Word by blob URLs like r222839 for RTF/RTFD and r222119 for images. 15 16 To avoid revealing privacy sensitive information such as the absolute local file path to the user's home directory 17 Microsoft Word and other applications in the system includes in the web archive placed in the system pasteboard, 18 this patch also introduces the mechanism to sanitize when the HTML content is read by DataTransfer's getData. 19 20 This patch also introduces the sanitization for when writing HTML into the pasteboard since other applications 21 in the syste which is capable to processing web archives are not necessarily equipped to pretect itself and the 22 rest of the system from potentially dangerous JavaScript included in the web archive placed in the system pasteboard. 23 24 Finally, this patch expands the list of clipboard types that are exposed as "text/html" to the Web platform by 25 adding the capability to convert RTF, RTFD, and web archive into HTML markup by introducing WebContentMarkupReader, 26 a new subclass of PasteboardWebContentReader which creates a HTML markup instead of a document fragment. Most of 27 the sanitization process happens in this new class, and will be expanded to WebContentReader to make pasting safer. 28 29 Tests: editing/pasteboard/data-transfer-get-data-on-pasting-html-uses-blob-url.html 30 editing/pasteboard/data-transfer-set-data-sanitizes-html-when-copying-in-null-origin.html 31 editing/pasteboard/data-transfer-set-data-sanitizes-html-when-copying.html 32 editing/pasteboard/data-transfer-set-data-sanitlize-html-when-dragging-in-null-origin.html 33 http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html.html 34 CopyHTML.Sanitizes 35 DataInteractionTests.DataTransferSanitizeHTML 36 PasteRTF.ExposesHTMLTypeInDataTransfer 37 PasteRTFD.ExposesHTMLTypeInDataTransfer 38 PasteRTFD.ImageElementUsesBlobURLInHTML 39 PasteWebArchive.ExposesHTMLTypeInDataTransfer 40 41 * dom/DataTransfer.cpp: 42 (WebCore::originIdentifierForDocument): Moved to Document::originIdentifierForPasteboard. 43 (WebCore::DataTransfer::createForCopyAndPaste): 44 (WebCore::DataTransfer::getDataForItem const): Use WebContentMarkupReader read HTMl content so that we can read 45 web arhive, RTF, and RTFD as text/html. 46 (WebCore::DataTransfer::getData const): 47 (WebCore::DataTransfer::setData): 48 (WebCore::DataTransfer::setDataFromItemList): Sanitize the HTML before placing into the system pasteboard. 49 (WebCore::DataTransfer::createForDragStartEvent): 50 (WebCore::DataTransfer::createForDrop): 51 (WebCore::DataTransfer::createForUpdatingDropTarget): 52 * dom/DataTransfer.h: 53 * dom/DataTransfer.idl: 54 * dom/DataTransferItem.cpp: 55 (WebCore::DataTransferItem::getAsString const): 56 * dom/Document.cpp: 57 (WebCore::Document::originIdentifierForPasteboard): Renamed from uniqueIdentifier. Moved the code to use the origin 58 string and then falling back to the UUID here from originIdentifierForDocument in DataTransfer.cpp. 59 * dom/Document.h: 60 * editing/WebContentReader.cpp: 61 (WebCore::WebContentMarkupReader::shouldSanitize const): Added. 62 * editing/WebContentReader.h: 63 (WebCore::WebContentMarkupReader): Added. 64 (WebCore::WebContentMarkupReader::WebContentMarkupReader): 65 * editing/cocoa/WebContentReaderCocoa.mm: 66 (WebCore::createFragmentFromWebArchive): Extracted out of WebContentReader::readWebArchive to share code. 67 (WebCore::WebContentReader::readWebArchive): 68 (WebCore::WebContentMarkupReader::readWebArchive): Added. Reads the web archive, replace all subresource URLs by 69 blob URLs, and re-generate the markup using our copy & paste code. The last step is requied to strip away any privacy 70 sensitive information as well as potentially dangerous JavaScript code. 71 (WebCore::stripMicrosoftPrefix): Extracted out of WebContentReader::readHTML to share code. 72 (WebCore::WebContentReader::readHTML): 73 (WebCore::WebContentMarkupReader::readHTML): Added. Only sanitize the markup when it comes from a different origin. 74 (WebCore::WebContentReader::readRTFD): Added a nullity check for frame.document(). 75 (WebCore::WebContentMarkupReader::readRTFD): Added. 76 (WebCore::WebContentMarkupReader::readRTF): Added. 77 * editing/markup.h: 78 * editing/markup.cpp: 79 (WebCore::createPageForSanitizingWebContent): Added. 80 (WebCore::sanitizeMarkup): Added. This function "pastes" the markup into a new isolated document then reserializes 81 using our serialization code for copy. It strips away all invisible information such as comments, and strips away 82 event handlers and script elements to remove potentially dangerous scripts. 83 * platform/Pasteboard.h: 84 * platform/ios/PasteboardIOS.mm: 85 (WebCore::Pasteboard::readPasteboardWebContentDataForType): Now that this code can be called by DataTransfer, added 86 the checks for the change count to make sure we stop letting web content read if the pasteboard had been changed by 87 some other applications. To do this, turned this function into a member of Pasteboard. Also changed the return type 88 to an enum with tri-state to exist the loop early in the call sites. 89 (WebCore::Pasteboard::read): 90 (WebCore::Pasteboard::readRespectingUTIFidelities): 91 * platform/ios/PlatformPasteboardIOS.mm: 92 (WebCore::safeTypeForDOMToReadAndWriteForPlatformType): Treat RTF, RTFD, and web archive as HTML. 93 * platform/mac/PasteboardMac.mm: 94 (WebCore::Pasteboard::read): Add the change count checks now that this code can be called by DataTransfer. 95 * platform/mac/PlatformPasteboardMac.mm: 96 (WebCore::safeTypeForDOMToReadAndWriteForPlatformType): Treat RTF, RTFD, and web archive as HTML. 97 1 98 2017-10-16 Ryan Haddad <ryanhaddad@apple.com> 2 99 -
trunk/Source/WebCore/dom/DataTransfer.cpp
r223340 r223440 31 31 #include "DataTransferItem.h" 32 32 #include "DataTransferItemList.h" 33 #include "DocumentFragment.h" 33 34 #include "DragData.h" 34 35 #include "Editor.h" … … 43 44 #include "StaticPasteboard.h" 44 45 #include "URLParser.h" 46 #include "WebContentReader.h" 45 47 #include "WebCorePasteboardFileReader.h" 48 #include "markup.h" 46 49 47 50 namespace WebCore { … … 79 82 } 80 83 81 static String originIdentifierForDocument(Document& document)82 {83 auto origin = document.securityOrigin().toString();84 if (origin == "null")85 return document.uniqueIdentifier();86 return origin;87 }88 89 84 Ref<DataTransfer> DataTransfer::createForCopyAndPaste(Document& document, StoreMode storeMode, std::unique_ptr<Pasteboard>&& pasteboard) 90 85 { 91 86 auto dataTransfer = adoptRef(*new DataTransfer(storeMode, WTFMove(pasteboard))); 92 dataTransfer->m_originIdentifier = originIdentifierForDocument(document);87 dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard(); 93 88 return dataTransfer; 94 89 } … … 147 142 } 148 143 149 String DataTransfer::getDataForItem( const String& type) const144 String DataTransfer::getDataForItem(Document& document, const String& type) const 150 145 { 151 146 if (!canReadData()) … … 165 160 return m_pasteboard->readString(lowercaseType); 166 161 167 bool isSameOrigin = false; 168 if (is<StaticPasteboard>(*m_pasteboard)) { 169 // StaticPasteboard is only used to stage data written by websites before being committed to the system pasteboard. 170 isSameOrigin = true; 171 } else if (!m_originIdentifier.isNull()) { 172 String originOfPasteboard = m_pasteboard->readOrigin(); 173 isSameOrigin = m_originIdentifier == originOfPasteboard; 174 } 175 176 if (!isSameOrigin) { 177 if (!Pasteboard::isSafeTypeForDOMToReadAndWrite(lowercaseType)) 162 // StaticPasteboard is only used to stage data written by websites before being committed to the system pasteboard. 163 bool isSameOrigin = is<StaticPasteboard>(*m_pasteboard) || (!m_originIdentifier.isNull() && m_originIdentifier == m_pasteboard->readOrigin()); 164 if (isSameOrigin) { 165 String value = m_pasteboard->readStringInCustomData(lowercaseType); 166 if (!value.isNull()) 167 return value; 168 } 169 if (!Pasteboard::isSafeTypeForDOMToReadAndWrite(lowercaseType)) 170 return { }; 171 172 if (!is<StaticPasteboard>(*m_pasteboard) && type == "text/html") { 173 if (!document.frame()) 178 174 return { }; 179 return m_pasteboard->readString(lowercaseType); 180 } 181 182 String value = m_pasteboard->readStringInCustomData(lowercaseType); 183 if (value.isNull() && Pasteboard::isSafeTypeForDOMToReadAndWrite(lowercaseType)) 184 value = m_pasteboard->readString(lowercaseType); 185 return value; 186 } 187 188 String DataTransfer::getData(const String& type) const 189 { 190 return getDataForItem(normalizeType(type)); 175 WebContentMarkupReader reader { *document.frame() }; 176 m_pasteboard->read(reader); 177 return reader.markup; 178 } 179 180 return m_pasteboard->readString(type); 181 } 182 183 String DataTransfer::getData(Document& document, const String& type) const 184 { 185 return getDataForItem(document, normalizeType(type)); 191 186 } 192 187 … … 223 218 224 219 String sanitizedData; 225 if (type == "text/uri-list") { 220 if (type == "text/html") 221 sanitizedData = sanitizeMarkup(data); 222 else if (type == "text/uri-list") { 226 223 auto url = URLParser(data).result(); 227 224 if (url.isValid()) 228 225 sanitizedData = url.string(); 229 } else if (type == "text/plain" || type == "text/html")226 } else if (type == "text/plain") 230 227 sanitizedData = data; // Nothing to sanitize. 231 228 … … 431 428 { 432 429 auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, std::make_unique<StaticPasteboard>(), Type::DragAndDropData)); 433 dataTransfer->m_originIdentifier = originIdentifierForDocument(document);430 dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard(); 434 431 return dataTransfer; 435 432 } … … 439 436 auto dataTransfer = adoptRef(*new DataTransfer(DataTransfer::StoreMode::Readonly, WTFMove(pasteboard), draggingFiles ? Type::DragAndDropFiles : Type::DragAndDropData)); 440 437 dataTransfer->setSourceOperation(sourceOperation); 441 dataTransfer->m_originIdentifier = originIdentifierForDocument(document);438 dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard(); 442 439 return dataTransfer; 443 440 } … … 454 451 auto dataTransfer = adoptRef(*new DataTransfer(mode, WTFMove(pasteboard), draggingFiles ? Type::DragAndDropFiles : Type::DragAndDropData)); 455 452 dataTransfer->setSourceOperation(sourceOperation); 456 dataTransfer->m_originIdentifier = originIdentifierForDocument(document);453 dataTransfer->m_originIdentifier = document.originIdentifierForPasteboard(); 457 454 return dataTransfer; 458 455 } -
trunk/Source/WebCore/dom/DataTransfer.h
r223340 r223440 65 65 void clearData(const String& type = String()); 66 66 67 String getData( const String& type) const;68 String getDataForItem( const String& type) const;67 String getData(Document&, const String& type) const; 68 String getDataForItem(Document&, const String& type) const; 69 69 70 70 void setData(const String& type, const String& data); -
trunk/Source/WebCore/dom/DataTransfer.idl
r220627 r223440 39 39 40 40 readonly attribute FrozenArray<DOMString> types; 41 DOMString getData(DOMString format);41 [CallWith=Document] DOMString getData(DOMString format); 42 42 void setData(DOMString format, DOMString data); 43 43 void clearData(optional DOMString format); -
trunk/Source/WebCore/dom/DataTransferItem.cpp
r223034 r223440 35 35 #include "DOMFileSystem.h" 36 36 #include "DataTransferItemList.h" 37 #include "Document.h" 37 38 #include "File.h" 38 39 #include "FileSystem.h" … … 86 87 } 87 88 88 void DataTransferItem::getAsString( ScriptExecutionContext& context, RefPtr<StringCallback>&& callback) const89 void DataTransferItem::getAsString(Document& document, RefPtr<StringCallback>&& callback) const 89 90 { 90 91 if (!callback || !m_list || m_file) … … 96 97 97 98 // FIXME: Make this async. 98 callback->scheduleCallback( context, dataTransfer.getDataForItem(m_type));99 callback->scheduleCallback(document, dataTransfer.getDataForItem(document, m_type)); 99 100 } 100 101 -
trunk/Source/WebCore/dom/DataTransferItem.h
r222904 r223440 61 61 String kind() const; 62 62 String type() const; 63 void getAsString( ScriptExecutionContext&, RefPtr<StringCallback>&&) const;63 void getAsString(Document&, RefPtr<StringCallback>&&) const; 64 64 RefPtr<File> getAsFile() const; 65 65 RefPtr<FileSystemEntry> getAsEntry(ScriptExecutionContext&) const; -
trunk/Source/WebCore/dom/DataTransferItem.idl
r221481 r223440 37 37 readonly attribute DOMString type; 38 38 39 [CallWith= ScriptExecutionContext] void getAsString(StringCallback? callback);39 [CallWith=Document] void getAsString(StringCallback? callback); 40 40 File getAsFile(); 41 41 -
trunk/Source/WebCore/dom/Document.cpp
r223425 r223440 5301 5301 #endif 5302 5302 5303 String Document::uniqueIdentifier() 5304 { 5303 String Document::originIdentifierForPasteboard() 5304 { 5305 auto origin = securityOrigin().toString(); 5306 if (origin != "null") 5307 return origin; 5305 5308 if (!m_uniqueIdentifier) 5306 5309 m_uniqueIdentifier = "null:" + createCanonicalUUIDString(); -
trunk/Source/WebCore/dom/Document.h
r223425 r223440 957 957 uint64_t domTreeVersion() const { return m_domTreeVersion; } 958 958 959 String uniqueIdentifier();959 String originIdentifierForPasteboard(); 960 960 961 961 // XPathEvaluator methods -
trunk/Source/WebCore/editing/WebContentReader.cpp
r222062 r223440 27 27 #include "WebContentReader.h" 28 28 29 #include "Document.h" 29 30 #include "DocumentFragment.h" 30 31 … … 39 40 } 40 41 42 bool WebContentMarkupReader::shouldSanitize() const 43 { 44 return frame.document() && frame.document()->originIdentifierForPasteboard() != contentOrigin; 41 45 } 42 46 47 } 48 -
trunk/Source/WebCore/editing/WebContentReader.h
r223140 r223440 66 66 }; 67 67 68 class WebContentMarkupReader final : public PasteboardWebContentReader { 69 public: 70 Frame& frame; 71 String markup; 72 73 explicit WebContentMarkupReader(Frame& frame) 74 : frame(frame) 75 { 76 } 77 78 private: 79 bool shouldSanitize() const; 80 81 #if PLATFORM(COCOA) 82 bool readWebArchive(SharedBuffer&) override; 83 bool readFilenames(const Vector<String>&) override { return false; } 84 bool readHTML(const String&) override; 85 bool readRTFD(SharedBuffer&) override; 86 bool readRTF(SharedBuffer&) override; 87 bool readImage(Ref<SharedBuffer>&&, const String&) override { return false; } 88 bool readURL(const URL&, const String&) override { return false; } 89 #endif 90 bool readPlainText(const String&) override { return false; } 91 }; 92 68 93 #if PLATFORM(COCOA) && defined(__OBJC__) 69 94 struct FragmentAndResources { -
trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm
r223140 r223440 40 40 #import "HTMLImageElement.h" 41 41 #import "LegacyWebArchive.h" 42 #import "MainFrame.h" 42 43 #import "Page.h" 43 44 #import "Settings.h" 45 #import "SocketProvider.h" 44 46 #import "WebArchiveResourceFromNSAttributedString.h" 45 47 #import "WebArchiveResourceWebResourceHandler.h" … … 180 182 } 181 183 182 bool WebContentReader::readWebArchive(SharedBuffer& buffer) 183 { 184 if (frame.settings().preferMIMETypeForImages() || !frame.document()) 185 return false; 186 184 struct FragmentAndArchive { 185 Ref<DocumentFragment> fragment; 186 Ref<Archive> archive; 187 }; 188 189 static std::optional<FragmentAndArchive> createFragmentFromWebArchive(Document& document, SharedBuffer& buffer, const std::function<bool(const String)>& canShowMIMETypeAsHTML) 190 { 187 191 auto archive = LegacyWebArchive::create(URL(), buffer); 188 192 if (!archive) 189 return false;193 return std::nullopt; 190 194 191 195 RefPtr<ArchiveResource> mainResource = archive->mainResource(); 192 196 if (!mainResource) 193 return false;197 return std::nullopt; 194 198 195 199 auto type = mainResource->mimeType(); 196 if (!frame.loader().client().canShowMIMETypeAsHTML(type)) 200 if (!canShowMIMETypeAsHTML(type)) 201 return std::nullopt; 202 203 auto markupString = String::fromUTF8(mainResource->data().data(), mainResource->data().size()); 204 auto fragment = createFragmentFromMarkup(document, markupString, mainResource->url(), DisallowScriptingAndPluginContent); 205 206 return FragmentAndArchive { WTFMove(fragment), archive.releaseNonNull() }; 207 } 208 209 bool WebContentReader::readWebArchive(SharedBuffer& buffer) 210 { 211 if (frame.settings().preferMIMETypeForImages() || !frame.document()) 197 212 return false; 198 213 199 214 DeferredLoadingScope scope(frame); 200 auto markupString = String::fromUTF8(mainResource->data().data(), mainResource->data().size()); 201 addFragment(createFragmentFromMarkup(*frame.document(), markupString, mainResource->url(), DisallowScriptingAndPluginContent)); 202 215 auto result = createFragmentFromWebArchive(*frame.document(), buffer, [&] (const String& type) { 216 return frame.loader().client().canShowMIMETypeAsHTML(type); 217 }); 218 if (!result) 219 return false; 220 221 fragment = WTFMove(result->fragment); 203 222 if (DocumentLoader* loader = frame.loader().documentLoader()) 204 loader->addAllArchiveResources(*archive); 205 206 return true; 207 } 208 209 bool WebContentReader::readHTML(const String& string) 210 { 211 String stringOmittingMicrosoftPrefix = string; 212 223 loader->addAllArchiveResources(result->archive.get()); 224 225 return true; 226 } 227 228 bool WebContentMarkupReader::readWebArchive(SharedBuffer& buffer) 229 { 230 auto page = createPageForSanitizingWebContent(); 231 Document* stagingDocument = page->mainFrame().document(); 232 ASSERT(stagingDocument); 233 234 DeferredLoadingScope scope(frame); 235 auto result = createFragmentFromWebArchive(*stagingDocument, buffer, [&] (const String& type) { 236 return frame.loader().client().canShowMIMETypeAsHTML(type); 237 }); 238 if (!result) 239 return false; 240 241 HashMap<AtomicString, AtomicString> blobURLMap; 242 for (const Ref<ArchiveResource>& subresource : result->archive->subresources()) { 243 auto blob = Blob::create(subresource->data(), subresource->mimeType()); 244 String blobURL = DOMURL::createObjectURL(*frame.document(), blob); 245 blobURLMap.set(subresource->url().string(), blobURL); 246 } 247 replaceSubresourceURLs(result->fragment.get(), WTFMove(blobURLMap)); 248 249 auto* bodyElement = stagingDocument->body(); 250 ASSERT(bodyElement); 251 bodyElement->appendChild(result->fragment); 252 253 auto range = Range::create(*stagingDocument); 254 range->selectNodeContents(*bodyElement); 255 markup = createMarkup(range.get(), nullptr, AnnotateForInterchange, false, ResolveNonLocalURLs); 256 257 return true; 258 } 259 260 static String stripMicrosoftPrefix(const String& string) 261 { 213 262 #if PLATFORM(MAC) 214 263 // This code was added to make HTML paste from Microsoft Word on Mac work, back in 2004. … … 218 267 size_t location = string.findIgnoringCase("<html"); 219 268 if (location != notFound) 220 stringOmittingMicrosoftPrefix = string.substring(location); 221 } 222 #endif 223 269 return string.substring(location); 270 } 271 #endif 272 return string; 273 } 274 275 bool WebContentReader::readHTML(const String& string) 276 { 277 if (frame.settings().preferMIMETypeForImages() || !frame.document()) 278 return false; 279 Document& document = *frame.document(); 280 281 String stringOmittingMicrosoftPrefix = stripMicrosoftPrefix(string); 224 282 if (stringOmittingMicrosoftPrefix.isEmpty()) 225 283 return false; 226 284 285 addFragment(createFragmentFromMarkup(document, stringOmittingMicrosoftPrefix, emptyString(), DisallowScriptingAndPluginContent)); 286 return true; 287 } 288 289 bool WebContentMarkupReader::readHTML(const String& string) 290 { 227 291 if (!frame.document()) 228 292 return false; 229 Document& document = *frame.document(); 230 231 addFragment(createFragmentFromMarkup(document, stringOmittingMicrosoftPrefix, emptyString(), DisallowScriptingAndPluginContent)); 232 return true; 293 294 String rawHTML = stripMicrosoftPrefix(string); 295 if (shouldSanitize()) 296 markup = sanitizeMarkup(rawHTML); 297 else 298 markup = rawHTML; 299 300 return !markup.isEmpty(); 233 301 } 234 302 235 303 bool WebContentReader::readRTFD(SharedBuffer& buffer) 236 304 { 237 if (frame.settings().preferMIMETypeForImages() )305 if (frame.settings().preferMIMETypeForImages() || !frame.document()) 238 306 return false; 239 307 … … 246 314 } 247 315 316 bool WebContentMarkupReader::readRTFD(SharedBuffer& buffer) 317 { 318 if (!frame.document()) 319 return false; 320 auto fragment = createFragmentAndAddResources(frame, adoptNS([[NSAttributedString alloc] initWithRTFD:buffer.createNSData().get() documentAttributes:nullptr]).get()); 321 markup = createMarkup(*fragment); 322 return true; 323 } 324 248 325 bool WebContentReader::readRTF(SharedBuffer& buffer) 249 326 { … … 256 333 addFragment(fragment.releaseNonNull()); 257 334 335 return true; 336 } 337 338 bool WebContentMarkupReader::readRTF(SharedBuffer& buffer) 339 { 340 if (!frame.document()) 341 return false; 342 auto fragment = createFragmentAndAddResources(frame, adoptNS([[NSAttributedString alloc] initWithRTF:buffer.createNSData().get() documentAttributes:nullptr]).get()); 343 if (!fragment) 344 return false; 345 markup = createMarkup(*fragment); 258 346 return true; 259 347 } -
trunk/Source/WebCore/editing/markup.cpp
r222839 r223440 35 35 #include "CSSValue.h" 36 36 #include "CSSValueKeywords.h" 37 #include "CacheStorageProvider.h" 37 38 #include "ChildListMutationScope.h" 38 39 #include "DocumentFragment.h" … … 41 42 #include "Editing.h" 42 43 #include "Editor.h" 44 #include "EditorClient.h" 43 45 #include "ElementIterator.h" 46 #include "EmptyClients.h" 44 47 #include "File.h" 45 48 #include "Frame.h" … … 56 59 #include "HTMLTextAreaElement.h" 57 60 #include "HTMLTextFormControlElement.h" 58 #include "URL.h" 61 #include "LibWebRTCProvider.h" 62 #include "MainFrame.h" 59 63 #include "MarkupAccumulator.h" 60 64 #include "NodeList.h" 65 #include "Page.h" 66 #include "PageConfiguration.h" 61 67 #include "Range.h" 62 68 #include "RenderBlock.h" 63 69 #include "Settings.h" 70 #include "SocketProvider.h" 64 71 #include "StyleProperties.h" 65 72 #include "TextIterator.h" 66 73 #include "TypedElementDescendantIterator.h" 74 #include "URL.h" 67 75 #include "VisibleSelection.h" 68 76 #include "VisibleUnits.h" … … 136 144 change.apply(); 137 145 } 146 147 std::unique_ptr<Page> createPageForSanitizingWebContent() 148 { 149 PageConfiguration pageConfiguration(createEmptyEditorClient(), SocketProvider::create(), LibWebRTCProvider::create(), CacheStorageProvider::create()); 150 151 fillWithEmptyClients(pageConfiguration); 152 153 auto page = std::make_unique<Page>(WTFMove(pageConfiguration)); 154 page->settings().setMediaEnabled(false); 155 page->settings().setScriptEnabled(false); 156 page->settings().setPluginsEnabled(false); 157 page->settings().setAcceleratedCompositingEnabled(false); 158 159 Frame& frame = page->mainFrame(); 160 frame.setView(FrameView::create(frame)); 161 frame.init(); 162 163 FrameLoader& loader = frame.loader(); 164 static char markup[] = "<!DOCTYPE html><html><body></body></html>"; 165 ASSERT(loader.activeDocumentLoader()); 166 loader.activeDocumentLoader()->writer().setMIMEType("text/html"); 167 loader.activeDocumentLoader()->writer().begin(); 168 loader.activeDocumentLoader()->writer().addData(markup, sizeof(markup)); 169 loader.activeDocumentLoader()->writer().end(); 170 171 return page; 172 } 173 174 175 String sanitizeMarkup(const String& rawHTML) 176 { 177 auto page = createPageForSanitizingWebContent(); 178 Document* stagingDocument = page->mainFrame().document(); 179 ASSERT(stagingDocument); 180 auto* bodyElement = stagingDocument->body(); 181 ASSERT(bodyElement); 182 183 auto fragment = createFragmentFromMarkup(*stagingDocument, rawHTML, emptyString(), DisallowScriptingAndPluginContent); 184 bodyElement->appendChild(fragment.get()); 185 186 auto range = Range::create(*stagingDocument); 187 range->selectNodeContents(*bodyElement); 188 return createMarkup(range.get(), nullptr, AnnotateForInterchange, false, ResolveNonLocalURLs); 189 } 190 138 191 139 192 class StyledMarkupAccumulator final : public MarkupAccumulator { -
trunk/Source/WebCore/editing/markup.h
r222839 r223440 43 43 class URL; 44 44 class Node; 45 class Page; 45 46 class QualifiedName; 46 47 class Range; 47 48 48 49 void replaceSubresourceURLs(Ref<DocumentFragment>&&, HashMap<AtomicString, AtomicString>&&); 50 std::unique_ptr<Page> createPageForSanitizingWebContent(); 51 String sanitizeMarkup(const String&); 49 52 50 53 enum EChildrenOnly { IncludeNode, ChildrenOnly }; -
trunk/Source/WebCore/platform/Pasteboard.h
r223340 r223440 128 128 class PasteboardWebContentReader { 129 129 public: 130 String contentOrigin; 131 130 132 virtual ~PasteboardWebContentReader() { } 131 133 132 #if !(PLATFORM(GTK) || PLATFORM(WIN))134 #if PLATFORM(COCOA) 133 135 virtual bool readWebArchive(SharedBuffer&) = 0; 134 136 virtual bool readFilenames(const Vector<String>&) = 0; … … 271 273 bool respectsUTIFidelities() const; 272 274 void readRespectingUTIFidelities(PasteboardWebContentReader&); 275 276 enum class ReaderResult { 277 ReadType, 278 DidNotReadType, 279 PasteboardWasChangedExternally 280 }; 281 ReaderResult readPasteboardWebContentDataForType(PasteboardWebContentReader&, PasteboardStrategy&, NSString *type, int itemIndex); 273 282 #endif 274 283 -
trunk/Source/WebCore/platform/ios/PasteboardIOS.mm
r223140 r223440 163 163 } 164 164 165 static bool readPasteboardWebContentDataForType(PasteboardWebContentReader& reader, PasteboardStrategy& strategy, NSString *type, int itemIndex, const String& pasteboardName)165 Pasteboard::ReaderResult Pasteboard::readPasteboardWebContentDataForType(PasteboardWebContentReader& reader, PasteboardStrategy& strategy, NSString *type, int itemIndex) 166 166 { 167 167 if ([type isEqualToString:WebArchivePboardType]) { 168 auto buffer = strategy.readBufferFromPasteboard(itemIndex, WebArchivePboardType, pasteboardName); 169 return buffer && reader.readWebArchive(*buffer); 168 auto buffer = strategy.readBufferFromPasteboard(itemIndex, WebArchivePboardType, m_pasteboardName); 169 if (m_changeCount != changeCount()) 170 return ReaderResult::PasteboardWasChangedExternally; 171 return buffer && reader.readWebArchive(*buffer) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 170 172 } 171 173 172 174 if ([type isEqualToString:(NSString *)kUTTypeHTML]) { 173 String htmlString = strategy.readStringFromPasteboard(itemIndex, kUTTypeHTML, pasteboardName); 174 return !htmlString.isNull() && reader.readHTML(htmlString); 175 String htmlString = strategy.readStringFromPasteboard(itemIndex, kUTTypeHTML, m_pasteboardName); 176 if (m_changeCount != changeCount()) 177 return ReaderResult::PasteboardWasChangedExternally; 178 return !htmlString.isNull() && reader.readHTML(htmlString) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 175 179 } 176 180 177 181 if ([type isEqualToString:(NSString *)kUTTypeFlatRTFD]) { 178 RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeFlatRTFD, pasteboardName); 179 return buffer && reader.readRTFD(*buffer); 182 RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeFlatRTFD, m_pasteboardName); 183 if (m_changeCount != changeCount()) 184 return ReaderResult::PasteboardWasChangedExternally; 185 return buffer && reader.readRTFD(*buffer) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 180 186 } 181 187 182 188 if ([type isEqualToString:(NSString *)kUTTypeRTF]) { 183 RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeRTF, pasteboardName); 184 return buffer && reader.readRTF(*buffer); 189 RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeRTF, m_pasteboardName); 190 if (m_changeCount != changeCount()) 191 return ReaderResult::PasteboardWasChangedExternally; 192 return buffer && reader.readRTF(*buffer) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 185 193 } 186 194 187 195 if ([supportedImageTypes() containsObject:type]) { 188 RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, type, pasteboardName); 189 return buffer && reader.readImage(buffer.releaseNonNull(), type); 196 RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, type, m_pasteboardName); 197 if (m_changeCount != changeCount()) 198 return ReaderResult::PasteboardWasChangedExternally; 199 return buffer && reader.readImage(buffer.releaseNonNull(), type) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 190 200 } 191 201 192 202 if ([type isEqualToString:(NSString *)kUTTypeURL]) { 193 203 String title; 194 URL url = strategy.readURLFromPasteboard(itemIndex, kUTTypeURL, pasteboardName, title); 195 return !url.isNull() && reader.readURL(url, title); 204 URL url = strategy.readURLFromPasteboard(itemIndex, kUTTypeURL, m_pasteboardName, title); 205 if (m_changeCount != changeCount()) 206 return ReaderResult::PasteboardWasChangedExternally; 207 return !url.isNull() && reader.readURL(url, title) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 196 208 } 197 209 198 210 if (UTTypeConformsTo((CFStringRef)type, kUTTypePlainText)) { 199 String string = strategy.readStringFromPasteboard(itemIndex, kUTTypePlainText, pasteboardName); 200 return !string.isNull() && reader.readPlainText(string); 211 String string = strategy.readStringFromPasteboard(itemIndex, kUTTypePlainText, m_pasteboardName); 212 if (m_changeCount != changeCount()) 213 return ReaderResult::PasteboardWasChangedExternally; 214 return !string.isNull() && reader.readPlainText(string) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 201 215 } 202 216 203 217 if (UTTypeConformsTo((CFStringRef)type, kUTTypeText)) { 204 String string = strategy.readStringFromPasteboard(itemIndex, kUTTypeText, pasteboardName); 205 return !string.isNull() && reader.readPlainText(string); 206 } 207 208 return false; 218 String string = strategy.readStringFromPasteboard(itemIndex, kUTTypeText, m_pasteboardName); 219 if (m_changeCount != changeCount()) 220 return ReaderResult::PasteboardWasChangedExternally; 221 return !string.isNull() && reader.readPlainText(string) ? ReaderResult::ReadType : ReaderResult::DidNotReadType; 222 } 223 224 return ReaderResult::DidNotReadType; 209 225 } 210 226 … … 223 239 return; 224 240 241 reader.contentOrigin = readOrigin(); 242 225 243 NSArray *types = supportedWebContentPasteboardTypes(); 226 244 int numberOfTypes = [types count]; … … 228 246 for (int i = 0; i < numberOfItems; i++) { 229 247 for (int typeIndex = 0; typeIndex < numberOfTypes; typeIndex++) { 230 if (readPasteboardWebContentDataForType(reader, strategy, [types objectAtIndex:typeIndex], i, m_pasteboardName)) 248 auto result = readPasteboardWebContentDataForType(reader, strategy, [types objectAtIndex:typeIndex], i); 249 if (result == ReaderResult::PasteboardWasChangedExternally) 250 return; 251 if (result == ReaderResult::ReadType) 231 252 break; 232 253 } … … 252 273 strategy.getTypesByFidelityForItemAtIndex(typesForItemInOrderOfFidelity, index, m_pasteboardName); 253 274 for (auto& type : typesForItemInOrderOfFidelity) { 254 if (readPasteboardWebContentDataForType(reader, strategy, type, index, m_pasteboardName)) 275 auto result = readPasteboardWebContentDataForType(reader, strategy, type, index); 276 if (result == ReaderResult::PasteboardWasChangedExternally) 277 return; 278 if (result == ReaderResult::ReadType) 255 279 break; 256 280 } -
trunk/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
r223410 r223440 356 356 return ASCIILiteral("text/plain"); 357 357 358 if (UTTypeConformsTo(cfType.get(), kUTTypeHTML)) 358 if (UTTypeConformsTo(cfType.get(), kUTTypeHTML) || UTTypeConformsTo(cfType.get(), (CFStringRef)WebArchivePboardType) 359 || UTTypeConformsTo(cfType.get(), kUTTypeRTF) || UTTypeConformsTo(cfType.get(), kUTTypeFlatRTFD)) 359 360 return ASCIILiteral("text/html"); 360 361 -
trunk/Source/WebCore/platform/mac/PasteboardMac.mm
r223140 r223440 333 333 strategy.getTypes(types, m_pasteboardName); 334 334 335 reader.contentOrigin = readOrigin(); 336 335 337 if (types.contains(WebArchivePboardType)) { 336 338 if (auto buffer = strategy.bufferForType(WebArchivePboardType, m_pasteboardName)) { 337 if ( reader.readWebArchive(*buffer))339 if (m_changeCount != changeCount() || reader.readWebArchive(*buffer)) 338 340 return; 339 341 } … … 343 345 Vector<String> paths; 344 346 strategy.getPathnamesForType(paths, NSFilenamesPboardType, m_pasteboardName); 345 if ( reader.readFilenames(paths))347 if (m_changeCount != changeCount() || reader.readFilenames(paths)) 346 348 return; 347 349 } … … 349 351 if (types.contains(String(NSHTMLPboardType))) { 350 352 String string = strategy.stringForType(NSHTMLPboardType, m_pasteboardName); 351 if ( !string.isNull() && reader.readHTML(string))353 if (m_changeCount != changeCount() || (!string.isNull() && reader.readHTML(string))) 352 354 return; 353 355 } … … 355 357 if (types.contains(String(NSRTFDPboardType))) { 356 358 if (RefPtr<SharedBuffer> buffer = strategy.bufferForType(NSRTFDPboardType, m_pasteboardName)) { 357 if ( reader.readRTFD(*buffer))359 if (m_changeCount != changeCount() || reader.readRTFD(*buffer)) 358 360 return; 359 361 } … … 362 364 if (types.contains(String(NSRTFPboardType))) { 363 365 if (RefPtr<SharedBuffer> buffer = strategy.bufferForType(NSRTFPboardType, m_pasteboardName)) { 364 if ( reader.readRTF(*buffer))366 if (m_changeCount != changeCount() || reader.readRTF(*buffer)) 365 367 return; 366 368 } … … 369 371 if (types.contains(String(NSTIFFPboardType))) { 370 372 if (RefPtr<SharedBuffer> buffer = strategy.bufferForType(NSTIFFPboardType, m_pasteboardName)) { 371 if ( reader.readImage(buffer.releaseNonNull(), ASCIILiteral("image/tiff")))373 if (m_changeCount != changeCount() || reader.readImage(buffer.releaseNonNull(), ASCIILiteral("image/tiff"))) 372 374 return; 373 375 } … … 376 378 if (types.contains(String(NSPDFPboardType))) { 377 379 if (RefPtr<SharedBuffer> buffer = strategy.bufferForType(NSPDFPboardType, m_pasteboardName)) { 378 if ( reader.readImage(buffer.releaseNonNull(), ASCIILiteral("application/pdf")))380 if (m_changeCount != changeCount() || reader.readImage(buffer.releaseNonNull(), ASCIILiteral("application/pdf"))) 379 381 return; 380 382 } … … 383 385 if (types.contains(String(kUTTypePNG))) { 384 386 if (RefPtr<SharedBuffer> buffer = strategy.bufferForType(kUTTypePNG, m_pasteboardName)) { 385 if ( reader.readImage(buffer.releaseNonNull(), ASCIILiteral("image/png")))387 if (m_changeCount != changeCount() || reader.readImage(buffer.releaseNonNull(), ASCIILiteral("image/png"))) 386 388 return; 387 389 } … … 390 392 if (types.contains(String(kUTTypeJPEG))) { 391 393 if (RefPtr<SharedBuffer> buffer = strategy.bufferForType(kUTTypeJPEG, m_pasteboardName)) { 392 if ( reader.readImage(buffer.releaseNonNull(), ASCIILiteral("image/jpeg")))394 if (m_changeCount != changeCount() || reader.readImage(buffer.releaseNonNull(), ASCIILiteral("image/jpeg"))) 393 395 return; 394 396 } … … 398 400 URL url = strategy.url(m_pasteboardName); 399 401 String title = strategy.stringForType(WebURLNamePboardType, m_pasteboardName); 400 if ( !url.isNull() && reader.readURL(url, title))402 if (m_changeCount != changeCount() || (!url.isNull() && reader.readURL(url, title))) 401 403 return; 402 404 } … … 404 406 if (types.contains(String(NSStringPboardType))) { 405 407 String string = strategy.stringForType(NSStringPboardType, m_pasteboardName); 406 if ( !string.isNull() && reader.readPlainText(string))408 if (m_changeCount != changeCount() || (!string.isNull() && reader.readPlainText(string))) 407 409 return; 408 410 } … … 410 412 if (types.contains(String(kUTTypeUTF8PlainText))) { 411 413 String string = strategy.stringForType(kUTTypeUTF8PlainText, m_pasteboardName); 412 if ( !string.isNull() && reader.readPlainText(string))414 if (m_changeCount != changeCount() || (!string.isNull() && reader.readPlainText(string))) 413 415 return; 414 416 } -
trunk/Source/WebCore/platform/mac/PlatformPasteboardMac.mm
r223340 r223440 108 108 return ASCIILiteral("text/uri-list"); 109 109 110 if (platformType == String(NSHTMLPboardType)) 110 if (platformType == String(NSHTMLPboardType) || platformType == String(WebArchivePboardType) 111 || platformType == String(NSRTFDPboardType) || platformType == String(NSRTFPboardType)) 111 112 return ASCIILiteral("text/html"); 112 113 -
trunk/Tools/ChangeLog
r223433 r223440 1 2017-10-15 Ryosuke Niwa <rniwa@webkit.org> 2 3 Cannot access images included in the content pasted from Microsoft Word 4 https://bugs.webkit.org/show_bug.cgi?id=124391 5 <rdar://problem/26862741> 6 7 Reviewed by Antti Koivisto. 8 9 Added tests for sanitizing HTML contents for copy & paste and drag & drop. 10 11 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: 12 * TestWebKitAPI/Tests/WebKitCocoa/CopyHTML.mm: Added. 13 (readHTMLFromPasteboard): Added. 14 (createWebViewWithCustomPasteboardDataEnabled): Added. 15 (CopyHTML.Sanitizes): Added. 16 17 * TestWebKitAPI/Tests/WebKitCocoa/CopyURL.mm: 18 (createWebViewWithCustomPasteboardDataEnabled): Added to enable more tests on bots. 19 20 * TestWebKitAPI/Tests/WebKitCocoa/PasteRTFD.mm: 21 (writeRTFToPasteboard): Added. 22 (createWebViewWithCustomPasteboardDataEnabled): Added. 23 (createHelloWorldString): Added. 24 (PasteRTF.ExposesHTMLTypeInDataTransfer): Added. 25 (PasteRTFD.ExposesHTMLTypeInDataTransfer): Added. 26 (PasteRTFD.ImageElementUsesBlobURLInHTML): Added. 27 28 * TestWebKitAPI/Tests/WebKitCocoa/copy-html.html: Added. 29 * TestWebKitAPI/Tests/WebKitCocoa/paste-rtfd.html: Store the clipboardData contents for 30 PasteRTF.ExposesHTMLTypeInDataTransfer and PasteRTFD.ExposesHTMLTypeInDataTransfer. 31 32 * TestWebKitAPI/Tests/ios/DataInteractionTests.mm: 33 (DataInteractionTests.DataTransferSanitizeHTML): 34 1 35 2017-10-16 Youenn Fablet <youenn@apple.com> 2 36 -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
r223427 r223440 543 543 9B0786A51C5885C300D159E3 /* InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B0786A41C5885C300D159E3 /* InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp */; }; 544 544 9B19CDA01F06DFE3000548DD /* NetworkProcessCrashWithPendingConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B19CD9E1F06DFE3000548DD /* NetworkProcessCrashWithPendingConnection.mm */; }; 545 9B1F6F781F90558400B55744 /* CopyHTML.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B1056411F9045C700D5583F /* CopyHTML.mm */; }; 546 9B1F6F791F90559E00B55744 /* copy-html.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B1056421F9047CC00D5583F /* copy-html.html */; }; 547 9B2346421F943E2700DB1D23 /* PasteWebArchive.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B2346411F943A2400DB1D23 /* PasteWebArchive.mm */; }; 545 548 9B26FCCA159D16DE00CC3765 /* HTMLFormCollectionNamedItem.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B26FCB4159D15E700CC3765 /* HTMLFormCollectionNamedItem.html */; }; 546 549 9B270FEE1DDC2C0B002D53F3 /* closed-shadow-tree-test.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B270FED1DDC25FD002D53F3 /* closed-shadow-tree-test.html */; }; … … 844 847 CD0BD0A81F79982D001AB2CF /* ContextMenuImgWithVideo.html in Copy Resources */, 845 848 5C2936961D5C00ED00DEAB1E /* CookieMessage.html in Copy Resources */, 849 9B1F6F791F90559E00B55744 /* copy-html.html in Copy Resources */, 846 850 9B62630C1F8C25C8007EE29B /* copy-url.html in Copy Resources */, 847 851 7AEAD4811E20122700416EFE /* CrossPartitionFileSchemeAccess.html in Copy Resources */, … … 1508 1512 9B0786A21C58830F00D159E3 /* InjectedBundleMakeAllShadowRootsOpen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleMakeAllShadowRootsOpen.cpp; sourceTree = "<group>"; }; 1509 1513 9B0786A41C5885C300D159E3 /* InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleMakeAllShadowRootsOpen_Bundle.cpp; sourceTree = "<group>"; }; 1514 9B1056411F9045C700D5583F /* CopyHTML.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CopyHTML.mm; sourceTree = "<group>"; }; 1515 9B1056421F9047CC00D5583F /* copy-html.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "copy-html.html"; sourceTree = "<group>"; }; 1510 1516 9B19CD9E1F06DFE3000548DD /* NetworkProcessCrashWithPendingConnection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkProcessCrashWithPendingConnection.mm; path = WebKit/NetworkProcessCrashWithPendingConnection.mm; sourceTree = "<group>"; }; 1517 9B2346411F943A2400DB1D23 /* PasteWebArchive.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PasteWebArchive.mm; sourceTree = "<group>"; }; 1511 1518 9B26FC6B159D061000CC3765 /* HTMLFormCollectionNamedItem.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLFormCollectionNamedItem.mm; sourceTree = "<group>"; }; 1512 1519 9B26FCB4159D15E700CC3765 /* HTMLFormCollectionNamedItem.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = HTMLFormCollectionNamedItem.html; sourceTree = "<group>"; }; … … 1987 1994 5CA1DED81F74A87100E71BD3 /* ContentRuleListNotification.mm */, 1988 1995 5C2936911D5BF63E00DEAB1E /* CookieAcceptPolicy.mm */, 1996 9B1056411F9045C700D5583F /* CopyHTML.mm */, 1989 1997 9999108A1F393C8B008AD455 /* Copying.mm */, 1990 1998 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */, … … 2027 2035 9BDCCD851F7D0B0700009A18 /* PasteImage.mm */, 2028 2036 9BDD95561F83683600D20C60 /* PasteRTFD.mm */, 2037 9B2346411F943A2400DB1D23 /* PasteWebArchive.mm */, 2029 2038 3FCC4FE41EC4E8520076E37C /* PictureInPictureDelegate.mm */, 2030 2039 83BAEE8C1EF4625500DDE894 /* PluginLoadClientPolicies.mm */, … … 2237 2246 A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */, 2238 2247 5C2936941D5BFD1900DEAB1E /* CookieMessage.html */, 2248 9B1056421F9047CC00D5583F /* copy-html.html */, 2239 2249 9B62630B1F8C2510007EE29B /* copy-url.html */, 2240 2250 F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */, … … 3230 3240 5C2936931D5BF70D00DEAB1E /* CookieAcceptPolicy.mm in Sources */, 3231 3241 51D1249B1E785425002B2820 /* CookieManager.cpp in Sources */, 3242 9B1F6F781F90558400B55744 /* CopyHTML.mm in Sources */, 3232 3243 9999108B1F393C96008AD455 /* Copying.mm in Sources */, 3233 3244 9B7A37C41F8AEBA5004AA228 /* CopyURL.mm in Sources */, … … 3390 3401 9BDCCD871F7D0B0700009A18 /* PasteImage.mm in Sources */, 3391 3402 9BDD95581F83683600D20C60 /* PasteRTFD.mm in Sources */, 3403 9B2346421F943E2700DB1D23 /* PasteWebArchive.mm in Sources */, 3392 3404 7C83E0531D0A643A00FEBCF3 /* PendingAPIRequestURL.cpp in Sources */, 3393 3405 3FCC4FE51EC4E8520076E37C /* PictureInPictureDelegate.mm in Sources */, -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/CopyURL.mm
r223195 r223440 58 58 #endif 59 59 60 static RetainPtr<TestWKWebView> createWebViewWithCustomPasteboardDataEnabled() 61 { 62 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]); 63 auto preferences = (WKPreferencesRef)[[webView configuration] preferences]; 64 WKPreferencesSetDataTransferItemsEnabled(preferences, true); 65 WKPreferencesSetCustomPasteboardDataEnabled(preferences, true); 66 return webView; 67 } 68 60 69 TEST(CopyURL, ValidURL) 61 70 { 62 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);71 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 63 72 [webView synchronouslyLoadTestPageNamed:@"copy-url"]; 64 73 [webView stringByEvaluatingJavaScript:@"URLToCopy = 'http://webkit.org/b/123';"]; … … 71 80 } 72 81 73 // FIXME: We should add a mechanism to enable custom pasteboard data in older OS for testing purposes.74 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110300) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED > 101300)75 76 82 TEST(CopyURL, UnescapedURL) 77 83 { 78 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);84 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 79 85 [webView synchronouslyLoadTestPageNamed:@"copy-url"]; 80 86 [webView stringByEvaluatingJavaScript:@"URLToCopy = 'http://webkit.org/b/\u4F60\u597D;?x=8 + 6';"]; … … 89 95 TEST(CopyURL, MalformedURL) 90 96 { 91 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);97 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 92 98 [webView synchronouslyLoadTestPageNamed:@"copy-url"]; 93 99 [webView stringByEvaluatingJavaScript:@"URLToCopy = 'bad url';"]; … … 100 106 } 101 107 102 #endif103 104 108 #endif // WK_API_ENABLED && PLATFORM(MAC) 105 109 -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteRTFD.mm
r222839 r223440 30 30 #import "PlatformUtilities.h" 31 31 #import "TestWKWebView.h" 32 #import <WebKit/WKPreferencesPrivate.h> 33 #import <WebKit/WKPreferencesRefPrivate.h> 34 #import <WebKit/WKWebViewConfigurationPrivate.h> 32 35 #import <wtf/RetainPtr.h> 33 36 #import <wtf/text/WTFString.h> … … 42 45 43 46 #if PLATFORM(MAC) 47 void writeRTFToPasteboard(NSData *data) 48 { 49 [[NSPasteboard generalPasteboard] declareTypes:@[NSPasteboardTypeRTF] owner:nil]; 50 [[NSPasteboard generalPasteboard] setData:data forType:NSPasteboardTypeRTF]; 51 } 52 44 53 void writeRTFDToPasteboard(NSData *data) 45 54 { … … 57 66 @end 58 67 68 void writeRTFToPasteboard(NSData *data) 69 { 70 [[UIPasteboard generalPasteboard] setItems:@[@{ (NSString *)kUTTypeRTF : data}]]; 71 } 72 59 73 void writeRTFDToPasteboard(NSData *data) 60 74 { … … 63 77 #endif 64 78 79 static RetainPtr<TestWKWebView> createWebViewWithCustomPasteboardDataEnabled() 80 { 81 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]); 82 auto preferences = (WKPreferencesRef)[[webView configuration] preferences]; 83 WKPreferencesSetDataTransferItemsEnabled(preferences, true); 84 WKPreferencesSetCustomPasteboardDataEnabled(preferences, true); 85 return webView; 86 } 87 88 static RetainPtr<NSAttributedString> createHelloWorldString() 89 { 90 auto hello = adoptNS([[NSAttributedString alloc] initWithString:@"hello" attributes:@{ NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle) }]); 91 auto world = adoptNS([[NSAttributedString alloc] initWithString:@", world" attributes:@{ }]); 92 auto string = adoptNS([[NSMutableAttributedString alloc] init]); 93 [string appendAttributedString:hello.get()]; 94 [string appendAttributedString:world.get()]; 95 return string; 96 } 97 98 TEST(PasteRTF, ExposesHTMLTypeInDataTransfer) 99 { 100 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 101 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; 102 103 auto string = createHelloWorldString(); 104 writeRTFToPasteboard([string RTFFromRange:NSMakeRange(0, [string length]) documentAttributes:@{ }]); 105 [webView paste:nil]; 106 107 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"]); 108 [webView stringByEvaluatingJavaScript:@"editor.innerHTML = clipboardData.values[0]; editor.focus()"]; 109 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue); 110 [webView stringByEvaluatingJavaScript:@"getSelection().modify('move', 'forward', 'lineboundary')"]; 111 EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue); 112 EXPECT_WK_STREQ("hello, world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]); 113 } 114 65 115 TEST(PasteRTFD, EmptyRTFD) 66 116 { 67 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);117 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 68 118 [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><html><body><div id='editor' contenteditable></div></body></html>"]; 69 119 … … 73 123 } 74 124 75 TEST(PasteRTFD, ImageElementsUseBlobURL)125 TEST(PasteRTFD, ExposesHTMLTypeInDataTransfer) 76 126 { 77 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]); 127 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 128 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; 129 130 auto string = createHelloWorldString(); 131 writeRTFDToPasteboard([string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:@{ }]); 132 [webView paste:nil]; 133 134 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"clipboardData.types.includes('text/html')"]); 135 [webView stringByEvaluatingJavaScript:@"editor.innerHTML = clipboardData.values[0]; editor.focus()"]; 136 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue); 137 [webView stringByEvaluatingJavaScript:@"getSelection().modify('move', 'forward', 'lineboundary')"]; 138 EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"document.queryCommandState('underline')"].boolValue); 139 EXPECT_WK_STREQ("hello, world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]); 140 } 141 142 TEST(PasteRTFD, ImageElementUsesBlobURL) 143 { 144 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 78 145 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; 79 146 … … 91 158 } 92 159 160 TEST(PasteRTFD, ImageElementUsesBlobURLInHTML) 161 { 162 auto webView = createWebViewWithCustomPasteboardDataEnabled(); 163 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; 164 165 auto *pngData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"sunset-in-cupertino-200px" ofType:@"png" inDirectory:@"TestWebKitAPI.resources"]]; 166 auto attachment = adoptNS([[NSTextAttachment alloc] initWithData:pngData ofType:(NSString *)kUTTypePNG]); 167 NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment.get()]; 168 NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:@{ }]; 169 170 writeRTFDToPasteboard(RTFDData); 171 [webView paste:nil]; 172 173 [webView waitForMessage:@"loaded"]; 174 EXPECT_WK_STREQ("[\"text/html\"]", [webView stringByEvaluatingJavaScript:@"JSON.stringify(clipboardData.types)"]); 175 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"imageElement = (new DOMParser).parseFromString(clipboardData.values[0], 'text/html').querySelector('img'); !!imageElement"].boolValue); 176 EXPECT_WK_STREQ("blob:", [webView stringByEvaluatingJavaScript:@"new URL(imageElement.src).protocol"]); 177 } 178 93 179 #endif // WK_API_ENABLED && PLATFORM(MAC) 94 180 -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/paste-rtfd.html
r222839 r223440 7 7 editor.focus(); 8 8 9 var clipboardData = {}; 9 10 editor.addEventListener('paste', (event) => { 11 clipboardData.types = Array.from(event.clipboardData.types); 12 clipboardData.items = Array.from(event.clipboardData.items).map((item) => ({kind: item.kind, type: item.type})); 13 clipboardData.values = clipboardData.types.map((type) => event.clipboardData.getData(type)); 14 clipboardData.files = Array.from(event.clipboardData.files); 15 10 16 setTimeout(() => { 11 17 let img = document.querySelector('img'); -
trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
r223340 r223440 1765 1765 } 1766 1766 1767 TEST(DataInteractionTests, DataTransferSanitizeHTML) 1768 { 1769 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); 1770 [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"]; 1771 auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); 1772 1773 [webView stringByEvaluatingJavaScript:@"select(rich)"]; 1774 [webView stringByEvaluatingJavaScript:@"customData = { 'text/html' : '<meta content=\"secret\">" 1775 "<b onmouseover=\"dangerousCode()\">hello</b><!-- secret-->, world<script>dangerousCode()</script>' }"]; 1776 [webView stringByEvaluatingJavaScript:@"writeCustomData = true"]; 1777 1778 __block bool done = false; 1779 [simulator.get() setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session) 1780 { 1781 EXPECT_EQ(1UL, session.items.count); 1782 auto *item = session.items[0].itemProvider; 1783 EXPECT_TRUE([item.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeHTML]); 1784 [item loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) { 1785 NSString *markup = [[[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding] autorelease]; 1786 EXPECT_TRUE([markup containsString:@"hello"]); 1787 EXPECT_TRUE([markup containsString:@", world"]); 1788 EXPECT_FALSE([markup containsString:@"secret"]); 1789 EXPECT_FALSE([markup containsString:@"dangerousCode"]); 1790 done = true; 1791 }]; 1792 return session.items; 1793 }]; 1794 [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)]; 1795 1796 checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{ 1797 @"dragover": @{ 1798 @"text/html": @"", 1799 }, 1800 @"drop": @{ 1801 @"text/html": @"<meta content=\"secret\"><b onmouseover=\"dangerousCode()\">hello</b><!-- secret-->, world<script>dangerousCode()</script>", 1802 } 1803 }); 1804 TestWebKitAPI::Util::run(&done); 1805 } 1806 1767 1807 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300 1768 1808
Note: See TracChangeset
for help on using the changeset viewer.