Changeset 195074 in webkit


Ignore:
Timestamp:
Jan 14, 2016 1:40:13 PM (8 years ago)
Author:
dbates@webkit.org
Message:

[XSS Auditor] Extract attribute truncation logic and formalize string canonicalization
https://bugs.webkit.org/show_bug.cgi?id=152874

Reviewed by Brent Fulgham.

Derived from Blink patch (by Tom Sepez <tsepez@chromium.org>):
<https://src.chromium.org/viewvc/blink?revision=176339&view=revision>

Extract the src-like and script-like attribute truncation logic into independent functions
towards making it more straightforward to re-purpose this logic. Additionally, formalize the
concept of string canonicalization as a member function that consolidates the process of
decoding URL escape sequences, truncating the decoded string (if applicable), and removing
characters that are considered noise.

  • html/parser/XSSAuditor.cpp:

(WebCore::truncateForSrcLikeAttribute): Extracted from XSSAuditor::decodedSnippetForAttribute().
(WebCore::truncateForScriptLikeAttribute): Ditto.
(WebCore::XSSAuditor::init): Write in terms of XSSAuditor::canonicalize().
(WebCore::XSSAuditor::filterCharacterToken): Updated to make use of formalized canonicalization methods.
(WebCore::XSSAuditor::filterScriptToken): Ditto.
(WebCore::XSSAuditor::filterObjectToken): Ditto.
(WebCore::XSSAuditor::filterParamToken): Ditto.
(WebCore::XSSAuditor::filterEmbedToken): Ditto.
(WebCore::XSSAuditor::filterAppletToken): Ditto.
(WebCore::XSSAuditor::filterFrameToken): Ditto.
(WebCore::XSSAuditor::filterInputToken): Ditto.
(WebCore::XSSAuditor::filterButtonToken): Ditto.
(WebCore::XSSAuditor::eraseDangerousAttributesIfInjected): Ditto.
(WebCore::XSSAuditor::eraseAttributeIfInjected): Updated code to use early return style and avoid an unnecessary string
comparison when we know that a src attribute was injected.
(WebCore::XSSAuditor::canonicalizedSnippetForTagName): Renamed; formerly known as XSSAuditor::decodedSnippetForName(). Updated
to make use of XSSAuditor::canonicalize().
(WebCore::XSSAuditor::snippetFromAttribute): Renamed; formerly known as XSSAuditor::decodedSnippetForAttribute(). Moved
truncation logic from here to WebCore::truncateFor{Script, Src}LikeAttribute.
(WebCore::XSSAuditor::canonicalize): Added.
(WebCore::XSSAuditor::canonicalizedSnippetForJavaScript): Added.
(WebCore::canonicalize): Deleted.
(WebCore::XSSAuditor::decodedSnippetForName): Deleted.
(WebCore::XSSAuditor::decodedSnippetForAttribute): Deleted.
(WebCore::XSSAuditor::decodedSnippetForJavaScript): Deleted.

  • html/parser/XSSAuditor.h: Define enum class for the various attribute truncation styles.
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r195073 r195074  
     12016-01-14  Daniel Bates  <dabates@apple.com>
     2
     3        [XSS Auditor] Extract attribute truncation logic and formalize string canonicalization
     4        https://bugs.webkit.org/show_bug.cgi?id=152874
     5
     6        Reviewed by Brent Fulgham.
     7
     8        Derived from Blink patch (by Tom Sepez <tsepez@chromium.org>):
     9        <https://src.chromium.org/viewvc/blink?revision=176339&view=revision>
     10
     11        Extract the src-like and script-like attribute truncation logic into independent functions
     12        towards making it more straightforward to re-purpose this logic. Additionally, formalize the
     13        concept of string canonicalization as a member function that consolidates the process of
     14        decoding URL escape sequences, truncating the decoded string (if applicable), and removing
     15        characters that are considered noise.
     16
     17        * html/parser/XSSAuditor.cpp:
     18        (WebCore::truncateForSrcLikeAttribute): Extracted from XSSAuditor::decodedSnippetForAttribute().
     19        (WebCore::truncateForScriptLikeAttribute): Ditto.
     20        (WebCore::XSSAuditor::init): Write in terms of XSSAuditor::canonicalize().
     21        (WebCore::XSSAuditor::filterCharacterToken): Updated to make use of formalized canonicalization methods.
     22        (WebCore::XSSAuditor::filterScriptToken): Ditto.
     23        (WebCore::XSSAuditor::filterObjectToken): Ditto.
     24        (WebCore::XSSAuditor::filterParamToken): Ditto.
     25        (WebCore::XSSAuditor::filterEmbedToken): Ditto.
     26        (WebCore::XSSAuditor::filterAppletToken): Ditto.
     27        (WebCore::XSSAuditor::filterFrameToken): Ditto.
     28        (WebCore::XSSAuditor::filterInputToken): Ditto.
     29        (WebCore::XSSAuditor::filterButtonToken): Ditto.
     30        (WebCore::XSSAuditor::eraseDangerousAttributesIfInjected): Ditto.
     31        (WebCore::XSSAuditor::eraseAttributeIfInjected): Updated code to use early return style and avoid an unnecessary string
     32        comparison when we know that a src attribute was injected.
     33        (WebCore::XSSAuditor::canonicalizedSnippetForTagName): Renamed; formerly known as XSSAuditor::decodedSnippetForName(). Updated
     34        to make use of XSSAuditor::canonicalize().
     35        (WebCore::XSSAuditor::snippetFromAttribute): Renamed; formerly known as XSSAuditor::decodedSnippetForAttribute(). Moved
     36        truncation logic from here to WebCore::truncateFor{Script, Src}LikeAttribute.
     37        (WebCore::XSSAuditor::canonicalize): Added.
     38        (WebCore::XSSAuditor::canonicalizedSnippetForJavaScript): Added.
     39        (WebCore::canonicalize): Deleted.
     40        (WebCore::XSSAuditor::decodedSnippetForName): Deleted.
     41        (WebCore::XSSAuditor::decodedSnippetForAttribute): Deleted.
     42        (WebCore::XSSAuditor::decodedSnippetForJavaScript): Deleted.
     43        * html/parser/XSSAuditor.h: Define enum class for the various attribute truncation styles.
     44
    1452016-01-14  Daniel Bates  <dabates@apple.com>
    246
  • trunk/Source/WebCore/html/parser/XSSAuditor.cpp

    r195073 r195074  
    6464}
    6565
    66 static String canonicalize(const String& string)
    67 {
    68     return string.removeCharacters(&isNonCanonicalCharacter);
    69 }
    70 
    7166static bool isRequiredForInjection(UChar c)
    7267{
     
    181176}
    182177
     178static void truncateForSrcLikeAttribute(String& decodedSnippet)
     179{
     180    // In HTTP URLs, characters following the first ?, #, or third slash may come from
     181    // the page itself and can be merely ignored by an attacker's server when a remote
     182    // script or script-like resource is requested. In DATA URLS, the payload starts at
     183    // the first comma, and the the first /*, //, or <!-- may introduce a comment. Characters
     184    // following this may come from the page itself and may be ignored when the script is
     185    // executed. For simplicity, we don't differentiate based on URL scheme, and stop at
     186    // the first # or ?, the third slash, or the first slash or < once a comma is seen.
     187    int slashCount = 0;
     188    bool commaSeen = false;
     189    for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) {
     190        UChar currentChar = decodedSnippet[currentLength];
     191        if (currentChar == '?'
     192            || currentChar == '#'
     193            || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2))
     194            || (currentChar == '<' && commaSeen)) {
     195            decodedSnippet.truncate(currentLength);
     196            return;
     197        }
     198        if (currentChar == ',')
     199            commaSeen = true;
     200    }
     201}
     202
     203static void truncateForScriptLikeAttribute(String& decodedSnippet)
     204{
     205    // Beware of trailing characters which came from the page itself, not the
     206    // injected vector. Excluding the terminating character covers common cases
     207    // where the page immediately ends the attribute, but doesn't cover more
     208    // complex cases where there is other page data following the injection.
     209    // Generally, these won't parse as JavaScript, so the injected vector
     210    // typically excludes them from consideration via a single-line comment or
     211    // by enclosing them in a string literal terminated later by the page's own
     212    // closing punctuation. Since the snippet has not been parsed, the vector
     213    // may also try to introduce these via entities. As a result, we'd like to
     214    // stop before the first "//", the first <!--, the first entity, or the first
     215    // quote not immediately following the first equals sign (taking whitespace
     216    // into consideration). To keep things simpler, we don't try to distinguish
     217    // between entity-introducing ampersands vs. other uses, nor do we bother to
     218    // check for a second slash for a comment, nor do we bother to check for
     219    // !-- following a less-than sign. We stop instead on any ampersand
     220    // slash, or less-than sign.
     221    size_t position = 0;
     222    if ((position = decodedSnippet.find('=')) != notFound
     223        && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound
     224        && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) {
     225        decodedSnippet.truncate(position);
     226    }
     227}
     228
    183229static ContentSecurityPolicy::ReflectedXSSDisposition combineXSSProtectionHeaderAndCSP(ContentSecurityPolicy::ReflectedXSSDisposition xssProtection, ContentSecurityPolicy::ReflectedXSSDisposition reflectedXSS)
    184230{
     
    270316        m_encoding = document->decoder()->encoding();
    271317
    272     m_decodedURL = canonicalize(fullyDecodeString(m_documentURL.string(), m_encoding));
     318    m_decodedURL = canonicalize(m_documentURL.string(), TruncationStyle::None);
    273319    if (m_decodedURL.find(isRequiredForInjection) == notFound)
    274320        m_decodedURL = String();
     
    308354            httpBodyAsString = httpBody->flattenToString();
    309355            if (!httpBodyAsString.isEmpty()) {
    310                 m_decodedHTTPBody = canonicalize(fullyDecodeString(httpBodyAsString, m_encoding));
     356                m_decodedHTTPBody = canonicalize(httpBodyAsString, TruncationStyle::None);
    311357                if (m_decodedHTTPBody.find(isRequiredForInjection) == notFound)
    312358                    m_decodedHTTPBody = String();
     
    390436{
    391437    ASSERT(m_scriptTagNestingLevel);
    392     if (m_wasScriptTagFoundInRequest && isContainedInRequest(decodedSnippetForJavaScript(request))) {
     438    if (m_wasScriptTagFoundInRequest && isContainedInRequest(canonicalizedSnippetForJavaScript(request))) {
    393439        request.token.clear();
    394440        LChar space = ' ';
     
    404450    ASSERT(hasName(request.token, scriptTag));
    405451
    406     m_wasScriptTagFoundInRequest = isContainedInRequest(decodedSnippetForName(request));
     452    m_wasScriptTagFoundInRequest = isContainedInRequest(canonicalizedSnippetForTagName(request));
    407453
    408454    bool didBlockScript = false;
    409455    if (m_wasScriptTagFoundInRequest) {
    410         didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), SrcLikeAttribute);
    411         didBlockScript |= eraseAttributeIfInjected(request, XLinkNames::hrefAttr, blankURL().string(), SrcLikeAttribute);
     456        didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
     457        didBlockScript |= eraseAttributeIfInjected(request, XLinkNames::hrefAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
    412458    }
    413459
     
    421467
    422468    bool didBlockScript = false;
    423     if (isContainedInRequest(decodedSnippetForName(request))) {
    424         didBlockScript |= eraseAttributeIfInjected(request, dataAttr, blankURL().string(), SrcLikeAttribute);
     469    if (isContainedInRequest(canonicalizedSnippetForTagName(request))) {
     470        didBlockScript |= eraseAttributeIfInjected(request, dataAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
    425471        didBlockScript |= eraseAttributeIfInjected(request, typeAttr);
    426472        didBlockScript |= eraseAttributeIfInjected(request, classidAttr);
     
    442488        return false;
    443489
    444     return eraseAttributeIfInjected(request, valueAttr, blankURL().string(), SrcLikeAttribute);
     490    return eraseAttributeIfInjected(request, valueAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
    445491}
    446492
     
    451497
    452498    bool didBlockScript = false;
    453     if (isContainedInRequest(decodedSnippetForName(request))) {
    454         didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), SrcLikeAttribute);
    455         didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), SrcLikeAttribute);
     499    if (isContainedInRequest(canonicalizedSnippetForTagName(request))) {
     500        didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), TruncationStyle::SrcLikeAttribute);
     501        didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
    456502        didBlockScript |= eraseAttributeIfInjected(request, typeAttr);
    457503    }
     
    465511
    466512    bool didBlockScript = false;
    467     if (isContainedInRequest(decodedSnippetForName(request))) {
    468         didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), SrcLikeAttribute);
     513    if (isContainedInRequest(canonicalizedSnippetForTagName(request))) {
     514        didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), TruncationStyle::SrcLikeAttribute);
    469515        didBlockScript |= eraseAttributeIfInjected(request, objectAttr);
    470516    }
     
    477523    ASSERT(hasName(request.token, iframeTag) || hasName(request.token, frameTag));
    478524
    479     bool didBlockScript = eraseAttributeIfInjected(request, srcdocAttr, String(), ScriptLikeAttribute);
    480     if (isContainedInRequest(decodedSnippetForName(request)))
    481         didBlockScript |= eraseAttributeIfInjected(request, srcAttr, String(), SrcLikeAttribute);
     525    bool didBlockScript = eraseAttributeIfInjected(request, srcdocAttr, String(), TruncationStyle::ScriptLikeAttribute);
     526    if (isContainedInRequest(canonicalizedSnippetForTagName(request)))
     527        didBlockScript |= eraseAttributeIfInjected(request, srcAttr, String(), TruncationStyle::SrcLikeAttribute);
    482528
    483529    return didBlockScript;
     
    513559    ASSERT(hasName(request.token, inputTag));
    514560
    515     return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute);
     561    return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
    516562}
    517563
     
    521567    ASSERT(hasName(request.token, buttonTag));
    522568
    523     return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute);
     569    return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
    524570}
    525571
     
    537583        if (!isInlineEventHandler && !valueContainsJavaScriptURL)
    538584            continue;
    539         if (!isContainedInRequest(decodedSnippetForAttribute(request, attribute, ScriptLikeAttribute)))
     585        if (!isContainedInRequest(canonicalize(snippetFromAttribute(request, attribute), TruncationStyle::ScriptLikeAttribute)))
    540586            continue;
    541587        request.token.eraseValueOfAttribute(i);
     
    547593}
    548594
    549 bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, const QualifiedName& attributeName, const String& replacementValue, AttributeKind treatment)
     595bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, const QualifiedName& attributeName, const String& replacementValue, TruncationStyle truncationStyle)
    550596{
    551597    size_t indexOfAttribute = 0;
    552     if (findAttributeWithName(request.token, attributeName, indexOfAttribute)) {
    553         const HTMLToken::Attribute& attribute = request.token.attributes().at(indexOfAttribute);
    554         if (isContainedInRequest(decodedSnippetForAttribute(request, attribute, treatment))) {
    555             if (threadSafeMatch(attributeName, srcAttr) && isLikelySafeResource(String(attribute.value)))
    556                 return false;
    557             if (threadSafeMatch(attributeName, http_equivAttr) && !isDangerousHTTPEquiv(String(attribute.value)))
    558                 return false;
    559             request.token.eraseValueOfAttribute(indexOfAttribute);
    560             if (!replacementValue.isEmpty())
    561                 request.token.appendToAttributeValue(indexOfAttribute, replacementValue);
    562             return true;
    563         }
    564     }
    565     return false;
    566 }
    567 
    568 String XSSAuditor::decodedSnippetForName(const FilterTokenRequest& request)
     598    if (!findAttributeWithName(request.token, attributeName, indexOfAttribute))
     599        return false;
     600
     601    const HTMLToken::Attribute& attribute = request.token.attributes().at(indexOfAttribute);
     602    if (!isContainedInRequest(canonicalize(snippetFromAttribute(request, attribute), truncationStyle)))
     603        return false;
     604
     605    if (threadSafeMatch(attributeName, srcAttr)) {
     606        if (isLikelySafeResource(String(attribute.value)))
     607            return false;
     608    } else if (threadSafeMatch(attributeName, http_equivAttr)) {
     609        if (!isDangerousHTTPEquiv(String(attribute.value)))
     610            return false;
     611    }
     612
     613    request.token.eraseValueOfAttribute(indexOfAttribute);
     614    if (!replacementValue.isEmpty())
     615        request.token.appendToAttributeValue(indexOfAttribute, replacementValue);
     616    return true;
     617}
     618
     619String XSSAuditor::canonicalizedSnippetForTagName(const FilterTokenRequest& request)
    569620{
    570621    // Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<").
    571     return canonicalize(fullyDecodeString(request.sourceTracker.source(request.token), m_encoding).substring(0, request.token.name().size() + 1));
    572 }
    573 
    574 String XSSAuditor::decodedSnippetForAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute, AttributeKind treatment)
     622    return canonicalize(request.sourceTracker.source(request.token).substring(0, request.token.name().size() + 1), TruncationStyle::None);
     623}
     624
     625String XSSAuditor::snippetFromAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute)
    575626{
    576627    // The range doesn't include the character which terminates the value. So,
     
    578629    // unquoted input of |name=value |, the snippet is |name=value|.
    579630    // FIXME: We should grab one character before the name also.
    580     unsigned start = attribute.startOffset;
    581     unsigned end = attribute.endOffset;
    582 
    583     // We defer canonicalizing the decoded string here to preserve embedded slashes (if any) that
    584     // may lead us to truncate the string.
    585     String decodedSnippet = fullyDecodeString(request.sourceTracker.source(request.token, start, end), m_encoding);
    586     decodedSnippet.truncate(kMaximumFragmentLengthTarget);
    587     if (treatment == SrcLikeAttribute) {
    588         int slashCount = 0;
    589         bool commaSeen = false;
    590         // In HTTP URLs, characters following the first ?, #, or third slash may come from
    591         // the page itself and can be merely ignored by an attacker's server when a remote
    592         // script or script-like resource is requested. In DATA URLS, the payload starts at
    593         // the first comma, and the the first /*, //, or <!-- may introduce a comment. Characters
    594         // following this may come from the page itself and may be ignored when the script is
    595         // executed. For simplicity, we don't differentiate based on URL scheme, and stop at
    596         // the first # or ?, the third slash, or the first slash or < once a comma is seen.
    597         for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) {
    598             UChar currentChar = decodedSnippet[currentLength];
    599             if (currentChar == '?'
    600                 || currentChar == '#'
    601                 || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2))
    602                 || (currentChar == '<' && commaSeen)) {
    603                 decodedSnippet.truncate(currentLength);
    604                 break;
    605             }
    606             if (currentChar == ',')
    607                 commaSeen = true;
    608         }
    609     } else if (treatment == ScriptLikeAttribute) {
    610         // Beware of trailing characters which came from the page itself, not the
    611         // injected vector. Excluding the terminating character covers common cases
    612         // where the page immediately ends the attribute, but doesn't cover more
    613         // complex cases where there is other page data following the injection.
    614         // Generally, these won't parse as javascript, so the injected vector
    615         // typically excludes them from consideration via a single-line comment or
    616         // by enclosing them in a string literal terminated later by the page's own
    617         // closing punctuation. Since the snippet has not been parsed, the vector
    618         // may also try to introduce these via entities. As a result, we'd like to
    619         // stop before the first "//", the first <!--, the first entity, or the first
    620         // quote not immediately following the first equals sign (taking whitespace
    621         // into consideration). To keep things simpler, we don't try to distinguish
    622         // between entity-introducing amperands vs. other uses, nor do we bother to
    623         // check for a second slash for a comment, nor do we bother to check for
    624         // !-- following a less-than sign. We stop instead on any ampersand
    625         // slash, or less-than sign.
    626         size_t position = 0;
    627         if ((position = decodedSnippet.find('=')) != notFound
    628             && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound
    629             && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) {
    630             decodedSnippet.truncate(position);
    631         }
    632     }
    633     return canonicalize(decodedSnippet);
    634 }
    635 
    636 String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request)
     631    return request.sourceTracker.source(request.token, attribute.startOffset, attribute.endOffset);
     632}
     633
     634String XSSAuditor::canonicalize(const String& snippet, TruncationStyle truncationStyle)
     635{
     636    String decodedSnippet = fullyDecodeString(snippet, m_encoding);
     637    if (truncationStyle != TruncationStyle::None) {
     638        decodedSnippet.truncate(kMaximumFragmentLengthTarget);
     639        if (truncationStyle == TruncationStyle::SrcLikeAttribute)
     640            truncateForSrcLikeAttribute(decodedSnippet);
     641        else if (truncationStyle == TruncationStyle::ScriptLikeAttribute)
     642            truncateForScriptLikeAttribute(decodedSnippet);
     643    }
     644    return decodedSnippet.removeCharacters(&isNonCanonicalCharacter);
     645}
     646
     647String XSSAuditor::canonicalizedSnippetForJavaScript(const FilterTokenRequest& request)
    637648{
    638649    String string = request.sourceTracker.source(request.token);
     
    688699                break;
    689700            }
    690 
    691701            if (foundPosition > startPosition + kMaximumFragmentLengthTarget) {
    692702                // After hitting the length target, we can only stop at a point where we know we are
     
    702712        }
    703713
    704         result = canonicalize(fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding));
     714        result = canonicalize(string.substring(startPosition, foundPosition - startPosition), TruncationStyle::None);
    705715        startPosition = foundPosition + 1;
    706716    }
  • trunk/Source/WebCore/html/parser/XSSAuditor.h

    r194982 r195074  
    7171    };
    7272
    73     enum AttributeKind {
     73    enum class TruncationStyle {
     74        None,
    7475        NormalAttribute,
    7576        SrcLikeAttribute,
     
    9394
    9495    bool eraseDangerousAttributesIfInjected(const FilterTokenRequest&);
    95     bool eraseAttributeIfInjected(const FilterTokenRequest&, const QualifiedName&, const String& replacementValue = String(), AttributeKind treatment = NormalAttribute);
     96    bool eraseAttributeIfInjected(const FilterTokenRequest&, const QualifiedName&, const String& replacementValue = String(), TruncationStyle = TruncationStyle::NormalAttribute);
    9697
    97     String decodedSnippetForToken(const HTMLToken&);
    98     String decodedSnippetForName(const FilterTokenRequest&);
    99     String decodedSnippetForAttribute(const FilterTokenRequest&, const HTMLToken::Attribute&, AttributeKind treatment = NormalAttribute);
    100     String decodedSnippetForJavaScript(const FilterTokenRequest&);
     98    String canonicalizedSnippetForTagName(const FilterTokenRequest&);
     99    String canonicalizedSnippetForJavaScript(const FilterTokenRequest&);
     100    String snippetFromAttribute(const FilterTokenRequest&, const HTMLToken::Attribute&);
     101    String canonicalize(const String&, TruncationStyle);
    101102
    102103    bool isContainedInRequest(const String&);
Note: See TracChangeset for help on using the changeset viewer.