<!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>[206457] 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/206457">206457</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2016-09-27 13:07:15 -0700 (Tue, 27 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Implement URLParser::syntaxViolation
https://bugs.webkit.org/show_bug.cgi?id=162593

Reviewed by Geoffrey Garen.

Source/WebCore:

Most of the time when parsing URLs, we just look at the URL, find offsets of the host, path, query, etc., 
and the String can be used untouched.  When this happens, we do not want to allocate and copy the String.
We want to just add a reference to an existing String.

Sometimes we need to canonicalize the String because there has been a syntaxViolation,
defined as any String that is different than its canonicalized URL String.  In such cases we need to
allocate a new String and fill it with the canonicalized URL String.  When a syntaxViolation happens for the
first time, we know that everything in the input String up to that point is equal to what it would have been
if we had canonicalized the beginning of the URL, copy it into a buffer, and continue parsing in a mode where
instead of just looking at the input URL String, we canonicalize each code point into the buffer.

Changes to behavior involve additional spec compliance with tabs and newlines in different places in URLs,
as well as additional spec compliance when parsing empty and null URLs relative to other URLs.
Both are covered by new API tests. Existing behavior covered by existing API tests.

This is about a 15% speed improvement on my URL parsing benchmark.

* platform/URL.cpp:
(WebCore::assertProtocolIsGood):
(WebCore::URL::protocolIs):
(WebCore::protocolIs):
* platform/URL.h:
* platform/URLParser.cpp:
(WebCore::isTabOrNewline):
(WebCore::URLParser::incrementIteratorSkippingTabsAndNewlines):
(WebCore::URLParser::isWindowsDriveLetter):
(WebCore::URLParser::appendToASCIIBuffer):
(WebCore::URLParser::checkWindowsDriveLetter):
(WebCore::URLParser::shouldCopyFileURL):
(WebCore::URLParser::utf8PercentEncode):
(WebCore::URLParser::utf8QueryEncode):
(WebCore::URLParser::copyURLPartsUntil):
(WebCore::URLParser::syntaxViolation):
(WebCore::URLParser::fragmentSyntaxViolation):
(WebCore::URLParser::parsedDataView):
(WebCore::URLParser::currentPosition):
(WebCore::URLParser::URLParser):
(WebCore::URLParser::parse):
(WebCore::URLParser::parseAuthority):
(WebCore::URLParser::parseIPv4Number):
(WebCore::URLParser::parseIPv4Host):
(WebCore::URLParser::parseIPv6Host):
(WebCore::URLParser::parsePort):
(WebCore::URLParser::parseHostAndPort):
(WebCore::serializeURLEncodedForm):
(WebCore::URLParser::allValuesEqual):
(WebCore::URLParser::internalValuesConsistent):
(WebCore::URLParser::incrementIteratorSkippingTabAndNewLine): Deleted.
(WebCore::URLParser::syntaxError): Deleted.
(WebCore::parseIPv4Number): Deleted.
* platform/URLParser.h:
(WebCore::URLParser::incrementIteratorSkippingTabsAndNewlines):

Tools:

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

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformURLcpp">trunk/Source/WebCore/platform/URL.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformURLh">trunk/Source/WebCore/platform/URL.h</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 (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Source/WebCore/ChangeLog        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2016-09-27  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        Implement URLParser::syntaxViolation
+        https://bugs.webkit.org/show_bug.cgi?id=162593
+
+        Reviewed by Geoffrey Garen.
+
+        Most of the time when parsing URLs, we just look at the URL, find offsets of the host, path, query, etc., 
+        and the String can be used untouched.  When this happens, we do not want to allocate and copy the String.
+        We want to just add a reference to an existing String.
+
+        Sometimes we need to canonicalize the String because there has been a syntaxViolation,
+        defined as any String that is different than its canonicalized URL String.  In such cases we need to
+        allocate a new String and fill it with the canonicalized URL String.  When a syntaxViolation happens for the
+        first time, we know that everything in the input String up to that point is equal to what it would have been
+        if we had canonicalized the beginning of the URL, copy it into a buffer, and continue parsing in a mode where
+        instead of just looking at the input URL String, we canonicalize each code point into the buffer.
+
+        Changes to behavior involve additional spec compliance with tabs and newlines in different places in URLs,
+        as well as additional spec compliance when parsing empty and null URLs relative to other URLs.
+        Both are covered by new API tests. Existing behavior covered by existing API tests.
+
+        This is about a 15% speed improvement on my URL parsing benchmark.
+
+        * platform/URL.cpp:
+        (WebCore::assertProtocolIsGood):
+        (WebCore::URL::protocolIs):
+        (WebCore::protocolIs):
+        * platform/URL.h:
+        * platform/URLParser.cpp:
+        (WebCore::isTabOrNewline):
+        (WebCore::URLParser::incrementIteratorSkippingTabsAndNewlines):
+        (WebCore::URLParser::isWindowsDriveLetter):
+        (WebCore::URLParser::appendToASCIIBuffer):
+        (WebCore::URLParser::checkWindowsDriveLetter):
+        (WebCore::URLParser::shouldCopyFileURL):
+        (WebCore::URLParser::utf8PercentEncode):
+        (WebCore::URLParser::utf8QueryEncode):
+        (WebCore::URLParser::copyURLPartsUntil):
+        (WebCore::URLParser::syntaxViolation):
+        (WebCore::URLParser::fragmentSyntaxViolation):
+        (WebCore::URLParser::parsedDataView):
+        (WebCore::URLParser::currentPosition):
+        (WebCore::URLParser::URLParser):
+        (WebCore::URLParser::parse):
+        (WebCore::URLParser::parseAuthority):
+        (WebCore::URLParser::parseIPv4Number):
+        (WebCore::URLParser::parseIPv4Host):
+        (WebCore::URLParser::parseIPv6Host):
+        (WebCore::URLParser::parsePort):
+        (WebCore::URLParser::parseHostAndPort):
+        (WebCore::serializeURLEncodedForm):
+        (WebCore::URLParser::allValuesEqual):
+        (WebCore::URLParser::internalValuesConsistent):
+        (WebCore::URLParser::incrementIteratorSkippingTabAndNewLine): Deleted.
+        (WebCore::URLParser::syntaxError): Deleted.
+        (WebCore::parseIPv4Number): Deleted.
+        * platform/URLParser.h:
+        (WebCore::URLParser::incrementIteratorSkippingTabsAndNewlines):
+
</ins><span class="cx"> 2016-09-27  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Related videos on YouTube (and YouTube playlists) cause media controls to disappear
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URL.cpp (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URL.cpp        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Source/WebCore/platform/URL.cpp        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -788,15 +788,15 @@
</span><span class="cx"> 
</span><span class="cx"> #ifdef NDEBUG
</span><span class="cx"> 
</span><del>-static inline void assertProtocolIsGood(const char*, size_t)
</del><ins>+static inline void assertProtocolIsGood(StringView)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #else
</span><span class="cx"> 
</span><del>-static void assertProtocolIsGood(const char* protocol, size_t length)
</del><ins>+static void assertProtocolIsGood(StringView protocol)
</ins><span class="cx"> {
</span><del>-    for (size_t i = 0; i &lt; length; ++i) {
</del><ins>+    for (size_t i = 0; i &lt; protocol.length(); ++i) {
</ins><span class="cx">         const char c = protocol[i];
</span><span class="cx">         ASSERT(c &gt; ' ' &amp;&amp; c &lt; 0x7F &amp;&amp; !(c &gt;= 'A' &amp;&amp; c &lt;= 'Z'));
</span><span class="cx">     }
</span><span class="lines">@@ -806,7 +806,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool URL::protocolIs(const char* protocol) const
</span><span class="cx"> {
</span><del>-    assertProtocolIsGood(protocol, strlen(protocol));
</del><ins>+    assertProtocolIsGood(StringView(reinterpret_cast&lt;const LChar*&gt;(protocol), strlen(protocol)));
</ins><span class="cx"> 
</span><span class="cx">     // JavaScript URLs are &quot;valid&quot; and should be executed even if URL decides they are invalid.
</span><span class="cx">     // The free function protocolIsJavaScript() should be used instead. 
</span><span class="lines">@@ -823,14 +823,14 @@
</span><span class="cx">     return !protocol[m_schemeEnd]; // We should have consumed all characters in the argument.
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool URL::protocolIs(const LChar* protocol, size_t length) const
</del><ins>+bool URL::protocolIs(StringView protocol) const
</ins><span class="cx"> {
</span><del>-    assertProtocolIsGood(reinterpret_cast&lt;const char*&gt;(protocol), length);
</del><ins>+    assertProtocolIsGood(protocol);
</ins><span class="cx"> 
</span><span class="cx">     if (!m_isValid)
</span><span class="cx">         return false;
</span><span class="cx">     
</span><del>-    if (m_schemeEnd != length)
</del><ins>+    if (m_schemeEnd != protocol.length())
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     // Do the comparison without making a new string object.
</span><span class="lines">@@ -1914,7 +1914,7 @@
</span><span class="cx"> 
</span><span class="cx"> static bool protocolIs(StringView stringURL, const char* protocol)
</span><span class="cx"> {
</span><del>-    assertProtocolIsGood(protocol, strlen(protocol));
</del><ins>+    assertProtocolIsGood(StringView(reinterpret_cast&lt;const LChar*&gt;(protocol), strlen(protocol)));
</ins><span class="cx">     unsigned length = stringURL.length();
</span><span class="cx">     for (unsigned i = 0; i &lt; length; ++i) {
</span><span class="cx">         if (!protocol[i])
</span><span class="lines">@@ -2141,7 +2141,7 @@
</span><span class="cx"> bool protocolIs(const String&amp; url, const char* protocol)
</span><span class="cx"> {
</span><span class="cx">     // Do the comparison without making a new string object.
</span><del>-    assertProtocolIsGood(protocol, strlen(protocol));
</del><ins>+    assertProtocolIsGood(StringView(reinterpret_cast&lt;const LChar*&gt;(protocol), strlen(protocol)));
</ins><span class="cx">     bool isLeading = true;
</span><span class="cx">     for (unsigned i = 0, j = 0; url[i]; ++i) {
</span><span class="cx">         // skip leading whitespace and control characters.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URL.h (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URL.h        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Source/WebCore/platform/URL.h        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -129,7 +129,7 @@
</span><span class="cx">     // Returns true if the current URL's protocol is the same as the null-
</span><span class="cx">     // terminated ASCII argument. The argument must be lower-case.
</span><span class="cx">     WEBCORE_EXPORT bool protocolIs(const char*) const;
</span><del>-    bool protocolIs(const LChar*, size_t) const;
</del><ins>+    bool protocolIs(StringView) const;
</ins><span class="cx">     bool protocolIsBlob() const { return protocolIs(&quot;blob&quot;); }
</span><span class="cx">     bool protocolIsData() const { return protocolIs(&quot;data&quot;); }
</span><span class="cx">     bool protocolIsInHTTPFamily() const;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.cpp (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.cpp        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Source/WebCore/platform/URLParser.cpp        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -410,11 +410,11 @@
</span><span class="cx"> static bool shouldPercentEncodeQueryByte(uint8_t byte) { return characterClassTable[byte] &amp; QueryPercent; }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><del>-void URLParser::incrementIteratorSkippingTabAndNewLine(CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</del><ins>+void URLParser::advance(CodePointIterator&lt;CharacterType&gt;&amp; iterator, const CodePointIterator&lt;CharacterType&gt;&amp; iteratorForSyntaxViolationPosition)
</ins><span class="cx"> {
</span><span class="cx">     ++iterator;
</span><del>-    while (!iterator.atEnd() &amp;&amp; isTabOrNewline(*iterator)) {
-        syntaxError(iterator);
</del><ins>+    while (UNLIKELY(!iterator.atEnd() &amp;&amp; isTabOrNewline(*iterator))) {
+        syntaxViolation(iteratorForSyntaxViolationPosition);
</ins><span class="cx">         ++iterator;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -424,13 +424,13 @@
</span><span class="cx"> {
</span><span class="cx">     if (iterator.atEnd() || !isASCIIAlpha(*iterator))
</span><span class="cx">         return false;
</span><del>-    incrementIteratorSkippingTabAndNewLine(iterator);
</del><ins>+    advance(iterator);
</ins><span class="cx">     if (iterator.atEnd())
</span><span class="cx">         return false;
</span><span class="cx">     if (*iterator == ':')
</span><span class="cx">         return true;
</span><del>-    if (*iterator == '|') {
-        syntaxError(iterator);
</del><ins>+    if (UNLIKELY(*iterator == '|')) {
+        syntaxViolation(iterator);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">     return false;
</span><span class="lines">@@ -447,7 +447,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_unicodeFragmentBuffer.isEmpty());
</span><span class="cx">     ASSERT(isASCII(codePoint));
</span><del>-    if (m_seenSyntaxError)
</del><ins>+    if (UNLIKELY(m_didSeeSyntaxViolation))
</ins><span class="cx">         m_asciiBuffer.append(codePoint);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -454,7 +454,7 @@
</span><span class="cx"> void URLParser::appendToASCIIBuffer(const char* characters, size_t length)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_unicodeFragmentBuffer.isEmpty());
</span><del>-    if (m_seenSyntaxError)
</del><ins>+    if (UNLIKELY(m_didSeeSyntaxViolation))
</ins><span class="cx">         m_asciiBuffer.append(characters, length);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -463,11 +463,11 @@
</span><span class="cx"> {
</span><span class="cx">     if (isWindowsDriveLetter(iterator)) {
</span><span class="cx">         appendToASCIIBuffer(*iterator);
</span><del>-        incrementIteratorSkippingTabAndNewLine(iterator);
</del><ins>+        advance(iterator);
</ins><span class="cx">         ASSERT(!iterator.atEnd());
</span><span class="cx">         ASSERT(*iterator == ':' || *iterator == '|');
</span><span class="cx">         appendToASCIIBuffer(':');
</span><del>-        incrementIteratorSkippingTabAndNewLine(iterator);
</del><ins>+        advance(iterator);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -478,10 +478,10 @@
</span><span class="cx">         return true;
</span><span class="cx">     if (iterator.atEnd())
</span><span class="cx">         return false;
</span><del>-    incrementIteratorSkippingTabAndNewLine(iterator);
</del><ins>+    advance(iterator);
</ins><span class="cx">     if (iterator.atEnd())
</span><span class="cx">         return true;
</span><del>-    incrementIteratorSkippingTabAndNewLine(iterator);
</del><ins>+    advance(iterator);
</ins><span class="cx">     if (iterator.atEnd())
</span><span class="cx">         return true;
</span><span class="cx">     return !isSlashQuestionOrHash(*iterator);
</span><span class="lines">@@ -504,17 +504,21 @@
</span><span class="cx"> const char replacementCharacterUTF8PercentEncoded[10] = &quot;%EF%BF%BD&quot;;
</span><span class="cx"> const size_t replacementCharacterUTF8PercentEncodedLength = sizeof(replacementCharacterUTF8PercentEncoded) - 1;
</span><span class="cx"> 
</span><del>-template&lt;bool(*isInCodeSet)(UChar32)&gt;
-void URLParser::utf8PercentEncode(UChar32 codePoint)
</del><ins>+template&lt;bool(*isInCodeSet)(UChar32), typename CharacterType&gt;
+void URLParser::utf8PercentEncode(const CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</ins><span class="cx"> {
</span><del>-    if (isASCII(codePoint)) {
-        if (isInCodeSet(codePoint))
</del><ins>+    ASSERT(!iterator.atEnd());
+    UChar32 codePoint = *iterator;
+    if (LIKELY(isASCII(codePoint))) {
+        if (UNLIKELY(isInCodeSet(codePoint))) {
+            syntaxViolation(iterator);
</ins><span class="cx">             percentEncodeByte(codePoint);
</span><del>-        else
</del><ins>+        } else
</ins><span class="cx">             appendToASCIIBuffer(codePoint);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     ASSERT_WITH_MESSAGE(isInCodeSet(codePoint), &quot;isInCodeSet should always return true for non-ASCII characters&quot;);
</span><ins>+    syntaxViolation(iterator);
</ins><span class="cx">     
</span><span class="cx">     if (!U_IS_UNICODE_CHAR(codePoint)) {
</span><span class="cx">         appendToASCIIBuffer(replacementCharacterUTF8PercentEncoded, replacementCharacterUTF8PercentEncodedLength);
</span><span class="lines">@@ -528,17 +532,22 @@
</span><span class="cx">         percentEncodeByte(buffer[i]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-void URLParser::utf8QueryEncode(UChar32 codePoint)
</del><ins>+template&lt;typename CharacterType&gt;
+void URLParser::utf8QueryEncode(const CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</ins><span class="cx"> {
</span><del>-    if (isASCII(codePoint)) {
-        if (shouldPercentEncodeQueryByte(codePoint))
</del><ins>+    ASSERT(!iterator.atEnd());
+    UChar32 codePoint = *iterator;
+    if (LIKELY(isASCII(codePoint))) {
+        if (UNLIKELY(shouldPercentEncodeQueryByte(codePoint))) {
+            syntaxViolation(iterator);
</ins><span class="cx">             percentEncodeByte(codePoint);
</span><del>-        else
</del><ins>+        } else
</ins><span class="cx">             appendToASCIIBuffer(codePoint);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    syntaxViolation(iterator);
+    
</ins><span class="cx">     if (!U_IS_UNICODE_CHAR(codePoint)) {
</span><span class="cx">         appendToASCIIBuffer(replacementCharacterUTF8PercentEncoded, replacementCharacterUTF8PercentEncodedLength);
</span><span class="cx">         return;
</span><span class="lines">@@ -748,8 +757,11 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void URLParser::copyURLPartsUntil(const URL&amp; base, URLPart part)
</del><ins>+template&lt;typename CharacterType&gt;
+void URLParser::copyURLPartsUntil(const URL&amp; base, URLPart part, const CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</ins><span class="cx"> {
</span><ins>+    syntaxViolation(iterator);
+
</ins><span class="cx">     m_asciiBuffer.clear();
</span><span class="cx">     m_unicodeFragmentBuffer.clear();
</span><span class="cx">     if (part == URLPart::FragmentEnd) {
</span><span class="lines">@@ -933,11 +945,47 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><del>-void URLParser::syntaxError(const CodePointIterator&lt;CharacterType&gt;&amp;)
</del><ins>+void URLParser::syntaxViolation(const CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</ins><span class="cx"> {
</span><del>-    // FIXME: Implement.
</del><ins>+    if (m_didSeeSyntaxViolation)
+        return;
+    m_didSeeSyntaxViolation = true;
+    
+    ASSERT(m_asciiBuffer.isEmpty());
+    ASSERT(m_unicodeFragmentBuffer.isEmpty());
+    ASSERT_WITH_MESSAGE(!m_url.m_queryEnd, &quot;syntaxViolation should not be used in the fragment, which might contain non-ASCII code points when serialized&quot;);
+    size_t codeUnitsToCopy = iterator.codeUnitsSince(reinterpret_cast&lt;const CharacterType*&gt;(m_inputBegin));
+    RELEASE_ASSERT(codeUnitsToCopy &lt;= m_inputString.length());
+    m_asciiBuffer.reserveCapacity(m_inputString.length());
+    for (size_t i = 0; i &lt; codeUnitsToCopy; ++i) {
+        ASSERT(isASCII(m_inputString[i]));
+        m_asciiBuffer.uncheckedAppend(m_inputString[i]);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename CharacterType&gt;
+void URLParser::fragmentSyntaxViolation(const CodePointIterator&lt;CharacterType&gt;&amp; iterator)
+{
+    if (m_didSeeSyntaxViolation)
+        return;
+    m_didSeeSyntaxViolation = true;
+
+    ASSERT(m_asciiBuffer.isEmpty());
+    ASSERT(m_unicodeFragmentBuffer.isEmpty());
+    size_t codeUnitsToCopy = iterator.codeUnitsSince(reinterpret_cast&lt;const CharacterType*&gt;(m_inputBegin));
+    size_t asciiCodeUnitsToCopy = m_url.m_queryEnd;
+    size_t unicodeCodeUnitsToCopy = codeUnitsToCopy - asciiCodeUnitsToCopy;
+    RELEASE_ASSERT(codeUnitsToCopy &lt;= m_inputString.length());
+    m_asciiBuffer.reserveCapacity(asciiCodeUnitsToCopy);
+    for (size_t i = 0; i &lt; asciiCodeUnitsToCopy; ++i) {
+        ASSERT(isASCII(m_inputString[i]));
+        m_asciiBuffer.uncheckedAppend(m_inputString[i]);
+    }
+    m_unicodeFragmentBuffer.reserveCapacity(m_inputString.length() - asciiCodeUnitsToCopy);
+    for (size_t i = asciiCodeUnitsToCopy; i &lt; asciiCodeUnitsToCopy + unicodeCodeUnitsToCopy; ++i)
+        m_unicodeFragmentBuffer.uncheckedAppend(m_inputString[i]);
+}
+
</ins><span class="cx"> void URLParser::failure()
</span><span class="cx"> {
</span><span class="cx">     m_url.invalidate();
</span><span class="lines">@@ -944,11 +992,23 @@
</span><span class="cx">     m_url.m_string = m_inputString;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+StringView URLParser::parsedDataView(size_t start, size_t length)
+{
+    if (UNLIKELY(m_didSeeSyntaxViolation)) {
+        ASSERT(start + length &lt;= m_asciiBuffer.size());
+        return StringView(m_asciiBuffer.data() + start, length);
+    }
+    ASSERT(start + length &lt;= m_inputString.length());
+    return StringView(m_inputString).substring(start, length);
+}
+
</ins><span class="cx"> template&lt;typename CharacterType&gt;
</span><span class="cx"> size_t URLParser::currentPosition(const CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</span><span class="cx"> {
</span><del>-    if (m_seenSyntaxError)
</del><ins>+    if (UNLIKELY(m_didSeeSyntaxViolation)) {
+        ASSERT(m_unicodeFragmentBuffer.isEmpty());
</ins><span class="cx">         return m_asciiBuffer.size();
</span><ins>+    }
</ins><span class="cx">     
</span><span class="cx">     return iterator.codeUnitsSince(reinterpret_cast&lt;const CharacterType*&gt;(m_inputBegin));
</span><span class="cx"> }
</span><span class="lines">@@ -956,8 +1016,11 @@
</span><span class="cx"> URLParser::URLParser(const String&amp; input, const URL&amp; base, const TextEncoding&amp; encoding)
</span><span class="cx">     : m_inputString(input)
</span><span class="cx"> {
</span><del>-    if (input.isNull())
</del><ins>+    if (input.isNull()) {
+        if (base.isValid() &amp;&amp; !base.m_cannotBeABaseURL)
+            m_url = base;
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     if (input.is8Bit()) {
</span><span class="cx">         m_inputBegin = input.characters8();
</span><span class="lines">@@ -966,6 +1029,9 @@
</span><span class="cx">         m_inputBegin = input.characters16();
</span><span class="cx">         parse(input.characters16(), input.length(), base, encoding);
</span><span class="cx">     }
</span><ins>+    ASSERT(!m_url.m_isValid
+        || m_didSeeSyntaxViolation == (m_url.string() != input)
+        || (input.isEmpty() &amp;&amp; m_url.m_string == base.m_string));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><span class="lines">@@ -975,18 +1041,21 @@
</span><span class="cx">     m_url = { };
</span><span class="cx">     ASSERT(m_asciiBuffer.isEmpty());
</span><span class="cx">     ASSERT(m_unicodeFragmentBuffer.isEmpty());
</span><del>-    m_asciiBuffer.reserveInitialCapacity(length);
</del><span class="cx">     
</span><span class="cx">     bool isUTF8Encoding = encoding == UTF8Encoding();
</span><span class="cx">     Vector&lt;UChar&gt; queryBuffer;
</span><span class="cx"> 
</span><span class="cx">     unsigned endIndex = length;
</span><del>-    while (endIndex &amp;&amp; isC0ControlOrSpace(input[endIndex - 1]))
</del><ins>+    while (UNLIKELY(endIndex &amp;&amp; isC0ControlOrSpace(input[endIndex - 1]))) {
+        syntaxViolation(CodePointIterator&lt;CharacterType&gt;(input, input));
</ins><span class="cx">         endIndex--;
</span><ins>+    }
</ins><span class="cx">     CodePointIterator&lt;CharacterType&gt; c(input, input + endIndex);
</span><span class="cx">     CodePointIterator&lt;CharacterType&gt; authorityOrHostBegin;
</span><del>-    while (!c.atEnd() &amp;&amp; isC0ControlOrSpace(*c))
</del><ins>+    while (UNLIKELY(!c.atEnd() &amp;&amp; isC0ControlOrSpace(*c))) {
+        syntaxViolation(c);
</ins><span class="cx">         ++c;
</span><ins>+    }
</ins><span class="cx">     auto beginAfterControlAndSpace = c;
</span><span class="cx"> 
</span><span class="cx">     enum class State : uint8_t {
</span><span class="lines">@@ -1011,13 +1080,13 @@
</span><span class="cx">         Fragment,
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-#define LOG_STATE(x) LOG(URLParser, &quot;State %s, code point %c, asciiBuffer size %zu&quot;, x, *c, currentPosition(c))
</del><ins>+#define LOG_STATE(x) LOG(URLParser, &quot;State %s, code point %c, parsed data &lt;%s&gt; size %zu&quot;, x, *c, parsedDataView(0, currentPosition(c)).utf8().data(), currentPosition(c))
</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="cx">     while (!c.atEnd()) {
</span><del>-        if (isTabOrNewline(*c)) {
-            syntaxError(c);
</del><ins>+        if (UNLIKELY(isTabOrNewline(*c))) {
+            syntaxViolation(c);
</ins><span class="cx">             ++c;
</span><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="lines">@@ -1026,8 +1095,10 @@
</span><span class="cx">         case State::SchemeStart:
</span><span class="cx">             LOG_STATE(&quot;SchemeStart&quot;);
</span><span class="cx">             if (isASCIIAlpha(*c)) {
</span><ins>+                if (UNLIKELY(isASCIIUpper(*c)))
+                    syntaxViolation(c);
</ins><span class="cx">                 appendToASCIIBuffer(toASCIILower(*c));
</span><del>-                incrementIteratorSkippingTabAndNewLine(c);
</del><ins>+                advance(c);
</ins><span class="cx">                 if (c.atEnd()) {
</span><span class="cx">                     m_asciiBuffer.clear();
</span><span class="cx">                     state = State::NoScheme;
</span><span class="lines">@@ -1039,36 +1110,40 @@
</span><span class="cx">             break;
</span><span class="cx">         case State::Scheme:
</span><span class="cx">             LOG_STATE(&quot;Scheme&quot;);
</span><del>-            if (isValidSchemeCharacter(*c))
</del><ins>+            if (isValidSchemeCharacter(*c)) {
+                if (UNLIKELY(isASCIIUpper(*c)))
+                    syntaxViolation(c);
</ins><span class="cx">                 appendToASCIIBuffer(toASCIILower(*c));
</span><del>-            else if (*c == ':') {
</del><ins>+            } else if (*c == ':') {
</ins><span class="cx">                 m_url.m_schemeEnd = currentPosition(c);
</span><del>-                StringView urlScheme = StringView(m_asciiBuffer.data(), m_url.m_schemeEnd);
</del><ins>+                StringView urlScheme = parsedDataView(0, m_url.m_schemeEnd);
</ins><span class="cx">                 m_url.m_protocolIsInHTTPFamily = urlScheme == &quot;http&quot; || urlScheme == &quot;https&quot;;
</span><ins>+                appendToASCIIBuffer(':');
</ins><span class="cx">                 if (urlScheme == &quot;file&quot;) {
</span><span class="cx">                     m_urlIsSpecial = true;
</span><span class="cx">                     state = State::File;
</span><del>-                    appendToASCIIBuffer(':');
</del><span class="cx">                     ++c;
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><del>-                appendToASCIIBuffer(':');
</del><span class="cx">                 if (isSpecialScheme(urlScheme)) {
</span><span class="cx">                     m_urlIsSpecial = true;
</span><del>-                    if (base.protocolIs(m_asciiBuffer.data(), currentPosition(c) - 1))
</del><ins>+                    if (base.protocolIs(urlScheme))
</ins><span class="cx">                         state = State::SpecialRelativeOrAuthority;
</span><span class="cx">                     else
</span><span class="cx">                         state = State::SpecialAuthoritySlashes;
</span><ins>+                    ++c;
</ins><span class="cx">                 } else {
</span><span class="cx">                     auto maybeSlash = c;
</span><del>-                    incrementIteratorSkippingTabAndNewLine(maybeSlash);
</del><ins>+                    advance(maybeSlash);
</ins><span class="cx">                     if (!maybeSlash.atEnd() &amp;&amp; *maybeSlash == '/') {
</span><span class="cx">                         appendToASCIIBuffer('/');
</span><del>-                        m_url.m_userStart = currentPosition(c);
</del><ins>+                        c = maybeSlash;
</ins><span class="cx">                         state = State::PathOrAuthority;
</span><del>-                        c = maybeSlash;
</del><span class="cx">                         ASSERT(*c == '/');
</span><ins>+                        ++c;
+                        m_url.m_userStart = currentPosition(c);
</ins><span class="cx">                     } else {
</span><ins>+                        ++c;
</ins><span class="cx">                         m_url.m_userStart = currentPosition(c);
</span><span class="cx">                         m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx">                         m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="lines">@@ -1079,7 +1154,6 @@
</span><span class="cx">                         state = State::CannotBeABaseURLPath;
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><del>-                ++c;
</del><span class="cx">                 break;
</span><span class="cx">             } else {
</span><span class="cx">                 m_asciiBuffer.clear();
</span><span class="lines">@@ -1087,7 +1161,7 @@
</span><span class="cx">                 c = beginAfterControlAndSpace;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            incrementIteratorSkippingTabAndNewLine(c);
</del><ins>+            advance(c);
</ins><span class="cx">             if (c.atEnd()) {
</span><span class="cx">                 m_asciiBuffer.clear();
</span><span class="cx">                 state = State::NoScheme;
</span><span class="lines">@@ -1101,7 +1175,7 @@
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             if (base.m_cannotBeABaseURL &amp;&amp; *c == '#') {
</span><del>-                copyURLPartsUntil(base, URLPart::QueryEnd);
</del><ins>+                copyURLPartsUntil(base, URLPart::QueryEnd, c);
</ins><span class="cx">                 state = State::Fragment;
</span><span class="cx">                 appendToASCIIBuffer('#');
</span><span class="cx">                 ++c;
</span><span class="lines">@@ -1111,7 +1185,7 @@
</span><span class="cx">                 state = State::Relative;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            copyURLPartsUntil(base, URLPart::SchemeEnd);
</del><ins>+            copyURLPartsUntil(base, URLPart::SchemeEnd, c);
</ins><span class="cx">             appendToASCIIBuffer(':');
</span><span class="cx">             state = State::File;
</span><span class="cx">             break;
</span><span class="lines">@@ -1119,7 +1193,7 @@
</span><span class="cx">             LOG_STATE(&quot;SpecialRelativeOrAuthority&quot;);
</span><span class="cx">             if (*c == '/') {
</span><span class="cx">                 appendToASCIIBuffer('/');
</span><del>-                incrementIteratorSkippingTabAndNewLine(c);
</del><ins>+                advance(c);
</ins><span class="cx">                 if (c.atEnd()) {
</span><span class="cx">                     failure();
</span><span class="cx">                     return;
</span><span class="lines">@@ -1137,12 +1211,12 @@
</span><span class="cx">             LOG_STATE(&quot;PathOrAuthority&quot;);
</span><span class="cx">             if (*c == '/') {
</span><span class="cx">                 appendToASCIIBuffer('/');
</span><del>-                m_url.m_userStart = currentPosition(c);
</del><span class="cx">                 state = State::AuthorityOrHost;
</span><span class="cx">                 ++c;
</span><ins>+                m_url.m_userStart = currentPosition(c);
</ins><span class="cx">                 authorityOrHostBegin = c;
</span><span class="cx">             } else {
</span><del>-                ASSERT(m_asciiBuffer.last() == '/');
</del><ins>+                ASSERT(parsedDataView(currentPosition(c) - 1, 1) == &quot;/&quot;);
</ins><span class="cx">                 m_url.m_userStart = currentPosition(c) - 1;
</span><span class="cx">                 m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx">                 m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="lines">@@ -1161,19 +1235,19 @@
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             case '?':
</span><del>-                copyURLPartsUntil(base, URLPart::PathEnd);
</del><ins>+                copyURLPartsUntil(base, URLPart::PathEnd, c);
</ins><span class="cx">                 appendToASCIIBuffer('?');
</span><span class="cx">                 state = State::Query;
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             case '#':
</span><del>-                copyURLPartsUntil(base, URLPart::QueryEnd);
</del><ins>+                copyURLPartsUntil(base, URLPart::QueryEnd, c);
</ins><span class="cx">                 appendToASCIIBuffer('#');
</span><span class="cx">                 state = State::Fragment;
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             default:
</span><del>-                copyURLPartsUntil(base, URLPart::PathAfterLastSlash);
</del><ins>+                copyURLPartsUntil(base, URLPart::PathAfterLastSlash, c);
</ins><span class="cx">                 state = State::Path;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -1182,11 +1256,11 @@
</span><span class="cx">             LOG_STATE(&quot;RelativeSlash&quot;);
</span><span class="cx">             if (*c == '/' || *c == '\\') {
</span><span class="cx">                 ++c;
</span><del>-                copyURLPartsUntil(base, URLPart::SchemeEnd);
</del><ins>+                copyURLPartsUntil(base, URLPart::SchemeEnd, c);
</ins><span class="cx">                 appendToASCIIBuffer(&quot;://&quot;, 3);
</span><span class="cx">                 state = State::SpecialAuthorityIgnoreSlashes;
</span><span class="cx">             } else {
</span><del>-                copyURLPartsUntil(base, URLPart::PortEnd);
</del><ins>+                copyURLPartsUntil(base, URLPart::PortEnd, c);
</ins><span class="cx">                 appendToASCIIBuffer('/');
</span><span class="cx">                 m_url.m_pathAfterLastSlash = base.m_portEnd + 1;
</span><span class="cx">                 state = State::Path;
</span><span class="lines">@@ -1194,11 +1268,23 @@
</span><span class="cx">             break;
</span><span class="cx">         case State::SpecialAuthoritySlashes:
</span><span class="cx">             LOG_STATE(&quot;SpecialAuthoritySlashes&quot;);
</span><del>-            appendToASCIIBuffer(&quot;//&quot;, 2);
-            if (*c == '/' || *c == '\\') {
-                incrementIteratorSkippingTabAndNewLine(c);
-                if (!c.atEnd() &amp;&amp; (*c == '/' || *c == '\\'))
</del><ins>+            if (LIKELY(*c == '/' || *c == '\\')) {
+                if (UNLIKELY(*c == '\\'))
+                    syntaxViolation(c);
+                appendToASCIIBuffer('/');
+                advance(c);
+                if (LIKELY(!c.atEnd() &amp;&amp; (*c == '/' || *c == '\\'))) {
+                    if (UNLIKELY(*c == '\\'))
+                        syntaxViolation(c);
</ins><span class="cx">                     ++c;
</span><ins>+                    appendToASCIIBuffer('/');
+                } else {
+                    syntaxViolation(c);
+                    appendToASCIIBuffer('/');
+                }
+            } else {
+                syntaxViolation(c);
+                appendToASCIIBuffer(&quot;//&quot;, 2);
</ins><span class="cx">             }
</span><span class="cx">             state = State::SpecialAuthorityIgnoreSlashes;
</span><span class="cx">             break;
</span><span class="lines">@@ -1213,8 +1299,8 @@
</span><span class="cx">             authorityOrHostBegin = c;
</span><span class="cx">             break;
</span><span class="cx">         case State::AuthorityOrHost:
</span><del>-            LOG_STATE(&quot;AuthorityOrHost&quot;);
-            {
</del><ins>+            do {
+                LOG_STATE(&quot;AuthorityOrHost&quot;);
</ins><span class="cx">                 if (*c == '@') {
</span><span class="cx">                     auto lastAt = c;
</span><span class="cx">                     auto findLastAt = c;
</span><span class="lines">@@ -1225,7 +1311,7 @@
</span><span class="cx">                     }
</span><span class="cx">                     parseAuthority(CodePointIterator&lt;CharacterType&gt;(authorityOrHostBegin, lastAt));
</span><span class="cx">                     c = lastAt;
</span><del>-                    incrementIteratorSkippingTabAndNewLine(c);
</del><ins>+                    advance(c);
</ins><span class="cx">                     authorityOrHostBegin = c;
</span><span class="cx">                     state = State::Host;
</span><span class="cx">                     m_hostHasPercentOrNonASCII = false;
</span><span class="lines">@@ -1233,13 +1319,14 @@
</span><span class="cx">                 }
</span><span class="cx">                 bool isSlash = *c == '/' || (m_urlIsSpecial &amp;&amp; *c == '\\');
</span><span class="cx">                 if (isSlash || *c == '?' || *c == '#') {
</span><del>-                    m_url.m_userEnd = currentPosition(c);
</del><ins>+                    m_url.m_userEnd = currentPosition(authorityOrHostBegin);
</ins><span class="cx">                     m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx">                     if (!parseHostAndPort(CodePointIterator&lt;CharacterType&gt;(authorityOrHostBegin, c))) {
</span><span class="cx">                         failure();
</span><span class="cx">                         return;
</span><span class="cx">                     }
</span><del>-                    if (!isSlash) {
</del><ins>+                    if (UNLIKELY(!isSlash)) {
+                        syntaxViolation(c);
</ins><span class="cx">                         appendToASCIIBuffer('/');
</span><span class="cx">                         m_url.m_pathAfterLastSlash = currentPosition(c);
</span><span class="cx">                     }
</span><span class="lines">@@ -1249,7 +1336,7 @@
</span><span class="cx">                 if (isPercentOrNonASCII(*c))
</span><span class="cx">                     m_hostHasPercentOrNonASCII = true;
</span><span class="cx">                 ++c;
</span><del>-            }
</del><ins>+            } while (!c.atEnd());
</ins><span class="cx">             break;
</span><span class="cx">         case State::Host:
</span><span class="cx">             LOG_STATE(&quot;Host&quot;);
</span><span class="lines">@@ -1268,15 +1355,18 @@
</span><span class="cx">         case State::File:
</span><span class="cx">             LOG_STATE(&quot;File&quot;);
</span><span class="cx">             switch (*c) {
</span><ins>+            case '\\':
+                syntaxViolation(c);
+                FALLTHROUGH;
</ins><span class="cx">             case '/':
</span><del>-            case '\\':
</del><span class="cx">                 appendToASCIIBuffer('/');
</span><span class="cx">                 state = State::FileSlash;
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             case '?':
</span><ins>+                syntaxViolation(c);
</ins><span class="cx">                 if (base.isValid() &amp;&amp; base.protocolIs(&quot;file&quot;))
</span><del>-                    copyURLPartsUntil(base, URLPart::PathEnd);
</del><ins>+                    copyURLPartsUntil(base, URLPart::PathEnd, c);
</ins><span class="cx">                 appendToASCIIBuffer(&quot;///?&quot;, 4);
</span><span class="cx">                 m_url.m_userStart = currentPosition(c) - 2;
</span><span class="cx">                 m_url.m_userEnd = m_url.m_userStart;
</span><span class="lines">@@ -1289,8 +1379,9 @@
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             case '#':
</span><ins>+                syntaxViolation(c);
</ins><span class="cx">                 if (base.isValid() &amp;&amp; base.protocolIs(&quot;file&quot;))
</span><del>-                    copyURLPartsUntil(base, URLPart::QueryEnd);
</del><ins>+                    copyURLPartsUntil(base, URLPart::QueryEnd, c);
</ins><span class="cx">                 appendToASCIIBuffer(&quot;///#&quot;, 4);
</span><span class="cx">                 m_url.m_userStart = currentPosition(c) - 2;
</span><span class="cx">                 m_url.m_userEnd = m_url.m_userStart;
</span><span class="lines">@@ -1304,8 +1395,9 @@
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             default:
</span><ins>+                syntaxViolation(c);
</ins><span class="cx">                 if (base.isValid() &amp;&amp; base.protocolIs(&quot;file&quot;) &amp;&amp; shouldCopyFileURL(c))
</span><del>-                    copyURLPartsUntil(base, URLPart::PathAfterLastSlash);
</del><ins>+                    copyURLPartsUntil(base, URLPart::PathAfterLastSlash, c);
</ins><span class="cx">                 else {
</span><span class="cx">                     appendToASCIIBuffer(&quot;///&quot;, 3);
</span><span class="cx">                     m_url.m_userStart = currentPosition(c) - 1;
</span><span class="lines">@@ -1322,7 +1414,9 @@
</span><span class="cx">             break;
</span><span class="cx">         case State::FileSlash:
</span><span class="cx">             LOG_STATE(&quot;FileSlash&quot;);
</span><del>-            if (*c == '/' || *c == '\\') {
</del><ins>+            if (LIKELY(*c == '/' || *c == '\\')) {
+                if (UNLIKELY(*c == '\\'))
+                    syntaxViolation(c);
</ins><span class="cx">                 ++c;
</span><span class="cx">                 appendToASCIIBuffer('/');
</span><span class="cx">                 m_url.m_userStart = currentPosition(c);
</span><span class="lines">@@ -1347,6 +1441,7 @@
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx">             }
</span><ins>+            syntaxViolation(c);
</ins><span class="cx">             appendToASCIIBuffer(&quot;//&quot;, 2);
</span><span class="cx">             m_url.m_userStart = currentPosition(c) - 1;
</span><span class="cx">             m_url.m_userEnd = m_url.m_userStart;
</span><span class="lines">@@ -1365,22 +1460,24 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                 if (authorityOrHostBegin == c) {
</span><del>-                    ASSERT(m_asciiBuffer[currentPosition(c) - 1] == '/');
-                    if (*c == '?') {
</del><ins>+                    ASSERT(parsedDataView(currentPosition(c) - 1, 1) == &quot;/&quot;);
+                    if (UNLIKELY(*c == '?')) {
+                        syntaxViolation(c);
</ins><span class="cx">                         appendToASCIIBuffer(&quot;/?&quot;, 2);
</span><ins>+                        ++c;
</ins><span class="cx">                         m_url.m_pathAfterLastSlash = currentPosition(c) - 1;
</span><span class="cx">                         m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx">                         state = State::Query;
</span><del>-                        ++c;
</del><span class="cx">                         break;
</span><span class="cx">                     }
</span><del>-                    if (*c == '#') {
</del><ins>+                    if (UNLIKELY(*c == '#')) {
+                        syntaxViolation(c);
</ins><span class="cx">                         appendToASCIIBuffer(&quot;/#&quot;, 2);
</span><ins>+                        ++c;
</ins><span class="cx">                         m_url.m_pathAfterLastSlash = currentPosition(c) - 1;
</span><span class="cx">                         m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx">                         m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
</span><span class="cx">                         state = State::Fragment;
</span><del>-                        ++c;
</del><span class="cx">                         break;
</span><span class="cx">                     }
</span><span class="cx">                     state = State::Path;
</span><span class="lines">@@ -1390,8 +1487,8 @@
</span><span class="cx">                     failure();
</span><span class="cx">                     return;
</span><span class="cx">                 }
</span><del>-                
-                if (StringView(m_asciiBuffer.data() + m_url.m_passwordEnd, currentPosition(c) - m_url.m_passwordEnd) == &quot;localhost&quot;)  {
</del><ins>+                if (UNLIKELY(equalLettersIgnoringASCIICase(parsedDataView(m_url.m_passwordEnd, currentPosition(c) - m_url.m_passwordEnd), &quot;localhost&quot;))) {
+                    syntaxViolation(c);
</ins><span class="cx">                     m_asciiBuffer.shrink(m_url.m_passwordEnd);
</span><span class="cx">                     m_url.m_hostEnd = currentPosition(c);
</span><span class="cx">                     m_url.m_portEnd = m_url.m_hostEnd;
</span><span class="lines">@@ -1413,18 +1510,22 @@
</span><span class="cx">         case State::Path:
</span><span class="cx">             LOG_STATE(&quot;Path&quot;);
</span><span class="cx">             if (*c == '/' || (m_urlIsSpecial &amp;&amp; *c == '\\')) {
</span><ins>+                if (UNLIKELY(m_urlIsSpecial &amp;&amp; *c == '\\'))
+                    syntaxViolation(c);
</ins><span class="cx">                 appendToASCIIBuffer('/');
</span><ins>+                ++c;
</ins><span class="cx">                 m_url.m_pathAfterLastSlash = currentPosition(c);
</span><del>-                ++c;
</del><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            if (currentPosition(c) &amp;&amp; m_asciiBuffer[currentPosition(c) - 1] == '/') {
-                if (isDoubleDotPathSegment(c)) {
</del><ins>+            if (UNLIKELY(currentPosition(c) &amp;&amp; parsedDataView(currentPosition(c) - 1, 1) == &quot;/&quot;)) {
+                if (UNLIKELY(isDoubleDotPathSegment(c))) {
+                    syntaxViolation(c);
</ins><span class="cx">                     consumeDoubleDotPathSegment(c);
</span><span class="cx">                     popPath();
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><del>-                if (m_asciiBuffer[currentPosition(c) - 1] == '/' &amp;&amp; isSingleDotPathSegment(c)) {
</del><ins>+                if (UNLIKELY(isSingleDotPathSegment(c))) {
+                    syntaxViolation(c);
</ins><span class="cx">                     consumeSingleDotPathSegment(c);
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="lines">@@ -1441,6 +1542,8 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             if (isPercentEncodedDot(c)) {
</span><ins>+                if (UNLIKELY(*c != '.'))
+                    syntaxViolation(c);
</ins><span class="cx">                 appendToASCIIBuffer('.');
</span><span class="cx">                 ASSERT(*c == '%');
</span><span class="cx">                 ++c;
</span><span class="lines">@@ -1450,7 +1553,7 @@
</span><span class="cx">                 ++c;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            utf8PercentEncode&lt;isInDefaultEncodeSet&gt;(*c);
</del><ins>+            utf8PercentEncode&lt;isInDefaultEncodeSet&gt;(c);
</ins><span class="cx">             ++c;
</span><span class="cx">             break;
</span><span class="cx">         case State::CannotBeABaseURLPath:
</span><span class="lines">@@ -1464,10 +1567,10 @@
</span><span class="cx">                 state = State::Fragment;
</span><span class="cx">             } else if (*c == '/') {
</span><span class="cx">                 appendToASCIIBuffer('/');
</span><ins>+                ++c;
</ins><span class="cx">                 m_url.m_pathAfterLastSlash = currentPosition(c);
</span><del>-                ++c;
</del><span class="cx">             } else {
</span><del>-                utf8PercentEncode&lt;isInSimpleEncodeSet&gt;(*c);
</del><ins>+                utf8PercentEncode&lt;isInSimpleEncodeSet&gt;(c);
</ins><span class="cx">                 ++c;
</span><span class="cx">             }
</span><span class="cx">             break;
</span><span class="lines">@@ -1481,18 +1584,31 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             if (isUTF8Encoding)
</span><del>-                utf8QueryEncode(*c);
</del><ins>+                utf8QueryEncode(c);
</ins><span class="cx">             else
</span><span class="cx">                 appendCodePoint(queryBuffer, *c);
</span><span class="cx">             ++c;
</span><span class="cx">             break;
</span><span class="cx">         case State::Fragment:
</span><del>-            LOG_STATE(&quot;Fragment&quot;);
-            if (m_unicodeFragmentBuffer.isEmpty() &amp;&amp; isASCII(*c))
-                appendToASCIIBuffer(*c);
-            else
-                appendCodePoint(m_unicodeFragmentBuffer, *c);
-            ++c;
</del><ins>+            do {
+                LOG(URLParser, &quot;State Fragment&quot;);
+                if (!m_didSeeUnicodeFragmentCodePoint &amp;&amp; isASCII(*c))
+                    appendToASCIIBuffer(*c);
+                else {
+                    m_didSeeUnicodeFragmentCodePoint = true;
+                    if (UNLIKELY(m_didSeeSyntaxViolation))
+                        appendCodePoint(m_unicodeFragmentBuffer, *c);
+                    else {
+                        ASSERT(m_asciiBuffer.isEmpty());
+                        ASSERT(m_unicodeFragmentBuffer.isEmpty());
+                    }
+                }
+                ++c;
+                while (UNLIKELY(!c.atEnd() &amp;&amp; isTabOrNewline(*c))) {
+                    fragmentSyntaxViolation(c);
+                    ++c;
+                }
+            } while (!c.atEnd());
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1500,7 +1616,7 @@
</span><span class="cx">     switch (state) {
</span><span class="cx">     case State::SchemeStart:
</span><span class="cx">         LOG_FINAL_STATE(&quot;SchemeStart&quot;);
</span><del>-        if (!currentPosition(c) &amp;&amp; base.isValid()) {
</del><ins>+        if (!currentPosition(c) &amp;&amp; base.isValid() &amp;&amp; !base.m_cannotBeABaseURL) {
</ins><span class="cx">             m_url = base;
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -1515,7 +1631,7 @@
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     case State::SpecialRelativeOrAuthority:
</span><span class="cx">         LOG_FINAL_STATE(&quot;SpecialRelativeOrAuthority&quot;);
</span><del>-        copyURLPartsUntil(base, URLPart::QueryEnd);
</del><ins>+        copyURLPartsUntil(base, URLPart::QueryEnd, c);
</ins><span class="cx">         m_url.m_fragmentEnd = m_url.m_queryEnd;
</span><span class="cx">         break;
</span><span class="cx">     case State::PathOrAuthority:
</span><span class="lines">@@ -1522,7 +1638,7 @@
</span><span class="cx">         LOG_FINAL_STATE(&quot;PathOrAuthority&quot;);
</span><span class="cx">         ASSERT(m_url.m_userStart);
</span><span class="cx">         ASSERT(m_url.m_userStart == currentPosition(c));
</span><del>-        ASSERT(m_asciiBuffer.last() == '/');
</del><ins>+        ASSERT(parsedDataView(currentPosition(c) - 1, 1) == &quot;/&quot;);
</ins><span class="cx">         m_url.m_userStart--;
</span><span class="cx">         m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx">         m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="lines">@@ -1535,11 +1651,11 @@
</span><span class="cx">         break;
</span><span class="cx">     case State::Relative:
</span><span class="cx">         LOG_FINAL_STATE(&quot;Relative&quot;);
</span><del>-        copyURLPartsUntil(base, URLPart::FragmentEnd);
</del><ins>+        copyURLPartsUntil(base, URLPart::FragmentEnd, c);
</ins><span class="cx">         break;
</span><span class="cx">     case State::RelativeSlash:
</span><span class="cx">         LOG_FINAL_STATE(&quot;RelativeSlash&quot;);
</span><del>-        copyURLPartsUntil(base, URLPart::PortEnd);
</del><ins>+        copyURLPartsUntil(base, URLPart::PortEnd, c);
</ins><span class="cx">         appendToASCIIBuffer('/');
</span><span class="cx">         m_url.m_pathAfterLastSlash = base.m_portEnd + 1;
</span><span class="cx">         m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
</span><span class="lines">@@ -1565,7 +1681,7 @@
</span><span class="cx">         break;
</span><span class="cx">     case State::AuthorityOrHost:
</span><span class="cx">         LOG_FINAL_STATE(&quot;AuthorityOrHost&quot;);
</span><del>-        m_url.m_userEnd = currentPosition(c);
</del><ins>+        m_url.m_userEnd = currentPosition(authorityOrHostBegin);
</ins><span class="cx">         m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx">         if (authorityOrHostBegin.atEnd()) {
</span><span class="cx">             m_url.m_hostEnd = m_url.m_userEnd;
</span><span class="lines">@@ -1574,6 +1690,7 @@
</span><span class="cx">             failure();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        syntaxViolation(c);
</ins><span class="cx">         appendToASCIIBuffer('/');
</span><span class="cx">         m_url.m_pathEnd = m_url.m_portEnd + 1;
</span><span class="cx">         m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
</span><span class="lines">@@ -1586,6 +1703,7 @@
</span><span class="cx">             failure();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        syntaxViolation(c);
</ins><span class="cx">         appendToASCIIBuffer('/');
</span><span class="cx">         m_url.m_pathEnd = m_url.m_portEnd + 1;
</span><span class="cx">         m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
</span><span class="lines">@@ -1595,9 +1713,10 @@
</span><span class="cx">     case State::File:
</span><span class="cx">         LOG_FINAL_STATE(&quot;File&quot;);
</span><span class="cx">         if (base.isValid() &amp;&amp; base.protocolIs(&quot;file&quot;)) {
</span><del>-            copyURLPartsUntil(base, URLPart::QueryEnd);
</del><ins>+            copyURLPartsUntil(base, URLPart::QueryEnd, c);
</ins><span class="cx">             appendToASCIIBuffer(':');
</span><span class="cx">         }
</span><ins>+        syntaxViolation(c);
</ins><span class="cx">         appendToASCIIBuffer(&quot;///&quot;, 3);
</span><span class="cx">         m_url.m_userStart = currentPosition(c) - 1;
</span><span class="cx">         m_url.m_userEnd = m_url.m_userStart;
</span><span class="lines">@@ -1611,8 +1730,9 @@
</span><span class="cx">         break;
</span><span class="cx">     case State::FileSlash:
</span><span class="cx">         LOG_FINAL_STATE(&quot;FileSlash&quot;);
</span><ins>+        syntaxViolation(c);
+        m_url.m_userStart = currentPosition(c) + 1;
</ins><span class="cx">         appendToASCIIBuffer(&quot;//&quot;, 2);
</span><del>-        m_url.m_userStart = currentPosition(c) - 1;
</del><span class="cx">         m_url.m_userEnd = m_url.m_userStart;
</span><span class="cx">         m_url.m_passwordEnd = m_url.m_userStart;
</span><span class="cx">         m_url.m_hostEnd = m_url.m_userStart;
</span><span class="lines">@@ -1625,6 +1745,7 @@
</span><span class="cx">     case State::FileHost:
</span><span class="cx">         LOG_FINAL_STATE(&quot;FileHost&quot;);
</span><span class="cx">         if (authorityOrHostBegin == c) {
</span><ins>+            syntaxViolation(c);
</ins><span class="cx">             appendToASCIIBuffer('/');
</span><span class="cx">             m_url.m_userStart = currentPosition(c) - 1;
</span><span class="cx">             m_url.m_userEnd = m_url.m_userStart;
</span><span class="lines">@@ -1643,7 +1764,8 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (StringView(m_asciiBuffer.data() + m_url.m_passwordEnd, currentPosition(c) - m_url.m_passwordEnd) == &quot;localhost&quot;)  {
</del><ins>+        syntaxViolation(c);
+        if (equalLettersIgnoringASCIICase(parsedDataView(m_url.m_passwordEnd, currentPosition(c) - m_url.m_passwordEnd), &quot;localhost&quot;)) {
</ins><span class="cx">             m_asciiBuffer.shrink(m_url.m_passwordEnd);
</span><span class="cx">             m_url.m_hostEnd = currentPosition(c);
</span><span class="cx">             m_url.m_portEnd = m_url.m_hostEnd;
</span><span class="lines">@@ -1677,20 +1799,24 @@
</span><span class="cx">         m_url.m_fragmentEnd = m_url.m_queryEnd;
</span><span class="cx">         break;
</span><span class="cx">     case State::Fragment:
</span><del>-        LOG_FINAL_STATE(&quot;Fragment&quot;);
-        m_url.m_fragmentEnd = currentPosition(c) + m_unicodeFragmentBuffer.size();
-        break;
</del><ins>+        {
+            LOG_FINAL_STATE(&quot;Fragment&quot;);
+            size_t length = m_didSeeSyntaxViolation ? m_asciiBuffer.size() + m_unicodeFragmentBuffer.size() : c.codeUnitsSince(reinterpret_cast&lt;const CharacterType*&gt;(m_inputBegin));
+            m_url.m_fragmentEnd = length;
+            break;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!m_seenSyntaxError) {
</del><ins>+    if (LIKELY(!m_didSeeSyntaxViolation)) {
</ins><span class="cx">         m_url.m_string = m_inputString;
</span><span class="cx">         ASSERT(m_asciiBuffer.isEmpty());
</span><span class="cx">         ASSERT(m_unicodeFragmentBuffer.isEmpty());
</span><del>-    } else if (m_unicodeFragmentBuffer.isEmpty())
</del><ins>+    } else if (!m_didSeeUnicodeFragmentCodePoint) {
+        ASSERT(m_unicodeFragmentBuffer.isEmpty());
</ins><span class="cx">         m_url.m_string = String::adopt(WTFMove(m_asciiBuffer));
</span><del>-    else {
</del><ins>+    } else {
</ins><span class="cx">         Vector&lt;UChar&gt; buffer;
</span><del>-        buffer.reserveInitialCapacity(currentPosition(c) + m_unicodeFragmentBuffer.size());
</del><ins>+        buffer.reserveInitialCapacity(m_asciiBuffer.size() + m_unicodeFragmentBuffer.size());
</ins><span class="cx">         buffer.appendVector(m_asciiBuffer);
</span><span class="cx">         buffer.appendVector(m_unicodeFragmentBuffer);
</span><span class="cx">         m_url.m_string = String::adopt(WTFMove(buffer));
</span><span class="lines">@@ -1703,16 +1829,20 @@
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><span class="cx"> void URLParser::parseAuthority(CodePointIterator&lt;CharacterType&gt; iterator)
</span><span class="cx"> {
</span><del>-    if (iterator.atEnd()) {
</del><ins>+    if (UNLIKELY(iterator.atEnd())) {
+        syntaxViolation(iterator);
</ins><span class="cx">         m_url.m_userEnd = currentPosition(iterator);
</span><span class="cx">         m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    for (; !iterator.atEnd(); ++iterator) {
</del><ins>+    auto authorityOrHostBegin = iterator;
+    for (; !iterator.atEnd(); advance(iterator)) {
</ins><span class="cx">         if (*iterator == ':') {
</span><del>-            ++iterator;
</del><span class="cx">             m_url.m_userEnd = currentPosition(iterator);
</span><del>-            if (iterator.atEnd()) {
</del><ins>+            auto iteratorAtColon = iterator;
+            advance(iterator, authorityOrHostBegin);
+            if (UNLIKELY(iterator.atEnd())) {
+                syntaxViolation(iteratorAtColon);
</ins><span class="cx">                 m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx">                 if (m_url.m_userEnd &gt; m_url.m_userStart)
</span><span class="cx">                     appendToASCIIBuffer('@');
</span><span class="lines">@@ -1721,10 +1851,10 @@
</span><span class="cx">             appendToASCIIBuffer(':');
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        utf8PercentEncode&lt;isInUserInfoEncodeSet&gt;(*iterator);
</del><ins>+        utf8PercentEncode&lt;isInUserInfoEncodeSet&gt;(iterator);
</ins><span class="cx">     }
</span><del>-    for (; !iterator.atEnd(); ++iterator)
-        utf8PercentEncode&lt;isInUserInfoEncodeSet&gt;(*iterator);
</del><ins>+    for (; !iterator.atEnd(); advance(iterator))
+        utf8PercentEncode&lt;isInUserInfoEncodeSet&gt;(iterator);
</ins><span class="cx">     m_url.m_passwordEnd = currentPosition(iterator);
</span><span class="cx">     if (!m_url.m_userEnd)
</span><span class="cx">         m_url.m_userEnd = m_url.m_passwordEnd;
</span><span class="lines">@@ -1824,7 +1954,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><del>-inline static Optional&lt;uint32_t&gt; parseIPv4Number(CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</del><ins>+Optional&lt;uint32_t&gt; URLParser::parseIPv4Number(CodePointIterator&lt;CharacterType&gt;&amp; iterator, const CodePointIterator&lt;CharacterType&gt;&amp; iteratorForSyntaxViolationPosition)
</ins><span class="cx"> {
</span><span class="cx">     // FIXME: Check for overflow.
</span><span class="cx">     enum class State : uint8_t {
</span><span class="lines">@@ -1843,7 +1973,7 @@
</span><span class="cx">         }
</span><span class="cx">         switch (state) {
</span><span class="cx">         case State::UnknownBase:
</span><del>-            if (*iterator == '0') {
</del><ins>+            if (UNLIKELY(*iterator == '0')) {
</ins><span class="cx">                 ++iterator;
</span><span class="cx">                 state = State::OctalOrHex;
</span><span class="cx">                 break;
</span><span class="lines">@@ -1851,6 +1981,7 @@
</span><span class="cx">             state = State::Decimal;
</span><span class="cx">             break;
</span><span class="cx">         case State::OctalOrHex:
</span><ins>+            syntaxViolation(iteratorForSyntaxViolationPosition);
</ins><span class="cx">             if (*iterator == 'x' || *iterator == 'X') {
</span><span class="cx">                 ++iterator;
</span><span class="cx">                 state = State::Hex;
</span><span class="lines">@@ -1866,6 +1997,7 @@
</span><span class="cx">             ++iterator;
</span><span class="cx">             break;
</span><span class="cx">         case State::Octal:
</span><ins>+            ASSERT(m_didSeeSyntaxViolation);
</ins><span class="cx">             if (*iterator &lt; '0' || *iterator &gt; '7')
</span><span class="cx">                 return Nullopt;
</span><span class="cx">             value *= 8;
</span><span class="lines">@@ -1873,6 +2005,7 @@
</span><span class="cx">             ++iterator;
</span><span class="cx">             break;
</span><span class="cx">         case State::Hex:
</span><ins>+            ASSERT(m_didSeeSyntaxViolation);
</ins><span class="cx">             if (!isASCIIHexDigit(*iterator))
</span><span class="cx">                 return Nullopt;
</span><span class="cx">             value *= 16;
</span><span class="lines">@@ -1894,12 +2027,14 @@
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><span class="cx"> Optional&lt;URLParser::IPv4Address&gt; URLParser::parseIPv4Host(CodePointIterator&lt;CharacterType&gt; iterator)
</span><span class="cx"> {
</span><ins>+    auto hostBegin = iterator;
+
</ins><span class="cx">     Vector&lt;uint32_t, 4&gt; items;
</span><span class="cx">     items.reserveInitialCapacity(4);
</span><span class="cx">     while (!iterator.atEnd()) {
</span><span class="cx">         if (items.size() &gt;= 4)
</span><span class="cx">             return Nullopt;
</span><del>-        if (auto item = parseIPv4Number(iterator))
</del><ins>+        if (auto item = parseIPv4Number(iterator, hostBegin))
</ins><span class="cx">             items.append(item.value());
</span><span class="cx">         else
</span><span class="cx">             return Nullopt;
</span><span class="lines">@@ -1918,6 +2053,10 @@
</span><span class="cx">         if (item &gt; 255)
</span><span class="cx">             return Nullopt;
</span><span class="cx">     }
</span><ins>+
+    if (UNLIKELY(items.size() != 4))
+        syntaxViolation(hostBegin);
+
</ins><span class="cx">     IPv4Address ipv4 = items.takeLast();
</span><span class="cx">     for (size_t counter = 0; counter &lt; items.size(); ++counter)
</span><span class="cx">         ipv4 += items[counter] * pow256(3 - counter);
</span><span class="lines">@@ -1927,6 +2066,9 @@
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><span class="cx"> Optional&lt;URLParser::IPv6Address&gt; URLParser::parseIPv6Host(CodePointIterator&lt;CharacterType&gt; c)
</span><span class="cx"> {
</span><ins>+    ASSERT(*c == '[');
+    auto hostBegin = c;
+    advance(c, hostBegin);
</ins><span class="cx">     if (c.atEnd())
</span><span class="cx">         return Nullopt;
</span><span class="cx"> 
</span><span class="lines">@@ -1935,12 +2077,12 @@
</span><span class="cx">     Optional&lt;size_t&gt; compressPointer;
</span><span class="cx"> 
</span><span class="cx">     if (*c == ':') {
</span><del>-        ++c;
</del><ins>+        advance(c, hostBegin);
</ins><span class="cx">         if (c.atEnd())
</span><span class="cx">             return Nullopt;
</span><span class="cx">         if (*c != ':')
</span><span class="cx">             return Nullopt;
</span><del>-        ++c;
</del><ins>+        advance(c, hostBegin);
</ins><span class="cx">         ++piecePointer;
</span><span class="cx">         compressPointer = piecePointer;
</span><span class="cx">     }
</span><span class="lines">@@ -1951,26 +2093,30 @@
</span><span class="cx">         if (*c == ':') {
</span><span class="cx">             if (compressPointer)
</span><span class="cx">                 return Nullopt;
</span><del>-            ++c;
</del><ins>+            advance(c, hostBegin);
</ins><span class="cx">             ++piecePointer;
</span><span class="cx">             compressPointer = piecePointer;
</span><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         uint16_t value = 0;
</span><del>-        for (size_t length = 0; length &lt; 4; length++) {
</del><ins>+        size_t length = 0;
+        for (; length &lt; 4; length++) {
</ins><span class="cx">             if (c.atEnd())
</span><span class="cx">                 break;
</span><span class="cx">             if (!isASCIIHexDigit(*c))
</span><span class="cx">                 break;
</span><span class="cx">             value = value * 0x10 + toASCIIHexValue(*c);
</span><del>-            ++c;
</del><ins>+            advance(c, hostBegin);
</ins><span class="cx">         }
</span><ins>+        if (UNLIKELY(length &gt; 1 &amp;&amp; !value))
+            syntaxViolation(hostBegin);
+
</ins><span class="cx">         address[piecePointer++] = value;
</span><span class="cx">         if (c.atEnd())
</span><span class="cx">             break;
</span><span class="cx">         if (*c != ':')
</span><span class="cx">             return Nullopt;
</span><del>-        ++c;
</del><ins>+        advance(c, hostBegin);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (!c.atEnd()) {
</span><span class="lines">@@ -1989,7 +2135,7 @@
</span><span class="cx">                     return Nullopt;
</span><span class="cx">                 else
</span><span class="cx">                     value = value.value() * 10 + number;
</span><del>-                ++c;
</del><ins>+                advance(c, hostBegin);
</ins><span class="cx">                 if (c.atEnd())
</span><span class="cx">                     return Nullopt;
</span><span class="cx">                 if (value.value() &gt; 255)
</span><span class="lines">@@ -2001,7 +2147,7 @@
</span><span class="cx">             if (dotsSeen == 1 || dotsSeen == 3)
</span><span class="cx">                 piecePointer++;
</span><span class="cx">             if (!c.atEnd())
</span><del>-                ++c;
</del><ins>+                advance(c, hostBegin);
</ins><span class="cx">             if (dotsSeen == 3 &amp;&amp; !c.atEnd())
</span><span class="cx">                 return Nullopt;
</span><span class="cx">             dotsSeen++;
</span><span class="lines">@@ -2014,6 +2160,13 @@
</span><span class="cx">             std::swap(address[piecePointer--], address[compressPointer.value() + swaps-- - 1]);
</span><span class="cx">     } else if (piecePointer != 8)
</span><span class="cx">         return Nullopt;
</span><ins>+
+    Optional&lt;size_t&gt; possibleCompressPointer = findLongestZeroSequence(address);
+    if (possibleCompressPointer)
+        possibleCompressPointer.value()++;
+    if (UNLIKELY(compressPointer != possibleCompressPointer))
+        syntaxViolation(hostBegin);
+    
</ins><span class="cx">     return address;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2105,15 +2258,20 @@
</span><span class="cx"> template&lt;typename CharacterType&gt;
</span><span class="cx"> bool URLParser::parsePort(CodePointIterator&lt;CharacterType&gt;&amp; iterator)
</span><span class="cx"> {
</span><ins>+    ASSERT(*iterator == ':');
+    auto colonIterator = iterator;
+    advance(iterator, colonIterator);
</ins><span class="cx">     uint32_t port = 0;
</span><del>-    if (iterator.atEnd()) {
-        m_url.m_portEnd = currentPosition(iterator);
</del><ins>+    if (UNLIKELY(iterator.atEnd())) {
+        m_url.m_portEnd = currentPosition(colonIterator);
+        syntaxViolation(colonIterator);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><del>-    appendToASCIIBuffer(':');
</del><span class="cx">     for (; !iterator.atEnd(); ++iterator) {
</span><del>-        if (isTabOrNewline(*iterator))
</del><ins>+        if (UNLIKELY(isTabOrNewline(*iterator))) {
+            syntaxViolation(colonIterator);
</ins><span class="cx">             continue;
</span><ins>+        }
</ins><span class="cx">         if (isASCIIDigit(*iterator)) {
</span><span class="cx">             port = port * 10 + *iterator - '0';
</span><span class="cx">             if (port &gt; std::numeric_limits&lt;uint16_t&gt;::max())
</span><span class="lines">@@ -2122,10 +2280,10 @@
</span><span class="cx">             return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (isDefaultPort(StringView(m_asciiBuffer.data(), m_url.m_schemeEnd), port)) {
-        ASSERT(m_asciiBuffer.last() == ':');
-        m_asciiBuffer.shrink(currentPosition(iterator) - 1);
-    } else {
</del><ins>+    if (UNLIKELY(isDefaultPort(parsedDataView(0, m_url.m_schemeEnd), port)))
+        syntaxViolation(colonIterator);
+    else {
+        appendToASCIIBuffer(':');
</ins><span class="cx">         ASSERT(port &lt;= std::numeric_limits&lt;uint16_t&gt;::max());
</span><span class="cx">         appendNumberToASCIIBuffer&lt;uint16_t&gt;(static_cast&lt;uint16_t&gt;(port));
</span><span class="cx">     }
</span><span class="lines">@@ -2140,27 +2298,27 @@
</span><span class="cx">     if (iterator.atEnd())
</span><span class="cx">         return false;
</span><span class="cx">     if (*iterator == '[') {
</span><del>-        ++iterator;
</del><span class="cx">         auto ipv6End = iterator;
</span><span class="cx">         while (!ipv6End.atEnd() &amp;&amp; *ipv6End != ']')
</span><span class="cx">             ++ipv6End;
</span><span class="cx">         if (auto address = parseIPv6Host(CodePointIterator&lt;CharacterType&gt;(iterator, ipv6End))) {
</span><span class="cx">             serializeIPv6(address.value());
</span><del>-            m_url.m_hostEnd = currentPosition(iterator);
</del><span class="cx">             if (!ipv6End.atEnd()) {
</span><del>-                ++ipv6End;
</del><ins>+                advance(ipv6End);
</ins><span class="cx">                 if (!ipv6End.atEnd() &amp;&amp; *ipv6End == ':') {
</span><del>-                    ++ipv6End;
</del><ins>+                    m_url.m_hostEnd = currentPosition(ipv6End);
</ins><span class="cx">                     return parsePort(ipv6End);
</span><span class="cx">                 }
</span><del>-                m_url.m_portEnd = currentPosition(iterator);
</del><ins>+                m_url.m_hostEnd = currentPosition(ipv6End);
+                m_url.m_portEnd = m_url.m_hostEnd;
</ins><span class="cx">                 return true;
</span><span class="cx">             }
</span><ins>+            m_url.m_hostEnd = currentPosition(ipv6End);
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
-    if (!m_hostHasPercentOrNonASCII) {
</del><ins>+
+    if (LIKELY(!m_hostHasPercentOrNonASCII)) {
</ins><span class="cx">         auto hostIterator = iterator;
</span><span class="cx">         for (; !iterator.atEnd(); ++iterator) {
</span><span class="cx">             if (isTabOrNewline(*iterator))
</span><span class="lines">@@ -2177,23 +2335,25 @@
</span><span class="cx">                 m_url.m_portEnd = currentPosition(iterator);
</span><span class="cx">                 return true;
</span><span class="cx">             }
</span><del>-            ++iterator;
</del><span class="cx">             return parsePort(iterator);
</span><span class="cx">         }
</span><span class="cx">         for (; hostIterator != iterator; ++hostIterator) {
</span><del>-            if (!isTabOrNewline(*hostIterator))
</del><ins>+            if (LIKELY(!isTabOrNewline(*hostIterator))) {
+                if (UNLIKELY(isASCIIUpper(*hostIterator)))
+                    syntaxViolation(hostIterator);
</ins><span class="cx">                 appendToASCIIBuffer(toASCIILower(*hostIterator));
</span><ins>+            } else
+                syntaxViolation(hostIterator);
</ins><span class="cx">         }
</span><span class="cx">         m_url.m_hostEnd = currentPosition(iterator);
</span><del>-        if (!hostIterator.atEnd()) {
-            ASSERT(*hostIterator == ':');
-            incrementIteratorSkippingTabAndNewLine(hostIterator);
</del><ins>+        if (!hostIterator.atEnd())
</ins><span class="cx">             return parsePort(hostIterator);
</span><del>-        }
</del><span class="cx">         m_url.m_portEnd = currentPosition(iterator);
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    syntaxViolation(iterator);
+    
</ins><span class="cx">     Vector&lt;LChar, defaultInlineBufferSize&gt; utf8Encoded;
</span><span class="cx">     for (; !iterator.atEnd(); ++iterator) {
</span><span class="cx">         if (isTabOrNewline(*iterator))
</span><span class="lines">@@ -2223,17 +2383,13 @@
</span><span class="cx">             m_url.m_portEnd = currentPosition(iterator);
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><del>-        ++iterator;
</del><span class="cx">         return parsePort(iterator);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     appendToASCIIBuffer(asciiDomainCharacters, asciiDomainValue.size());
</span><span class="cx">     m_url.m_hostEnd = currentPosition(iterator);
</span><del>-    if (!iterator.atEnd()) {
-        ASSERT(*iterator == ':');
-        incrementIteratorSkippingTabAndNewLine(iterator);
</del><ins>+    if (!iterator.atEnd())
</ins><span class="cx">         return parsePort(iterator);
</span><del>-    }
</del><span class="cx">     m_url.m_portEnd = currentPosition(iterator);
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="lines">@@ -2281,7 +2437,7 @@
</span><span class="cx">             || (byte &gt;= 0x30 &amp;&amp; byte &lt;= 0x39)
</span><span class="cx">             || (byte &gt;= 0x41 &amp;&amp; byte &lt;= 0x5A)
</span><span class="cx">             || byte == 0x5F
</span><del>-            || (byte &gt;= 0x61 &amp;&amp; byte &lt;= 0x7A))
</del><ins>+            || (byte &gt;= 0x61 &amp;&amp; byte &lt;= 0x7A)) // FIXME: Put these in the characterClassTable to avoid branches.
</ins><span class="cx">             output.append(byte);
</span><span class="cx">         else
</span><span class="cx">             percentEncodeByte(byte, output);
</span><span class="lines">@@ -2349,7 +2505,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool URLParser::internalValuesConsistent(const URL&amp; url)
</span><del>-{    
</del><ins>+{
</ins><span class="cx">     return url.m_schemeEnd &lt;= url.m_userStart
</span><span class="cx">         &amp;&amp; url.m_userStart &lt;= url.m_userEnd
</span><span class="cx">         &amp;&amp; url.m_userEnd &lt;= url.m_passwordEnd
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.h (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.h        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Source/WebCore/platform/URLParser.h        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -28,7 +28,6 @@
</span><span class="cx"> #include &quot;TextEncoding.h&quot;
</span><span class="cx"> #include &quot;URL.h&quot;
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><del>-#include &lt;wtf/text/StringBuilder.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -53,13 +52,13 @@
</span><span class="cx">     URL m_url;
</span><span class="cx">     Vector&lt;LChar&gt; m_asciiBuffer;
</span><span class="cx">     Vector&lt;UChar&gt; m_unicodeFragmentBuffer;
</span><ins>+    bool m_didSeeUnicodeFragmentCodePoint { false };
</ins><span class="cx">     bool m_urlIsSpecial { false };
</span><span class="cx">     bool m_hostHasPercentOrNonASCII { false };
</span><span class="cx">     String m_inputString;
</span><span class="cx">     const void* m_inputBegin { nullptr };
</span><span class="cx"> 
</span><del>-    // FIXME: This should start out as false and only change to true when we see a syntax error once syntax error handling is implemented.
-    bool m_seenSyntaxError { true };
</del><ins>+    bool m_didSeeSyntaxViolation { false };
</ins><span class="cx"> 
</span><span class="cx">     template&lt;typename CharacterType&gt; void parse(const CharacterType*, const unsigned length, const URL&amp;, const TextEncoding&amp;);
</span><span class="cx">     template&lt;typename CharacterType&gt; void parseAuthority(CodePointIterator&lt;CharacterType&gt;);
</span><span class="lines">@@ -67,15 +66,17 @@
</span><span class="cx">     template&lt;typename CharacterType&gt; bool parsePort(CodePointIterator&lt;CharacterType&gt;&amp;);
</span><span class="cx"> 
</span><span class="cx">     void failure();
</span><del>-    template&lt;typename CharacterType&gt; void incrementIteratorSkippingTabAndNewLine(CodePointIterator&lt;CharacterType&gt;&amp;);
-    template&lt;typename CharacterType&gt; void syntaxError(const CodePointIterator&lt;CharacterType&gt;&amp;);
</del><ins>+    template&lt;typename CharacterType&gt; void advance(CodePointIterator&lt;CharacterType&gt;&amp; iterator) { advance(iterator, iterator); }
+    template&lt;typename CharacterType&gt; void advance(CodePointIterator&lt;CharacterType&gt;&amp;, const CodePointIterator&lt;CharacterType&gt;&amp; iteratorForSyntaxViolationPosition);
+    template&lt;typename CharacterType&gt; void syntaxViolation(const CodePointIterator&lt;CharacterType&gt;&amp;);
+    template&lt;typename CharacterType&gt; void fragmentSyntaxViolation(const CodePointIterator&lt;CharacterType&gt;&amp;);
</ins><span class="cx">     template&lt;typename CharacterType&gt; bool isWindowsDriveLetter(CodePointIterator&lt;CharacterType&gt;);
</span><span class="cx">     template&lt;typename CharacterType&gt; bool shouldCopyFileURL(CodePointIterator&lt;CharacterType&gt;);
</span><span class="cx">     template&lt;typename CharacterType&gt; void checkWindowsDriveLetter(CodePointIterator&lt;CharacterType&gt;&amp;);
</span><span class="cx">     template&lt;typename CharacterType&gt; size_t currentPosition(const CodePointIterator&lt;CharacterType&gt;&amp;);
</span><span class="cx">     template&lt;typename UnsignedIntegerType&gt; void appendNumberToASCIIBuffer(UnsignedIntegerType);
</span><del>-    template&lt;bool(*isInCodeSet)(UChar32)&gt; void utf8PercentEncode(UChar32);
-    void utf8QueryEncode(UChar32);
</del><ins>+    template&lt;bool(*isInCodeSet)(UChar32), typename CharacterType&gt; void utf8PercentEncode(const CodePointIterator&lt;CharacterType&gt;&amp;);
+    template&lt;typename CharacterType&gt; void utf8QueryEncode(const CodePointIterator&lt;CharacterType&gt;&amp;);
</ins><span class="cx">     void percentEncodeByte(uint8_t);
</span><span class="cx">     void appendToASCIIBuffer(UChar32);
</span><span class="cx">     void appendToASCIIBuffer(const char*, size_t);
</span><span class="lines">@@ -82,10 +83,12 @@
</span><span class="cx">     void appendToASCIIBuffer(const LChar* characters, size_t size) { appendToASCIIBuffer(reinterpret_cast&lt;const char*&gt;(characters), size); }
</span><span class="cx">     void encodeQuery(const Vector&lt;UChar&gt;&amp; source, const TextEncoding&amp;);
</span><span class="cx">     void copyASCIIStringUntil(const String&amp;, size_t lengthIf8Bit, size_t lengthIf16Bit);
</span><ins>+    StringView parsedDataView(size_t start, size_t length);
</ins><span class="cx"> 
</span><span class="cx">     using IPv4Address = uint32_t;
</span><span class="cx">     void serializeIPv4(IPv4Address);
</span><span class="cx">     template&lt;typename CharacterType&gt; Optional&lt;IPv4Address&gt; parseIPv4Host(CodePointIterator&lt;CharacterType&gt;);
</span><ins>+    template&lt;typename CharacterType&gt; Optional&lt;uint32_t&gt; parseIPv4Number(CodePointIterator&lt;CharacterType&gt;&amp;, const CodePointIterator&lt;CharacterType&gt;&amp; iteratorForSyntaxViolationPosition);
</ins><span class="cx">     using IPv6Address = std::array&lt;uint16_t, 8&gt;;
</span><span class="cx">     template&lt;typename CharacterType&gt; Optional&lt;IPv6Address&gt; parseIPv6Host(CodePointIterator&lt;CharacterType&gt;);
</span><span class="cx">     void serializeIPv6Piece(uint16_t piece);
</span><span class="lines">@@ -92,7 +95,7 @@
</span><span class="cx">     void serializeIPv6(URLParser::IPv6Address);
</span><span class="cx"> 
</span><span class="cx">     enum class URLPart;
</span><del>-    void copyURLPartsUntil(const URL&amp; base, URLPart);
</del><ins>+    template&lt;typename CharacterType&gt; void copyURLPartsUntil(const URL&amp; base, URLPart, const CodePointIterator&lt;CharacterType&gt;&amp;);
</ins><span class="cx">     static size_t urlLengthUntilPart(const URL&amp;, URLPart);
</span><span class="cx">     void popPath();
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Tools/ChangeLog        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-09-26  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        Implement URLParser::syntaxViolation
+        https://bugs.webkit.org/show_bug.cgi?id=162593
+
+        Reviewed by Geoffrey Garen.
+
+        * TestWebKitAPI/Tests/WebCore/URLParser.cpp:
+        (TestWebKitAPI::TEST_F):
+
</ins><span class="cx"> 2016-09-27  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Turns out OptionSet.cpp wasn't added to the right target. Add it and fix the build for real.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp (206456 => 206457)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-09-27 19:49:38 UTC (rev 206456)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-09-27 20:07:15 UTC (rev 206457)
</span><span class="lines">@@ -119,6 +119,15 @@
</span><span class="cx">     checkURL(&quot;http://[0:f::f:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f::f:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f::f:f:0:0]/&quot;});
</span><span class="cx">     checkURL(&quot;http://[0:f:0:0:f::]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]/&quot;});
</span><span class="cx">     checkURL(&quot;http://[::f:0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
</span><ins>+    checkURL(&quot;http://[0:f:0:0:f::]:&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]/&quot;});
+    checkURL(&quot;http://[0:f:0:0:f::]:\t&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]/&quot;});
+    checkURL(&quot;http://[0:f:0:0:f::]\t:&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]/&quot;});
+    checkURL(&quot;http://\t[::f:0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
+    checkURL(&quot;http://[\t::f:0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
+    checkURL(&quot;http://[:\t:f:0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
+    checkURL(&quot;http://[::\tf:0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
+    checkURL(&quot;http://[::f\t:0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
+    checkURL(&quot;http://[::f:\t0:0:f:0:0]&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[::f:0:0:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[::f:0:0:f:0:0]/&quot;});
</ins><span class="cx">     checkURL(&quot;http://example.com/path1/path2/.&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/path2/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.com/path1/path2/&quot;});
</span><span class="cx">     checkURL(&quot;http://example.com/path1/path2/..&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.com/path1/&quot;});
</span><span class="cx">     checkURL(&quot;http://example.com/path1/path2/./path3&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/path1/path2/path3&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.com/path1/path2/path3&quot;});
</span><span class="lines">@@ -191,12 +200,23 @@
</span><span class="cx">     checkURL(&quot;http://host/a%20B&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/a%20B&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/a%20B&quot;});
</span><span class="cx">     checkURL(&quot;http://host?q=@ &lt;&gt;!#fragment&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;q=@%20%3C%3E!&quot;, &quot;fragment&quot;, &quot;http://host/?q=@%20%3C%3E!#fragment&quot;});
</span><span class="cx">     checkURL(&quot;http://user:@host&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://user@host/&quot;});
</span><ins>+    checkURL(&quot;http://user:@\thost&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://user@host/&quot;});
+    checkURL(&quot;http://user\t:@host&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://user@host/&quot;});
+    checkURL(&quot;http://use\tr:@host&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://user@host/&quot;});
</ins><span class="cx">     checkURL(&quot;http://127.0.0.1:10100/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 10100, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1:10100/path&quot;});
</span><span class="cx">     checkURL(&quot;http://127.0.0.1:/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1/path&quot;});
</span><ins>+    checkURL(&quot;http://127.0.0.1\t:/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1/path&quot;});
+    checkURL(&quot;http://127.0.0.1:\t/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1/path&quot;});
+    checkURL(&quot;http://127.0.0.1:/\tpath&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1/path&quot;});
</ins><span class="cx">     checkURL(&quot;http://127.0.0.1:123&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1:123/&quot;});
</span><span class="cx">     checkURL(&quot;http://127.0.0.1:&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;127.0.0.1&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://127.0.0.1/&quot;});
</span><span class="cx">     checkURL(&quot;http://[0:f::f:f:0:0]:123/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f::f:f:0:0]&quot;, 123, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f::f:f:0:0]:123/path&quot;});
</span><span class="cx">     checkURL(&quot;http://[0:f::f:f:0:0]:123&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f::f:f:0:0]&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f::f:f:0:0]:123/&quot;});
</span><ins>+    checkURL(&quot;http://[0:f:0:0:f:\t:]:123&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]:123/&quot;});
+    checkURL(&quot;http://[0:f:0:0:f::\t]:123&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]:123/&quot;});
+    checkURL(&quot;http://[0:f:0:0:f::]\t:123&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]:123/&quot;});
+    checkURL(&quot;http://[0:f:0:0:f::]:\t123&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]:123/&quot;});
+    checkURL(&quot;http://[0:f:0:0:f::]:1\t23&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f:0:0:f::]&quot;, 123, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f:0:0:f::]:123/&quot;});
</ins><span class="cx">     checkURL(&quot;http://[0:f::f:f:0:0]:/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f::f:f:0:0]&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f::f:f:0:0]/path&quot;});
</span><span class="cx">     checkURL(&quot;http://[0:f::f:f:0:0]:&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;[0:f::f:f:0:0]&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://[0:f::f:f:0:0]/&quot;});
</span><span class="cx">     checkURL(&quot;http://host:10100/path&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 10100, &quot;/path&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host:10100/path&quot;});
</span><span class="lines">@@ -210,6 +230,9 @@
</span><span class="cx">     checkURL(&quot;sc:/pa/&quot;, {&quot;sc&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/pa/&quot;, &quot;&quot;, &quot;&quot;, &quot;sc:/pa/&quot;});
</span><span class="cx">     checkURL(&quot;notspecial:/notuser:notpassword@nothost&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/notuser:notpassword@nothost&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:/notuser:notpassword@nothost&quot;});
</span><span class="cx">     checkURL(&quot;sc://pa/&quot;, {&quot;sc&quot;, &quot;&quot;, &quot;&quot;, &quot;pa&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;sc://pa/&quot;});
</span><ins>+    checkURL(&quot;sc://\tpa/&quot;, {&quot;sc&quot;, &quot;&quot;, &quot;&quot;, &quot;pa&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;sc://pa/&quot;});
+    checkURL(&quot;sc:/\t/pa/&quot;, {&quot;sc&quot;, &quot;&quot;, &quot;&quot;, &quot;pa&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;sc://pa/&quot;});
+    checkURL(&quot;sc:\t//pa/&quot;, {&quot;sc&quot;, &quot;&quot;, &quot;&quot;, &quot;pa&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;sc://pa/&quot;});
</ins><span class="cx">     checkURL(&quot;http://host   \a   &quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/&quot;});
</span><span class="cx">     checkURL(&quot;notspecial:/a&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/a&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:/a&quot;});
</span><span class="cx">     checkURL(&quot;notspecial:&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:&quot;});
</span><span class="lines">@@ -217,11 +240,14 @@
</span><span class="cx">     checkURL(&quot;http://256/&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;256&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://256/&quot;});
</span><span class="cx">     checkURL(&quot;http://256./&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;256.&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://256./&quot;});
</span><span class="cx">     checkURL(&quot;http://123.256/&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;123.256&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://123.256/&quot;});
</span><ins>+    checkURL(&quot;http://123\t.256/&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;123.256&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://123.256/&quot;});
+    checkURL(&quot;http://123.\t256/&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;123.256&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://123.256/&quot;});
</ins><span class="cx">     checkURL(&quot;notspecial:/a&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/a&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:/a&quot;});
</span><span class="cx">     checkURL(&quot;notspecial:&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:&quot;});
</span><span class="cx">     checkURL(&quot;notspecial:/&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:/&quot;});
</span><span class="cx">     checkURL(&quot;data:image/png;base64,encoded-data-follows-here&quot;, {&quot;data&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;image/png;base64,encoded-data-follows-here&quot;, &quot;&quot;, &quot;&quot;, &quot;data:image/png;base64,encoded-data-follows-here&quot;});
</span><span class="cx">     checkURL(&quot;data:image/png;base64,encoded/data-with-slash&quot;, {&quot;data&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;image/png;base64,encoded/data-with-slash&quot;, &quot;&quot;, &quot;&quot;, &quot;data:image/png;base64,encoded/data-with-slash&quot;});
</span><ins>+    checkURL(&quot;about:~&quot;, {&quot;about&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;~&quot;, &quot;&quot;, &quot;&quot;, &quot;about:~&quot;});
</ins><span class="cx"> 
</span><span class="cx">     // This disagrees with the web platform test for http://:@www.example.com but agrees with Chrome and URL::parse,
</span><span class="cx">     // and Firefox fails the web platform test differently. Maybe the web platform test ought to be changed.
</span><span class="lines">@@ -287,6 +313,8 @@
</span><span class="cx">     checkRelativeURL(&quot;\\@&quot;, &quot;http://example.org/foo/bar&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/@&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.org/@&quot;});
</span><span class="cx">     checkRelativeURL(&quot;/path3&quot;, &quot;http://user@example.org/path1/path2&quot;, {&quot;http&quot;, &quot;user&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/path3&quot;, &quot;&quot;, &quot;&quot;, &quot;http://user@example.org/path3&quot;});
</span><span class="cx">     checkRelativeURL(&quot;&quot;, &quot;http://example.org/foo/bar&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/foo/bar&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.org/foo/bar&quot;});
</span><ins>+    checkRelativeURL(&quot;\t&quot;, &quot;http://example.org/foo/bar&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/foo/bar&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.org/foo/bar&quot;});
+    checkRelativeURL(&quot; &quot;, &quot;http://example.org/foo/bar&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/foo/bar&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.org/foo/bar&quot;});
</ins><span class="cx">     checkRelativeURL(&quot;  \a  \t\n&quot;, &quot;http://example.org/foo/bar&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/foo/bar&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.org/foo/bar&quot;});
</span><span class="cx">     checkRelativeURL(&quot;:foo.com\\&quot;, &quot;http://example.org/foo/bar&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.org&quot;, 0, &quot;/foo/:foo.com/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.org/foo/:foo.com/&quot;});
</span><span class="cx">     checkRelativeURL(&quot;http:/example.com/&quot;, &quot;about:blank&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;example.com&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://example.com/&quot;});
</span><span class="lines">@@ -314,6 +342,7 @@
</span><span class="cx">     checkRelativeURL(&quot;notspecial:/&quot;, &quot;http://host&quot;, {&quot;notspecial&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;notspecial:/&quot;});
</span><span class="cx">     checkRelativeURL(&quot;foo:/&quot;, &quot;http://example.org/foo/bar&quot;, {&quot;foo&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;foo:/&quot;});
</span><span class="cx">     checkRelativeURL(&quot;://:0/&quot;, &quot;http://webkit.org/&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;webkit.org&quot;, 0, &quot;/://:0/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://webkit.org/://:0/&quot;});
</span><ins>+    checkRelativeURL(String(), &quot;http://webkit.org/&quot;, {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;webkit.org&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://webkit.org/&quot;});
</ins><span class="cx"> 
</span><span class="cx">     // The checking of slashes in SpecialAuthoritySlashes needed to get this to pass contradicts what is in the spec,
</span><span class="cx">     // but it is included in the web platform tests.
</span><span class="lines">@@ -590,6 +619,27 @@
</span><span class="cx">     checkURLDifferences(utf16String(u&quot;http://host/path#šŸ’©\tšŸ’©&quot;),
</span><span class="cx">         {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/path&quot;, &quot;&quot;, utf16String(u&quot;šŸ’©šŸ’©&quot;), utf16String(u&quot;http://host/path#šŸ’©šŸ’©&quot;)},
</span><span class="cx">         {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/path&quot;, &quot;&quot;, &quot;%F0%9F%92%A9%F0%9F%92%A9&quot;, &quot;http://host/path#%F0%9F%92%A9%F0%9F%92%A9&quot;});
</span><ins>+    checkURLDifferences(&quot;http://%48OsT&quot;,
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/&quot;},
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;%48ost&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://%48ost/&quot;});
+    checkURLDifferences(&quot;http://h%4FsT&quot;,
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/&quot;},
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;h%4fst&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://h%4fst/&quot;});
+    checkURLDifferences(&quot;http://h%4fsT&quot;,
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/&quot;},
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;h%4fst&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://h%4fst/&quot;});
+    checkURLDifferences(&quot;http://h%6fsT&quot;,
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/&quot;},
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;h%6fst&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://h%6fst/&quot;});
+    checkURLDifferences(&quot;http://host/`&quot;,
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/%60&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/%60&quot;},
+        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/`&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/`&quot;});
+    checkURLDifferences(&quot;aA://&quot;,
+        {&quot;aa&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;aa:///&quot;},
+        {&quot;aa&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;//&quot;, &quot;&quot;, &quot;&quot;, &quot;aa://&quot;});
+    checkURLDifferences(&quot;A://&quot;,
+        {&quot;a&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;a:///&quot;},
+        {&quot;a&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, 0, &quot;//&quot;, &quot;&quot;, &quot;&quot;, &quot;a://&quot;});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> TEST_F(URLParserTest, DefaultPort)
</span><span class="lines">@@ -596,6 +646,15 @@
</span><span class="cx"> {
</span><span class="cx">     checkURL(&quot;FtP://host:21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
</span><span class="cx">     checkURL(&quot;ftp://host:21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
</span><ins>+    checkURL(&quot;f\ttp://host:21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;f\ttp://host\t:21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;f\ttp://host:\t21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;f\ttp://host:2\t1/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;f\ttp://host:21\t/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;ftp://host\t:21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;ftp://host:\t21/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;ftp://host:2\t1/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
+    checkURL(&quot;ftp://host:21\t/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;});
</ins><span class="cx">     checkURL(&quot;ftp://host:22/&quot;, {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 22, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host:22/&quot;});
</span><span class="cx">     checkURLDifferences(&quot;ftp://host:21&quot;,
</span><span class="cx">         {&quot;ftp&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;ftp://host/&quot;},
</span><span class="lines">@@ -670,12 +729,6 @@
</span><span class="cx">     checkURLDifferences(&quot;unknown://host:81&quot;,
</span><span class="cx">         {&quot;unknown&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 81, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;unknown://host:81/&quot;},
</span><span class="cx">         {&quot;unknown&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 81, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;unknown://host:81&quot;});
</span><del>-    checkURLDifferences(&quot;http://%48OsT&quot;,
-        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/&quot;},
-        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;%48ost&quot;, 0, &quot;/&quot;, &quot;&quot;, &quot;&quot;, &quot;http://%48ost/&quot;});
-    checkURLDifferences(&quot;http://host/`&quot;,
-        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/%60&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/%60&quot;},
-        {&quot;http&quot;, &quot;&quot;, &quot;&quot;, &quot;host&quot;, 0, &quot;/`&quot;, &quot;&quot;, &quot;&quot;, &quot;http://host/`&quot;});
</del><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> static void shouldFail(const String&amp; urlString)
</span><span class="lines">@@ -694,6 +747,8 @@
</span><span class="cx">     shouldFail(&quot;  \a  &quot;);
</span><span class="cx">     shouldFail(&quot;&quot;);
</span><span class="cx">     shouldFail(String());
</span><ins>+    shouldFail(&quot;&quot;, &quot;about:blank&quot;);
+    shouldFail(String(), &quot;about:blank&quot;);
</ins><span class="cx">     shouldFail(&quot;http://127.0.0.1:abc&quot;);
</span><span class="cx">     shouldFail(&quot;http://host:abc&quot;);
</span><span class="cx">     shouldFail(&quot;http://a:@&quot;, &quot;about:blank&quot;);
</span><span class="lines">@@ -723,6 +778,7 @@
</span><span class="cx">     shouldFail(&quot;://:0/&quot;);
</span><span class="cx">     shouldFail(&quot;://:0/&quot;, &quot;&quot;);
</span><span class="cx">     shouldFail(&quot;://:0/&quot;, &quot;about:blank&quot;);
</span><ins>+    shouldFail(&quot;about~&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // These are in the spec but not in the web platform tests.
</span></span></pre>
</div>
</div>

</body>
</html>