<!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>[204544] 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/204544">204544</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2016-08-16 17:41:30 -0700 (Tue, 16 Aug 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>URLParser should parse URLs without credentials
https://bugs.webkit.org/show_bug.cgi?id=160913
Reviewed by Brady Eidson.
Source/WebCore:
When parsing a URL, after the scheme we do not know if we are parsing a username and password
or if we are parsing the host until we hit a '@' indicating the end of the credentials or a /, ?, or #
indicating the end of the host. Because there are significantly different rules for serializing usernames,
passwords, and hosts (all of which have yet to be implemented in URLParser) we put the code points after the
scheme in a special buffer that will be processed once we know what we are parsing.
In the future, this could be optimized by assuming that we are parsing the host and if we encounter a '@' character,
then do some extra work. This would save us the effort of copying the host twice because most URLs don't have credentials.
This is covered by a new URLParser API test.
* platform/Logging.h:
* platform/URLParser.cpp:
(WebCore::isC0Control):
(WebCore::isC0ControlOrSpace):
(WebCore::isTabOrNewline):
(WebCore::isSpecialScheme):
(WebCore::URLParser::parse):
(WebCore::URLParser::authorityEndReached):
(WebCore::URLParser::hostEndReached):
(WebCore::URLParser::allValuesEqual):
(WebCore::isASCIIDigit): Deleted.
(WebCore::isASCIIAlpha): Deleted.
(WebCore::isASCIIAlphanumeric): Deleted.
* platform/URLParser.h:
(WebCore::URLParser::parse):
Tools:
* TestWebKitAPI/Tests/WebCore/URLParser.cpp:
(TestWebKitAPI::s):
(TestWebKitAPI::checkURL):
(TestWebKitAPI::TEST_F):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformLoggingh">trunk/Source/WebCore/platform/Logging.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 (204543 => 204544)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-08-17 00:25:36 UTC (rev 204543)
+++ trunk/Source/WebCore/ChangeLog        2016-08-17 00:41:30 UTC (rev 204544)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2016-08-16 Alex Christensen <achristensen@webkit.org>
+
+ URLParser should parse URLs without credentials
+ https://bugs.webkit.org/show_bug.cgi?id=160913
+
+ Reviewed by Brady Eidson.
+
+ When parsing a URL, after the scheme we do not know if we are parsing a username and password
+ or if we are parsing the host until we hit a '@' indicating the end of the credentials or a /, ?, or #
+ indicating the end of the host. Because there are significantly different rules for serializing usernames,
+ passwords, and hosts (all of which have yet to be implemented in URLParser) we put the code points after the
+ scheme in a special buffer that will be processed once we know what we are parsing.
+
+ In the future, this could be optimized by assuming that we are parsing the host and if we encounter a '@' character,
+ then do some extra work. This would save us the effort of copying the host twice because most URLs don't have credentials.
+
+ This is covered by a new URLParser API test.
+
+ * platform/Logging.h:
+ * platform/URLParser.cpp:
+ (WebCore::isC0Control):
+ (WebCore::isC0ControlOrSpace):
+ (WebCore::isTabOrNewline):
+ (WebCore::isSpecialScheme):
+ (WebCore::URLParser::parse):
+ (WebCore::URLParser::authorityEndReached):
+ (WebCore::URLParser::hostEndReached):
+ (WebCore::URLParser::allValuesEqual):
+ (WebCore::isASCIIDigit): Deleted.
+ (WebCore::isASCIIAlpha): Deleted.
+ (WebCore::isASCIIAlphanumeric): Deleted.
+ * platform/URLParser.h:
+ (WebCore::URLParser::parse):
+
</ins><span class="cx"> 2016-08-16 Chris Dumez <cdumez@apple.com>
</span><span class="cx">
</span><span class="cx"> Add support for ShadowRoot.mode attribute
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformLoggingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/Logging.h (204543 => 204544)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/Logging.h        2016-08-17 00:25:36 UTC (rev 204543)
+++ trunk/Source/WebCore/platform/Logging.h        2016-08-17 00:41:30 UTC (rev 204544)
</span><span class="lines">@@ -78,6 +78,7 @@
</span><span class="cx"> M(StorageAPI) \
</span><span class="cx"> M(TextAutosizing) \
</span><span class="cx"> M(Threading) \
</span><ins>+ M(URLParser) \
</ins><span class="cx"> M(WebAudio) \
</span><span class="cx"> M(WebGL) \
</span><span class="cx"> M(WebReplay) \
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.cpp (204543 => 204544)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.cpp        2016-08-17 00:25:36 UTC (rev 204543)
+++ trunk/Source/WebCore/platform/URLParser.cpp        2016-08-17 00:41:30 UTC (rev 204544)
</span><span class="lines">@@ -25,18 +25,16 @@
</span><span class="cx">
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "URLParser.h"
</span><ins>+
+#include "Logging.h"
</ins><span class="cx"> #include "NotImplemented.h"
</span><del>-
</del><span class="cx"> #include <wtf/text/StringBuilder.h>
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><del>-static bool isC0Control(const StringView::CodePoints::Iterator& c) { return *c <= 0x001F; }
-static bool isC0ControlOrSpace(const StringView::CodePoints::Iterator& c) { return isC0Control(c) || *c == 0x0020; }
-static bool isTabOrNewline(const StringView::CodePoints::Iterator& c) { return *c == 0x0009 || *c == 0x000A || *c == 0x000D; }
-static bool isASCIIDigit(const StringView::CodePoints::Iterator& c) { return *c >= 0x0030 && *c <= 0x0039; }
-static bool isASCIIAlpha(const StringView::CodePoints::Iterator& c) { return (*c >= 0x0041 && *c <= 0x005A) || (*c >= 0x0061 && *c <= 0x007A); }
-static bool isASCIIAlphanumeric(const StringView::CodePoints::Iterator& c) { return isASCIIDigit(c) || isASCIIAlpha(c); }
</del><ins>+template<typename CharacterType> static bool isC0Control(CharacterType character) { return character <= 0x0001F; }
+template<typename CharacterType> static bool isC0ControlOrSpace(CharacterType character) { return isC0Control(character) || character == 0x0020; }
+template<typename CharacterType> static bool isTabOrNewline(CharacterType character) { return character == 0x0009 || character == 0x000A || character == 0x000D; }
</ins><span class="cx">
</span><span class="cx"> static bool isSpecialScheme(const String& scheme)
</span><span class="cx"> {
</span><span class="lines">@@ -51,13 +49,14 @@
</span><span class="cx">
</span><span class="cx"> Optional<URL> URLParser::parse(const String& input, const URL& base, const TextEncoding&)
</span><span class="cx"> {
</span><del>- URL url;
-
</del><ins>+ m_url = { };
+ m_buffer.clear();
+ m_authorityOrHostBuffer.clear();
+
</ins><span class="cx"> auto codePoints = StringView(input).codePoints();
</span><span class="cx"> auto c = codePoints.begin();
</span><span class="cx"> auto end = codePoints.end();
</span><del>- StringBuilder buffer;
- while (isC0ControlOrSpace(c))
</del><ins>+ while (c != end && isC0ControlOrSpace(*c))
</ins><span class="cx"> ++c;
</span><span class="cx">
</span><span class="cx"> enum class State : uint8_t {
</span><span class="lines">@@ -71,10 +70,8 @@
</span><span class="cx"> RelativeSlash,
</span><span class="cx"> SpecialAuthoritySlashes,
</span><span class="cx"> SpecialAuthorityIgnoreSlashes,
</span><del>- Authority,
</del><ins>+ AuthorityOrHost,
</ins><span class="cx"> Host,
</span><del>- Hostname,
- Port,
</del><span class="cx"> File,
</span><span class="cx"> FileSlash,
</span><span class="cx"> FileHost,
</span><span class="lines">@@ -85,11 +82,12 @@
</span><span class="cx"> Fragment,
</span><span class="cx"> };
</span><span class="cx">
</span><del>-#define LOG_STATE(x)
</del><ins>+#define LOG_STATE(x) LOG(URLParser, x)
+#define LOG_FINAL_STATE(x) LOG(URLParser, "Final State: %s", x)
</ins><span class="cx">
</span><span class="cx"> State state = State::SchemeStart;
</span><span class="cx"> while (c != end) {
</span><del>- if (isTabOrNewline(c)) {
</del><ins>+ if (isTabOrNewline(*c)) {
</ins><span class="cx"> ++c;
</span><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="lines">@@ -97,8 +95,8 @@
</span><span class="cx"> switch (state) {
</span><span class="cx"> case State::SchemeStart:
</span><span class="cx"> LOG_STATE("SchemeStart");
</span><del>- if (isASCIIAlpha(c)) {
- buffer.append(toASCIILower(*c));
</del><ins>+ if (isASCIIAlpha(*c)) {
+ m_buffer.append(toASCIILower(*c));
</ins><span class="cx"> state = State::Scheme;
</span><span class="cx"> } else
</span><span class="cx"> state = State::NoScheme;
</span><span class="lines">@@ -106,12 +104,12 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::Scheme:
</span><span class="cx"> LOG_STATE("Scheme");
</span><del>- if (isASCIIAlphanumeric(c) || *c == '+' || *c == '-' || *c == '.')
- buffer.append(toASCIILower(*c));
</del><ins>+ if (isASCIIAlphanumeric(*c) || *c == '+' || *c == '-' || *c == '.')
+ m_buffer.append(toASCIILower(*c));
</ins><span class="cx"> else if (*c == ':') {
</span><del>- url.m_schemeEnd = buffer.length();
- String urlScheme = buffer.toString(); // FIXME: Find a way to do this without shrinking the buffer.
- url.m_protocolIsInHTTPFamily = urlScheme == "http" || urlScheme == "https";
</del><ins>+ m_url.m_schemeEnd = m_buffer.length();
+ String urlScheme = m_buffer.toString(); // FIXME: Find a way to do this without shrinking the m_buffer.
+ m_url.m_protocolIsInHTTPFamily = urlScheme == "http" || urlScheme == "https";
</ins><span class="cx"> if (urlScheme == "file")
</span><span class="cx"> state = State::File;
</span><span class="cx"> else if (isSpecialScheme(urlScheme)) {
</span><span class="lines">@@ -121,9 +119,9 @@
</span><span class="cx"> state = State::SpecialAuthoritySlashes;
</span><span class="cx"> } else
</span><span class="cx"> state = State::SchemeEndCheckForSlashes;
</span><del>- buffer.append(':');
</del><ins>+ m_buffer.append(':');
</ins><span class="cx"> } else {
</span><del>- buffer.clear();
</del><ins>+ m_buffer.clear();
</ins><span class="cx"> state = State::NoScheme;
</span><span class="cx"> // FIXME: Find a way to start over here.
</span><span class="cx"> notImplemented();
</span><span class="lines">@@ -179,9 +177,9 @@
</span><span class="cx"> ++c;
</span><span class="cx"> if (c == end)
</span><span class="cx"> return Nullopt;
</span><del>- buffer.append('/');
</del><ins>+ m_buffer.append('/');
</ins><span class="cx"> if (*c == '/') {
</span><del>- buffer.append('/');
</del><ins>+ m_buffer.append('/');
</ins><span class="cx"> state = State::SpecialAuthorityIgnoreSlashes;
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="lines">@@ -193,59 +191,32 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::SpecialAuthorityIgnoreSlashes:
</span><span class="cx"> LOG_STATE("SpecialAuthorityIgnoreSlashes");
</span><del>- if (*c != '/' && *c != '\\') {
- state = State::Authority;
- break;
- }
- notImplemented();
- ++c;
</del><ins>+ if (*c == '/' || *c == '\\')
+ ++c;
+ m_url.m_userStart = m_buffer.length();
+ state = State::AuthorityOrHost;
</ins><span class="cx"> break;
</span><del>- case State::Authority:
- LOG_STATE("Authority");
- if (!url.m_userStart)
- url.m_userStart = buffer.length();
</del><ins>+ case State::AuthorityOrHost:
+ LOG_STATE("AuthorityOrHost");
</ins><span class="cx"> if (*c == '@') {
</span><del>- url.m_passwordEnd = buffer.length();
- buffer.append('@');
</del><ins>+ authorityEndReached();
</ins><span class="cx"> state = State::Host;
</span><del>- notImplemented();
- } else if (*c == ':') {
- url.m_userEnd = buffer.length();
- buffer.append(*c);
- } else {
- if (*c == '/' || *c == '?' || *c == '#') {
- url.m_passwordEnd = buffer.length();
- state = State::Host;
- }
- buffer.append(*c);
- }
- ++c;
- break;
- case State::Host:
- case State::Hostname:
- LOG_STATE("Host/Hostname");
- if (*c == ':') {
- url.m_hostEnd = buffer.length();
- buffer.append(':');
- state = State::Port;
</del><span class="cx"> } else if (*c == '/' || *c == '?' || *c == '#') {
</span><del>- url.m_hostEnd = buffer.length();
</del><ins>+ hostEndReached();
</ins><span class="cx"> state = State::Path;
</span><del>- continue;
</del><ins>+ break;
</ins><span class="cx"> } else
</span><del>- buffer.append(*c);
</del><ins>+ m_authorityOrHostBuffer.append(*c);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><del>- case State::Port:
- LOG_STATE("Port");
- if (isASCIIDigit(c)) {
- buffer.append(*c);
- } else if (*c == '/' || *c == '?' || *c == '#') {
- url.m_portEnd = buffer.length();
- state = State::PathStart;
</del><ins>+ case State::Host:
+ LOG_STATE("Host");
+ if (*c == '/' || *c == '?' || *c == '#') {
+ hostEndReached();
+ state = State::Path;
</ins><span class="cx"> continue;
</span><del>- } else
- return Nullopt;
</del><ins>+ }
+ m_authorityOrHostBuffer.append(*c);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> case State::File:
</span><span class="lines">@@ -270,8 +241,8 @@
</span><span class="cx"> case State::Path:
</span><span class="cx"> LOG_STATE("Path");
</span><span class="cx"> if (*c == '/') {
</span><del>- buffer.append('/');
- url.m_pathAfterLastSlash = buffer.length();
</del><ins>+ m_buffer.append('/');
+ m_url.m_pathAfterLastSlash = m_buffer.length();
</ins><span class="cx"> ++c;
</span><span class="cx"> if (c == end)
</span><span class="cx"> break;
</span><span class="lines">@@ -284,16 +255,16 @@
</span><span class="cx"> notImplemented();
</span><span class="cx"> }
</span><span class="cx"> } else if (*c == '?') {
</span><del>- url.m_pathEnd = buffer.length();
</del><ins>+ m_url.m_pathEnd = m_buffer.length();
</ins><span class="cx"> state = State::Query;
</span><span class="cx"> continue;
</span><span class="cx"> } else if (*c == '#') {
</span><del>- url.m_pathEnd = buffer.length();
</del><ins>+ m_url.m_pathEnd = m_buffer.length();
</ins><span class="cx"> state = State::Fragment;
</span><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx"> // FIXME: Percent encode c
</span><del>- buffer.append(*c);
</del><ins>+ m_buffer.append(*c);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> case State::CannotBeABaseURLPath:
</span><span class="lines">@@ -304,79 +275,177 @@
</span><span class="cx"> case State::Query:
</span><span class="cx"> LOG_STATE("Query");
</span><span class="cx"> if (*c == '#') {
</span><del>- url.m_queryEnd = buffer.length();
</del><ins>+ m_url.m_queryEnd = m_buffer.length();
</ins><span class="cx"> state = State::Fragment;
</span><span class="cx"> continue;
</span><span class="cx"> }
</span><del>- buffer.append(*c);
</del><ins>+ m_buffer.append(*c);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> case State::Fragment:
</span><span class="cx"> LOG_STATE("Fragment");
</span><del>- buffer.append(*c);
</del><ins>+ m_buffer.append(*c);
</ins><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> switch (state) {
</span><span class="cx"> case State::SchemeStart:
</span><ins>+ LOG_FINAL_STATE("SchemeStart");
+ return Nullopt;
+ break;
</ins><span class="cx"> case State::Scheme:
</span><ins>+ LOG_FINAL_STATE("Scheme");
+ break;
</ins><span class="cx"> case State::SchemeEndCheckForSlashes:
</span><ins>+ LOG_FINAL_STATE("SchemeEndCheckForSlashes");
+ break;
</ins><span class="cx"> case State::NoScheme:
</span><ins>+ LOG_FINAL_STATE("NoScheme");
+ break;
</ins><span class="cx"> case State::SpecialRelativeOrAuthority:
</span><ins>+ LOG_FINAL_STATE("SpecialRelativeOrAuthority");
+ break;
</ins><span class="cx"> case State::PathOrAuthority:
</span><ins>+ LOG_FINAL_STATE("PathOrAuthority");
+ break;
</ins><span class="cx"> case State::Relative:
</span><ins>+ LOG_FINAL_STATE("Relative");
+ break;
</ins><span class="cx"> case State::RelativeSlash:
</span><ins>+ LOG_FINAL_STATE("RelativeSlash");
+ break;
</ins><span class="cx"> case State::SpecialAuthoritySlashes:
</span><ins>+ LOG_FINAL_STATE("SpecialAuthoritySlashes");
+ break;
</ins><span class="cx"> case State::SpecialAuthorityIgnoreSlashes:
</span><del>- case State::Authority:
</del><ins>+ LOG_FINAL_STATE("SpecialAuthorityIgnoreSlashes");
</ins><span class="cx"> break;
</span><ins>+ case State::AuthorityOrHost:
+ LOG_FINAL_STATE("AuthorityOrHost");
+ m_url.m_userEnd = m_buffer.length();
+ m_url.m_passwordEnd = m_url.m_userEnd;
+ FALLTHROUGH;
</ins><span class="cx"> case State::Host:
</span><del>- case State::Hostname:
- url.m_hostEnd = buffer.length();
- url.m_portEnd = url.m_hostEnd;
- buffer.append('/');
- url.m_pathEnd = url.m_hostEnd + 1;
- url.m_pathAfterLastSlash = url.m_pathEnd;
- url.m_queryEnd = url.m_pathEnd;
- url.m_fragmentEnd = url.m_pathEnd;
</del><ins>+ if (state == State::Host)
+ LOG_FINAL_STATE("Host");
+ hostEndReached();
+ m_buffer.append('/');
+ m_url.m_pathEnd = m_url.m_portEnd + 1;
+ m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
+ m_url.m_queryEnd = m_url.m_pathEnd;
+ m_url.m_fragmentEnd = m_url.m_pathEnd;
</ins><span class="cx"> break;
</span><del>- case State::Port:
- url.m_portEnd = buffer.length();
- buffer.append('/');
- url.m_pathEnd = url.m_portEnd + 1;
- url.m_pathAfterLastSlash = url.m_pathEnd;
- url.m_queryEnd = url.m_pathEnd;
- url.m_fragmentEnd = url.m_pathEnd;
</del><ins>+ case State::File:
+ LOG_FINAL_STATE("File");
</ins><span class="cx"> break;
</span><del>- case State::File:
</del><span class="cx"> case State::FileSlash:
</span><ins>+ LOG_FINAL_STATE("FileSlash");
+ break;
</ins><span class="cx"> case State::FileHost:
</span><ins>+ LOG_FINAL_STATE("FileHost");
+ break;
</ins><span class="cx"> case State::PathStart:
</span><ins>+ LOG_FINAL_STATE("PathStart");
+ break;
</ins><span class="cx"> case State::Path:
</span><del>- url.m_pathEnd = buffer.length();
- url.m_queryEnd = url.m_pathEnd;
- url.m_fragmentEnd = url.m_pathEnd;
</del><ins>+ LOG_FINAL_STATE("Path");
+ m_url.m_pathEnd = m_buffer.length();
+ m_url.m_queryEnd = m_url.m_pathEnd;
+ m_url.m_fragmentEnd = m_url.m_pathEnd;
</ins><span class="cx"> break;
</span><span class="cx"> case State::CannotBeABaseURLPath:
</span><ins>+ LOG_FINAL_STATE("CannotBeABaseURLPath");
</ins><span class="cx"> break;
</span><span class="cx"> case State::Query:
</span><del>- url.m_queryEnd = buffer.length();
- url.m_fragmentEnd = url.m_queryEnd;
</del><ins>+ LOG_FINAL_STATE("Query");
+ m_url.m_queryEnd = m_buffer.length();
+ m_url.m_fragmentEnd = m_url.m_queryEnd;
</ins><span class="cx"> break;
</span><span class="cx"> case State::Fragment:
</span><del>- url.m_fragmentEnd = buffer.length();
</del><ins>+ LOG_FINAL_STATE("Fragment");
+ m_url.m_fragmentEnd = m_buffer.length();
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- url.m_string = buffer.toString();
- url.m_isValid = true;
- return url;
</del><ins>+ m_url.m_string = m_buffer.toString();
+ m_url.m_isValid = true;
+ return m_url;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+void URLParser::authorityEndReached()
+{
+ auto codePoints = StringView(m_authorityOrHostBuffer.toString()).codePoints();
+ auto iterator = codePoints.begin();
+ auto end = codePoints.end();
+ for (; iterator != end; ++iterator) {
+ m_buffer.append(*iterator);
+ if (*iterator == ':') {
+ ++iterator;
+ m_url.m_userEnd = m_buffer.length() - 1;
+ break;
+ }
+ }
+ for (; iterator != end; ++iterator)
+ m_buffer.append(*iterator);
+ m_url.m_passwordEnd = m_buffer.length();
+ m_buffer.append('@');
+ m_authorityOrHostBuffer.clear();
+}
+
+void URLParser::hostEndReached()
+{
+ auto codePoints = StringView(m_authorityOrHostBuffer.toString()).codePoints();
+ auto iterator = codePoints.begin();
+ auto end = codePoints.end();
+ for (; iterator != end; ++iterator) {
+ if (*iterator == ':') {
+ ++iterator;
+ m_url.m_hostEnd = m_buffer.length();
+ m_buffer.append(':');
+ for (; iterator != end; ++iterator)
+ m_buffer.append(*iterator);
+ m_url.m_portEnd = m_buffer.length();
+ return;
+ }
+ m_buffer.append(*iterator);
+ }
+ m_url.m_hostEnd = m_buffer.length();
+ m_url.m_portEnd = m_url.m_hostEnd;
+ m_authorityOrHostBuffer.clear();
+}
+
</ins><span class="cx"> bool URLParser::allValuesEqual(const URL& a, const URL& b)
</span><span class="cx"> {
</span><ins>+ LOG(URLParser, "%d %d %d %d %d %d %d %d %d %d %d %d %s\n%d %d %d %d %d %d %d %d %d %d %d %d %s",
+ a.m_isValid,
+ a.m_protocolIsInHTTPFamily,
+ a.m_schemeEnd,
+ a.m_userStart,
+ a.m_userEnd,
+ a.m_passwordEnd,
+ a.m_hostEnd,
+ a.m_portEnd,
+ a.m_pathAfterLastSlash,
+ a.m_pathEnd,
+ a.m_queryEnd,
+ a.m_fragmentEnd,
+ a.m_string.utf8().data(),
+ b.m_isValid,
+ b.m_protocolIsInHTTPFamily,
+ b.m_schemeEnd,
+ b.m_userStart,
+ b.m_userEnd,
+ b.m_passwordEnd,
+ b.m_hostEnd,
+ b.m_portEnd,
+ b.m_pathAfterLastSlash,
+ b.m_pathEnd,
+ b.m_queryEnd,
+ b.m_fragmentEnd,
+ b.m_string.utf8().data());
+
</ins><span class="cx"> return a.m_string == b.m_string
</span><span class="cx"> && a.m_isValid == b.m_isValid
</span><span class="cx"> && a.m_protocolIsInHTTPFamily == b.m_protocolIsInHTTPFamily
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.h (204543 => 204544)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.h        2016-08-17 00:25:36 UTC (rev 204543)
+++ trunk/Source/WebCore/platform/URLParser.h        2016-08-17 00:41:30 UTC (rev 204544)
</span><span class="lines">@@ -28,13 +28,20 @@
</span><span class="cx"> #include "TextEncoding.h"
</span><span class="cx"> #include "URL.h"
</span><span class="cx"> #include <wtf/Forward.h>
</span><ins>+#include <wtf/text/StringBuilder.h>
</ins><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><span class="cx"> class URLParser {
</span><span class="cx"> public:
</span><del>- WEBCORE_EXPORT static Optional<URL> parse(const String&, const URL& = { }, const TextEncoding& = UTF8Encoding());
</del><ins>+ WEBCORE_EXPORT Optional<URL> parse(const String&, const URL& = { }, const TextEncoding& = UTF8Encoding());
</ins><span class="cx"> WEBCORE_EXPORT static bool allValuesEqual(const URL&, const URL&);
</span><ins>+private:
+ URL m_url;
+ StringBuilder m_buffer;
+ StringBuilder m_authorityOrHostBuffer;
+ void authorityEndReached();
+ void hostEndReached();
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (204543 => 204544)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-08-17 00:25:36 UTC (rev 204543)
+++ trunk/Tools/ChangeLog        2016-08-17 00:41:30 UTC (rev 204544)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-08-16 Alex Christensen <achristensen@webkit.org>
+
+ URLParser should parse URLs without credentials
+ https://bugs.webkit.org/show_bug.cgi?id=160913
+
+ Reviewed by Brady Eidson.
+
+ * TestWebKitAPI/Tests/WebCore/URLParser.cpp:
+ (TestWebKitAPI::s):
+ (TestWebKitAPI::checkURL):
+ (TestWebKitAPI::TEST_F):
+
</ins><span class="cx"> 2016-08-16 Anders Carlsson <andersca@apple.com>
</span><span class="cx">
</span><span class="cx"> Add WTF::ScopeExit
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp (204543 => 204544)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-08-17 00:25:36 UTC (rev 204543)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp        2016-08-17 00:41:30 UTC (rev 204544)
</span><span class="lines">@@ -53,7 +53,8 @@
</span><span class="cx"> static const char* s(const String& s) { return s.utf8().data(); }
</span><span class="cx"> static void checkURL(const String& urlString, const ExpectedParts& parts)
</span><span class="cx"> {
</span><del>- auto url = URLParser::parse(urlString);
</del><ins>+ URLParser parser;
+ auto url = parser.parse(urlString);
</ins><span class="cx"> EXPECT_STREQ(s(parts.protocol), s(url->protocol()));
</span><span class="cx"> EXPECT_STREQ(s(parts.user), s(url->user()));
</span><span class="cx"> EXPECT_STREQ(s(parts.password), s(url->pass()));
</span><span class="lines">@@ -86,6 +87,19 @@
</span><span class="cx"> checkURL("http://user:pass@webkit.org:123/", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
</span><span class="cx"> checkURL("http://user:pass@webkit.org:123", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
</span><span class="cx"> checkURL("http://user:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
</span><ins>+ checkURL("http://webkit.org", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+static void shouldFail(const String& urlString)
+{
+ URLParser parser;
+ auto invalidURL = parser.parse(urlString);
+ EXPECT_TRUE(invalidURL == Nullopt);
+}
+
+TEST_F(URLParserTest, ParserFailures)
+{
+ shouldFail(" ");
+}
+
</ins><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre>
</div>
</div>
</body>
</html>