Changeset 206044 in webkit


Ignore:
Timestamp:
Sep 16, 2016 1:35:16 PM (8 years ago)
Author:
achristensen@apple.com
Message:

Use Vector<LChar> instead of StringBuilder for the ASCII parts of URLParser
https://bugs.webkit.org/show_bug.cgi?id=162035

Reviewed by Chris Dumez.

StringBuilder::append checks to see whether its StringBuffer is 8-bit or 16-bit each time it is called.
When parsing URLs, almost all of the parsed URL is guaranteed to be 8-bit ASCII.
Using a Vector<LChar> for this allows us to use uncheckedAppend in some places, and it always eliminates the 8-bit check.
This is a ~20% speedup in url parsing.

Covered by existing API tests.

  • platform/URLParser.cpp:

(WebCore::isWindowsDriveLetter):
(WebCore::percentEncode):
(WebCore::utf8PercentEncode):
(WebCore::utf8PercentEncodeQuery):
(WebCore::encodeQuery):
(WebCore::URLParser::copyURLPartsUntil):
(WebCore::URLParser::popPath):
(WebCore::URLParser::parse):
(WebCore::URLParser::parseAuthority):
(WebCore::appendNumber):
(WebCore::serializeIPv4):
(WebCore::serializeIPv6Piece):
(WebCore::serializeIPv6):
(WebCore::URLParser::parsePort):
(WebCore::URLParser::parseHost):
(WebCore::serializeURLEncodedForm):
(WebCore::URLParser::serialize):
(WebCore::bufferView): Deleted.

  • platform/URLParser.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r206043 r206044  
     12016-09-16  Alex Christensen  <achristensen@webkit.org>
     2
     3        Use Vector<LChar> instead of StringBuilder for the ASCII parts of URLParser
     4        https://bugs.webkit.org/show_bug.cgi?id=162035
     5
     6        Reviewed by Chris Dumez.
     7
     8        StringBuilder::append checks to see whether its StringBuffer is 8-bit or 16-bit each time it is called.
     9        When parsing URLs, almost all of the parsed URL is guaranteed to be 8-bit ASCII.
     10        Using a Vector<LChar> for this allows us to use uncheckedAppend in some places, and it always eliminates the 8-bit check.
     11        This is a ~20% speedup in url parsing.
     12
     13        Covered by existing API tests.
     14
     15        * platform/URLParser.cpp:
     16        (WebCore::isWindowsDriveLetter):
     17        (WebCore::percentEncode):
     18        (WebCore::utf8PercentEncode):
     19        (WebCore::utf8PercentEncodeQuery):
     20        (WebCore::encodeQuery):
     21        (WebCore::URLParser::copyURLPartsUntil):
     22        (WebCore::URLParser::popPath):
     23        (WebCore::URLParser::parse):
     24        (WebCore::URLParser::parseAuthority):
     25        (WebCore::appendNumber):
     26        (WebCore::serializeIPv4):
     27        (WebCore::serializeIPv6Piece):
     28        (WebCore::serializeIPv6):
     29        (WebCore::URLParser::parsePort):
     30        (WebCore::URLParser::parseHost):
     31        (WebCore::serializeURLEncodedForm):
     32        (WebCore::URLParser::serialize):
     33        (WebCore::bufferView): Deleted.
     34        * platform/URLParser.h:
     35
    1362016-09-16  Dave Hyatt  <hyatt@apple.com>
    237
  • trunk/Source/WebCore/platform/URLParser.cpp

    r206036 r206044  
    110110{
    111111    ASSERT(!atEnd());
    112     if (U16_IS_LEAD(m_begin[0]) && m_begin < m_end && U16_IS_TRAIL(m_begin[1]))
    113         m_begin += 2;
    114     else
    115         m_begin++;
     112    unsigned i = 0;
     113    size_t length = m_end - m_begin;
     114    U16_FWD_1(m_begin, i, length);
     115    m_begin += i;
    116116    return *this;
    117117}
     
    406406}
    407407
    408 static bool isWindowsDriveLetter(const StringBuilder& builder, size_t index)
    409 {
    410     if (builder.length() < index + 2)
    411         return false;
    412     return isASCIIAlpha(builder[index]) && (builder[index + 1] == ':' || builder[index + 1] == '|');
     408static bool isWindowsDriveLetter(const Vector<LChar>& buffer, size_t index)
     409{
     410    if (buffer.size() < index + 2)
     411        return false;
     412    return isASCIIAlpha(buffer[index]) && (buffer[index + 1] == ':' || buffer[index + 1] == '|');
    413413}
    414414
     
    429429}
    430430
    431 static void percentEncode(uint8_t byte, StringBuilder& builder)
    432 {
    433     builder.append('%');
    434     builder.append(upperNibbleToASCIIHexDigit(byte));
    435     builder.append(lowerNibbleToASCIIHexDigit(byte));
    436 }
    437 
    438 static void utf8PercentEncode(UChar32 codePoint, StringBuilder& builder, bool(*isInCodeSet)(UChar32))
     431static void percentEncode(uint8_t byte, Vector<LChar>& buffer)
     432{
     433    buffer.append('%');
     434    buffer.append(upperNibbleToASCIIHexDigit(byte));
     435    buffer.append(lowerNibbleToASCIIHexDigit(byte));
     436}
     437
     438static void utf8PercentEncode(UChar32 codePoint, Vector<LChar>& destination, bool(*isInCodeSet)(UChar32))
    439439{
    440440    if (isInCodeSet(codePoint)) {
     
    445445        // FIXME: Check error.
    446446        for (int32_t i = 0; i < offset; ++i)
    447             percentEncode(buffer[i], builder);
    448     } else
    449         builder.append(codePoint);
    450 }
    451 
    452 static void utf8PercentEncodeQuery(UChar32 codePoint, StringBuilder& builder)
     447            percentEncode(buffer[i], destination);
     448    } else {
     449        ASSERT_WITH_MESSAGE(isASCII(codePoint), "isInCodeSet should always return true for non-ASCII characters");
     450        destination.append(codePoint);
     451    }
     452}
     453
     454static void utf8PercentEncodeQuery(UChar32 codePoint, Vector<LChar>& destination)
    453455{
    454456    uint8_t buffer[U8_MAX_LENGTH];
     
    461463        auto byte = buffer[i];
    462464        if (shouldPercentEncodeQueryByte(byte))
    463             percentEncode(byte, builder);
     465            percentEncode(byte, destination);
    464466        else
    465             builder.append(byte);
     467            destination.append(byte);
    466468    }
    467469}
    468470   
    469 static void encodeQuery(const StringBuilder& source, StringBuilder& destination, const TextEncoding& encoding)
     471static void encodeQuery(const StringBuilder& source, Vector<LChar>& destination, const TextEncoding& encoding)
    470472{
    471473    // FIXME: It is unclear in the spec what to do when encoding fails. The behavior should be specified and tested.
     
    594596        return false;
    595597    }
    596 }
    597 
    598 template<typename T>
    599 static StringView bufferView(const T& buffer, unsigned start, unsigned length)
    600 {
    601     ASSERT(buffer.length() >= length);
    602     if (buffer.is8Bit())
    603         return StringView(buffer.characters8() + start, length);
    604     return StringView(buffer.characters16() + start, length);
    605598}
    606599
     
    645638    return 0;
    646639}
    647    
     640
     641static void copyASCIIStringUntil(Vector<LChar>& destination, const String& string, size_t lengthIf8Bit, size_t lengthIf16Bit)
     642{
     643    ASSERT(destination.isEmpty());
     644    if (string.is8Bit()) {
     645        RELEASE_ASSERT(lengthIf8Bit <= string.length());
     646        destination.append(string.characters8(), lengthIf8Bit);
     647    } else {
     648        RELEASE_ASSERT(lengthIf16Bit <= string.length());
     649        destination.reserveCapacity(lengthIf16Bit);
     650        const UChar* characters = string.characters16();
     651        for (size_t i = 0; i < lengthIf16Bit; ++i) {
     652            UChar c = characters[i];
     653            ASSERT_WITH_SECURITY_IMPLICATION(isASCII(c));
     654            destination.uncheckedAppend(c);
     655        }
     656    }
     657}
     658
    648659void URLParser::copyURLPartsUntil(const URL& base, URLPart part)
    649660{
    650     m_buffer.clear();
    651     m_buffer.append(base.m_string.substring(0, urlLengthUntilPart(base, part)));
     661    m_asciiBuffer.clear();
     662    m_unicodeFragmentBuffer.clear();
     663    if (part == URLPart::FragmentEnd) {
     664        copyASCIIStringUntil(m_asciiBuffer, base.m_string, urlLengthUntilPart(base, URLPart::FragmentEnd), urlLengthUntilPart(base, URLPart::QueryEnd));
     665        if (!base.m_string.is8Bit()) {
     666            const String& fragment = base.m_string;
     667            bool seenUnicode = false;
     668            for (size_t i = base.m_queryEnd; i < base.m_fragmentEnd; ++i) {
     669                if (!seenUnicode && !isASCII(fragment[i]))
     670                    seenUnicode = true;
     671                if (seenUnicode)
     672                    m_unicodeFragmentBuffer.uncheckedAppend(fragment[i]);
     673                else
     674                    m_asciiBuffer.uncheckedAppend(fragment[i]);
     675            }
     676        }
     677    } else {
     678        size_t length = urlLengthUntilPart(base, part);
     679        copyASCIIStringUntil(m_asciiBuffer, base.m_string, length, length);
     680    }
    652681    switch (part) {
    653682    case URLPart::FragmentEnd:
     
    683712        m_url.m_schemeEnd = base.m_schemeEnd;
    684713    }
    685     m_urlIsSpecial = isSpecialScheme(bufferView(m_buffer, 0, m_url.m_schemeEnd));
     714    m_urlIsSpecial = isSpecialScheme(StringView(m_asciiBuffer.data(), m_url.m_schemeEnd));
    686715}
    687716
     
    803832    if (m_url.m_pathAfterLastSlash > m_url.m_portEnd + 1) {
    804833        m_url.m_pathAfterLastSlash--;
    805         if (m_buffer[m_url.m_pathAfterLastSlash] == '/')
     834        if (m_asciiBuffer[m_url.m_pathAfterLastSlash] == '/')
    806835            m_url.m_pathAfterLastSlash--;
    807         while (m_url.m_pathAfterLastSlash > m_url.m_portEnd && m_buffer[m_url.m_pathAfterLastSlash] != '/')
     836        while (m_url.m_pathAfterLastSlash > m_url.m_portEnd && m_asciiBuffer[m_url.m_pathAfterLastSlash] != '/')
    808837            m_url.m_pathAfterLastSlash--;
    809838        m_url.m_pathAfterLastSlash++;
    810839    }
    811     m_buffer.resize(m_url.m_pathAfterLastSlash);
     840    m_asciiBuffer.resize(m_url.m_pathAfterLastSlash);
    812841}
    813842
     
    845874    LOG(URLParser, "Parsing URL <%s> base <%s>", String(input, length).utf8().data(), base.string().utf8().data());
    846875    m_url = { };
    847     m_buffer.clear();
    848     m_buffer.reserveCapacity(length);
     876    m_asciiBuffer.clear();
     877    m_unicodeFragmentBuffer.clear();
     878    m_asciiBuffer.reserveCapacity(length);
    849879   
    850880    bool isUTF8Encoding = encoding == UTF8Encoding();
     
    882912    };
    883913
    884 #define LOG_STATE(x) LOG(URLParser, "State %s, code point %c, buffer length %d", x, *c, m_buffer.length())
     914#define LOG_STATE(x) LOG(URLParser, "State %s, code point %c, asciiBuffer size %zu", x, *c, m_asciiBuffer.size())
    885915#define LOG_FINAL_STATE(x) LOG(URLParser, "Final State: %s", x)
    886916
     
    896926            LOG_STATE("SchemeStart");
    897927            if (isASCIIAlpha(*c)) {
    898                 m_buffer.append(toASCIILower(*c));
     928                m_asciiBuffer.uncheckedAppend(toASCIILower(*c));
    899929                ++c;
    900930                state = State::Scheme;
     
    905935            LOG_STATE("Scheme");
    906936            if (isASCIIAlphanumeric(*c) || *c == '+' || *c == '-' || *c == '.')
    907                 m_buffer.append(toASCIILower(*c));
     937                m_asciiBuffer.append(toASCIILower(*c));
    908938            else if (*c == ':') {
    909                 m_url.m_schemeEnd = m_buffer.length();
    910                 StringView urlScheme = bufferView(m_buffer, 0, m_url.m_schemeEnd);
     939                m_url.m_schemeEnd = m_asciiBuffer.size();
     940                StringView urlScheme = StringView(m_asciiBuffer.data(), m_url.m_schemeEnd);
    911941                m_url.m_protocolIsInHTTPFamily = urlScheme == "http" || urlScheme == "https";
    912942                if (urlScheme == "file") {
    913943                    m_urlIsSpecial = true;
    914944                    state = State::File;
    915                     m_buffer.append(':');
     945                    m_asciiBuffer.append(':');
    916946                    ++c;
    917947                    break;
    918948                }
    919                 m_buffer.append(':');
     949                m_asciiBuffer.append(':');
    920950                if (isSpecialScheme(urlScheme)) {
    921951                    m_urlIsSpecial = true;
     
    927957                        state = State::SpecialAuthoritySlashes;
    928958                } else {
    929                     m_url.m_userStart = m_buffer.length();
     959                    m_url.m_userStart = m_asciiBuffer.size();
    930960                    m_url.m_userEnd = m_url.m_userStart;
    931961                    m_url.m_passwordEnd = m_url.m_userStart;
     
    937967                        ++maybeSlash;
    938968                    if (!maybeSlash.atEnd() && *maybeSlash == '/') {
    939                         m_buffer.append('/');
     969                        m_asciiBuffer.append('/');
    940970                        m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
    941971                        state = State::PathOrAuthority;
     
    951981                break;
    952982            } else {
    953                 m_buffer.clear();
     983                m_asciiBuffer.clear();
    954984                state = State::NoScheme;
    955985                c = beginAfterControlAndSpace;
     
    960990                ++c;
    961991            if (c.atEnd()) {
    962                 m_buffer.clear();
     992                m_asciiBuffer.clear();
    963993                state = State::NoScheme;
    964994                c = beginAfterControlAndSpace;
     
    9721002                copyURLPartsUntil(base, URLPart::QueryEnd);
    9731003                state = State::Fragment;
    974                 m_buffer.append('#');
     1004                m_asciiBuffer.append('#');
    9751005                ++c;
    9761006                break;
     
    9811011            }
    9821012            copyURLPartsUntil(base, URLPart::SchemeEnd);
    983             m_buffer.append(':');
     1013            m_asciiBuffer.append(':');
    9841014            state = State::File;
    9851015            break;
     
    9871017            LOG_STATE("SpecialRelativeOrAuthority");
    9881018            if (*c == '/') {
    989                 m_buffer.append('/');
     1019                m_asciiBuffer.append('/');
    9901020                ++c;
    9911021                while (!c.atEnd() && isTabOrNewline(*c))
     
    9941024                    return failure(input, length);
    9951025                if (*c == '/') {
    996                     m_buffer.append('/');
     1026                    m_asciiBuffer.append('/');
    9971027                    state = State::SpecialAuthorityIgnoreSlashes;
    9981028                    ++c;
     
    10041034            LOG_STATE("PathOrAuthority");
    10051035            if (*c == '/') {
    1006                 m_buffer.append('/');
    1007                 m_url.m_userStart = m_buffer.length();
     1036                m_asciiBuffer.append('/');
     1037                m_url.m_userStart = m_asciiBuffer.size();
    10081038                state = State::AuthorityOrHost;
    10091039                ++c;
     
    10221052            case '?':
    10231053                copyURLPartsUntil(base, URLPart::PathEnd);
    1024                 m_buffer.append('?');
     1054                m_asciiBuffer.append('?');
    10251055                state = State::Query;
    10261056                ++c;
     
    10281058            case '#':
    10291059                copyURLPartsUntil(base, URLPart::QueryEnd);
    1030                 m_buffer.append('#');
     1060                m_asciiBuffer.append('#');
    10311061                state = State::Fragment;
    10321062                ++c;
     
    10431073                ++c;
    10441074                copyURLPartsUntil(base, URLPart::SchemeEnd);
    1045                 m_buffer.append("://");
     1075                m_asciiBuffer.append("://", 3);
    10461076                state = State::SpecialAuthorityIgnoreSlashes;
    10471077            } else {
    10481078                copyURLPartsUntil(base, URLPart::PortEnd);
    1049                 m_buffer.append('/');
     1079                m_asciiBuffer.append('/');
    10501080                m_url.m_pathAfterLastSlash = base.m_portEnd + 1;
    10511081                state = State::Path;
     
    10541084        case State::SpecialAuthoritySlashes:
    10551085            LOG_STATE("SpecialAuthoritySlashes");
    1056             m_buffer.append("//");
     1086            m_asciiBuffer.append("//", 2);
    10571087            if (*c == '/' || *c == '\\') {
    10581088                ++c;
     
    10671097            LOG_STATE("SpecialAuthorityIgnoreSlashes");
    10681098            if (*c == '/' || *c == '\\') {
    1069                 m_buffer.append('/');
    1070                 ++c;
    1071             }
    1072             m_url.m_userStart = m_buffer.length();
     1099                m_asciiBuffer.append('/');
     1100                ++c;
     1101            }
     1102            m_url.m_userStart = m_asciiBuffer.size();
    10731103            state = State::AuthorityOrHost;
    10741104            authorityOrHostBegin = c;
     
    10891119                bool isSlash = *c == '/' || (m_urlIsSpecial && *c == '\\');
    10901120                if (isSlash || *c == '?' || *c == '#') {
    1091                     m_url.m_userEnd = m_buffer.length();
     1121                    m_url.m_userEnd = m_asciiBuffer.size();
    10921122                    m_url.m_passwordEnd = m_url.m_userEnd;
    10931123                    if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
    10941124                        return failure(input, length);
    10951125                    if (!isSlash) {
    1096                         m_buffer.append('/');
    1097                         m_url.m_pathAfterLastSlash = m_buffer.length();
     1126                        m_asciiBuffer.append('/');
     1127                        m_url.m_pathAfterLastSlash = m_asciiBuffer.size();
    10981128                    }
    10991129                    state = State::Path;
     
    11221152            case '/':
    11231153            case '\\':
    1124                 m_buffer.append('/');
     1154                m_asciiBuffer.append('/');
    11251155                state = State::FileSlash;
    11261156                ++c;
     
    11291159                if (!base.isNull() && base.protocolIs("file"))
    11301160                    copyURLPartsUntil(base, URLPart::PathEnd);
    1131                 m_buffer.append("///?");
    1132                 m_url.m_userStart = m_buffer.length() - 2;
     1161                m_asciiBuffer.append("///?", 4);
     1162                m_url.m_userStart = m_asciiBuffer.size() - 2;
    11331163                m_url.m_userEnd = m_url.m_userStart;
    11341164                m_url.m_passwordEnd = m_url.m_userStart;
     
    11431173                if (!base.isNull() && base.protocolIs("file"))
    11441174                    copyURLPartsUntil(base, URLPart::QueryEnd);
    1145                 m_buffer.append("///#");
    1146                 m_url.m_userStart = m_buffer.length() - 2;
     1175                m_asciiBuffer.append("///#", 4);
     1176                m_url.m_userStart = m_asciiBuffer.size() - 2;
    11471177                m_url.m_userEnd = m_url.m_userStart;
    11481178                m_url.m_passwordEnd = m_url.m_userStart;
     
    11591189                    copyURLPartsUntil(base, URLPart::PathAfterLastSlash);
    11601190                else {
    1161                     m_buffer.append("///");
    1162                     m_url.m_userStart = m_buffer.length() - 1;
     1191                    m_asciiBuffer.append("///", 3);
     1192                    m_url.m_userStart = m_asciiBuffer.size() - 1;
    11631193                    m_url.m_userEnd = m_url.m_userStart;
    11641194                    m_url.m_passwordEnd = m_url.m_userStart;
     
    11751205            if (*c == '/' || *c == '\\') {
    11761206                ++c;
    1177                 m_buffer.append('/');
    1178                 m_url.m_userStart = m_buffer.length();
     1207                m_asciiBuffer.append('/');
     1208                m_url.m_userStart = m_asciiBuffer.size();
    11791209                m_url.m_userEnd = m_url.m_userStart;
    11801210                m_url.m_passwordEnd = m_url.m_userStart;
     
    11931223                        : isWindowsDriveLetter(CodePointIterator<UChar>(basePath.characters16(), basePath.characters16() + basePath.length()));
    11941224                    if (windowsQuirk) {
    1195                         m_buffer.append(basePath[0]);
    1196                         m_buffer.append(basePath[1]);
     1225                        m_asciiBuffer.append(basePath[0]);
     1226                        m_asciiBuffer.append(basePath[1]);
    11971227                    }
    11981228                }
     
    12001230                break;
    12011231            }
    1202             m_buffer.append("//");
    1203             m_url.m_userStart = m_buffer.length() - 1;
     1232            m_asciiBuffer.append("//", 2);
     1233            m_url.m_userStart = m_asciiBuffer.size() - 1;
    12041234            m_url.m_userEnd = m_url.m_userStart;
    12051235            m_url.m_passwordEnd = m_url.m_userStart;
     
    12121242            LOG_STATE("FileHost");
    12131243            if (isSlashQuestionOrHash(*c)) {
    1214                 if (isWindowsDriveLetter(m_buffer, m_url.m_portEnd + 1)) {
     1244                if (isWindowsDriveLetter(m_asciiBuffer, m_url.m_portEnd + 1)) {
    12151245                    state = State::Path;
    12161246                    break;
    12171247                }
    12181248                if (authorityOrHostBegin == c) {
    1219                     ASSERT(m_buffer[m_buffer.length() - 1] == '/');
     1249                    ASSERT(m_asciiBuffer[m_asciiBuffer.size() - 1] == '/');
    12201250                    if (*c == '?') {
    1221                         m_buffer.append("/?");
    1222                         m_url.m_pathAfterLastSlash = m_buffer.length() - 1;
     1251                        m_asciiBuffer.append("/?", 2);
     1252                        m_url.m_pathAfterLastSlash = m_asciiBuffer.size() - 1;
    12231253                        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
    12241254                        state = State::Query;
     
    12271257                    }
    12281258                    if (*c == '#') {
    1229                         m_buffer.append("/#");
    1230                         m_url.m_pathAfterLastSlash = m_buffer.length() - 1;
     1259                        m_asciiBuffer.append("/#", 2);
     1260                        m_url.m_pathAfterLastSlash = m_asciiBuffer.size() - 1;
    12311261                        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
    12321262                        m_url.m_queryEnd = m_url.m_pathAfterLastSlash;
     
    12411271                    return failure(input, length);
    12421272               
    1243                 if (bufferView(m_buffer, m_url.m_passwordEnd, m_buffer.length() - m_url.m_passwordEnd) == "localhost")  {
    1244                     m_buffer.resize(m_url.m_passwordEnd);
    1245                     m_url.m_hostEnd = m_buffer.length();
     1273                if (StringView(m_asciiBuffer.data() + m_url.m_passwordEnd, m_asciiBuffer.size() - m_url.m_passwordEnd) == "localhost")  {
     1274                    m_asciiBuffer.shrink(m_url.m_passwordEnd);
     1275                    m_url.m_hostEnd = m_asciiBuffer.size();
    12461276                    m_url.m_portEnd = m_url.m_hostEnd;
    12471277                }
     
    12631293            LOG_STATE("Path");
    12641294            if (*c == '/' || (m_urlIsSpecial && *c == '\\')) {
    1265                 m_buffer.append('/');
    1266                 m_url.m_pathAfterLastSlash = m_buffer.length();
    1267                 ++c;
    1268                 break;
    1269             }
    1270             if (m_buffer.length() && m_buffer[m_buffer.length() - 1] == '/') {
     1295                m_asciiBuffer.append('/');
     1296                m_url.m_pathAfterLastSlash = m_asciiBuffer.size();
     1297                ++c;
     1298                break;
     1299            }
     1300            if (m_asciiBuffer.size() && m_asciiBuffer[m_asciiBuffer.size() - 1] == '/') {
    12711301                if (isDoubleDotPathSegment(c)) {
    12721302                    consumeDoubleDotPathSegment(c);
     
    12741304                    break;
    12751305                }
    1276                 if (m_buffer[m_buffer.length() - 1] == '/' && isSingleDotPathSegment(c)) {
     1306                if (m_asciiBuffer[m_asciiBuffer.size() - 1] == '/' && isSingleDotPathSegment(c)) {
    12771307                    consumeSingleDotPathSegment(c);
    12781308                    break;
     
    12801310            }
    12811311            if (*c == '?') {
    1282                 m_url.m_pathEnd = m_buffer.length();
     1312                m_url.m_pathEnd = m_asciiBuffer.size();
    12831313                state = State::Query;
    12841314                break;
    12851315            }
    12861316            if (*c == '#') {
    1287                 m_url.m_pathEnd = m_buffer.length();
     1317                m_url.m_pathEnd = m_asciiBuffer.size();
    12881318                m_url.m_queryEnd = m_url.m_pathEnd;
    12891319                state = State::Fragment;
     
    12911321            }
    12921322            if (isPercentEncodedDot(c)) {
    1293                 m_buffer.append('.');
     1323                m_asciiBuffer.append('.');
    12941324                ASSERT(*c == '%');
    12951325                ++c;
     
    13001330                break;
    13011331            }
    1302             utf8PercentEncode(*c, m_buffer, isInDefaultEncodeSet);
     1332            utf8PercentEncode(*c, m_asciiBuffer, isInDefaultEncodeSet);
    13031333            ++c;
    13041334            break;
     
    13061336            LOG_STATE("CannotBeABaseURLPath");
    13071337            if (*c == '?') {
    1308                 m_url.m_pathEnd = m_buffer.length();
     1338                m_url.m_pathEnd = m_asciiBuffer.size();
    13091339                state = State::Query;
    13101340            } else if (*c == '#') {
    1311                 m_url.m_pathEnd = m_buffer.length();
     1341                m_url.m_pathEnd = m_asciiBuffer.size();
    13121342                m_url.m_queryEnd = m_url.m_pathEnd;
    13131343                state = State::Fragment;
    13141344            } else {
    1315                 utf8PercentEncode(*c, m_buffer, isInSimpleEncodeSet);
     1345                utf8PercentEncode(*c, m_asciiBuffer, isInSimpleEncodeSet);
    13161346                ++c;
    13171347            }
     
    13211351            if (*c == '#') {
    13221352                if (!isUTF8Encoding)
    1323                     encodeQuery(queryBuffer, m_buffer, encoding);
    1324                 m_url.m_queryEnd = m_buffer.length();
     1353                    encodeQuery(queryBuffer, m_asciiBuffer, encoding);
     1354                m_url.m_queryEnd = m_asciiBuffer.size();
    13251355                state = State::Fragment;
    13261356                break;
    13271357            }
    13281358            if (isUTF8Encoding)
    1329                 utf8PercentEncodeQuery(*c, m_buffer);
     1359                utf8PercentEncodeQuery(*c, m_asciiBuffer);
    13301360            else
    13311361                queryBuffer.append(*c);
     
    13341364        case State::Fragment:
    13351365            LOG_STATE("Fragment");
    1336             m_buffer.append(*c);
     1366            if (m_unicodeFragmentBuffer.isEmpty() && isASCII(*c))
     1367                m_asciiBuffer.append(*c);
     1368            else
     1369                m_unicodeFragmentBuffer.append(*c);
    13371370            ++c;
    13381371            break;
     
    13431376    case State::SchemeStart:
    13441377        LOG_FINAL_STATE("SchemeStart");
    1345         if (!m_buffer.length() && !base.isNull())
     1378        if (!m_asciiBuffer.size() && !base.isNull())
    13461379            return base;
    13471380        return failure(input, length);
     
    13701403        LOG_FINAL_STATE("RelativeSlash");
    13711404        copyURLPartsUntil(base, URLPart::PortEnd);
    1372         m_buffer.append('/');
     1405        m_asciiBuffer.append('/');
    13731406        m_url.m_pathAfterLastSlash = base.m_portEnd + 1;
    13741407        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
     
    13781411    case State::SpecialAuthoritySlashes:
    13791412        LOG_FINAL_STATE("SpecialAuthoritySlashes");
    1380         m_url.m_userStart = m_buffer.length();
     1413        m_url.m_userStart = m_asciiBuffer.size();
    13811414        m_url.m_userEnd = m_url.m_userStart;
    13821415        m_url.m_passwordEnd = m_url.m_userStart;
     
    13941427    case State::AuthorityOrHost:
    13951428        LOG_FINAL_STATE("AuthorityOrHost");
    1396         m_url.m_userEnd = m_buffer.length();
     1429        m_url.m_userEnd = m_asciiBuffer.size();
    13971430        m_url.m_passwordEnd = m_url.m_userEnd;
    13981431        FALLTHROUGH;
     
    14021435        if (!parseHost(authorityOrHostBegin))
    14031436            return failure(input, length);
    1404         m_buffer.append('/');
     1437        m_asciiBuffer.append('/');
    14051438        m_url.m_pathEnd = m_url.m_portEnd + 1;
    14061439        m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
     
    14121445        if (!base.isNull() && base.protocol() == "file") {
    14131446            copyURLPartsUntil(base, URLPart::QueryEnd);
    1414             m_buffer.append(':');
    1415         }
    1416         m_buffer.append("///");
    1417         m_url.m_userStart = m_buffer.length() - 1;
     1447            m_asciiBuffer.append(':');
     1448        }
     1449        m_asciiBuffer.append("///", 3);
     1450        m_url.m_userStart = m_asciiBuffer.size() - 1;
    14181451        m_url.m_userEnd = m_url.m_userStart;
    14191452        m_url.m_passwordEnd = m_url.m_userStart;
     
    14271460    case State::FileSlash:
    14281461        LOG_FINAL_STATE("FileSlash");
    1429         m_buffer.append("//");
    1430         m_url.m_userStart = m_buffer.length() - 1;
     1462        m_asciiBuffer.append("//", 2);
     1463        m_url.m_userStart = m_asciiBuffer.size() - 1;
    14311464        m_url.m_userEnd = m_url.m_userStart;
    14321465        m_url.m_passwordEnd = m_url.m_userStart;
     
    14411474        LOG_FINAL_STATE("FileHost");
    14421475        if (authorityOrHostBegin == c) {
    1443             m_buffer.append('/');
    1444             m_url.m_userStart = m_buffer.length() - 1;
     1476            m_asciiBuffer.append('/');
     1477            m_url.m_userStart = m_asciiBuffer.size() - 1;
    14451478            m_url.m_userEnd = m_url.m_userStart;
    14461479            m_url.m_passwordEnd = m_url.m_userStart;
     
    14561489        if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
    14571490            return failure(input, length);
    1458        
    1459         if (bufferView(m_buffer, m_url.m_passwordEnd, m_buffer.length() - m_url.m_passwordEnd) == "localhost")  {
    1460             m_buffer.resize(m_url.m_passwordEnd);
    1461             m_url.m_hostEnd = m_buffer.length();
     1491
     1492        if (StringView(m_asciiBuffer.data() + m_url.m_passwordEnd, m_asciiBuffer.size() - m_url.m_passwordEnd) == "localhost")  {
     1493            m_asciiBuffer.shrink(m_url.m_passwordEnd);
     1494            m_url.m_hostEnd = m_asciiBuffer.size();
    14621495            m_url.m_portEnd = m_url.m_hostEnd;
    14631496        }
    1464         m_buffer.append('/');
     1497        m_asciiBuffer.append('/');
    14651498        m_url.m_pathAfterLastSlash = m_url.m_hostEnd + 1;
    14661499        m_url.m_pathEnd = m_url.m_pathAfterLastSlash;
     
    14731506    case State::Path:
    14741507        LOG_FINAL_STATE("Path");
    1475         m_url.m_pathEnd = m_buffer.length();
     1508        m_url.m_pathEnd = m_asciiBuffer.size();
    14761509        m_url.m_queryEnd = m_url.m_pathEnd;
    14771510        m_url.m_fragmentEnd = m_url.m_pathEnd;
     
    14791512    case State::CannotBeABaseURLPath:
    14801513        LOG_FINAL_STATE("CannotBeABaseURLPath");
    1481         m_url.m_pathEnd = m_buffer.length();
     1514        m_url.m_pathEnd = m_asciiBuffer.size();
    14821515        m_url.m_queryEnd = m_url.m_pathEnd;
    14831516        m_url.m_fragmentEnd = m_url.m_pathEnd;
     
    14861519        LOG_FINAL_STATE("Query");
    14871520        if (!isUTF8Encoding)
    1488             encodeQuery(queryBuffer, m_buffer, encoding);
    1489         m_url.m_queryEnd = m_buffer.length();
     1521            encodeQuery(queryBuffer, m_asciiBuffer, encoding);
     1522        m_url.m_queryEnd = m_asciiBuffer.size();
    14901523        m_url.m_fragmentEnd = m_url.m_queryEnd;
    14911524        break;
    14921525    case State::Fragment:
    14931526        LOG_FINAL_STATE("Fragment");
    1494         m_url.m_fragmentEnd = m_buffer.length();
     1527        m_url.m_fragmentEnd = m_asciiBuffer.size() + m_unicodeFragmentBuffer.size();
    14951528        break;
    14961529    }
    14971530
    1498     m_url.m_string = m_buffer.toString();
     1531    if (m_unicodeFragmentBuffer.isEmpty()) {
     1532        // FIXME: String::adopt should require a WTFMove.
     1533        m_url.m_string = String::adopt(m_asciiBuffer);
     1534    } else {
     1535        StringBuilder builder;
     1536        builder.reserveCapacity(m_asciiBuffer.size() + m_unicodeFragmentBuffer.size());
     1537        builder.append(m_asciiBuffer.data(), m_asciiBuffer.size());
     1538        for (size_t i = 0; i < m_unicodeFragmentBuffer.size(); ++i)
     1539            builder.append(m_unicodeFragmentBuffer[i]);
     1540        m_url.m_string = builder.toString();
     1541    }
    14991542    m_url.m_isValid = true;
    15001543    LOG(URLParser, "Parsed URL <%s>", m_url.m_string.utf8().data());
     
    15061549{
    15071550    if (iterator.atEnd()) {
    1508         m_url.m_userEnd = m_buffer.length();
     1551        m_url.m_userEnd = m_asciiBuffer.size();
    15091552        m_url.m_passwordEnd = m_url.m_userEnd;
    15101553        return;
     
    15131556        if (*iterator == ':') {
    15141557            ++iterator;
    1515             m_url.m_userEnd = m_buffer.length();
     1558            m_url.m_userEnd = m_asciiBuffer.size();
    15161559            if (iterator.atEnd()) {
    15171560                m_url.m_passwordEnd = m_url.m_userEnd;
    15181561                if (m_url.m_userEnd > m_url.m_userStart)
    1519                     m_buffer.append('@');
     1562                    m_asciiBuffer.append('@');
    15201563                return;
    15211564            }
    1522             m_buffer.append(':');
    1523             break;
    1524         }
    1525         utf8PercentEncode(*iterator, m_buffer, isInUserInfoEncodeSet);
     1565            m_asciiBuffer.append(':');
     1566            break;
     1567        }
     1568        utf8PercentEncode(*iterator, m_asciiBuffer, isInUserInfoEncodeSet);
    15261569    }
    15271570    for (; !iterator.atEnd(); ++iterator)
    1528         utf8PercentEncode(*iterator, m_buffer, isInUserInfoEncodeSet);
    1529     m_url.m_passwordEnd = m_buffer.length();
     1571        utf8PercentEncode(*iterator, m_asciiBuffer, isInUserInfoEncodeSet);
     1572    m_url.m_passwordEnd = m_asciiBuffer.size();
    15301573    if (!m_url.m_userEnd)
    15311574        m_url.m_userEnd = m_url.m_passwordEnd;
    1532     m_buffer.append('@');
    1533 }
    1534 
    1535 static void serializeIPv4(uint32_t address, StringBuilder& buffer)
    1536 {
    1537     buffer.appendNumber(address >> 24);
     1575    m_asciiBuffer.append('@');
     1576}
     1577
     1578template<typename UnsignedIntegerType>
     1579void append(Vector<LChar>& destination, UnsignedIntegerType number)
     1580{
     1581    LChar buf[sizeof(UnsignedIntegerType) * 3 + 1];
     1582    LChar* end = buf + WTF_ARRAY_LENGTH(buf);
     1583    LChar* p = end;
     1584    do {
     1585        *--p = (number % 10) + '0';
     1586        number /= 10;
     1587    } while (number);
     1588    destination.append(p, end - p);
     1589}
     1590
     1591static void serializeIPv4(uint32_t address, Vector<LChar>& buffer)
     1592{
     1593    append<uint8_t>(buffer, address >> 24);
    15381594    buffer.append('.');
    1539     buffer.appendNumber((address >> 16) & 0xFF);
     1595    append<uint8_t>(buffer, address >> 16);
    15401596    buffer.append('.');
    1541     buffer.appendNumber((address >> 8) & 0xFF);
     1597    append<uint8_t>(buffer, address >> 8);
    15421598    buffer.append('.');
    1543     buffer.appendNumber(address & 0xFF);
     1599    append<uint8_t>(buffer, address);
    15441600}
    15451601   
     
    15711627}
    15721628   
    1573 static void serializeIPv6Piece(uint16_t piece, StringBuilder& buffer)
     1629static void serializeIPv6Piece(uint16_t piece, Vector<LChar>& buffer)
    15741630{
    15751631    bool printed = false;
     
    15891645}
    15901646
    1591 static void serializeIPv6(std::array<uint16_t, 8> address, StringBuilder& buffer)
     1647static void serializeIPv6(std::array<uint16_t, 8> address, Vector<LChar>& buffer)
    15921648{
    15931649    buffer.append('[');
     
    15991655                buffer.append(':');
    16001656            else
    1601                 buffer.append("::");
     1657                buffer.append("::", 2);
    16021658            while (piece < 8 && !address[piece])
    16031659                piece++;
     
    18811937    uint32_t port = 0;
    18821938    if (iterator.atEnd()) {
    1883         m_url.m_portEnd = m_buffer.length();
     1939        m_url.m_portEnd = m_asciiBuffer.size();
    18841940        return true;
    18851941    }
    1886     m_buffer.append(':');
     1942    m_asciiBuffer.append(':');
    18871943    for (; !iterator.atEnd(); ++iterator) {
    18881944        if (isTabOrNewline(*iterator))
     
    18951951            return false;
    18961952    }
    1897    
    1898     if (isDefaultPort(bufferView(m_buffer, 0, m_url.m_schemeEnd), port)) {
    1899         ASSERT(m_buffer[m_buffer.length() - 1] == ':');
    1900         m_buffer.resize(m_buffer.length() - 1);
     1953
     1954    if (isDefaultPort(StringView(m_asciiBuffer.data(), m_url.m_schemeEnd), port)) {
     1955        ASSERT(m_asciiBuffer.last() == ':');
     1956        m_asciiBuffer.shrink(m_asciiBuffer.size() - 1);
    19011957    } else
    1902         m_buffer.appendNumber(port);
    1903 
    1904     m_url.m_portEnd = m_buffer.length();
     1958        append<uint16_t>(m_asciiBuffer, static_cast<uint16_t>(port));
     1959
     1960    m_url.m_portEnd = m_asciiBuffer.size();
    19051961    return true;
    19061962}
     
    19171973            ++ipv6End;
    19181974        if (auto address = parseIPv6Host(CodePointIterator<CharacterType>(iterator, ipv6End))) {
    1919             serializeIPv6(address.value(), m_buffer);
    1920             m_url.m_hostEnd = m_buffer.length();
     1975            serializeIPv6(address.value(), m_asciiBuffer);
     1976            m_url.m_hostEnd = m_asciiBuffer.size();
    19211977            if (!ipv6End.atEnd()) {
    19221978                ++ipv6End;
     
    19251981                    return parsePort(ipv6End);
    19261982                }
    1927                 m_url.m_portEnd = m_buffer.length();
     1983                m_url.m_portEnd = m_asciiBuffer.size();
    19281984                return true;
    19291985            }
     
    19431999        }
    19442000        if (auto address = parseIPv4Host(CodePointIterator<CharacterType>(hostIterator, iterator))) {
    1945             serializeIPv4(address.value(), m_buffer);
    1946             m_url.m_hostEnd = m_buffer.length();
     2001            serializeIPv4(address.value(), m_asciiBuffer);
     2002            m_url.m_hostEnd = m_asciiBuffer.size();
    19472003            if (iterator.atEnd()) {
    1948                 m_url.m_portEnd = m_buffer.length();
     2004                m_url.m_portEnd = m_asciiBuffer.size();
    19492005                return true;
    19502006            }
     
    19542010        for (; hostIterator != iterator; ++hostIterator) {
    19552011            if (!isTabOrNewline(*hostIterator))
    1956                 m_buffer.append(toASCIILower(*hostIterator));
    1957         }
    1958         m_url.m_hostEnd = m_buffer.length();
     2012                m_asciiBuffer.append(toASCIILower(*hostIterator));
     2013        }
     2014        m_url.m_hostEnd = m_asciiBuffer.size();
    19592015        if (!hostIterator.atEnd()) {
    19602016            ASSERT(*hostIterator == ':');
     
    19642020            return parsePort(hostIterator);
    19652021        }
    1966         m_url.m_portEnd = m_buffer.length();
     2022        m_url.m_portEnd = m_asciiBuffer.size();
    19672023        return true;
    19682024    }
     
    19932049    RELEASE_ASSERT(asciiDomainValue.is8Bit());
    19942050    const LChar* asciiDomainCharacters = asciiDomainValue.characters8();
    1995    
     2051
    19962052    if (auto address = parseIPv4Host(CodePointIterator<LChar>(asciiDomainCharacters, asciiDomainCharacters + asciiDomainValue.length()))) {
    1997         serializeIPv4(address.value(), m_buffer);
    1998         m_url.m_hostEnd = m_buffer.length();
     2053        serializeIPv4(address.value(), m_asciiBuffer);
     2054        m_url.m_hostEnd = m_asciiBuffer.size();
    19992055        if (iterator.atEnd()) {
    2000             m_url.m_portEnd = m_buffer.length();
     2056            m_url.m_portEnd = m_asciiBuffer.size();
    20012057            return true;
    20022058        }
     
    20042060        return parsePort(iterator);
    20052061    }
    2006    
    2007     m_buffer.append(asciiDomain.value());
    2008     m_url.m_hostEnd = m_buffer.length();
     2062
     2063    m_asciiBuffer.append(asciiDomainCharacters, asciiDomainValue.length());
     2064    m_url.m_hostEnd = m_asciiBuffer.size();
    20092065    if (!iterator.atEnd()) {
    20102066        ASSERT(*iterator == ':');
     
    20142070        return parsePort(iterator);
    20152071    }
    2016     m_url.m_portEnd = m_buffer.length();
     2072    m_url.m_portEnd = m_asciiBuffer.size();
    20172073    return true;
    20182074}
     
    20482104}
    20492105
    2050 static void serializeURLEncodedForm(const String& input, StringBuilder& output)
     2106static void serializeURLEncodedForm(const String& input, Vector<LChar>& output)
    20512107{
    20522108    auto utf8 = input.utf8(StrictConversion);
     
    20712127String URLParser::serialize(const URLEncodedForm& tuples)
    20722128{
    2073     StringBuilder output;
     2129    Vector<LChar> output;
    20742130    for (auto& tuple : tuples) {
    20752131        if (!output.isEmpty())
     
    20792135        serializeURLEncodedForm(tuple.second, output);
    20802136    }
    2081     return output.toString();
     2137    return String::adopt(output);
    20822138}
    20832139
  • trunk/Source/WebCore/platform/URLParser.h

    r205986 r206044  
    4949private:
    5050    URL m_url;
    51     StringBuilder m_buffer;
     51    Vector<LChar> m_asciiBuffer;
     52    Vector<UChar32> m_unicodeFragmentBuffer;
    5253    bool m_urlIsSpecial { false };
    5354    bool m_hostHasPercentOrNonASCII { false };
Note: See TracChangeset for help on using the changeset viewer.