Changeset 267965 in webkit


Ignore:
Timestamp:
Oct 5, 2020 7:51:18 AM (4 years ago)
Author:
achristensen@apple.com
Message:

URLParser should fail to parse URLs with hosts containing invalid punycode encodings
https://bugs.webkit.org/show_bug.cgi?id=217285

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

  • web-platform-tests/url/a-element-expected.txt:
  • web-platform-tests/url/a-element-xhtml-expected.txt:
  • web-platform-tests/url/failure-expected.txt:
  • web-platform-tests/url/toascii.window-expected.txt:
  • web-platform-tests/url/url-constructor-expected.txt:

Source/WTF:

URLParser has a fast path for parsing hosts that are all ASCII, but that does not validate hosts that are invalid punycode, such as "xn--".
Since all punycode encoded strings start with "xn--", if the input string starts with "xn--" then skip the fast path and let ICU decide if it's valid.

  • wtf/URLParser.cpp:

(WTF::URLParser::domainToASCII):
(WTF::URLParser::startsWithXNDashDash):
(WTF::URLParser::parseHostAndPort):

  • wtf/URLParser.h:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r267964 r267965  
     12020-10-05  Alex Christensen  <achristensen@webkit.org>
     2
     3        URLParser should fail to parse URLs with hosts containing invalid punycode encodings
     4        https://bugs.webkit.org/show_bug.cgi?id=217285
     5
     6        Reviewed by Darin Adler.
     7
     8        * web-platform-tests/url/a-element-expected.txt:
     9        * web-platform-tests/url/a-element-xhtml-expected.txt:
     10        * web-platform-tests/url/failure-expected.txt:
     11        * web-platform-tests/url/toascii.window-expected.txt:
     12        * web-platform-tests/url/url-constructor-expected.txt:
     13
    1142020-10-05  Alex Christensen  <achristensen@webkit.org>
    215
  • trunk/LayoutTests/imported/w3c/web-platform-tests/url/a-element-expected.txt

    r267964 r267965  
    580580PASS Parsing: <file://­/p> against <about:blank>
    581581PASS Parsing: <file://%C2%AD/p> against <about:blank>
    582 FAIL Parsing: <file://xn--/p> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code
     582PASS Parsing: <file://xn--/p> against <about:blank>
    583583PASS Parsing: <#link> against <https://example.org/##link>
    584584PASS Parsing: <non-special:cannot-be-a-base-url-\0
  • trunk/LayoutTests/imported/w3c/web-platform-tests/url/a-element-xhtml-expected.txt

    r267964 r267965  
    580580PASS Parsing: <file://­/p> against <about:blank>
    581581PASS Parsing: <file://%C2%AD/p> against <about:blank>
    582 FAIL Parsing: <file://xn--/p> against <about:blank> assert_unreached: Expected URL to fail parsing Reached unreachable code
     582PASS Parsing: <file://xn--/p> against <about:blank>
    583583PASS Parsing: <#link> against <https://example.org/##link>
    584584PASS Parsing: <non-special:cannot-be-a-base-url-\0
  • trunk/LayoutTests/imported/w3c/web-platform-tests/url/failure-expected.txt

    r267647 r267965  
    44Blocked access to external URL http://./y:
    55CONSOLE MESSAGE: Beacon API cannot load http://./y: due to access control checks.
    6 CONSOLE MESSAGE: Not allowed to load local resource: p
    7 CONSOLE MESSAGE: Not allowed to load local resource: p
    86
    97PASS Loading data…
     
    380378FAIL Location's href: file://%C2%AD/p should throw assert_throws_js: function "() => self[0].location = test.input" did not throw
    381379PASS window.open(): file://%C2%AD/p should throw
    382 FAIL URL's constructor's base argument: file://xn--/p should throw assert_throws_js: function "() => new URL("about:blank", test.input)" did not throw
    383 FAIL URL's href: file://xn--/p should throw assert_throws_js: function "() => url.href = test.input" did not throw
    384 FAIL XHR: file://xn--/p should throw assert_throws_dom: function "() => client.open("GET", test.input)" did not throw
     380PASS URL's constructor's base argument: file://xn--/p should throw
     381PASS URL's href: file://xn--/p should throw
     382PASS XHR: file://xn--/p should throw
    385383PASS sendBeacon(): file://xn--/p should throw
    386384FAIL Location's href: file://xn--/p should throw assert_throws_js: function "() => self[0].location = test.input" did not throw
    387 FAIL window.open(): file://xn--/p should throw assert_throws_dom: function "() => self.open(test.input).close()" did not throw
     385PASS window.open(): file://xn--/p should throw
    388386
  • trunk/LayoutTests/imported/w3c/web-platform-tests/url/toascii.window-expected.txt

    r267647 r267965  
    100100FAIL x..β (using <area>.host) assert_equals: expected "x..xn--nxa" but got "x"
    101101FAIL x..β (using <area>.hostname) assert_equals: expected "x..xn--nxa" but got "x"
    102 FAIL xn--a (using URL) assert_throws_js: function "() => makeURL("url", hostTest.input)" did not throw
    103 FAIL xn--a (using URL.host) assert_equals: expected "x" but got "xn--a"
    104 FAIL xn--a (using URL.hostname) assert_equals: expected "x" but got "xn--a"
    105 FAIL xn--a (using <a>) assert_equals: expected "" but got "xn--a"
    106 FAIL xn--a (using <a>.host) assert_equals: expected "x" but got "xn--a"
    107 FAIL xn--a (using <a>.hostname) assert_equals: expected "x" but got "xn--a"
    108 FAIL xn--a (using <area>) assert_equals: expected "" but got "xn--a"
    109 FAIL xn--a (using <area>.host) assert_equals: expected "x" but got "xn--a"
    110 FAIL xn--a (using <area>.hostname) assert_equals: expected "x" but got "xn--a"
    111 FAIL xn--a.xn--nxa (using URL) assert_throws_js: function "() => makeURL("url", hostTest.input)" did not throw
    112 FAIL xn--a.xn--nxa (using URL.host) assert_equals: expected "x" but got "xn--a.xn--nxa"
    113 FAIL xn--a.xn--nxa (using URL.hostname) assert_equals: expected "x" but got "xn--a.xn--nxa"
    114 FAIL xn--a.xn--nxa (using <a>) assert_equals: expected "" but got "xn--a.xn--nxa"
    115 FAIL xn--a.xn--nxa (using <a>.host) assert_equals: expected "x" but got "xn--a.xn--nxa"
    116 FAIL xn--a.xn--nxa (using <a>.hostname) assert_equals: expected "x" but got "xn--a.xn--nxa"
    117 FAIL xn--a.xn--nxa (using <area>) assert_equals: expected "" but got "xn--a.xn--nxa"
    118 FAIL xn--a.xn--nxa (using <area>.host) assert_equals: expected "x" but got "xn--a.xn--nxa"
    119 FAIL xn--a.xn--nxa (using <area>.hostname) assert_equals: expected "x" but got "xn--a.xn--nxa"
     102PASS xn--a (using URL)
     103PASS xn--a (using URL.host)
     104PASS xn--a (using URL.hostname)
     105PASS xn--a (using <a>)
     106PASS xn--a (using <a>.host)
     107PASS xn--a (using <a>.hostname)
     108PASS xn--a (using <area>)
     109PASS xn--a (using <area>.host)
     110PASS xn--a (using <area>.hostname)
     111PASS xn--a.xn--nxa (using URL)
     112PASS xn--a.xn--nxa (using URL.host)
     113PASS xn--a.xn--nxa (using URL.hostname)
     114PASS xn--a.xn--nxa (using <a>)
     115PASS xn--a.xn--nxa (using <a>.host)
     116PASS xn--a.xn--nxa (using <a>.hostname)
     117PASS xn--a.xn--nxa (using <area>)
     118PASS xn--a.xn--nxa (using <area>.host)
     119PASS xn--a.xn--nxa (using <area>.hostname)
    120120PASS xn--a.β (using URL)
    121121PASS xn--a.β (using URL.host)
     
    172172PASS ‍.example (using <area>.host)
    173173PASS ‍.example (using <area>.hostname)
    174 FAIL xn--1ug.example (using URL) assert_throws_js: function "() => makeURL("url", hostTest.input)" did not throw
    175 FAIL xn--1ug.example (using URL.host) assert_equals: expected "x" but got "xn--1ug.example"
    176 FAIL xn--1ug.example (using URL.hostname) assert_equals: expected "x" but got "xn--1ug.example"
    177 FAIL xn--1ug.example (using <a>) assert_equals: expected "" but got "xn--1ug.example"
    178 FAIL xn--1ug.example (using <a>.host) assert_equals: expected "x" but got "xn--1ug.example"
    179 FAIL xn--1ug.example (using <a>.hostname) assert_equals: expected "x" but got "xn--1ug.example"
    180 FAIL xn--1ug.example (using <area>) assert_equals: expected "" but got "xn--1ug.example"
    181 FAIL xn--1ug.example (using <area>.host) assert_equals: expected "x" but got "xn--1ug.example"
    182 FAIL xn--1ug.example (using <area>.hostname) assert_equals: expected "x" but got "xn--1ug.example"
     174PASS xn--1ug.example (using URL)
     175PASS xn--1ug.example (using URL.host)
     176PASS xn--1ug.example (using URL.hostname)
     177PASS xn--1ug.example (using <a>)
     178PASS xn--1ug.example (using <a>.host)
     179PASS xn--1ug.example (using <a>.hostname)
     180PASS xn--1ug.example (using <area>)
     181PASS xn--1ug.example (using <area>.host)
     182PASS xn--1ug.example (using <area>.hostname)
    183183PASS يa (using URL)
    184184PASS يa (using URL.host)
     
    190190PASS يa (using <area>.host)
    191191PASS يa (using <area>.hostname)
    192 FAIL xn--a-yoc (using URL) assert_throws_js: function "() => makeURL("url", hostTest.input)" did not throw
    193 FAIL xn--a-yoc (using URL.host) assert_equals: expected "x" but got "xn--a-yoc"
    194 FAIL xn--a-yoc (using URL.hostname) assert_equals: expected "x" but got "xn--a-yoc"
    195 FAIL xn--a-yoc (using <a>) assert_equals: expected "" but got "xn--a-yoc"
    196 FAIL xn--a-yoc (using <a>.host) assert_equals: expected "x" but got "xn--a-yoc"
    197 FAIL xn--a-yoc (using <a>.hostname) assert_equals: expected "x" but got "xn--a-yoc"
    198 FAIL xn--a-yoc (using <area>) assert_equals: expected "" but got "xn--a-yoc"
    199 FAIL xn--a-yoc (using <area>.host) assert_equals: expected "x" but got "xn--a-yoc"
    200 FAIL xn--a-yoc (using <area>.hostname) assert_equals: expected "x" but got "xn--a-yoc"
     192PASS xn--a-yoc (using URL)
     193PASS xn--a-yoc (using URL.host)
     194PASS xn--a-yoc (using URL.hostname)
     195PASS xn--a-yoc (using <a>)
     196PASS xn--a-yoc (using <a>.host)
     197PASS xn--a-yoc (using <a>.hostname)
     198PASS xn--a-yoc (using <area>)
     199PASS xn--a-yoc (using <area>.host)
     200PASS xn--a-yoc (using <area>.hostname)
    201201PASS ශ්‍රී (using URL)
    202202PASS ශ්‍රී (using URL.host)
     
    226226PASS �.com (using <area>.host)
    227227PASS �.com (using <area>.hostname)
    228 FAIL xn--zn7c.com (using URL) assert_throws_js: function "() => makeURL("url", hostTest.input)" did not throw
    229 FAIL xn--zn7c.com (using URL.host) assert_equals: expected "x" but got "xn--zn7c.com"
    230 FAIL xn--zn7c.com (using URL.hostname) assert_equals: expected "x" but got "xn--zn7c.com"
    231 FAIL xn--zn7c.com (using <a>) assert_equals: expected "" but got "xn--zn7c.com"
    232 FAIL xn--zn7c.com (using <a>.host) assert_equals: expected "x" but got "xn--zn7c.com"
    233 FAIL xn--zn7c.com (using <a>.hostname) assert_equals: expected "x" but got "xn--zn7c.com"
    234 FAIL xn--zn7c.com (using <area>) assert_equals: expected "" but got "xn--zn7c.com"
    235 FAIL xn--zn7c.com (using <area>.host) assert_equals: expected "x" but got "xn--zn7c.com"
    236 FAIL xn--zn7c.com (using <area>.hostname) assert_equals: expected "x" but got "xn--zn7c.com"
     228PASS xn--zn7c.com (using URL)
     229PASS xn--zn7c.com (using URL.host)
     230PASS xn--zn7c.com (using URL.hostname)
     231PASS xn--zn7c.com (using <a>)
     232PASS xn--zn7c.com (using <a>.host)
     233PASS xn--zn7c.com (using <a>.hostname)
     234PASS xn--zn7c.com (using <area>)
     235PASS xn--zn7c.com (using <area>.host)
     236PASS xn--zn7c.com (using <area>.hostname)
    237237PASS x01234567890123456789012345678901234567890123456789012345678901x (using URL)
    238238PASS x01234567890123456789012345678901234567890123456789012345678901x (using URL.host)
     
    334334PASS %C2%AD (using <area>.host)
    335335PASS %C2%AD (using <area>.hostname)
    336 FAIL xn-- (using URL) assert_throws_js: function "() => makeURL("url", hostTest.input)" did not throw
    337 FAIL xn-- (using URL.host) assert_equals: expected "x" but got "xn--"
    338 FAIL xn-- (using URL.hostname) assert_equals: expected "x" but got "xn--"
    339 FAIL xn-- (using <a>) assert_equals: expected "" but got "xn--"
    340 FAIL xn-- (using <a>.host) assert_equals: expected "x" but got "xn--"
    341 FAIL xn-- (using <a>.hostname) assert_equals: expected "x" but got "xn--"
    342 FAIL xn-- (using <area>) assert_equals: expected "" but got "xn--"
    343 FAIL xn-- (using <area>.host) assert_equals: expected "x" but got "xn--"
    344 FAIL xn-- (using <area>.hostname) assert_equals: expected "x" but got "xn--"
     336PASS xn-- (using URL)
     337PASS xn-- (using URL.host)
     338PASS xn-- (using URL.hostname)
     339PASS xn-- (using <a>)
     340PASS xn-- (using <a>.host)
     341PASS xn-- (using <a>.hostname)
     342PASS xn-- (using <area>)
     343PASS xn-- (using <area>.host)
     344PASS xn-- (using <area>.hostname)
    345345
  • trunk/LayoutTests/imported/w3c/web-platform-tests/url/url-constructor-expected.txt

    r267964 r267965  
    581581PASS Parsing: <file://­/p> against <about:blank>
    582582PASS Parsing: <file://%C2%AD/p> against <about:blank>
    583 FAIL Parsing: <file://xn--/p> against <about:blank> assert_throws_js: function "function () {
    584           bURL(expected.input, expected.base)
    585         }" did not throw
     583PASS Parsing: <file://xn--/p> against <about:blank>
    586584PASS Parsing: <#link> against <https://example.org/##link>
    587585PASS Parsing: <non-special:cannot-be-a-base-url-\0
  • trunk/Source/WTF/ChangeLog

    r267964 r267965  
     12020-10-05  Alex Christensen  <achristensen@webkit.org>
     2
     3        URLParser should fail to parse URLs with hosts containing invalid punycode encodings
     4        https://bugs.webkit.org/show_bug.cgi?id=217285
     5
     6        Reviewed by Darin Adler.
     7
     8        URLParser has a fast path for parsing hosts that are all ASCII, but that does not validate hosts that are invalid punycode, such as "xn--".
     9        Since all punycode encoded strings start with "xn--", if the input string starts with "xn--" then skip the fast path and let ICU decide if it's valid.
     10
     11        * wtf/URLParser.cpp:
     12        (WTF::URLParser::domainToASCII):
     13        (WTF::URLParser::startsWithXNDashDash):
     14        (WTF::URLParser::parseHostAndPort):
     15        * wtf/URLParser.h:
     16
    1172020-10-05  Alex Christensen  <achristensen@webkit.org>
    218
  • trunk/Source/WTF/wtf/URLParser.cpp

    r267964 r267965  
    25182518{
    25192519    LCharBuffer ascii;
    2520     if (domain.isAllASCII()) {
     2520    if (domain.isAllASCII() && !startsWithLettersIgnoringASCIICase(domain, "xn--")) {
    25212521        size_t length = domain.length();
    25222522        if (domain.is8Bit()) {
     
    26222622    RELEASE_ASSERT(portLength <= URL::maxPortLength);
    26232623    m_url.m_portLength = portLength;
     2624    return true;
     2625}
     2626
     2627template<typename CharacterType>
     2628bool URLParser::startsWithXNDashDash(CodePointIterator<CharacterType> iterator)
     2629{
     2630    if (iterator.atEnd() || (*iterator != 'x' && *iterator != 'X'))
     2631        return false;
     2632    advance<CharacterType, ReportSyntaxViolation::No>(iterator);
     2633    if (iterator.atEnd() || (*iterator != 'n' && *iterator != 'N'))
     2634        return false;
     2635    advance<CharacterType, ReportSyntaxViolation::No>(iterator);
     2636    if (iterator.atEnd() || *iterator != '-')
     2637        return false;
     2638    advance<CharacterType, ReportSyntaxViolation::No>(iterator);
     2639    if (iterator.atEnd() || *iterator != '-')
     2640        return false;
    26242641    return true;
    26252642}
     
    26742691    }
    26752692   
    2676     if (LIKELY(!m_hostHasPercentOrNonASCII)) {
     2693    if (LIKELY(!m_hostHasPercentOrNonASCII && !startsWithXNDashDash(iterator))) {
    26772694        auto hostIterator = iterator;
    26782695        for (; !iterator.atEnd(); ++iterator) {
  • trunk/Source/WTF/wtf/URLParser.h

    r267837 r267965  
    114114    StringView parsedDataView(size_t start, size_t length);
    115115    UChar parsedDataView(size_t position);
     116    template<typename CharacterType> bool startsWithXNDashDash(CodePointIterator<CharacterType>);
    116117
    117118    bool needsNonSpecialDotSlash() const;
Note: See TracChangeset for help on using the changeset viewer.