Title: [205493] trunk
Revision
205493
Author
achristen...@apple.com
Date
2016-09-06 11:16:07 -0700 (Tue, 06 Sep 2016)

Log Message

Implement relative file urls and begin implementing character encoding in URLParser
https://bugs.webkit.org/show_bug.cgi?id=161618

Reviewed by Tim Horton.

Source/WebCore:

Covered by new API tests.
Also, this is a significant step towards passing the URL web platform tests when using the URLParser,
which is still off by default.

* platform/URLParser.cpp:
(WebCore::isInSimpleEncodeSet):
(WebCore::isInDefaultEncodeSet):
(WebCore::isInUserInfoEncodeSet):
(WebCore::isInvalidDomainCharacter):
(WebCore::shouldCopyFileURL):
(WebCore::percentEncode):
(WebCore::utf8PercentEncode):
(WebCore::encodeQuery):
(WebCore::isDefaultPort):
(WebCore::isPercentEncodedDot):
(WebCore::URLParser::parse):
(WebCore::percentDecode):
(WebCore::domainToASCII):
(WebCore::hasInvalidDomainCharacter):
(WebCore::URLParser::parsePort):
(WebCore::URLParser::parseHost):
(WebCore::isTabOrNewline): Deleted.
* platform/URLParser.h:

Tools:

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

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (205492 => 205493)


--- trunk/Source/WebCore/ChangeLog	2016-09-06 18:02:28 UTC (rev 205492)
+++ trunk/Source/WebCore/ChangeLog	2016-09-06 18:16:07 UTC (rev 205493)
@@ -1,3 +1,34 @@
+2016-09-05  Alex Christensen  <achristen...@webkit.org>
+
+        Implement relative file urls and begin implementing character encoding in URLParser
+        https://bugs.webkit.org/show_bug.cgi?id=161618
+
+        Reviewed by Tim Horton.
+
+        Covered by new API tests.
+        Also, this is a significant step towards passing the URL web platform tests when using the URLParser,
+        which is still off by default.
+
+        * platform/URLParser.cpp:
+        (WebCore::isInSimpleEncodeSet):
+        (WebCore::isInDefaultEncodeSet):
+        (WebCore::isInUserInfoEncodeSet):
+        (WebCore::isInvalidDomainCharacter):
+        (WebCore::shouldCopyFileURL):
+        (WebCore::percentEncode):
+        (WebCore::utf8PercentEncode):
+        (WebCore::encodeQuery):
+        (WebCore::isDefaultPort):
+        (WebCore::isPercentEncodedDot):
+        (WebCore::URLParser::parse):
+        (WebCore::percentDecode):
+        (WebCore::domainToASCII):
+        (WebCore::hasInvalidDomainCharacter):
+        (WebCore::URLParser::parsePort):
+        (WebCore::URLParser::parseHost):
+        (WebCore::isTabOrNewline): Deleted.
+        * platform/URLParser.h:
+
 2016-09-06  Daniel Bates  <daba...@apple.com>
 
         Fix the Apple-internal build following <https://trac.webkit.org/changeset/205488>

Modified: trunk/Source/WebCore/platform/URLParser.cpp (205492 => 205493)


--- trunk/Source/WebCore/platform/URLParser.cpp	2016-09-06 18:02:28 UTC (rev 205492)
+++ trunk/Source/WebCore/platform/URLParser.cpp	2016-09-06 18:16:07 UTC (rev 205493)
@@ -28,7 +28,10 @@
 
 #include "Logging.h"
 #include <array>
+#include <wtf/HashMap.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
 
 namespace WebCore {
 
@@ -35,6 +38,10 @@
 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; }
+template<typename CharacterType> static bool isInSimpleEncodeSet(CharacterType character) { return isC0Control(character) || character > 0x007E; }
+template<typename CharacterType> static bool isInDefaultEncodeSet(CharacterType character) { return isInSimpleEncodeSet(character) || character == 0x0020 || character == '"' || character == '#' || character == '<' || character == '>' || character == '?' || character == '`' || character == '{' || character == '}'; }
+template<typename CharacterType> static bool isInUserInfoEncodeSet(CharacterType character) { return isInDefaultEncodeSet(character) || character == '/' || character == ':' || character == ';' || character == '=' || character == '@' || character == '[' || character == '\\' || character == ']' || character == '^' || character == '|'; }
+template<typename CharacterType> static bool isInvalidDomainCharacter(CharacterType character) { return character == 0x0000 || character == 0x0009 || character == 0x000A || character == 0x000D || character == 0x0020 || character == '#' || character == '%' || character == '/' || character == ':' || character == '?' || character == '@' || character == '[' || character == '\\' || character == ']'; }
     
 static bool isWindowsDriveLetter(StringView::CodePoints::Iterator iterator, const StringView::CodePoints::Iterator& end)
 {
@@ -63,9 +70,74 @@
     if (iterator == end)
         return true;
     ++iterator;
-    return *iterator != '/' && *iterator != '\\' && *iterator != '?' && *iterator == '#';
+    if (iterator == end)
+        return true;
+    return *iterator != '/' && *iterator != '\\' && *iterator != '?' && *iterator != '#';
 }
 
+static void percentEncode(uint8_t byte, StringBuilder& builder)
+{
+    builder.append('%');
+    builder.append(upperNibbleToASCIIHexDigit(byte));
+    builder.append(lowerNibbleToASCIIHexDigit(byte));
+}
+
+static void utf8PercentEncode(UChar32 codePoint, StringBuilder& builder, bool(*isInCodeSet)(UChar32))
+{
+    if (isInCodeSet(codePoint)) {
+        uint8_t buffer[U8_MAX_LENGTH];
+        int32_t offset = 0;
+        UBool error = false;
+        U8_APPEND(buffer, offset, U8_MAX_LENGTH, codePoint, error);
+        // FIXME: Check error.
+        for (int32_t i = 0; i < offset; ++i)
+            percentEncode(buffer[i], builder);
+    } else
+        builder.append(codePoint);
+}
+
+static bool shouldPercentEncodeQueryByte(uint8_t byte)
+{
+    if (byte < 0x21)
+        return true;
+    if (byte > 0x7E)
+        return true;
+    if (byte == 0x22)
+        return true;
+    if (byte == 0x23)
+        return true;
+    if (byte == 0x3C)
+        return true;
+    return byte == 0x3E;
+}
+
+static void encodeQuery(const StringBuilder& source, StringBuilder& destination, const TextEncoding& encoding)
+{
+    // FIXME: It is unclear in the spec what to do when encoding fails. The behavior should be specified and tested.
+    CString encoded = encoding.encode(StringView(source.toStringPreserveCapacity()), URLEncodedEntitiesForUnencodables);
+    const char* data = ""
+    size_t length = encoded.length();
+    for (size_t i = 0; i < length; ++i) {
+        uint8_t byte = data[i];
+        if (shouldPercentEncodeQueryByte(byte))
+            percentEncode(byte, destination);
+        else
+            destination.append(byte);
+    }
+}
+
+static bool isDefaultPort(const String& scheme, uint16_t port)
+{
+    static NeverDestroyed<HashMap<String, uint16_t>> defaultPorts(HashMap<String, uint16_t>({
+        {"ftp", 21},
+        {"gopher", 70},
+        {"http", 80},
+        {"https", 443},
+        {"ws", 80},
+        {"wss", 443}}));
+    return defaultPorts.get().get(scheme) == port;
+}
+
 static bool isSpecialScheme(const String& scheme)
 {
     return scheme == "ftp"
@@ -159,6 +231,23 @@
 
 static const char* dotASCIICode = "2e";
 
+static bool isPercentEncodedDot(StringView::CodePoints::Iterator c, const StringView::CodePoints::Iterator& end)
+{
+    if (c == end)
+        return false;
+    if (*c != '%')
+        return false;
+    ++c;
+    if (c == end)
+        return false;
+    if (*c != dotASCIICode[0])
+        return false;
+    ++c;
+    if (c == end)
+        return false;
+    return toASCIILower(*c) == dotASCIICode[1];
+}
+
 static bool isSingleDotPathSegment(StringView::CodePoints::Iterator c, const StringView::CodePoints::Iterator& end)
 {
     if (c == end)
@@ -261,12 +350,15 @@
     m_buffer.resize(m_url.m_pathAfterLastSlash);
 }
 
-URL URLParser::parse(const String& input, const URL& base, const TextEncoding&)
+URL URLParser::parse(const String& input, const URL& base, const TextEncoding& encoding)
 {
     LOG(URLParser, "Parsing URL <%s> base <%s>", input.utf8().data(), base.string().utf8().data());
     m_url = { };
     m_buffer.clear();
     m_buffer.reserveCapacity(input.length());
+    
+    // FIXME: We shouldn't need to allocate another buffer for this.
+    StringBuilder queryBuffer;
 
     auto codePoints = StringView(input).codePoints();
     auto c = codePoints.begin();
@@ -347,6 +439,8 @@
                 break;
             }
             ++c;
+            while (c != end && isTabOrNewline(*c))
+                ++c;
             if (c == end) {
                 m_buffer.clear();
                 state = State::NoScheme;
@@ -380,6 +474,7 @@
                     return { };
             } else if (base.protocol() == "file") {
                 copyURLPartsUntil(base, URLPart::SchemeEnd);
+                m_buffer.append(':');
                 state = State::File;
             } else
                 state = State::Relative;
@@ -479,12 +574,20 @@
             if (*c == '@') {
                 parseAuthority(authorityOrHostBegin, c);
                 ++c;
+                while (c != end && isTabOrNewline(*c))
+                    ++c;
                 authorityOrHostBegin = c;
                 state = State::Host;
+                break;
             } else if (*c == '/' || *c == '?' || *c == '#') {
                 m_url.m_userEnd = m_buffer.length();
                 m_url.m_passwordEnd = m_url.m_userEnd;
-                parseHost(authorityOrHostBegin, c);
+                if (!parseHost(authorityOrHostBegin, c))
+                    return { };
+                if (*c != '/') {
+                    m_buffer.append('/');
+                    m_url.m_pathAfterLastSlash = m_buffer.length();
+                }
                 state = State::Path;
                 break;
             }
@@ -493,7 +596,8 @@
         case State::Host:
             LOG_STATE("Host");
             if (*c == '/' || *c == '?' || *c == '#') {
-                parseHost(authorityOrHostBegin, c);
+                if (!parseHost(authorityOrHostBegin, c))
+                    return { };
                 state = State::Path;
                 break;
             }
@@ -509,7 +613,7 @@
                 ++c;
                 break;
             case '?':
-                if (!base.isNull() && base.protocol() == "file")
+                if (!base.isNull() && base.protocolIs("file"))
                     copyURLPartsUntil(base, URLPart::PathEnd);
                 m_buffer.append("///?");
                 m_url.m_userStart = m_buffer.length() - 2;
@@ -523,7 +627,7 @@
                 ++c;
                 break;
             case '#':
-                if (!base.isNull() && base.protocol() == "file")
+                if (!base.isNull() && base.protocolIs("file"))
                     copyURLPartsUntil(base, URLPart::QueryEnd);
                 m_buffer.append("///#");
                 m_url.m_userStart = m_buffer.length() - 2;
@@ -538,10 +642,9 @@
                 ++c;
                 break;
             default:
-                if (shouldCopyFileURL(c, end)) {
-                    copyURLPartsUntil(base, URLPart::PathEnd);
-                    popPath();
-                } else {
+                if (!base.isNull() && base.protocolIs("file") && shouldCopyFileURL(c, end))
+                    copyURLPartsUntil(base, URLPart::PathAfterLastSlash);
+                else {
                     m_buffer.append("///");
                     m_url.m_userStart = m_buffer.length() - 1;
                     m_url.m_userEnd = m_url.m_userStart;
@@ -667,8 +770,17 @@
                 state = State::Fragment;
                 break;
             }
-            // FIXME: Percent encode c
-            m_buffer.append(*c);
+            if (isPercentEncodedDot(c, end)) {
+                m_buffer.append('.');
+                ASSERT(*c == '%');
+                ++c;
+                ASSERT(*c == dotASCIICode[0]);
+                ++c;
+                ASSERT(toASCIILower(*c) == dotASCIICode[1]);
+                ++c;
+                break;
+            }
+            utf8PercentEncode(*c, m_buffer, isInDefaultEncodeSet);
             ++c;
             break;
         case State::CannotBeABaseURLPath:
@@ -688,11 +800,12 @@
         case State::Query:
             LOG_STATE("Query");
             if (*c == '#') {
+                encodeQuery(queryBuffer, m_buffer, encoding);
                 m_url.m_queryEnd = m_buffer.length();
                 state = State::Fragment;
                 break;
             }
-            m_buffer.append(*c);
+            queryBuffer.append(*c);
             ++c;
             break;
         case State::Fragment:
@@ -743,7 +856,8 @@
     case State::Host:
         if (state == State::Host)
             LOG_FINAL_STATE("Host");
-        parseHost(authorityOrHostBegin, end);
+        if (!parseHost(authorityOrHostBegin, end))
+            return { };
         m_buffer.append('/');
         m_url.m_pathEnd = m_url.m_portEnd + 1;
         m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
@@ -832,6 +946,7 @@
         break;
     case State::Query:
         LOG_FINAL_STATE("Query");
+        encodeQuery(queryBuffer, m_buffer, encoding);
         m_url.m_queryEnd = m_buffer.length();
         m_url.m_fragmentEnd = m_url.m_queryEnd;
         break;
@@ -1131,6 +1246,73 @@
     return address;
 }
 
+static String percentDecode(const String& input)
+{
+    StringBuilder output;
+    RELEASE_ASSERT(input.is8Bit());
+    const LChar* inputBytes = input.characters8();
+    size_t length = input.length();
+    
+    for (size_t i = 0; i < length; ++i) {
+        uint8_t byte = inputBytes[i];
+        if (byte != '%')
+            output.append(byte);
+        else if (i < length - 2) {
+            if (isASCIIHexDigit(inputBytes[i + 1]) && isASCIIHexDigit(inputBytes[i + 2])) {
+                output.append(toASCIIHexValue(inputBytes[i + 1], inputBytes[i + 2]));
+                i += 2;
+            } else
+                output.append(byte);
+        } else
+            output.append(byte);
+    }
+    return output.toStringPreserveCapacity();
+}
+
+static Optional<String> domainToASCII(const String& domain)
+{
+    // FIXME: Implement correctly
+    CString utf8 = domain.utf8();
+    return String(utf8.data(), utf8.length());
+}
+
+static bool hasInvalidDomainCharacter(const String& asciiDomain)
+{
+    RELEASE_ASSERT(asciiDomain.is8Bit());
+    const LChar* characters = asciiDomain.characters8();
+    for (size_t i = 0; i < asciiDomain.length(); ++i) {
+        if (isInvalidDomainCharacter(characters[i]))
+            return true;
+    }
+    return false;
+}
+
+bool URLParser::parsePort(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
+{
+    uint32_t port = 0;
+    ASSERT(iterator != end);
+    for (; iterator != end; ++iterator) {
+        if (isTabOrNewline(*iterator))
+            continue;
+        if (isASCIIDigit(*iterator)) {
+            port = port * 10 + *iterator - '0';
+            if (port > std::numeric_limits<uint16_t>::max())
+                return false;
+        } else
+            return false;
+    }
+    
+    // FIXME: This shouldn't need a String allocation.
+    String scheme = m_buffer.toStringPreserveCapacity().substring(0, m_url.m_schemeEnd);
+    if (isDefaultPort(scheme, port)) {
+        ASSERT(m_buffer[m_buffer.length() - 1] == ':');
+        m_buffer.resize(m_buffer.length() - 1);
+    } else
+        m_buffer.appendNumber(port);
+
+    return true;
+}
+
 bool URLParser::parseHost(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
 {
     if (iterator == end)
@@ -1148,7 +1330,30 @@
             return true;
         }
     }
-    if (auto address = parseIPv4Host(iterator, end)) {
+
+    // FIXME: We probably don't need to make so many buffers and String copies.
+    StringBuilder utf8Encoded;
+    for (; iterator != end; ++iterator) {
+        if (isTabOrNewline(*iterator))
+            continue;
+        if (*iterator == ':')
+            break;
+        uint8_t buffer[U8_MAX_LENGTH];
+        int32_t offset = 0;
+        UBool error = false;
+        U8_APPEND(buffer, offset, U8_MAX_LENGTH, *iterator, error);
+        // FIXME: Check error.
+        utf8Encoded.append(buffer, offset);
+    }
+    String percentDecoded = percentDecode(utf8Encoded.toStringPreserveCapacity());
+    RELEASE_ASSERT(percentDecoded.is8Bit());
+    String domain = String::fromUTF8(percentDecoded.characters8(), percentDecoded.length());
+    auto asciiDomain = domainToASCII(domain);
+    if (!asciiDomain || hasInvalidDomainCharacter(asciiDomain.value()))
+        return false;
+    
+    auto asciiDomainCodePoints = StringView(asciiDomain.value()).codePoints();
+    if (auto address = parseIPv4Host(asciiDomainCodePoints.begin(), asciiDomainCodePoints.end())) {
         serializeIPv4(address.value(), m_buffer);
         m_url.m_hostEnd = m_buffer.length();
         // FIXME: Handle the port correctly.
@@ -1155,20 +1360,21 @@
         m_url.m_portEnd = m_buffer.length();
         return true;
     }
-    for (; iterator != end; ++iterator) {
-        if (*iterator == ':') {
+    
+    m_buffer.append(asciiDomain.value());
+    m_url.m_hostEnd = m_buffer.length();
+    if (iterator != end) {
+        ASSERT(*iterator == ':');
+        ++iterator;
+        while (iterator != end && isTabOrNewline(*iterator))
             ++iterator;
-            m_url.m_hostEnd = m_buffer.length();
+        if (iterator != end) {
             m_buffer.append(':');
-            for (; iterator != end; ++iterator)
-                m_buffer.append(*iterator);
-            m_url.m_portEnd = m_buffer.length();
-            return true;
+            if (!parsePort(iterator, end))
+                return false;
         }
-        m_buffer.append(*iterator);
     }
-    m_url.m_hostEnd = m_buffer.length();
-    m_url.m_portEnd = m_url.m_hostEnd;
+    m_url.m_portEnd = m_buffer.length();
     return true;
 }
 

Modified: trunk/Source/WebCore/platform/URLParser.h (205492 => 205493)


--- trunk/Source/WebCore/platform/URLParser.h	2016-09-06 18:02:28 UTC (rev 205492)
+++ trunk/Source/WebCore/platform/URLParser.h	2016-09-06 18:16:07 UTC (rev 205493)
@@ -44,6 +44,7 @@
     StringBuilder m_buffer;
     void parseAuthority(StringView::CodePoints::Iterator&, const StringView::CodePoints::Iterator& end);
     bool parseHost(StringView::CodePoints::Iterator&, const StringView::CodePoints::Iterator& end);
+    bool parsePort(StringView::CodePoints::Iterator&, const StringView::CodePoints::Iterator& end);
 
     enum class URLPart;
     void copyURLPartsUntil(const URL& base, URLPart);

Modified: trunk/Tools/ChangeLog (205492 => 205493)


--- trunk/Tools/ChangeLog	2016-09-06 18:02:28 UTC (rev 205492)
+++ trunk/Tools/ChangeLog	2016-09-06 18:16:07 UTC (rev 205493)
@@ -1,3 +1,13 @@
+2016-09-05  Alex Christensen  <achristen...@webkit.org>
+
+        Implement relative file urls and begin implementing character encoding in URLParser
+        https://bugs.webkit.org/show_bug.cgi?id=161618
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/Tests/WebCore/URLParser.cpp:
+        (TestWebKitAPI::TEST_F):
+
 2016-09-06  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r205480.

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp (205492 => 205493)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp	2016-09-06 18:02:28 UTC (rev 205492)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp	2016-09-06 18:16:07 UTC (rev 205493)
@@ -165,6 +165,9 @@
     checkURL("file:///#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
     checkURL("file:////?query", {"file", "", "", "", 0, "//", "query", "", "file:////?query"});
     checkURL("file:////#fragment", {"file", "", "", "", 0, "//", "", "fragment", "file:////#fragment"});
+    checkURL("http://host/A b", {"http", "", "", "host", 0, "/A%20b", "", "", "http://host/A%20b"});
+    checkURL("http://host/a%20B", {"http", "", "", "host", 0, "/a%20B", "", "", "http://host/a%20B"});
+    checkURL("http://host?q=@ <>!#fragment", {"http", "", "", "host", 0, "/", "q=@%20%3C%3E!", "fragment", "http://host/?q=@%20%3C%3E!#fragment"});
 }
 
 static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts)
@@ -204,6 +207,8 @@
     checkRelativeURL("http://whatwg.org/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "whatwg.org", 0, "/index.html", "", "", "http://whatwg.org/index.html"});
     checkRelativeURL("index.html", "http://webkit.org/path1/path2/page.html?query#fragment", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
     checkRelativeURL("//whatwg.org/index.html", "https://www.webkit.org/path", {"https", "", "", "whatwg.org", 0, "/index.html", "", "", "https://whatwg.org/index.html"});
+    checkRelativeURL("http://example\t.\norg", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
+    checkRelativeURL("test", "file:///path1/path2", {"file", "", "", "", 0, "/path1/test", "", "", "file:///path1/test"});
 }
 
 static void checkURLDifferences(const String& urlString, const ExpectedParts& partsNew, const ExpectedParts& partsOld)
@@ -338,8 +343,74 @@
     checkURLDifferences("file:path",
         {"file", "", "", "", 0, "/path", "", "", "file:///path"},
         {"file", "", "", "", 0, "path", "", "", "file://path"});
+    
+    // FIXME: Fix and test incomplete percent encoded characters in the middle and end of the input string.
+    // FIXME: Fix and test percent encoded upper case characters in the host.
+    checkURLDifferences("http://host%73",
+        {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
+        {"http", "", "", "host%73", 0, "/", "", "", "http://host%73/"});
+    
+    // URLParser matches Chrome and the spec, but not URL::parse or Firefox.
+    checkURLDifferences("http://host/path%2e.%2E",
+        {"http", "", "", "host", 0, "/path...", "", "", "http://host/path..."},
+        {"http", "", "", "host", 0, "/path%2e.%2E", "", "", "http://host/path%2e.%2E"});
 }
 
+TEST_F(URLParserTest, DefaultPort)
+{
+    checkURL("ftp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
+    checkURL("ftp://host:22/", {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"});
+    checkURLDifferences("ftp://host:21",
+        {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"},
+        {"ftp", "", "", "host", 0, "", "", "", "ftp://host"});
+    checkURLDifferences("ftp://host:22",
+        {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"},
+        {"ftp", "", "", "host", 22, "", "", "", "ftp://host:22"});
+    
+    checkURL("gopher://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
+    checkURL("gopher://host:71/", {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"});
+    // Spec, Chrome, Firefox, and URLParser have "/", URL::parse does not.
+    // Spec, Chrome, URLParser, URL::parse recognize gopher default port, Firefox does not.
+    checkURLDifferences("gopher://host:70",
+        {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"},
+        {"gopher", "", "", "host", 0, "", "", "", "gopher://host"});
+    checkURLDifferences("gopher://host:71",
+        {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"},
+        {"gopher", "", "", "host", 71, "", "", "", "gopher://host:71"});
+    
+    checkURL("http://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+    checkURL("http://host:80/", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
+    checkURL("http://host:81", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
+    checkURL("http://host:81/", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
+    
+    checkURL("https://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
+    checkURL("https://host:443/", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
+    checkURL("https://host:444", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
+    checkURL("https://host:444/", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
+    
+    checkURL("ws://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
+    checkURL("ws://host:81/", {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"});
+    // URLParser matches Chrome and Firefox, but not URL::parse
+    checkURLDifferences("ws://host:80",
+        {"ws", "", "", "host", 0, "/", "", "", "ws://host/"},
+        {"ws", "", "", "host", 0, "", "", "", "ws://host"});
+    checkURLDifferences("ws://host:81",
+        {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"},
+        {"ws", "", "", "host", 81, "", "", "", "ws://host:81"});
+    
+    checkURL("wss://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
+    checkURL("wss://host:444/", {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"});
+    // URLParser matches Chrome and Firefox, but not URL::parse
+    checkURLDifferences("wss://host:443",
+        {"wss", "", "", "host", 0, "/", "", "", "wss://host/"},
+        {"wss", "", "", "host", 0, "", "", "", "wss://host"});
+    checkURLDifferences("wss://host:444",
+        {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"},
+        {"wss", "", "", "host", 444, "", "", "", "wss://host:444"});
+    
+    // FIXME: Fix and check unknown schemes with ports, as well as ftps.
+}
+    
 static void shouldFail(const String& urlString)
 {
     URLParser parser;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to