Title: [205273] trunk
Revision
205273
Author
achristen...@apple.com
Date
2016-08-31 17:23:47 -0700 (Wed, 31 Aug 2016)

Log Message

Implement IPv6 parsing in URLParser
https://bugs.webkit.org/show_bug.cgi?id=161390

Reviewed by Darin Adler.

Source/WebCore:

Covered by new API tests.

* platform/URLParser.cpp:
(WebCore::zeroSequenceLength):
(WebCore::findLongestZeroSequence):
(WebCore::nibbleToHex):
(WebCore::serializeIPv6Piece):
(WebCore::serializeIPv6):
(WebCore::parseIPv6Host):
(WebCore::URLParser::hostEndReached):

Source/WTF:

* wtf/ASCIICType.h:
(WTF::lowerNibbleToLowercaseASCIIHexDigit):
(WTF::upperNibbleToLowercaseASCIIHexDigit):

Tools:

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

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (205272 => 205273)


--- trunk/Source/WTF/ChangeLog	2016-09-01 00:17:00 UTC (rev 205272)
+++ trunk/Source/WTF/ChangeLog	2016-09-01 00:23:47 UTC (rev 205273)
@@ -1,3 +1,14 @@
+2016-08-31  Alex Christensen  <achristen...@webkit.org>
+
+        Implement IPv6 parsing in URLParser
+        https://bugs.webkit.org/show_bug.cgi?id=161390
+
+        Reviewed by Darin Adler.
+
+        * wtf/ASCIICType.h:
+        (WTF::lowerNibbleToLowercaseASCIIHexDigit):
+        (WTF::upperNibbleToLowercaseASCIIHexDigit):
+
 2016-08-30  Brady Eidson  <beid...@apple.com>
 
         GameController.framework backend for gamepad API.

Modified: trunk/Source/WTF/wtf/ASCIICType.h (205272 => 205273)


--- trunk/Source/WTF/wtf/ASCIICType.h	2016-09-01 00:17:00 UTC (rev 205272)
+++ trunk/Source/WTF/wtf/ASCIICType.h	2016-09-01 00:23:47 UTC (rev 205273)
@@ -187,6 +187,18 @@
     return nibble + (nibble < 10 ? '0' : 'A' - 10);
 }
 
+inline char lowerNibbleToLowercaseASCIIHexDigit(uint8_t value)
+{
+    uint8_t nibble = value & 0xF;
+    return nibble + (nibble < 10 ? '0' : 'a' - 10);
+}
+
+inline char upperNibbleToLowercaseASCIIHexDigit(uint8_t value)
+{
+    uint8_t nibble = value >> 4;
+    return nibble + (nibble < 10 ? '0' : 'a' - 10);
+}
+
 template<typename CharacterType> inline bool isASCIIAlphaCaselessEqual(CharacterType inputCharacter, char expectedASCIILowercaseLetter)
 {
     // Name of this argument says this must be a lowercase letter, but it can actually be:
@@ -219,10 +231,12 @@
 using WTF::isASCIISpace;
 using WTF::isASCIIUpper;
 using WTF::lowerNibbleToASCIIHexDigit;
+using WTF::lowerNibbleToLowercaseASCIIHexDigit;
 using WTF::toASCIIHexValue;
 using WTF::toASCIILower;
 using WTF::toASCIILowerUnchecked;
 using WTF::toASCIIUpper;
 using WTF::upperNibbleToASCIIHexDigit;
+using WTF::upperNibbleToLowercaseASCIIHexDigit;
 
 #endif

Modified: trunk/Source/WebCore/ChangeLog (205272 => 205273)


--- trunk/Source/WebCore/ChangeLog	2016-09-01 00:17:00 UTC (rev 205272)
+++ trunk/Source/WebCore/ChangeLog	2016-09-01 00:23:47 UTC (rev 205273)
@@ -1,3 +1,21 @@
+2016-08-31  Alex Christensen  <achristen...@webkit.org>
+
+        Implement IPv6 parsing in URLParser
+        https://bugs.webkit.org/show_bug.cgi?id=161390
+
+        Reviewed by Darin Adler.
+
+        Covered by new API tests.
+
+        * platform/URLParser.cpp:
+        (WebCore::zeroSequenceLength):
+        (WebCore::findLongestZeroSequence):
+        (WebCore::nibbleToHex):
+        (WebCore::serializeIPv6Piece):
+        (WebCore::serializeIPv6):
+        (WebCore::parseIPv6Host):
+        (WebCore::URLParser::hostEndReached):
+
 2016-08-31  Ricky Mondello  <rmonde...@apple.com>
 
         Break pluginReplacementEnabled into youTubeFlashPluginReplacementEnabled and quickTimePluginReplacementEnabled

Modified: trunk/Source/WebCore/platform/URLParser.cpp (205272 => 205273)


--- trunk/Source/WebCore/platform/URLParser.cpp	2016-09-01 00:17:00 UTC (rev 205272)
+++ trunk/Source/WebCore/platform/URLParser.cpp	2016-09-01 00:23:47 UTC (rev 205273)
@@ -563,6 +563,74 @@
     buffer.appendNumber(address & 0xFF);
 }
     
+static size_t zeroSequenceLength(const std::array<uint16_t, 8>& address, size_t begin)
+{
+    size_t end = begin;
+    for (; end < 8; end++) {
+        if (address[end])
+            break;
+    }
+    return end - begin;
+}
+
+static Optional<size_t> findLongestZeroSequence(const std::array<uint16_t, 8>& address)
+{
+    Optional<size_t> longest;
+    size_t longestLength = 0;
+    for (size_t i = 0; i < 8; i++) {
+        size_t length = zeroSequenceLength(address, i);
+        if (length) {
+            if (length > 1 && (!longest || longestLength < length)) {
+                longest = i;
+                longestLength = length;
+            }
+            i += length;
+        }
+    }
+    return longest;
+}
+    
+static void serializeIPv6Piece(uint16_t piece, StringBuilder& buffer)
+{
+    bool printed = false;
+    if (auto nibble0 = piece >> 12) {
+        buffer.append(lowerNibbleToLowercaseASCIIHexDigit(nibble0));
+        printed = true;
+    }
+    auto nibble1 = piece >> 8 & 0xF;
+    if (printed || nibble1) {
+        buffer.append(lowerNibbleToLowercaseASCIIHexDigit(nibble1));
+        printed = true;
+    }
+    auto nibble2 = piece >> 4 & 0xF;
+    if (printed || nibble2)
+        buffer.append(lowerNibbleToLowercaseASCIIHexDigit(nibble2));
+    buffer.append(lowerNibbleToLowercaseASCIIHexDigit(piece & 0xF));
+}
+
+static void serializeIPv6(std::array<uint16_t, 8> address, StringBuilder& buffer)
+{
+    buffer.append('[');
+    auto compressPointer = findLongestZeroSequence(address);
+    for (size_t piece = 0; piece < 8; piece++) {
+        if (compressPointer && compressPointer.value() == piece) {
+            ASSERT(!address[piece]);
+            if (piece)
+                buffer.append(':');
+            else
+                buffer.append("::");
+            while (!address[piece])
+                piece++;
+            if (piece == 8)
+                break;
+        }
+        serializeIPv6Piece(address[piece], buffer);
+        if (piece < 7)
+            buffer.append(':');
+    }
+    buffer.append(']');
+}
+
 static Optional<uint32_t> parseIPv4Number(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
 {
     // FIXME: Check for overflow.
@@ -660,10 +728,96 @@
     return ipv4;
 }
 
-static Optional<std::array<uint16_t, 8>> parseIPv6Host(StringView::CodePoints::Iterator, StringView::CodePoints::Iterator)
+static Optional<std::array<uint16_t, 8>> parseIPv6Host(StringView::CodePoints::Iterator c, StringView::CodePoints::Iterator end)
 {
-    notImplemented();
-    return Nullopt;
+    if (c == end)
+        return Nullopt;
+
+    std::array<uint16_t, 8> address = {{0, 0, 0, 0, 0, 0, 0, 0}};
+    size_t piecePointer = 0;
+    Optional<size_t> compressPointer;
+
+    if (*c == ':') {
+        ++c;
+        if (c == end)
+            return Nullopt;
+        if (*c != ':')
+            return Nullopt;
+        ++c;
+        ++piecePointer;
+        compressPointer = piecePointer;
+    }
+    
+    while (c != end) {
+        if (piecePointer == 8)
+            return Nullopt;
+        if (*c == ':') {
+            if (compressPointer)
+                return Nullopt;
+            ++c;
+            ++piecePointer;
+            compressPointer = piecePointer;
+            continue;
+        }
+        uint16_t value = 0;
+        for (size_t length = 0; length < 4; length++) {
+            if (c == end)
+                break;
+            if (!isASCIIHexDigit(*c))
+                break;
+            value = value * 0x10 + toASCIIHexValue(*c);
+            ++c;
+        }
+        address[piecePointer++] = value;
+        if (c == end)
+            break;
+        if (*c != ':')
+            return Nullopt;
+        ++c;
+    }
+    
+    if (c != end) {
+        if (piecePointer > 6)
+            return Nullopt;
+        size_t dotsSeen = 0;
+        while (c != end) {
+            Optional<uint16_t> value;
+            if (!isASCIIDigit(*c))
+                return Nullopt;
+            while (isASCIIDigit(*c)) {
+                auto number = *c - '0';
+                if (!value)
+                    value = number;
+                else if (!value.value())
+                    return Nullopt;
+                else
+                    value = value.value() * 10 + number;
+                ++c;
+                if (c == end)
+                    return Nullopt;
+                if (value.value() > 255)
+                    return Nullopt;
+            }
+            if (dotsSeen < 3 && *c != '.')
+                return Nullopt;
+            address[piecePointer] = address[piecePointer] * 0x100 + value.valueOr(0);
+            if (dotsSeen == 1 || dotsSeen == 3)
+                piecePointer++;
+            if (c != end)
+                ++c;
+            if (dotsSeen == 3 && c != end)
+                return Nullopt;
+            dotsSeen++;
+        }
+    }
+    if (compressPointer) {
+        size_t swaps = piecePointer - compressPointer.value();
+        piecePointer = 7;
+        while (swaps)
+            std::swap(address[piecePointer--], address[compressPointer.value() + swaps-- - 1]);
+    } else if (piecePointer != 8)
+        return Nullopt;
+    return address;
 }
 
 void URLParser::hostEndReached()
@@ -675,8 +829,16 @@
         return;
     if (*iterator == '[') {
         ++iterator;
-        parseIPv6Host(iterator, end);
-        return;
+        auto ipv6End = iterator;
+        while (ipv6End != end && *ipv6End != ']')
+            ++ipv6End;
+        if (auto address = parseIPv6Host(iterator, ipv6End)) {
+            serializeIPv6(address.value(), m_buffer);
+            m_url.m_hostEnd = m_buffer.length();
+            // FIXME: Handle the port correctly.
+            m_url.m_portEnd = m_buffer.length();            
+            return;
+        }
     }
     if (auto address = parseIPv4Host(iterator, end)) {
         serializeIPv4(address.value(), m_buffer);

Modified: trunk/Tools/ChangeLog (205272 => 205273)


--- trunk/Tools/ChangeLog	2016-09-01 00:17:00 UTC (rev 205272)
+++ trunk/Tools/ChangeLog	2016-09-01 00:23:47 UTC (rev 205273)
@@ -1,3 +1,14 @@
+2016-08-31  Alex Christensen  <achristen...@webkit.org>
+
+        Implement IPv6 parsing in URLParser
+        https://bugs.webkit.org/show_bug.cgi?id=161390
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WebCore/URLParser.cpp:
+        (TestWebKitAPI::TEST_F):
+        (TestWebKitAPI::checkURLDifferences):
+
 2016-08-31  Brady Eidson  <beid...@apple.com>
 
         WK2 Gamepad provider on iOS.

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp (205272 => 205273)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp	2016-09-01 00:17:00 UTC (rev 205272)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp	2016-09-01 00:23:47 UTC (rev 205273)
@@ -50,7 +50,12 @@
     String string;
 };
 
-static bool eq(const String& s1, const String& s2) { return s1.utf8() == s2.utf8(); }
+static bool eq(const String& s1, const String& s2)
+{
+    EXPECT_STREQ(s1.utf8().data(), s2.utf8().data());
+    return s1.utf8() == s2.utf8();
+}
+
 static void checkURL(const String& urlString, const ExpectedParts& parts)
 {
     URLParser parser;
@@ -94,6 +99,9 @@
     checkURL("about:blank", {"about", "", "", "", 0, "blank", "", "", "about:blank"});
     checkURL("about:blank?query", {"about", "", "", "", 0, "blank", "query", "", "about:blank?query"});
     checkURL("about:blank#fragment", {"about", "", "", "", 0, "blank", "", "fragment", "about:blank#fragment"});
+    checkURL("http://[0:f::f:f:0:0]", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
+    checkURL("http://[0:f:0:0:f::]", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
+    checkURL("http://[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
 }
 
 static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts)
@@ -202,6 +210,18 @@
     checkURLDifferences("http://011.11.0X11.0x011",
         {"http", "", "", "9.11.17.17", 0, "/", "", "", "http://9.11.17.17/"},
         {"http", "", "", "011.11.0x11.0x011", 0, "/", "", "", "http://011.11.0x11.0x011/"});
+    checkURLDifferences("http://[1234:0078:90AB:CdEf:0123:0007:89AB:0000]",
+        {"http", "", "", "[1234:78:90ab:cdef:123:7:89ab:0]", 0, "/", "", "", "http://[1234:78:90ab:cdef:123:7:89ab:0]/"},
+        {"http", "", "", "[1234:0078:90ab:cdef:0123:0007:89ab:0000]", 0, "/", "", "", "http://[1234:0078:90ab:cdef:0123:0007:89ab:0000]/"});
+    checkURLDifferences("http://[0:f:0:0:f:f:0:0]",
+        {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"},
+        {"http", "", "", "[0:f:0:0:f:f:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:f:0:0]/"});
+    checkURLDifferences("http://[0:f:0:0:f:0:0:0]",
+        {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"},
+        {"http", "", "", "[0:f:0:0:f:0:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:0:0:0]/"});
+    checkURLDifferences("http://[0:0:f:0:0:f:0:0]",
+        {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"},
+        {"http", "", "", "[0:0:f:0:0:f:0:0]", 0, "/", "", "", "http://[0:0:f:0:0:f:0:0]/"});
 
     // FIXME: This behavior ought to be specified in the standard.
     // With the existing URL::parse, WebKit returns "https:/", Firefox returns "https:///", and Chrome throws an error.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to