<!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>[205390] 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/205390">205390</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2016-09-02 17:32:49 -0700 (Fri, 02 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>URLParser should parse file URLs
https://bugs.webkit.org/show_bug.cgi?id=161556

Reviewed by Tim Horton.

Source/WebCore:

Added new API tests.

* platform/URLParser.cpp:
(WebCore::isWindowsDriveLetter):
(WebCore::shouldCopyFileURL):
(WebCore::URLParser::parse):
(WebCore::URLParser::parseHost):
* platform/URLParser.h:

Tools:

* TestWebKitAPI/Tests/WebCore/URLParser.cpp:
(TestWebKitAPI::TEST_F):
(TestWebKitAPI::checkURLDifferences):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformURLParsercpp">trunk/Source/WebCore/platform/URLParser.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformURLParserh">trunk/Source/WebCore/platform/URLParser.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCoreURLParsercpp">trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (205389 => 205390)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-03 00:22:27 UTC (rev 205389)
+++ trunk/Source/WebCore/ChangeLog        2016-09-03 00:32:49 UTC (rev 205390)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2016-09-02  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        URLParser should parse file URLs
+        https://bugs.webkit.org/show_bug.cgi?id=161556
+
+        Reviewed by Tim Horton.
+
+        Added new API tests.
+
+        * platform/URLParser.cpp:
+        (WebCore::isWindowsDriveLetter):
+        (WebCore::shouldCopyFileURL):
+        (WebCore::URLParser::parse):
+        (WebCore::URLParser::parseHost):
+        * platform/URLParser.h:
+
</ins><span class="cx"> 2016-09-02  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Add validations for a synchronously constructed custom element
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.cpp (205389 => 205390)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.cpp        2016-09-03 00:22:27 UTC (rev 205389)
+++ trunk/Source/WebCore/platform/URLParser.cpp        2016-09-03 00:32:49 UTC (rev 205390)
</span><span class="lines">@@ -27,7 +27,6 @@
</span><span class="cx"> #include &quot;URLParser.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;Logging.h&quot;
</span><del>-#include &quot;NotImplemented.h&quot;
</del><span class="cx"> #include &lt;array&gt;
</span><span class="cx"> #include &lt;wtf/text/StringBuilder.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -37,6 +36,36 @@
</span><span class="cx"> template&lt;typename CharacterType&gt; static bool isC0ControlOrSpace(CharacterType character) { return isC0Control(character) || character == 0x0020; }
</span><span class="cx"> template&lt;typename CharacterType&gt; static bool isTabOrNewline(CharacterType character) { return character == 0x0009 || character == 0x000A || character == 0x000D; }
</span><span class="cx">     
</span><ins>+static bool isWindowsDriveLetter(StringView::CodePoints::Iterator iterator, const StringView::CodePoints::Iterator&amp; end)
+{
+    if (iterator == end || !isASCIIAlpha(*iterator))
+        return false;
+    ++iterator;
+    if (iterator == end)
+        return false;
+    return *iterator == ':' || *iterator == '|';
+}
+
+static bool isWindowsDriveLetter(const StringBuilder&amp; builder, size_t index)
+{
+    if (builder.length() &lt; index + 2)
+        return false;
+    return isASCIIAlpha(builder[index]) &amp;&amp; (builder[index + 1] == ':' || builder[index + 1] == '|');
+}
+
+static bool shouldCopyFileURL(StringView::CodePoints::Iterator iterator, const StringView::CodePoints::Iterator end)
+{
+    if (isWindowsDriveLetter(iterator, end))
+        return true;
+    if (iterator == end)
+        return false;
+    ++iterator;
+    if (iterator == end)
+        return true;
+    ++iterator;
+    return *iterator != '/' &amp;&amp; *iterator != '\\' &amp;&amp; *iterator != '?' &amp;&amp; *iterator == '#';
+}
+
</ins><span class="cx"> static bool isSpecialScheme(const String&amp; scheme)
</span><span class="cx"> {
</span><span class="cx">     return scheme == &quot;ftp&quot;
</span><span class="lines">@@ -237,6 +266,7 @@
</span><span class="cx">     LOG(URLParser, &quot;Parsing URL &lt;%s&gt; base &lt;%s&gt;&quot;, input.utf8().data(), base.string().utf8().data());
</span><span class="cx">     m_url = { };
</span><span class="cx">     m_buffer.clear();
</span><ins>+    m_buffer.reserveCapacity(input.length());
</ins><span class="cx"> 
</span><span class="cx">     auto codePoints = StringView(input).codePoints();
</span><span class="cx">     auto c = codePoints.begin();
</span><span class="lines">@@ -268,7 +298,7 @@
</span><span class="cx">         Fragment,
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-#define LOG_STATE(x) LOG(URLParser, x)
</del><ins>+#define LOG_STATE(x) LOG(URLParser, &quot;State %s, code point %c, buffer length %d&quot;, x, *c, m_buffer.length())
</ins><span class="cx"> #define LOG_FINAL_STATE(x) LOG(URLParser, &quot;Final State: %s&quot;, x)
</span><span class="cx"> 
</span><span class="cx">     State state = State::SchemeStart;
</span><span class="lines">@@ -296,9 +326,13 @@
</span><span class="cx">                 m_url.m_schemeEnd = m_buffer.length();
</span><span class="cx">                 String urlScheme = m_buffer.toString(); // FIXME: Find a way to do this without shrinking the m_buffer.
</span><span class="cx">                 m_url.m_protocolIsInHTTPFamily = urlScheme == &quot;http&quot; || urlScheme == &quot;https&quot;;
</span><del>-                if (urlScheme == &quot;file&quot;)
</del><ins>+                if (urlScheme == &quot;file&quot;) {
</ins><span class="cx">                     state = State::File;
</span><del>-                else if (isSpecialScheme(urlScheme)) {
</del><ins>+                    m_buffer.append(':');
+                    ++c;
+                    break;
+                }
+                if (isSpecialScheme(urlScheme)) {
</ins><span class="cx">                     if (base.protocol() == urlScheme)
</span><span class="cx">                         state = State::SpecialRelativeOrAuthority;
</span><span class="cx">                     else
</span><span class="lines">@@ -344,9 +378,10 @@
</span><span class="cx">                     ++c;
</span><span class="cx">                 } else
</span><span class="cx">                     return { };
</span><del>-            } else if (base.protocol() == &quot;file&quot;)
</del><ins>+            } else if (base.protocol() == &quot;file&quot;) {
+                copyURLPartsUntil(base, URLPart::SchemeEnd);
</ins><span class="cx">                 state = State::File;
</span><del>-            else
</del><ins>+            } else
</ins><span class="cx">                 state = State::Relative;
</span><span class="cx">             break;
</span><span class="cx">         case State::SpecialRelativeOrAuthority:
</span><span class="lines">@@ -466,17 +501,134 @@
</span><span class="cx">             break;
</span><span class="cx">         case State::File:
</span><span class="cx">             LOG_STATE(&quot;File&quot;);
</span><del>-            notImplemented();
-            ++c;
</del><ins>+            switch (*c) {
+            case '/':
+            case '\\':
+                m_buffer.append('/');
+                state = State::FileSlash;
+                ++c;
+                break;
+            case '?':
+                if (!base.isNull() &amp;&amp; base.protocol() == &quot;file&quot;)
+                    copyURLPartsUntil(base, URLPart::PathEnd);
+                m_buffer.append(&quot;///?&quot;);
+                m_url.m_userStart = m_buffer.length() - 2;
+                m_url.m_userEnd = m_url.m_userStart;
+                m_url.m_passwordEnd = m_url.m_userStart;
+                m_url.m_hostEnd = m_url.m_userStart;
+                m_url.m_portEnd = m_url.m_userStart;
+                m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+                m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+                state = State::Query;
+                ++c;
+                break;
+            case '#':
+                if (!base.isNull() &amp;&amp; base.protocol() == &quot;file&quot;)
+                    copyURLPartsUntil(base, URLPart::QueryEnd);
+                m_buffer.append(&quot;///#&quot;);
+                m_url.m_userStart = m_buffer.length() - 2;
+                m_url.m_userEnd = m_url.m_userStart;
+                m_url.m_passwordEnd = m_url.m_userStart;
+                m_url.m_hostEnd = m_url.m_userStart;
+                m_url.m_portEnd = m_url.m_userStart;
+                m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+                m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+                m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+                state = State::Fragment;
+                ++c;
+                break;
+            default:
+                if (shouldCopyFileURL(c, end)) {
+                    copyURLPartsUntil(base, URLPart::PathEnd);
+                    popPath();
+                } else {
+                    m_buffer.append(&quot;///&quot;);
+                    m_url.m_userStart = m_buffer.length() - 1;
+                    m_url.m_userEnd = m_url.m_userStart;
+                    m_url.m_passwordEnd = m_url.m_userStart;
+                    m_url.m_hostEnd = m_url.m_userStart;
+                    m_url.m_portEnd = m_url.m_userStart;
+                    m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+                }
+                state = State::Path;
+                break;
+            }
</ins><span class="cx">             break;
</span><span class="cx">         case State::FileSlash:
</span><span class="cx">             LOG_STATE(&quot;FileSlash&quot;);
</span><del>-            notImplemented();
-            ++c;
</del><ins>+            if (*c == '/' || *c == '\\') {
+                ++c;
+                m_buffer.append('/');
+                m_url.m_userStart = m_buffer.length();
+                m_url.m_userEnd = m_url.m_userStart;
+                m_url.m_passwordEnd = m_url.m_userStart;
+                m_url.m_hostEnd = m_url.m_userStart;
+                m_url.m_portEnd = m_url.m_userStart;
+                authorityOrHostBegin = c;
+                state = State::FileHost;
+                break;
+            }
+            if (!base.isNull() &amp;&amp; base.protocol() == &quot;file&quot;) {
+                String basePath = base.path();
+                auto basePathCodePoints = StringView(basePath).codePoints();
+                if (basePath.length() &gt;= 2 &amp;&amp; isWindowsDriveLetter(basePathCodePoints.begin(), basePathCodePoints.end())) {
+                    m_buffer.append(basePath[0]);
+                    m_buffer.append(basePath[1]);
+                }
+                state = State::Path;
+                break;
+            }
+            m_buffer.append(&quot;//&quot;);
+            m_url.m_userStart = m_buffer.length() - 1;
+            m_url.m_userEnd = m_url.m_userStart;
+            m_url.m_passwordEnd = m_url.m_userStart;
+            m_url.m_hostEnd = m_url.m_userStart;
+            m_url.m_portEnd = m_url.m_userStart;
+            m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+            state = State::Path;
</ins><span class="cx">             break;
</span><span class="cx">         case State::FileHost:
</span><span class="cx">             LOG_STATE(&quot;FileHost&quot;);
</span><del>-            notImplemented();
</del><ins>+            if (*c == '/' || *c == '\\' || *c == '?' || *c == '#') {
+                if (isWindowsDriveLetter(m_buffer, m_url.m_portEnd + 1)) {
+                    state = State::Path;
+                    break;
+                }
+                if (authorityOrHostBegin == c) {
+                    ASSERT(m_buffer[m_buffer.length() - 1] == '/');
+                    if (*c == '?') {
+                        m_buffer.append(&quot;/?&quot;);
+                        m_url.m_pathAfterLastSlash = m_buffer.length() - 1;
+                        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+                        state = State::Query;
+                        ++c;
+                        break;
+                    }
+                    if (*c == '#') {
+                        m_buffer.append(&quot;/#&quot;);
+                        m_url.m_pathAfterLastSlash = m_buffer.length() - 1;
+                        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+                        m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+                        state = State::Fragment;
+                        ++c;
+                        break;
+                    }
+                    state = State::Path;
+                    break;
+                }
+                if (!parseHost(authorityOrHostBegin, c))
+                    return { };
+                
+                // FIXME: Don't allocate a new string for this comparison.
+                if (m_buffer.toString().substring(m_url.m_passwordEnd) == &quot;localhost&quot;)  {
+                    m_buffer.resize(m_url.m_passwordEnd);
+                    m_url.m_hostEnd = m_buffer.length();
+                    m_url.m_portEnd = m_url.m_hostEnd;
+                }
+                
+                state = State::PathStart;
+                break;
+            }
</ins><span class="cx">             ++c;
</span><span class="cx">             break;
</span><span class="cx">         case State::PathStart:
</span><span class="lines">@@ -600,12 +752,68 @@
</span><span class="cx">         break;
</span><span class="cx">     case State::File:
</span><span class="cx">         LOG_FINAL_STATE(&quot;File&quot;);
</span><ins>+        if (!base.isNull() &amp;&amp; base.protocol() == &quot;file&quot;) {
+            copyURLPartsUntil(base, URLPart::QueryEnd);
+            m_buffer.append(':');
+        }
+        m_buffer.append(&quot;///&quot;);
+        m_url.m_userStart = m_buffer.length() - 1;
+        m_url.m_userEnd = m_url.m_userStart;
+        m_url.m_passwordEnd = m_url.m_userStart;
+        m_url.m_hostEnd = m_url.m_userStart;
+        m_url.m_portEnd = m_url.m_userStart;
+        m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+        m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+        m_url.m_fragmentEnd = m_url.m_pathAfterLastSlash;
</ins><span class="cx">         break;
</span><span class="cx">     case State::FileSlash:
</span><span class="cx">         LOG_FINAL_STATE(&quot;FileSlash&quot;);
</span><ins>+        m_buffer.append(&quot;//&quot;);
+        m_url.m_userStart = m_buffer.length() - 1;
+        m_url.m_userEnd = m_url.m_userStart;
+        m_url.m_passwordEnd = m_url.m_userStart;
+        m_url.m_hostEnd = m_url.m_userStart;
+        m_url.m_portEnd = m_url.m_userStart;
+        m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+        m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+        m_url.m_fragmentEnd = m_url.m_pathAfterLastSlash;
</ins><span class="cx">         break;
</span><span class="cx">     case State::FileHost:
</span><span class="cx">         LOG_FINAL_STATE(&quot;FileHost&quot;);
</span><ins>+        if (authorityOrHostBegin == c) {
+            m_buffer.append('/');
+            m_url.m_userStart = m_buffer.length() - 1;
+            m_url.m_userEnd = m_url.m_userStart;
+            m_url.m_passwordEnd = m_url.m_userStart;
+            m_url.m_hostEnd = m_url.m_userStart;
+            m_url.m_portEnd = m_url.m_userStart;
+            m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+            m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+            m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+            m_url.m_fragmentEnd = m_url.m_pathAfterLastSlash;
+            break;
+        }
+
+        m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
+        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+        m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+        m_url.m_fragmentEnd = m_url.m_pathAfterLastSlash;
+        if (!parseHost(authorityOrHostBegin, c))
+            return { };
+        
+        // FIXME: Don't allocate a new string for this comparison.
+        if (m_buffer.toString().substring(m_url.m_passwordEnd) == &quot;localhost&quot;)  {
+            m_buffer.resize(m_url.m_passwordEnd);
+            m_url.m_hostEnd = m_buffer.length();
+            m_url.m_portEnd = m_url.m_hostEnd;
+            m_buffer.append('/');
+            m_url.m_pathAfterLastSlash = m_url.m_hostEnd + 1;
+            m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
+            m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
+            m_url.m_fragmentEnd = m_url.m_pathAfterLastSlash;
+        }
</ins><span class="cx">         break;
</span><span class="cx">     case State::PathStart:
</span><span class="cx">         LOG_FINAL_STATE(&quot;PathStart&quot;);
</span><span class="lines">@@ -923,10 +1131,10 @@
</span><span class="cx">     return address;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void URLParser::parseHost(StringView::CodePoints::Iterator&amp; iterator, const StringView::CodePoints::Iterator&amp; end)
</del><ins>+bool URLParser::parseHost(StringView::CodePoints::Iterator&amp; iterator, const StringView::CodePoints::Iterator&amp; end)
</ins><span class="cx"> {
</span><span class="cx">     if (iterator == end)
</span><del>-        return;
</del><ins>+        return false;
</ins><span class="cx">     if (*iterator == '[') {
</span><span class="cx">         ++iterator;
</span><span class="cx">         auto ipv6End = iterator;
</span><span class="lines">@@ -937,7 +1145,7 @@
</span><span class="cx">             m_url.m_hostEnd = m_buffer.length();
</span><span class="cx">             // FIXME: Handle the port correctly.
</span><span class="cx">             m_url.m_portEnd = m_buffer.length();            
</span><del>-            return;
</del><ins>+            return true;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     if (auto address = parseIPv4Host(iterator, end)) {
</span><span class="lines">@@ -945,7 +1153,7 @@
</span><span class="cx">         m_url.m_hostEnd = m_buffer.length();
</span><span class="cx">         // FIXME: Handle the port correctly.
</span><span class="cx">         m_url.m_portEnd = m_buffer.length();
</span><del>-        return;
</del><ins>+        return true;
</ins><span class="cx">     }
</span><span class="cx">     for (; iterator != end; ++iterator) {
</span><span class="cx">         if (*iterator == ':') {
</span><span class="lines">@@ -955,12 +1163,13 @@
</span><span class="cx">             for (; iterator != end; ++iterator)
</span><span class="cx">                 m_buffer.append(*iterator);
</span><span class="cx">             m_url.m_portEnd = m_buffer.length();
</span><del>-            return;
</del><ins>+            return true;
</ins><span class="cx">         }
</span><span class="cx">         m_buffer.append(*iterator);
</span><span class="cx">     }
</span><span class="cx">     m_url.m_hostEnd = m_buffer.length();
</span><span class="cx">     m_url.m_portEnd = m_url.m_hostEnd;
</span><ins>+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool URLParser::allValuesEqual(const URL&amp; a, const URL&amp; b)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.h (205389 => 205390)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.h        2016-09-03 00:22:27 UTC (rev 205389)
+++ trunk/Source/WebCore/platform/URLParser.h        2016-09-03 00:32:49 UTC (rev 205390)
</span><span class="lines">@@ -43,7 +43,7 @@
</span><span class="cx">     URL m_url;
</span><span class="cx">     StringBuilder m_buffer;
</span><span class="cx">     void parseAuthority(StringView::CodePoints::Iterator&amp;, const StringView::CodePoints::Iterator&amp; end);
</span><del>-    void parseHost(StringView::CodePoints::Iterator&amp;, const StringView::CodePoints::Iterator&amp; end);
</del><ins>+    bool parseHost(StringView::CodePoints::Iterator&amp;, const StringView::CodePoints::Iterator&amp; end);
</ins><span class="cx"> 
</span><span class="cx">     enum class URLPart;
</span><span class="cx">     void copyURLPartsUntil(const URL&amp; base, URLPart);
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (205389 => 205390)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-09-03 00:22:27 UTC (rev 205389)
+++ trunk/Tools/ChangeLog        2016-09-03 00:32:49 UTC (rev 205390)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-09-02  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        URLParser should parse file URLs
+        https://bugs.webkit.org/show_bug.cgi?id=161556
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/Tests/WebCore/URLParser.cpp:
+        (TestWebKitAPI::TEST_F):
+        (TestWebKitAPI::checkURLDifferences):
+
</ins><span class="cx"> 2016-09-01  Michael Saboff  &lt;msaboff@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Import Chakra tests to JSC
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp (205389 => 205390)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-09-03 00:22:27 UTC (rev 205389)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-09-03 00:32:49 UTC (rev 205390)
</span><span class="lines">@@ -84,7 +84,7 @@
</span><span class="cx">     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST_F(URLParserTest, Parse)
</del><ins>+TEST_F(URLParserTest, Basic)
</ins><span class="cx"> {
</span><span class="cx">     checkURL(&quot;http://user:pass@webkit.org:123/path?query#fragment&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;pass&quot;, &quot;webkit.org&quot;, 123, &quot;/path&quot;, &quot;query&quot;, &quot;fragment&quot;, &quot;http://user:pass@webkit.org:123/path?query#fragment&quot;});
</span><span class="cx">     checkURL(&quot;http://user:pass@webkit.org:123/path?query&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;pass&quot;, &quot;webkit.org&quot;, 123, &quot;/path&quot;, &quot;query&quot;, &quot;&quot;, &quot;http://user:pass@webkit.org:123/path?query&quot;});
</span><span class="lines">@@ -139,6 +139,32 @@
</span><span class="cx">     checkURL(&quot;http://example.com/path1/path2/..?query&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/&quot;, &quot;query&quot;, &quot;&quot;, &quot;http://example.com/path1/?query&quot;});
</span><span class="cx">     checkURL(&quot;http://example.com/path1/path2/.#fragment&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/path2/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;http://example.com/path1/path2/#fragment&quot;});
</span><span class="cx">     checkURL(&quot;http://example.com/path1/path2/..#fragment&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;http://example.com/path1/#fragment&quot;});
</span><ins>+
+    checkURL(&quot;file:&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///&quot;});
+    checkURL(&quot;file:/&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///&quot;});
+    checkURL(&quot;file://&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///&quot;});
+    checkURL(&quot;file:///&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///&quot;});
+    checkURL(&quot;file:////&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;//&quot;, &quot;&quot;, &quot;&quot;, &quot;file:////&quot;}); // This matches Firefox and URL::parse which I believe are correct, but not Chrome.
+    checkURL(&quot;file:/path&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///path&quot;});
+    checkURL(&quot;file://host/path&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file://host/path&quot;});
+    checkURL(&quot;file:///path&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///path&quot;});
+    checkURL(&quot;file:////path&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;//path&quot;, &quot;&quot;, &quot;&quot;, &quot;file:////path&quot;});
+    checkURL(&quot;file://localhost/path&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///path&quot;});
+    checkURL(&quot;file://localhost/&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///&quot;});
+    checkURL(&quot;file://localhost&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///&quot;});
+    // FIXME: check file://lOcAlHoSt etc.
+    checkURL(&quot;file:?query&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;query&quot;, &quot;&quot;, &quot;file:///?query&quot;});
+    checkURL(&quot;file:#fragment&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;file:///#fragment&quot;});
+    checkURL(&quot;file:?query#fragment&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;query&quot;, &quot;fragment&quot;, &quot;file:///?query#fragment&quot;});
+    checkURL(&quot;file:#fragment?notquery&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;fragment?notquery&quot;, &quot;file:///#fragment?notquery&quot;});
+    checkURL(&quot;file:/?query&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;query&quot;, &quot;&quot;, &quot;file:///?query&quot;});
+    checkURL(&quot;file:/#fragment&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;file:///#fragment&quot;});
+    checkURL(&quot;file://?query&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;query&quot;, &quot;&quot;, &quot;file:///?query&quot;});
+    checkURL(&quot;file://#fragment&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;file:///#fragment&quot;});
+    checkURL(&quot;file:///?query&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;query&quot;, &quot;&quot;, &quot;file:///?query&quot;});
+    checkURL(&quot;file:///#fragment&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;file:///#fragment&quot;});
+    checkURL(&quot;file:////?query&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;//&quot;, &quot;query&quot;, &quot;&quot;, &quot;file:////?query&quot;});
+    checkURL(&quot;file:////#fragment&quot;, {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;//&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;file:////#fragment&quot;});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void checkRelativeURL(const String&amp; urlString, const String&amp; baseURLString, const ExpectedParts&amp; parts)
</span><span class="lines">@@ -296,6 +322,9 @@
</span><span class="cx">     checkURLDifferences(&quot;http://example.com/path1/path2/%2e%2e#fragment&quot;,
</span><span class="cx">         {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;http://example.com/path1/#fragment&quot;},
</span><span class="cx">         {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/path2/%2e%2e&quot;, &quot;&quot;, &quot;fragment&quot;, &quot;http://example.com/path1/path2/%2e%2e#fragment&quot;});
</span><ins>+    checkURLDifferences(&quot;file://[0:a:0:0:b:c:0:0]/path&quot;,
+        {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:a::b:c:0:0]&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file://[0:a::b:c:0:0]/path&quot;},
+        {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:a:0:0:b:c:0:0]&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file://[0:a:0:0:b:c:0:0]/path&quot;});
</ins><span class="cx"> 
</span><span class="cx">     // FIXME: This behavior ought to be specified in the standard.
</span><span class="cx">     // With the existing URL::parse, WebKit returns &quot;https:/&quot;, Firefox returns &quot;https:///&quot;, and Chrome throws an error.
</span><span class="lines">@@ -302,6 +331,13 @@
</span><span class="cx">     checkRelativeURLDifferences(&quot;//&quot;, &quot;https://www.webkit.org/path&quot;,
</span><span class="cx">         {&quot;https&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;https://&quot;},
</span><span class="cx">         {&quot;https&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;https:/&quot;});
</span><ins>+    
+    // This behavior matches Chrome and Firefox, but not WebKit using URL::parse.
+    // The behavior of URL::parse is clearly wrong because reparsing file://path would make path the host.
+    // The spec is unclear.
+    checkURLDifferences(&quot;file:path&quot;,
+        {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;file:///path&quot;},
+        {&quot;file&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;path&quot;, &quot;&quot;, &quot;&quot;, &quot;file://path&quot;});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void shouldFail(const String&amp; urlString)
</span></span></pre>
</div>
</div>

</body>
</html>