<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[226272] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/226272">226272</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2017-12-22 12:41:48 -0800 (Fri, 22 Dec 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/223678">r223678</a>): Cannot copy & paste a web page content into Yahoo! Mail
https://bugs.webkit.org/show_bug.cgi?id=181114

Reviewed by Geoffrey Garen.

Source/WebCore:

Turns out converting all URLs to blob isn't Web compatible. Don't do this conversion on HTTP, HTTP, and data URLs
since websites tend to have access to contents accessible via those protocols, and blob URL conversion would break
Yahoo! Mail, Gmail, and other major online email services.

We've also considered using data URLs instead of blob URLs for conversion but pasting a large image converted into
a data URL seems to break WordPress (it stores an empty post instead of the one with the image) so it's not likely
to be Web compatible either.

This patch therefore disables the blob conversion in sanitizeMarkupWithArchive for HTTP, HTTPS, data URLs for
cross-origin content, restoring the behavior prior to <a href="http://trac.webkit.org/projects/webkit/changeset/223678">r223678</a>. For contents converted from attributed strings,
we continue to convert to blob URL since there is no other way for websites to read local files or images references
by an in-memory web archive.

Tests: http/tests/security/clipboard/copy-paste-html-cross-in-origin-iframe-across-origin.html

* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::shouldConvertToBlob): Added.
(WebCore::sanitizeMarkupWithArchive):

LayoutTests:

Updated http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html to test the new behavior
whereby which HTTP/HTTPs and data URLs are not converted to blob URLs.

* http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html.html:
* http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin-expected.txt: Renamed.
* http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html: Added more test cases for data URLs.
* http/tests/security/clipboard/resources/content-to-copy.html: Notify the parent that the page had finished loading.
* http/tests/security/clipboard/resources/data-url-content-to-copy.html: Added.
* http/tests/security/clipboard/resources/subdirectory/paste-html.html: Since we can no longer access contents
in the pasted frames but scripts DO run in the pasted cross-origin iframes, rely on those frames to postMessage
this frame when the image had finished loading.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestshttptestsmisccopyresolvesurlsexpectedtxt">trunk/LayoutTests/http/tests/misc/copy-resolves-urls-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestssecurityclipboardcopypastehtmlcrossoriginiframeacrossoriginexpectedtxt">trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestssecurityclipboardcopypastehtmlcrossoriginiframeacrossoriginhtml">trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html</a></li>
<li><a href="#trunkLayoutTestshttptestssecurityclipboardresourcescontenttocopyhtml">trunk/LayoutTests/http/tests/security/clipboard/resources/content-to-copy.html</a></li>
<li><a href="#trunkLayoutTestshttptestssecurityclipboardresourcessubdirectorypastehtmlhtml">trunk/LayoutTests/http/tests/security/clipboard/resources/subdirectory/paste-html.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreeditingcocoaWebContentReaderCocoamm">trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestssecurityclipboardresourcesdataurlcontenttocopyhtml">trunk/LayoutTests/http/tests/security/clipboard/resources/data-url-content-to-copy.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/LayoutTests/ChangeLog 2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2017-12-21  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION(r223678): Cannot copy & paste a web page content into Yahoo! Mail
+        https://bugs.webkit.org/show_bug.cgi?id=181114
+
+        Reviewed by Geoffrey Garen.
+
+        Updated http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html to test the new behavior
+        whereby which HTTP/HTTPs and data URLs are not converted to blob URLs.
+
+        * http/tests/security/clipboard/copy-paste-html-across-origin-sanitizes-html.html:
+        * http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin-expected.txt: Renamed.
+        * http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html: Added more test cases for data URLs.
+        * http/tests/security/clipboard/resources/content-to-copy.html: Notify the parent that the page had finished loading.
+        * http/tests/security/clipboard/resources/data-url-content-to-copy.html: Added.
+        * http/tests/security/clipboard/resources/subdirectory/paste-html.html: Since we can no longer access contents
+        in the pasted frames but scripts DO run in the pasted cross-origin iframes, rely on those frames to postMessage
+        this frame when the image had finished loading.
+
</ins><span class="cx"> 2017-12-21  John Wilander  <wilander@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Skip http/tests/storageAccess/request-and-grant-storage-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-non-recent-user-interaction-and-try-access-from-right-frame.html
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsmisccopyresolvesurlsexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/misc/copy-resolves-urls-expected.txt (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/misc/copy-resolves-urls-expected.txt        2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/LayoutTests/http/tests/misc/copy-resolves-urls-expected.txt   2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -2,4 +2,4 @@
</span><span class="cx"> 
</span><span class="cx"> link
</span><span class="cx"> link
</span><del>-<a href="http://127.0.0.1:8000/relative/path/foo.html">link</a><img src="blob://localhost:8080/...">
</del><ins>+<a href="http://127.0.0.1:8000/relative/path/foo.html">link</a><img src="http://127.0.0.1:8000/misc/resources/compass.jpg">
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestssecurityclipboardcopypastehtmlcrossoriginiframeacrossoriginexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin-expected.txt (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin-expected.txt   2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin-expected.txt      2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -1,3 +1,7 @@
</span><ins>+CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://localhost:8080". Protocols, domains, and ports must match.
</ins><span class="cx"> This tests copying and pasting HTML by the default action. WebKit should sanitize the HTML across origin.
</span><span class="cx"> 
</span><span class="cx"> On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
</span><span class="lines">@@ -6,18 +10,28 @@
</span><span class="cx"> html in DataTransfer
</span><span class="cx"> PASS html.includes("hello") is true
</span><span class="cx"> PASS fragment = (new DOMParser).parseFromString(html, "text/html"); img = fragment.querySelector("img"); !!img is true
</span><del>-PASS new URL(img.src).protocol is "blob:"
-PASS new URL(fragment.querySelector(".same-origin-frame").src).protocol is "blob:"
-PASS new URL(fragment.querySelector(".cross-origin-frame").src).protocol is "blob:"
-PASS frames.length is 2
-PASS new URL(frames[0].src).protocol is "blob:"
-PASS frames[0].canAccessContentDocument is true
-PASS frames[0].hasImage is true
</del><ins>+PASS new URL(img.src).protocol is "http:"
+PASS new URL(fragment.querySelector(".same-origin-frame").src).protocol is "http:"
+PASS new URL(fragment.querySelector(".cross-origin-frame").src).protocol is "http:"
+PASS new URL(fragment.querySelector(".same-origin-frame-with-data-url").src).protocol is "http:"
+PASS new URL(fragment.querySelector(".cross-origin-frame-with-data-url").src).protocol is "http:"
+PASS frames.length is 4
+PASS new URL(frames[0].src).protocol is "http:"
+PASS frames[0].canAccessContentDocument is false
+PASS new URL(frames[0].imageSrc).protocol is "http:"
</ins><span class="cx"> PASS frames[0].imageWidth is 80
</span><del>-PASS new URL(frames[1].src).protocol is "blob:"
-PASS frames[1].canAccessContentDocument is true
-PASS frames[1].hasImage is true
</del><ins>+PASS new URL(frames[1].src).protocol is "http:"
+PASS frames[1].canAccessContentDocument is false
+PASS new URL(frames[1].imageSrc).protocol is "http:"
</ins><span class="cx"> PASS frames[1].imageWidth is 80
</span><ins>+PASS new URL(frames[2].src).protocol is "http:"
+PASS frames[2].canAccessContentDocument is false
+PASS new URL(frames[2].imageSrc).protocol is "data:"
+PASS frames[2].imageWidth is 10
+PASS new URL(frames[3].src).protocol is "http:"
+PASS frames[3].canAccessContentDocument is false
+PASS new URL(frames[3].imageSrc).protocol is "data:"
+PASS frames[3].imageWidth is 10
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestshttptestssecurityclipboardcopypastehtmlcrossoriginiframeacrossoriginhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html   2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/LayoutTests/http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-across-origin.html      2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -12,6 +12,8 @@
</span><span class="cx">     <img onclick="dangerousCode()" src="resources/apple.gif"><br>
</span><span class="cx">     <iframe class="same-origin-frame" src="resources/content-to-copy.html" width=80 height=80></iframe>
</span><span class="cx">     <iframe class="cross-origin-frame" src="http://localhost:8080/security/clipboard/resources/content-to-copy.html" width="100" height="100"></iframe>
</span><ins>+    <iframe class="same-origin-frame-with-data-url" src="resources/data-url-content-to-copy.html" width=80 height=80></iframe>
+    <iframe class="cross-origin-frame-with-data-url" src="http://localhost:8080/security/clipboard/resources/data-url-content-to-copy.html" width=80 height=80></iframe>
</ins><span class="cx"> </div>
</span><span class="cx"> <iframe id="destinationFrame" src="http://localhost:8000/security/clipboard/resources/subdirectory/paste-html.html"></iframe>
</span><span class="cx"> </div>
</span><span class="lines">@@ -23,6 +25,8 @@
</span><span class="cx"> if (window.internals)
</span><span class="cx">     internals.settings.setCustomPasteboardDataEnabled(true);
</span><span class="cx"> 
</span><ins>+setTimeout(finishJSTest, 3000);
+
</ins><span class="cx"> function runTest() {
</span><span class="cx">     document.getElementById('source').focus();
</span><span class="cx">     document.execCommand('selectAll');
</span><span class="lines">@@ -39,20 +43,30 @@
</span><span class="cx">         debug('html in DataTransfer');
</span><span class="cx">         shouldBeTrue('html.includes("hello")');
</span><span class="cx">         shouldBeTrue('fragment = (new DOMParser).parseFromString(html, "text/html"); img = fragment.querySelector("img"); !!img');
</span><del>-        shouldBeEqualToString('new URL(img.src).protocol', 'blob:');
-        shouldBeEqualToString('new URL(fragment.querySelector(".same-origin-frame").src).protocol', 'blob:');
-        shouldBeEqualToString('new URL(fragment.querySelector(".cross-origin-frame").src).protocol', 'blob:');
</del><ins>+        shouldBeEqualToString('new URL(img.src).protocol', 'http:');
+        shouldBeEqualToString('new URL(fragment.querySelector(".same-origin-frame").src).protocol', 'http:');
+        shouldBeEqualToString('new URL(fragment.querySelector(".cross-origin-frame").src).protocol', 'http:');
+        shouldBeEqualToString('new URL(fragment.querySelector(".same-origin-frame-with-data-url").src).protocol', 'http:');
+        shouldBeEqualToString('new URL(fragment.querySelector(".cross-origin-frame-with-data-url").src).protocol', 'http:');
</ins><span class="cx">     } else if (event.data.type == 'checkedState') {
</span><span class="cx">         frames = event.data.frames;
</span><del>-        shouldBe('frames.length', '2');
-        shouldBeEqualToString('new URL(frames[0].src).protocol', 'blob:');
-        shouldBeTrue('frames[0].canAccessContentDocument');
-        shouldBeTrue('frames[0].hasImage');
</del><ins>+        shouldBe('frames.length', '4');
+        shouldBeEqualToString('new URL(frames[0].src).protocol', 'http:');
+        shouldBeFalse('frames[0].canAccessContentDocument');
+        shouldBeEqualToString('new URL(frames[0].imageSrc).protocol', 'http:');
</ins><span class="cx">         shouldBe('frames[0].imageWidth', '80');
</span><del>-        shouldBeEqualToString('new URL(frames[1].src).protocol', 'blob:');
-        shouldBeTrue('frames[1].canAccessContentDocument');
-        shouldBeTrue('frames[1].hasImage');
</del><ins>+        shouldBeEqualToString('new URL(frames[1].src).protocol', 'http:');
+        shouldBeFalse('frames[1].canAccessContentDocument');
+        shouldBeEqualToString('new URL(frames[1].imageSrc).protocol', 'http:');
</ins><span class="cx">         shouldBe('frames[1].imageWidth', '80');
</span><ins>+        shouldBeEqualToString('new URL(frames[2].src).protocol', 'http:');
+        shouldBeFalse('frames[2].canAccessContentDocument');
+        shouldBeEqualToString('new URL(frames[2].imageSrc).protocol', 'data:');
+        shouldBe('frames[2].imageWidth', '10');
+        shouldBeEqualToString('new URL(frames[3].src).protocol', 'http:');
+        shouldBeFalse('frames[3].canAccessContentDocument');
+        shouldBeEqualToString('new URL(frames[3].imageSrc).protocol', 'data:');
+        shouldBe('frames[3].imageWidth', '10');
</ins><span class="cx">         if (window.testRunner)
</span><span class="cx">             container.remove();
</span><span class="cx">         finishJSTest();
</span></span></pre></div>
<a id="trunkLayoutTestshttptestssecurityclipboardresourcescontenttocopyhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/security/clipboard/resources/content-to-copy.html (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/security/clipboard/resources/content-to-copy.html   2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/LayoutTests/http/tests/security/clipboard/resources/content-to-copy.html      2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -3,7 +3,10 @@
</span><span class="cx"> <body>
</span><span class="cx"> <img src="mozilla.gif">
</span><span class="cx"> <script>
</span><del>-window.onload = parent.postMessage({type: 'contentLoaded'}, '*');
</del><ins>+window.onload = () => {
+    const image = document.querySelector('img');
+    parent.postMessage({type: 'contentLoaded', imageSrc: image.src, imageWidth: image.width}, '*');
+}
</ins><span class="cx"> </script>
</span><span class="cx"> </body>
</span><span class="cx"> </html>
</span></span></pre></div>
<a id="trunkLayoutTestshttptestssecurityclipboardresourcesdataurlcontenttocopyhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/security/clipboard/resources/data-url-content-to-copy.html (0 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/security/clipboard/resources/data-url-content-to-copy.html                          (rev 0)
+++ trunk/LayoutTests/http/tests/security/clipboard/resources/data-url-content-to-copy.html     2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAUFJREFUGNMBNgHJ/gPcUkznH/n8lGR5YkMIIMDXFhgoVNnfqeM5dbre55MDGkF/U6tMmi12K6QBpfkB4H3NyPZAiyjm6kp//uPtAA4pZhHPJ8xbkSop4chy5ecPsVSqkC03ozAmk77SOwOHR+fDXmoF5UUJU9YsnVfehg/iLC7p3etC3w3LEA8D0eGf/DZozPPzoSSX6gTVlQ/L4Ylt4SrFiOgqNDQPAPvl/JQuLv33xK66eAgGCn+OAIUu1Fugs2hsZNIB6gPhrZ80q7sXNUEuIE7EGNC5Dc2ExcIe9tseb4r7usAAralzLgdas9URX21wGUqSgDnf/jMydhxMIEx4w9TtAfCQPsbi30EEVABXFJYnOZgfbQK3CLkwg6PDGG27KwOYF7jD+sIHhdwoUyILAF5sv/6bI6S56fbULB5OToUjFpS7UHGrVgAAAABJRU5ErkJggg==">
+<script>
+window.onload = () => {
+    const image = document.querySelector('img');
+    parent.postMessage({type: 'contentLoaded', imageSrc: image.src, imageWidth: image.width}, '*');
+}
+</script>
+</body>
+</html>
+
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestssecurityclipboardresourcessubdirectorypastehtmlhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/security/clipboard/resources/subdirectory/paste-html.html (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/security/clipboard/resources/subdirectory/paste-html.html   2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/LayoutTests/http/tests/security/clipboard/resources/subdirectory/paste-html.html      2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -2,6 +2,7 @@
</span><span class="cx"> <html>
</span><span class="cx"> <head>
</span><span class="cx"> <script>
</span><ins>+let loadedContent = [];
</ins><span class="cx"> onmessage = function (event) {
</span><span class="cx">     if (event.data.type == 'paste') {
</span><span class="cx">         document.body.focus();
</span><span class="lines">@@ -8,6 +9,9 @@
</span><span class="cx">         document.execCommand('selectAll');
</span><span class="cx">         if (window.testRunner)
</span><span class="cx">             document.execCommand('paste');
</span><ins>+    } else if (event.data.type == 'contentLoaded') {
+        loadedContent.push(event.data);
+        checkIfLoadCompleted();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -14,41 +18,23 @@
</span><span class="cx"> let frames = [];
</span><span class="cx"> function doPaste(event) {
</span><span class="cx">     top.postMessage({type: 'pasted', html: event.clipboardData.getData('text/html')}, '*');
</span><del>-    setTimeout(() => {
-        frames = Array.from(document.body.querySelectorAll('iframe'));
</del><ins>+}
</ins><span class="cx"> 
</span><del>-        Promise.all(frames.map((frame) => {
-            return new Promise((resolve) => {
-                const waitForImage = () => {
-                    const img = frame.contentDocument.querySelector('img');
-                    if (img && !img.complete)
-                        img.onload = resolve;
-                    else
-                        resolve();
-                }
</del><ins>+function checkIfLoadCompleted() {
+    const frames = Array.from(document.body.querySelectorAll('iframe'));
+    if (loadedContent.length < frames.length)
+        return;
</ins><span class="cx"> 
</span><del>-                if (frame.contentDocument && (!frame.contentDocument.body || frame.contentDocument.body.innerHTML == ''))
-                    frame.onload = waitForImage;
-                else
-                    waitForImage();
-
-            });
-        })).then(checkState);
-    }, 0);
-}
-
-function checkState() {
</del><span class="cx">     top.postMessage({
</span><span class="cx">         type: 'checkedState',
</span><span class="cx">         html: document.body.innerHTML,
</span><del>-        frames: frames.map((frame) => {
-            const img = frame.contentDocument ? frame.contentDocument.querySelector('img') : null;
</del><ins>+        frames: frames.map((frame, i) => {
</ins><span class="cx">             return {
</span><span class="cx">                 src: frame.src,
</span><span class="cx">                 class: frame.className,
</span><span class="cx">                 canAccessContentDocument: !!frame.contentDocument,
</span><del>-                hasImage: !!img,
-                imageWidth: img ? img.width : null,
</del><ins>+                imageSrc: loadedContent[i].imageSrc,
+                imageWidth: loadedContent[i].imageWidth,
</ins><span class="cx">             }
</span><span class="cx">         })}, '*');
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/Source/WebCore/ChangeLog      2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2017-12-21  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION(r223678): Cannot copy & paste a web page content into Yahoo! Mail
+        https://bugs.webkit.org/show_bug.cgi?id=181114
+
+        Reviewed by Geoffrey Garen.
+
+        Turns out converting all URLs to blob isn't Web compatible. Don't do this conversion on HTTP, HTTP, and data URLs
+        since websites tend to have access to contents accessible via those protocols, and blob URL conversion would break
+        Yahoo! Mail, Gmail, and other major online email services.
+
+        We've also considered using data URLs instead of blob URLs for conversion but pasting a large image converted into
+        a data URL seems to break WordPress (it stores an empty post instead of the one with the image) so it's not likely
+        to be Web compatible either.
+
+        This patch therefore disables the blob conversion in sanitizeMarkupWithArchive for HTTP, HTTPS, data URLs for
+        cross-origin content, restoring the behavior prior to r223678. For contents converted from attributed strings,
+        we continue to convert to blob URL since there is no other way for websites to read local files or images references
+        by an in-memory web archive.
+
+        Tests: http/tests/security/clipboard/copy-paste-html-cross-in-origin-iframe-across-origin.html
+
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::shouldConvertToBlob): Added.
+        (WebCore::sanitizeMarkupWithArchive):
+
</ins><span class="cx"> 2017-12-22  Michael Catanzaro  <mcatanzaro@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         Credentials warning spam when running CodeGenerator.pm
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingcocoaWebContentReaderCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm (226271 => 226272)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm      2017-12-22 20:40:23 UTC (rev 226271)
+++ trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm 2017-12-22 20:41:48 UTC (rev 226272)
</span><span class="lines">@@ -353,6 +353,11 @@
</span><span class="cx">     return createMarkup(range.get(), nullptr, AnnotateForInterchange, false, ResolveNonLocalURLs);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool shouldConvertToBlob(const URL& url)
+{
+    return !(url.protocolIsInHTTPFamily() || url.protocolIsData());
+}
+
</ins><span class="cx"> static String sanitizeMarkupWithArchive(Document& destinationDocument, MarkupAndArchive& markupAndArchive, const std::function<bool(const String)>& canShowMIMETypeAsHTML)
</span><span class="cx"> {
</span><span class="cx">     auto page = createPageForSanitizingWebContent();
</span><span class="lines">@@ -367,9 +372,12 @@
</span><span class="cx"> 
</span><span class="cx">     HashMap<AtomicString, AtomicString> blobURLMap;
</span><span class="cx">     for (const Ref<ArchiveResource>& subresource : markupAndArchive.archive->subresources()) {
</span><ins>+        auto& subresourceURL = subresource->url();
+        if (!shouldConvertToBlob(subresourceURL))
+            continue;
</ins><span class="cx">         auto blob = Blob::create(subresource->data(), subresource->mimeType());
</span><span class="cx">         String blobURL = DOMURL::createObjectURL(destinationDocument, blob);
</span><del>-        blobURLMap.set(subresource->url().string(), blobURL);
</del><ins>+        blobURLMap.set(subresourceURL.string(), blobURL);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     auto contentOrigin = SecurityOrigin::create(markupAndArchive.mainResource->url());
</span><span class="lines">@@ -383,6 +391,9 @@
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="cx">         auto subframeURL = subframeMainResource->url();
</span><ins>+        if (!shouldConvertToBlob(subframeURL))
+            continue;
+
</ins><span class="cx">         MarkupAndArchive subframeContent = { String::fromUTF8(subframeMainResource->data().data(), subframeMainResource->data().size()),
</span><span class="cx">             subframeMainResource.releaseNonNull(), subframeArchive.copyRef() };
</span><span class="cx">         auto subframeMarkup = sanitizeMarkupWithArchive(destinationDocument, subframeContent, canShowMIMETypeAsHTML);
</span></span></pre>
</div>
</div>

</body>
</html>