<!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>[204417] 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/204417">204417</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2016-08-12 13:03:49 -0700 (Fri, 12 Aug 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Initial URLParser implementation
https://bugs.webkit.org/show_bug.cgi?id=160811

Reviewed by Brady Eidson.

Source/WebCore:

There are a lot of missing parts, but it works in one case, so I test that one case.

* platform/URLParser.cpp:
(WebCore::isC0Control):
(WebCore::isC0ControlOrSpace):
(WebCore::isTabOrNewline):
(WebCore::isASCIIDigit):
(WebCore::isASCIIAlpha):
(WebCore::isASCIIAlphanumeric):
(WebCore::isSpecialScheme):
(WebCore::URLParser::parse):

Tools:

* TestWebKitAPI/Tests/WebCore/URLParser.cpp:
(TestWebKitAPI::eq):
(TestWebKitAPI::checkURL):
(TestWebKitAPI::TEST_F):</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="#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 (204416 => 204417)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-08-12 18:53:51 UTC (rev 204416)
+++ trunk/Source/WebCore/ChangeLog        2016-08-12 20:03:49 UTC (rev 204417)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2016-08-12  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        Initial URLParser implementation
+        https://bugs.webkit.org/show_bug.cgi?id=160811
+
+        Reviewed by Brady Eidson.
+
+        There are a lot of missing parts, but it works in one case, so I test that one case.
+
+        * platform/URLParser.cpp:
+        (WebCore::isC0Control):
+        (WebCore::isC0ControlOrSpace):
+        (WebCore::isTabOrNewline):
+        (WebCore::isASCIIDigit):
+        (WebCore::isASCIIAlpha):
+        (WebCore::isASCIIAlphanumeric):
+        (WebCore::isSpecialScheme):
+        (WebCore::URLParser::parse):
+
</ins><span class="cx"> 2016-08-12  Commit Queue  &lt;commit-queue@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r204404.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.cpp (204416 => 204417)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.cpp        2016-08-12 18:53:51 UTC (rev 204416)
+++ trunk/Source/WebCore/platform/URLParser.cpp        2016-08-12 20:03:49 UTC (rev 204417)
</span><span class="lines">@@ -25,12 +25,301 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;URLParser.h&quot;
</span><ins>+#include &quot;NotImplemented.h&quot;
</ins><span class="cx"> 
</span><ins>+#include &lt;wtf/text/StringBuilder.h&gt;
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-Optional&lt;URL&gt; URLParser::parse(const String&amp;, const URL&amp;, const TextEncoding&amp;)
</del><ins>+// 1. Infrastructure
+static bool isC0Control(const StringView::CodePoints::Iterator&amp; c) { return *c &lt;= 0x001F; }
+static bool isC0ControlOrSpace(const StringView::CodePoints::Iterator&amp; c) { return isC0Control(c) || *c == 0x0020; }
+static bool isTabOrNewline(const StringView::CodePoints::Iterator&amp; c) { return *c == 0x0009 || *c == 0x000A || *c == 0x000D; }
+static bool isASCIIDigit(const StringView::CodePoints::Iterator&amp; c) { return *c &gt;= 0x0030  &amp;&amp; *c &lt;= 0x0039; }
+static bool isASCIIAlpha(const StringView::CodePoints::Iterator&amp; c) { return (*c &gt;= 0x0041 &amp;&amp; *c &lt;= 0x005A) || (*c &gt;= 0x0061 &amp;&amp; *c &lt;= 0x007A); }
+static bool isASCIIAlphanumeric(const StringView::CodePoints::Iterator&amp; c) { return isASCIIDigit(c) || isASCIIAlpha(c); }
+    
+// 4. URLs
+static bool isSpecialScheme(const String&amp; scheme)
</ins><span class="cx"> {
</span><del>-    return Nullopt;
</del><ins>+    return scheme == &quot;ftp&quot;
+        || scheme == &quot;file&quot;
+        || scheme == &quot;gopher&quot;
+        || scheme == &quot;http&quot;
+        || scheme == &quot;https&quot;
+        || scheme == &quot;ws&quot;
+        || scheme == &quot;wss&quot;;
</ins><span class="cx"> }
</span><ins>+
+Optional&lt;URL&gt; URLParser::parse(const String&amp; input, const URL&amp; base, const TextEncoding&amp;)
+{
+    URL url;
</ins><span class="cx">     
</span><ins>+    auto codePoints = StringView(input).codePoints();
+    auto c = codePoints.begin();
+    auto end = codePoints.end();
+    StringBuilder buffer;
+    while (isC0ControlOrSpace(c))
+        ++c;
+    
+    enum class State : uint8_t {
+        SchemeStart,
+        Scheme,
+        SchemeEndCheckForSlashes, // Scheme state steps 2. 8.
+        NoScheme,
+        SpecialRelativeOrAuthority,
+        PathOrAuthority,
+        Relative,
+        RelativeSlash,
+        SpecialAuthoritySlashes,
+        SpecialAuthorityIgnoreSlashes,
+        Authority,
+        Host,
+        Hostname,
+        Port,
+        File,
+        FileSlash,
+        FileHost,
+        PathStart,
+        Path,
+        CannotBeABaseURLPath,
+        Query,
+        Fragment,
+    };
+
+#define LOG_STATE(x)
+
+    State state = State::SchemeStart;
+    while (c != end) {
+        if (isTabOrNewline(c)) {
+            ++c;
+            continue;
+        }
+
+        switch (state) {
+        case State::SchemeStart:
+            LOG_STATE(&quot;SchemeStart&quot;);
+            if (isASCIIAlpha(c)) {
+                buffer.append(toASCIILower(*c));
+                state = State::Scheme;
+            } else
+                state = State::NoScheme;
+            ++c;
+            break;
+        case State::Scheme:
+            LOG_STATE(&quot;Scheme&quot;);
+            if (isASCIIAlphanumeric(c) || *c == '+' || *c == '-' || *c == '.')
+                buffer.append(toASCIILower(*c));
+            else if (*c == ':') {
+                url.m_schemeEnd = buffer.length();
+                String urlScheme = buffer.toString(); // FIXME: Find a way to do this without shrinking the buffer.
+                if (urlScheme == &quot;file&quot;)
+                    state = State::File;
+                else if (isSpecialScheme(urlScheme)) {
+                    if (base.protocol() == urlScheme)
+                        state = State::SpecialRelativeOrAuthority;
+                    else
+                        state = State::SpecialAuthoritySlashes;
+                } else
+                    state = State::SchemeEndCheckForSlashes;
+                buffer.append(':');
+            } else {
+                buffer.clear();
+                state = State::NoScheme;
+                // FIXME: Find a way to start over here.
+                notImplemented();
+                continue;
+            }
+            ++c;
+            break;
+        case State::SchemeEndCheckForSlashes:
+            LOG_STATE(&quot;SchemeEndCheckForSlashes&quot;);
+            if (*c == '/') {
+                state = State::PathOrAuthority;
+                ++c;
+            } else
+                state = State::CannotBeABaseURLPath;
+            break;
+        case State::NoScheme:
+            LOG_STATE(&quot;NoScheme&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::SpecialRelativeOrAuthority:
+            LOG_STATE(&quot;SpecialRelativeOrAuthority&quot;);
+            if (*c == '/') {
+                ++c;
+                if (c == end)
+                    return Nullopt;
+                if (*c == '/') {
+                    state = State::SpecialAuthorityIgnoreSlashes;
+                    ++c;
+                } else
+                    notImplemented();
+            } else
+                state = State::Relative;
+            break;
+        case State::PathOrAuthority:
+            LOG_STATE(&quot;PathOrAuthority&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::Relative:
+            LOG_STATE(&quot;Relative&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::RelativeSlash:
+            LOG_STATE(&quot;RelativeSlash&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::SpecialAuthoritySlashes:
+            LOG_STATE(&quot;SpecialAuthoritySlashes&quot;);
+            if (*c == '/') {
+                ++c;
+                if (c == end)
+                    return Nullopt;
+                buffer.append('/');
+                if (*c == '/') {
+                    buffer.append('/');
+                    state = State::SpecialAuthorityIgnoreSlashes;
+                    ++c;
+                    break;
+                }
+                notImplemented();
+            } else
+                notImplemented();
+            ++c;
+            break;
+        case State::SpecialAuthorityIgnoreSlashes:
+            LOG_STATE(&quot;SpecialAuthorityIgnoreSlashes&quot;);
+            if (*c != '/' &amp;&amp; *c != '\\') {
+                state = State::Authority;
+                break;
+            }
+            notImplemented();
+            ++c;
+            break;
+        case State::Authority:
+            LOG_STATE(&quot;Authority&quot;);
+            if (!url.m_userStart)
+                url.m_userStart = buffer.length();
+            if (*c == '@') {
+                url.m_passwordEnd = buffer.length();
+                buffer.append('@');
+                state = State::Host;
+                notImplemented();
+            } else if (*c == ':') {
+                url.m_userEnd = buffer.length();
+                buffer.append(*c);
+            } else {
+                if (*c == '/' || *c == '?' || *c == '#') {
+                    url.m_passwordEnd = buffer.length();
+                    state = State::Host;
+                }
+                buffer.append(*c);
+            }
+            ++c;
+            break;
+        case State::Host:
+        case State::Hostname:
+            LOG_STATE(&quot;Host/Hostname&quot;);
+            if (*c == ':') {
+                url.m_hostEnd = buffer.length();
+                buffer.append(':');
+                state = State::Port;
+            } else if (*c == '/' || *c == '?' || *c == '#') {
+                url.m_hostEnd = buffer.length();
+                state = State::Path;
+                continue;
+            } else
+                buffer.append(*c);
+            ++c;
+            break;
+        case State::Port:
+            LOG_STATE(&quot;Port&quot;);
+            if (isASCIIDigit(c)) {
+                buffer.append(*c);
+            } else if (*c == '/' || *c == '?' || *c == '#') {
+                url.m_portEnd = buffer.length();
+                state = State::PathStart;
+                continue;
+            } else
+                return Nullopt;
+            ++c;
+            break;
+        case State::File:
+            LOG_STATE(&quot;File&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::FileSlash:
+            LOG_STATE(&quot;FileSlash&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::FileHost:
+            LOG_STATE(&quot;FileHost&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::PathStart:
+            LOG_STATE(&quot;PathStart&quot;);
+            state = State::Path;
+            continue;
+        case State::Path:
+            LOG_STATE(&quot;Path&quot;);
+            if (*c == '/') {
+                ++c;
+                if (c == end)
+                    return Nullopt;
+                if (*c == '.') {
+                    ++c;
+                    if (c == end)
+                        return Nullopt;
+                    if (*c == '.')
+                        notImplemented();
+                    notImplemented();
+                }
+                buffer.append('/');
+            } else if (*c == '?') {
+                url.m_pathEnd = buffer.length();
+                state = State::Query;
+                continue;
+            } else if (*c == '#') {
+                url.m_pathEnd = buffer.length();
+                state = State::Fragment;
+                continue;
+            }
+            // FIXME: Percent encode c
+            buffer.append(*c);
+            ++c;
+            break;
+        case State::CannotBeABaseURLPath:
+            LOG_STATE(&quot;CannotBeABaseURLPath&quot;);
+            notImplemented();
+            ++c;
+            break;
+        case State::Query:
+            LOG_STATE(&quot;Query&quot;);
+            if (*c == '#') {
+                url.m_queryEnd = buffer.length();
+                state = State::Fragment;
+                continue;
+            }
+            buffer.append(*c);
+            ++c;
+            break;
+        case State::Fragment:
+            LOG_STATE(&quot;Fragment&quot;);
+            buffer.append(*c);
+            ++c;
+            break;
+        }
+    }
+    url.m_string = buffer.toString();
+    return url;
+}
+    
</ins><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (204416 => 204417)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-08-12 18:53:51 UTC (rev 204416)
+++ trunk/Tools/ChangeLog        2016-08-12 20:03:49 UTC (rev 204417)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-08-12  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        Initial URLParser implementation
+        https://bugs.webkit.org/show_bug.cgi?id=160811
+
+        Reviewed by Brady Eidson.
+
+        * TestWebKitAPI/Tests/WebCore/URLParser.cpp:
+        (TestWebKitAPI::eq):
+        (TestWebKitAPI::checkURL):
+        (TestWebKitAPI::TEST_F):
+
</ins><span class="cx"> 2016-08-12  Brady Eidson  &lt;beidson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix the 32-bit Mac build after:
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp (204416 => 204417)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-08-12 18:53:51 UTC (rev 204416)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-08-12 20:03:49 UTC (rev 204417)
</span><span class="lines">@@ -38,9 +38,34 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+struct ExpectedParts {
+    String protocol;
+    String user;
+    String password;
+    String host;
+    unsigned short port;
+    String path;
+    String query;
+    String fragment;
+};
+    
+static void eq(const String&amp; s1, const String&amp; s2) { EXPECT_STREQ(s1.utf8().data(), s2.utf8().data()); }
+static void checkURL(const URL&amp; url, const ExpectedParts&amp; parts)
+{
+    eq(url.protocol(), parts.protocol);
+    eq(url.user(), parts.user);
+    eq(url.pass(), parts.password);
+    eq(url.host(), parts.host);
+    EXPECT_EQ(url.port(), parts.port);
+    eq(url.path(), parts.path);
+    eq(url.query(), parts.query);
+    eq(url.fragmentIdentifier(), parts.fragment);
+}
+
</ins><span class="cx"> TEST_F(URLParserTest, Parse)
</span><span class="cx"> {
</span><del>-    EXPECT_TRUE(WebCore::URLParser::parse(&quot;invalid&quot;) == Nullopt);
</del><ins>+    auto url = URLParser::parse(&quot;http://user:pass@webkit.org:123/path?query#fragment&quot;);
+    checkURL(url.value(), {&quot;http&quot;, &quot;user&quot;, &quot;pass&quot;, &quot;webkit.org&quot;, 123, &quot;/path&quot;, &quot;query&quot;, &quot;fragment&quot;});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre>
</div>
</div>

</body>
</html>