<!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>[244617] 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/244617">244617</a></dd>
<dt>Author</dt> <dd>beidson@apple.com</dd>
<dt>Date</dt> <dd>2019-04-24 15:03:04 -0700 (Wed, 24 Apr 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>XMLHTTPRequest POSTs to a custom WKURLSchemeHandler protocol are missing the HTTP body.
https://bugs.webkit.org/show_bug.cgi?id=191362

Reviewed by Alex Christensen.

Source/WebCore:

Covered by new API tests.

In 2008 some refactoring added an HTTP(S)-only restriction to copying the form body for
XHRs that POST, and it added that restriction with no explanation.

We definitely want to allow that.

Blobs are broken at this time (covered by bug 197237)

* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::send):
(WebCore::XMLHttpRequest::sendBytesData):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm: Add a test that POSTs all sorts of things
  from an XHR to a custom protocol.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorexmlXMLHttpRequestcpp">trunk/Source/WebCore/xml/XMLHttpRequest.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitCocoaWKURLSchemeHandler1mm">trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (244616 => 244617)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-04-24 21:41:42 UTC (rev 244616)
+++ trunk/Source/WebCore/ChangeLog      2019-04-24 22:03:04 UTC (rev 244617)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2019-04-24  Brady Eidson  <beidson@apple.com>
+
+        XMLHTTPRequest POSTs to a custom WKURLSchemeHandler protocol are missing the HTTP body.
+        https://bugs.webkit.org/show_bug.cgi?id=191362
+
+        Reviewed by Alex Christensen.
+
+        Covered by new API tests.
+
+        In 2008 some refactoring added an HTTP(S)-only restriction to copying the form body for
+        XHRs that POST, and it added that restriction with no explanation.
+
+        We definitely want to allow that.
+
+        Blobs are broken at this time (covered by bug 197237)
+
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::send):
+        (WebCore::XMLHttpRequest::sendBytesData):
+
</ins><span class="cx"> 2019-04-24  John Wilander  <wilander@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Age out unconverted Ad Click Attributions after one week.
</span></span></pre></div>
<a id="trunkSourceWebCorexmlXMLHttpRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (244616 => 244617)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp      2019-04-24 21:41:42 UTC (rev 244616)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2019-04-24 22:03:04 UTC (rev 244617)
</span><span class="lines">@@ -459,7 +459,7 @@
</span><span class="cx">     if (auto result = prepareToSend())
</span><span class="cx">         return WTFMove(result.value());
</span><span class="cx"> 
</span><del>-    if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
</del><ins>+    if (m_method != "GET" && m_method != "HEAD") {
</ins><span class="cx">         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType)) {
</span><span class="cx"> #if ENABLE(DASHBOARD_SUPPORT)
</span><span class="cx">             if (usesDashboardBackwardCompatibilityMode())
</span><span class="lines">@@ -489,7 +489,7 @@
</span><span class="cx">     if (auto result = prepareToSend())
</span><span class="cx">         return WTFMove(result.value());
</span><span class="cx"> 
</span><del>-    if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
</del><ins>+    if (!body.isNull() && m_method != "GET" && m_method != "HEAD") {
</ins><span class="cx">         String contentType = m_requestHeaders.get(HTTPHeaderName::ContentType);
</span><span class="cx">         if (contentType.isNull()) {
</span><span class="cx"> #if ENABLE(DASHBOARD_SUPPORT)
</span><span class="lines">@@ -516,7 +516,17 @@
</span><span class="cx">     if (auto result = prepareToSend())
</span><span class="cx">         return WTFMove(result.value());
</span><span class="cx"> 
</span><del>-    if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
</del><ins>+    if (m_method != "GET" && m_method != "HEAD") {
+        if (!m_url.protocolIsInHTTPFamily()) {
+            // FIXME: We would like to support posting Blobs to non-http URLs (e.g. custom URL schemes)
+            // but because of the architecture of blob-handling that will require a fair amount of work.
+            
+            ASCIILiteral consoleMessage { "POST of a Blob to non-HTTP protocols in XMLHttpRequest.send() is currently unsupported."_s };
+            scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, consoleMessage);
+            
+            return createRequest();
+        }
+        
</ins><span class="cx">         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType)) {
</span><span class="cx">             const String& blobType = body.type();
</span><span class="cx">             if (!blobType.isEmpty() && isValidContentType(blobType))
</span><span class="lines">@@ -539,7 +549,7 @@
</span><span class="cx">     if (auto result = prepareToSend())
</span><span class="cx">         return WTFMove(result.value());
</span><span class="cx"> 
</span><del>-    if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
</del><ins>+    if (m_method != "GET" && m_method != "HEAD") {
</ins><span class="cx">         m_requestEntityBody = FormData::createMultiPart(body, document());
</span><span class="cx">         m_requestEntityBody->generateFiles(document());
</span><span class="cx">         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType))
</span><span class="lines">@@ -566,7 +576,7 @@
</span><span class="cx">     if (auto result = prepareToSend())
</span><span class="cx">         return WTFMove(result.value());
</span><span class="cx"> 
</span><del>-    if (m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFamily()) {
</del><ins>+    if (m_method != "GET" && m_method != "HEAD") {
</ins><span class="cx">         m_requestEntityBody = FormData::create(data, length);
</span><span class="cx">         if (m_upload)
</span><span class="cx">             m_requestEntityBody->setAlwaysStream(true);
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (244616 => 244617)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2019-04-24 21:41:42 UTC (rev 244616)
+++ trunk/Tools/ChangeLog       2019-04-24 22:03:04 UTC (rev 244617)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2019-04-24  Brady Eidson  <beidson@apple.com>
+
+        XMLHTTPRequest POSTs to a custom WKURLSchemeHandler protocol are missing the HTTP body.
+        https://bugs.webkit.org/show_bug.cgi?id=191362
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm: Add a test that POSTs all sorts of things
+          from an XHR to a custom protocol.
+
</ins><span class="cx"> 2019-04-24  John Wilander  <wilander@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Age out unconverted Ad Click Attributions after one week.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitCocoaWKURLSchemeHandler1mm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm (244616 => 244617)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm      2019-04-24 21:41:42 UTC (rev 244616)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKURLSchemeHandler-1.mm 2019-04-24 22:03:04 UTC (rev 244617)
</span><span class="lines">@@ -27,6 +27,9 @@
</span><span class="cx"> 
</span><span class="cx"> #import "PlatformUtilities.h"
</span><span class="cx"> #import "Test.h"
</span><ins>+#import "TestNavigationDelegate.h"
+#import "TestURLSchemeHandler.h"
+#import "TestWKWebView.h"
</ins><span class="cx"> #import <WebKit/WKURLSchemeHandler.h>
</span><span class="cx"> #import <WebKit/WKURLSchemeTaskPrivate.h>
</span><span class="cx"> #import <WebKit/WKWebViewConfigurationPrivate.h>
</span><span class="lines">@@ -579,4 +582,113 @@
</span><span class="cx">     TestWebKitAPI::Util::run(&done);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static const char* xhrPostDocument = R"XHRPOSTRESOURCE(<html><head><script>
+window.onload = function()
+{
+    {
+        var xhr = new XMLHttpRequest();
+        xhr.open('POST', '/arraybuffer');
+        
+        var chars = [];
+        var str = "Hi there";
+        for (var i = 0; i < str.length; ++i)
+            chars.push(str.charCodeAt(i));
</ins><span class="cx"> 
</span><ins>+        xhr.send(new Uint8Array(chars));
+    }
+    {
+        var xhr = new XMLHttpRequest();
+        xhr.open('POST', '/string');
+        xhr.send('foo=bar');
+    }
+    {
+        var xhr = new XMLHttpRequest();
+        xhr.open('POST', '/document');
+        xhr.send(window.document);
+    }
+    {
+        var xhr = new XMLHttpRequest();
+        xhr.open('POST', '/formdata');
+        
+        var formData = new FormData();
+        formData.append("foo", "baz");
+        xhr.send(formData);
+    }
+    {
+//        // FIXME: XHR posting of Blobs is currently unsupported
+//        // https://bugs.webkit.org/show_bug.cgi?id=197237
+//        var xhr = new XMLHttpRequest();
+//        xhr.open('POST', '/blob');
+//        var blob = new Blob(["Hello world!"], {type: "text/plain"});
+//        xhr.send(blob);
+    }
+};
+</script></head>
+<body>
+Hello world!
+</body></html>)XHRPOSTRESOURCE";
+
+
+TEST(URLSchemeHandler, XHRPost)
+{
+    auto handler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration setURLSchemeHandler:handler.get() forURLScheme:@"xhrpost"];
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+
+    static bool done;
+    static uint8_t seenTasks;
+    [handler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
+        if ([task.request.URL.absoluteString isEqualToString:@"xhrpost://example/string"]) {
+            static bool reached;
+            EXPECT_FALSE(reached);
+            reached = true;
+            EXPECT_EQ(task.request.HTTPBody.length, 7u);
+            EXPECT_STREQ(static_cast<const char*>(task.request.HTTPBody.bytes), "foo=bar");
+        } else if ([task.request.URL.absoluteString isEqualToString:@"xhrpost://example/arraybuffer"]) {
+            static bool reached;
+            EXPECT_FALSE(reached);
+            reached = true;
+            EXPECT_EQ(task.request.HTTPBody.length, 8u);
+            EXPECT_STREQ(static_cast<const char*>(task.request.HTTPBody.bytes), "Hi there");
+        } else if ([task.request.URL.absoluteString isEqualToString:@"xhrpost://example/document"]) {
+            static bool reached;
+            EXPECT_FALSE(reached);
+            reached = true;
+            EXPECT_EQ(task.request.HTTPBody.length, strlen(xhrPostDocument));
+            EXPECT_STREQ(static_cast<const char*>(task.request.HTTPBody.bytes), xhrPostDocument);
+        } else if ([task.request.URL.absoluteString isEqualToString:@"xhrpost://example/formdata"]) {
+            static bool reached;
+            EXPECT_FALSE(reached);
+            reached = true;
+            // The length of this is variable
+            auto *formDataString = [NSString stringWithUTF8String:static_cast<const char*>(task.request.HTTPBody.bytes)];
+            EXPECT_TRUE([formDataString containsString:@"Content-Disposition: form-data; name=\"foo\""]);
+            EXPECT_TRUE([formDataString containsString:@"baz"]);
+            EXPECT_TRUE([formDataString containsString:@"WebKitFormBoundary"]);
+        } else if ([task.request.URL.absoluteString isEqualToString:@"xhrpost://example/blob"]) {
+            static bool reached;
+            EXPECT_FALSE(reached);
+            reached = true;
+            
+            // FIXME: XHR posting of Blobs is currently unsupported
+            // https://bugs.webkit.org/show_bug.cgi?id=197237
+
+            FAIL();
+        } else {
+            // We only expect one of the 5 URLs up above.
+            FAIL();
+        }
+
+        auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:0 textEncodingName:nil]);
+        [task didReceiveResponse:response.get()];
+        [task didFinish];
+        
+        if (++seenTasks == 4)
+            done = true;
+    }];
+    
+    [webView loadHTMLString:[NSString stringWithUTF8String:xhrPostDocument] baseURL:[NSURL URLWithString:@"xhrpost://example/xhrtest"]];
+    TestWebKitAPI::Util::run(&done);
+}
+
</ins></span></pre>
</div>
</div>

</body>
</html>