Changeset 240331 in webkit


Ignore:
Timestamp:
Jan 23, 2019 3:32:55 AM (5 years ago)
Author:
commit-queue@webkit.org
Message:

Update MIME type parser
https://bugs.webkit.org/show_bug.cgi?id=180526

Patch by Rob Buis <rbuis@igalia.com> on 2019-01-23
Reviewed by Frédéric Wang.

LayoutTests/imported/w3c:

Update improved test expectations.

  • web-platform-tests/xhr/overridemimetype-blob-expected.txt:

Source/WebCore:

Add an enum to allow two modes of MIME type parsing, one mode
to keep supporting RFC2045 as before, and one mode to support
the updated MIME parser from mimesniff [1]. Mimesniff support
brings the following changes:

  • allows parameter names without matching =value.
  • skips whitespace after subtype, parameter value and before parameter name.
  • lower cases MIME type and parameter name.
  • parameter names parsed before are discarded.

The old mode is still used by CDM.cpp and MIMEHeader.cpp.

[1] https://mimesniff.spec.whatwg.org/

  • Modules/encryptedmedia/CDM.cpp:

(WebCore::CDM::getSupportedCapabilitiesForAudioVideoType):

  • platform/network/MIMEHeader.cpp:

(WebCore::MIMEHeader::parseHeader):

  • platform/network/ParsedContentType.cpp:

(WebCore::DummyParsedContentType::setContentType const):
(WebCore::DummyParsedContentType::setContentTypeParameter const):
(WebCore::isQuotedStringTokenCharacter):
(WebCore::isTokenCharacter):
(WebCore::parseToken):
(WebCore::containsNonTokenCharacters):
(WebCore::parseQuotedString):
(WebCore::isNotForwardSlash):
(WebCore::isNotSemicolon):
(WebCore::isNotSemicolonOrEqualSign):
(WebCore::parseContentType):
(WebCore::isValidContentType):
(WebCore::ParsedContentType::ParsedContentType):
(WebCore::ParsedContentType::setContentType):
(WebCore::isNonTokenCharacter):
(WebCore::isNonQuotedStringTokenCharacter):
(WebCore::ParsedContentType::setContentTypeParameter):

  • platform/network/ParsedContentType.h:

Test: web-platform-tests/xhr/overridemimetype-blob.html

Tools:

Add unit tests for both parse modes of ParsedContentType.

  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WebCore/ParsedContentType.cpp: Added.

(TestWebKitAPI::TEST):

LayoutTests:

Adjust test expectation.

  • http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt:
  • http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt:
  • http/tests/xmlhttprequest/post-blob-content-type-tests.js:
Location:
trunk
Files:
1 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r240326 r240331  
     12019-01-23  Rob Buis  <rbuis@igalia.com>
     2
     3        Update MIME type parser
     4        https://bugs.webkit.org/show_bug.cgi?id=180526
     5
     6        Reviewed by Frédéric Wang.
     7
     8        Adjust test expectation.
     9
     10        * http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt:
     11        * http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt:
     12        * http/tests/xmlhttprequest/post-blob-content-type-tests.js:
     13
    1142019-01-22  Simon Fraser  <simon.fraser@apple.com>
    215
  • trunk/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt

    r205473 r240331  
    1313PASS expectedMimeType is ""
    1414PASS expectedMimeType is ""
    15 PASS expectedMimeType is ""
     15PASS expectedMimeType is "multipart/mixed;boundary=\"--blob-boundary"
    1616PASS expectedMimeType is "multipart/mixed;boundary=\"--blob-boundary\""
    1717PASS expectedMimeType is ""
  • trunk/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt

    r231000 r240331  
    1313PASS expectedMimeType is ""
    1414PASS expectedMimeType is ""
    15 PASS expectedMimeType is ""
     15PASS expectedMimeType is "multipart/mixed;boundary=\"--blob-boundary"
    1616PASS expectedMimeType is "multipart/mixed;boundary=\"--blob-boundary\""
    1717PASS expectedMimeType is ""
  • trunk/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-tests.js

    r148105 r240331  
    2424}, {
    2525    mime: 'multipart/mixed;boundary="--blob-boundary',
    26     expectedMime: ''
     26    expectedMime: 'multipart/mixed;boundary="--blob-boundary'
    2727}, {
    2828    mime: 'multipart/mixed;boundary="--blob-boundary"',
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r240320 r240331  
     12019-01-23  Rob Buis  <rbuis@igalia.com>
     2
     3        Update MIME type parser
     4        https://bugs.webkit.org/show_bug.cgi?id=180526
     5
     6        Reviewed by Frédéric Wang.
     7
     8        Update improved test expectations.
     9
     10        * web-platform-tests/xhr/overridemimetype-blob-expected.txt:
     11
    1122019-01-22  Youenn Fablet  <youenn@apple.com>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/xhr/overridemimetype-blob-expected.txt

    r238124 r240331  
    55FAIL 1) MIME types need to be parsed and serialized: text/html;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
    66FAIL 2) MIME types need to be parsed and serialized: TEXT/HTML;CHARSET=GBK assert_equals: expected "text/html;charset=GBK" but got "text/html"
    7 FAIL 3) MIME types need to be parsed and serialized: text/html;charset=gbk( assert_equals: expected "text/html;charset=\"gbk(\"" but got "application/octet-stream"
    8 FAIL 4) MIME types need to be parsed and serialized: text/html;x=(;charset=gbk assert_equals: expected "text/html;x=\"(\";charset=gbk" but got "application/octet-stream"
     7FAIL 3) MIME types need to be parsed and serialized: text/html;charset=gbk( assert_equals: expected "text/html;charset=\"gbk(\"" but got "text/html"
     8FAIL 4) MIME types need to be parsed and serialized: text/html;x=(;charset=gbk assert_equals: expected "text/html;x=\"(\";charset=gbk" but got "text/html"
    99FAIL 5) MIME types need to be parsed and serialized: text/html;charset=gbk;charset=windows-1255 assert_equals: expected "text/html;charset=gbk" but got "text/html"
    10 FAIL 6) MIME types need to be parsed and serialized: text/html;charset=();charset=GBK assert_equals: expected "text/html;charset=\"()\"" but got "application/octet-stream"
    11 FAIL 7) MIME types need to be parsed and serialized: text/html;charset =gbk assert_equals: expected "text/html" but got "application/octet-stream"
     10FAIL 6) MIME types need to be parsed and serialized: text/html;charset=();charset=GBK assert_equals: expected "text/html;charset=\"()\"" but got "text/html"
     11PASS 7) MIME types need to be parsed and serialized: text/html;charset =gbk
    1212FAIL 8) MIME types need to be parsed and serialized: text/html ;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
    1313FAIL 9) MIME types need to be parsed and serialized: text/html; charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
    14 FAIL 10) MIME types need to be parsed and serialized: text/html;charset= gbk assert_equals: expected "text/html;charset=\" gbk\"" but got "application/octet-stream"
    15 FAIL 11) MIME types need to be parsed and serialized: text/html;charset= "gbk" assert_equals: expected "text/html;charset=\" \\\"gbk\\"\"" but got "application/octet-stream"
     14FAIL 10) MIME types need to be parsed and serialized: text/html;charset= gbk assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html"
     15FAIL 11) MIME types need to be parsed and serialized: text/html;charset= "gbk" assert_equals: expected "text/html;charset=\" \\\"gbk\\"\"" but got "text/html"
    1616FAIL 12) MIME types need to be parsed and serialized: text/html;charset='gbk' assert_equals: expected "text/html;charset='gbk'" but got "text/html"
    1717FAIL 13) MIME types need to be parsed and serialized: text/html;charset='gbk assert_equals: expected "text/html;charset='gbk" but got "text/html"
    1818FAIL 14) MIME types need to be parsed and serialized: text/html;charset=gbk' assert_equals: expected "text/html;charset=gbk'" but got "text/html"
    1919FAIL 15) MIME types need to be parsed and serialized: text/html;charset=';charset=GBK assert_equals: expected "text/html;charset='" but got "text/html"
    20 FAIL 16) MIME types need to be parsed and serialized: text/html;test;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
     20FAIL 16) MIME types need to be parsed and serialized: text/html;test;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
    2121FAIL 17) MIME types need to be parsed and serialized: text/html;test=;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
    22 FAIL 18) MIME types need to be parsed and serialized: text/html;';charset=gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
    23 FAIL 19) MIME types need to be parsed and serialized: text/html;";charset=gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
    24 FAIL 20) MIME types need to be parsed and serialized: text/html ; ; charset=gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
    25 FAIL 21) MIME types need to be parsed and serialized: text/html;;;;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
    26 FAIL 22) MIME types need to be parsed and serialized: text/html;charset= ";charset=GBK assert_equals: expected "text/html;charset=GBK" but got "application/octet-stream"
     22FAIL 18) MIME types need to be parsed and serialized: text/html;';charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
     23FAIL 19) MIME types need to be parsed and serialized: text/html;";charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
     24FAIL 20) MIME types need to be parsed and serialized: text/html ; ; charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
     25FAIL 21) MIME types need to be parsed and serialized: text/html;;;;charset=gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
     26FAIL 22) MIME types need to be parsed and serialized: text/html;charset= ";charset=GBK assert_equals: expected "text/html;charset=GBK" but got "text/html"
    2727FAIL 23) MIME types need to be parsed and serialized: text/html;charset=";charset=foo";charset=GBK assert_equals: expected "text/html;charset=GBK" but got "text/html"
    2828FAIL 24) MIME types need to be parsed and serialized: text/html;charset="gbk" assert_equals: expected "text/html;charset=gbk" but got "text/html"
    29 FAIL 25) MIME types need to be parsed and serialized: text/html;charset="gbk assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
    30 FAIL 26) MIME types need to be parsed and serialized: text/html;charset=gbk" assert_equals: expected "text/html;charset=\"gbk\\\"\"" but got "application/octet-stream"
     29FAIL 25) MIME types need to be parsed and serialized: text/html;charset="gbk assert_equals: expected "text/html;charset=gbk" but got "text/html"
     30FAIL 26) MIME types need to be parsed and serialized: text/html;charset=gbk" assert_equals: expected "text/html;charset=\"gbk\\\"\"" but got "text/html"
    3131FAIL 27) MIME types need to be parsed and serialized: text/html;charset=" gbk" assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html"
    3232FAIL 28) MIME types need to be parsed and serialized: text/html;charset="gbk " assert_equals: expected "text/html;charset=\"gbk \"" but got "text/html"
    3333FAIL 29) MIME types need to be parsed and serialized: text/html;charset="\ gbk" assert_equals: expected "text/html;charset=\" gbk\"" but got "text/html"
    3434FAIL 30) MIME types need to be parsed and serialized: text/html;charset="\g\b\k" assert_equals: expected "text/html;charset=gbk" but got "text/html"
    35 FAIL 31) MIME types need to be parsed and serialized: text/html;charset="gbk"x assert_equals: expected "text/html;charset=gbk" but got "application/octet-stream"
     35FAIL 31) MIME types need to be parsed and serialized: text/html;charset="gbk"x assert_equals: expected "text/html;charset=gbk" but got "text/html"
    3636FAIL 32) MIME types need to be parsed and serialized: text/html;charset="";charset=GBK assert_equals: expected "text/html;charset=\"\"" but got "text/html"
    37 FAIL 33) MIME types need to be parsed and serialized: text/html;charset=";charset=GBK assert_equals: expected "text/html;charset=\";charset=GBK\"" but got "application/octet-stream"
     37FAIL 33) MIME types need to be parsed and serialized: text/html;charset=";charset=GBK assert_equals: expected "text/html;charset=\";charset=GBK\"" but got "text/html"
    3838FAIL 34) MIME types need to be parsed and serialized: text/html;charset={gbk} assert_equals: expected "text/html;charset=\"{gbk}\"" but got "text/html"
    3939FAIL 35) MIME types need to be parsed and serialized: text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk assert_equals: expected "text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk" but got "text/html"
     
    4343†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" assert_equals: expected "x/x;x=\"\t !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„
    4444†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"" but got "x/x"
    45 FAIL 39) MIME types need to be parsed and serialized: x/x;test assert_equals: expected "x/x" but got "application/octet-stream"
    46 FAIL 40) MIME types need to be parsed and serialized: x/x;test="\ assert_equals: expected "x/x;test=\"\\\\"" but got "application/octet-stream"
    47 FAIL 41) MIME types need to be parsed and serialized: x/x;x=  assert_equals: expected "x/x" but got "application/octet-stream"
    48 FAIL 42) MIME types need to be parsed and serialized: x/x;x=     assert_equals: expected "x/x" but got "application/octet-stream"
    49 FAIL 43) MIME types need to be parsed and serialized: text/html;test=ÿ;charset=gbk assert_equals: expected "text/html;test=\"ÿ\";charset=gbk" but got "application/octet-stream"
    50 FAIL 44) MIME types need to be parsed and serialized: x/x;test=�;x=x assert_equals: expected "x/x;x=x" but got "application/octet-stream"
     45PASS 39) MIME types need to be parsed and serialized: x/x;test
     46FAIL 40) MIME types need to be parsed and serialized: x/x;test="\ assert_equals: expected "x/x;test=\"\\\\"" but got "x/x"
     47PASS 41) MIME types need to be parsed and serialized: x/x;x= 
     48PASS 42) MIME types need to be parsed and serialized: x/x;x=     
     49FAIL 43) MIME types need to be parsed and serialized: text/html;test=ÿ;charset=gbk assert_equals: expected "text/html;test=\"ÿ\";charset=gbk" but got "text/html"
     50FAIL 44) MIME types need to be parsed and serialized: x/x;test=�;x=x assert_equals: expected "x/x;x=x" but got "x/x"
    5151PASS 45) MIME types need to be parsed and serialized: 
    5252PASS 46) MIME types need to be parsed and serialized:   
     
    5454PASS 48) MIME types need to be parsed and serialized: bogus
    5555PASS 49) MIME types need to be parsed and serialized: bogus/
    56 PASS 50) MIME types need to be parsed and serialized: bogus/ 
     56FAIL 50) MIME types need to be parsed and serialized: bogus/  assert_equals: expected "application/octet-stream" but got "bogus/"
    5757PASS 51) MIME types need to be parsed and serialized: bogus/bogus/;
    5858PASS 52) MIME types need to be parsed and serialized: </>
    5959PASS 53) MIME types need to be parsed and serialized: (/)
    6060PASS 54) MIME types need to be parsed and serialized: ÿ/ÿ
    61 FAIL 55) MIME types need to be parsed and serialized: text/html(;doesnot=matter assert_equals: expected "application/octet-stream" but got "text/html("
     61PASS 55) MIME types need to be parsed and serialized: text/html(;doesnot=matter
    6262FAIL 56) MIME types need to be parsed and serialized: {/} assert_equals: expected "application/octet-stream" but got "{/}"
    6363PASS 57) MIME types need to be parsed and serialized: Ā/Ā
  • trunk/Source/WebCore/ChangeLog

    r240328 r240331  
     12019-01-23  Rob Buis  <rbuis@igalia.com>
     2
     3        Update MIME type parser
     4        https://bugs.webkit.org/show_bug.cgi?id=180526
     5
     6        Reviewed by Frédéric Wang.
     7
     8        Add an enum to allow two modes of MIME type parsing, one mode
     9        to keep supporting RFC2045 as before, and one mode to support
     10        the updated MIME parser from mimesniff [1]. Mimesniff support
     11        brings the following changes:
     12        - allows parameter names without matching =value.
     13        - skips whitespace after subtype, parameter value and before
     14          parameter name.
     15        - lower cases MIME type and parameter name.
     16        - parameter names parsed before are discarded.
     17
     18        The old mode is still used by CDM.cpp and MIMEHeader.cpp.
     19
     20        [1] https://mimesniff.spec.whatwg.org/
     21
     22        * Modules/encryptedmedia/CDM.cpp:
     23        (WebCore::CDM::getSupportedCapabilitiesForAudioVideoType):
     24        * platform/network/MIMEHeader.cpp:
     25        (WebCore::MIMEHeader::parseHeader):
     26        * platform/network/ParsedContentType.cpp:
     27        (WebCore::DummyParsedContentType::setContentType const):
     28        (WebCore::DummyParsedContentType::setContentTypeParameter const):
     29        (WebCore::isQuotedStringTokenCharacter):
     30        (WebCore::isTokenCharacter):
     31        (WebCore::parseToken):
     32        (WebCore::containsNonTokenCharacters):
     33        (WebCore::parseQuotedString):
     34        (WebCore::isNotForwardSlash):
     35        (WebCore::isNotSemicolon):
     36        (WebCore::isNotSemicolonOrEqualSign):
     37        (WebCore::parseContentType):
     38        (WebCore::isValidContentType):
     39        (WebCore::ParsedContentType::ParsedContentType):
     40        (WebCore::ParsedContentType::setContentType):
     41        (WebCore::isNonTokenCharacter):
     42        (WebCore::isNonQuotedStringTokenCharacter):
     43        (WebCore::ParsedContentType::setContentTypeParameter):
     44        * platform/network/ParsedContentType.h:
     45
     46        Test: web-platform-tests/xhr/overridemimetype-blob.html
     47
    1482019-01-22  Wenson Hsieh  <wenson_hsieh@apple.com>
    249
  • trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp

    r239427 r240331  
    434434
    435435        // 3.4. If content type is an invalid or unrecognized MIME type, continue to the next iteration.
    436         if (!isValidContentType(requestedCapability.contentType))
     436        if (!isValidContentType(requestedCapability.contentType, Mode::Rfc2045))
    437437            continue;
    438438
  • trunk/Source/WebCore/platform/network/MIMEHeader.cpp

    r215686 r240331  
    8888    KeyValueMap::iterator mimeParametersIterator = keyValuePairs.find("content-type");
    8989    if (mimeParametersIterator != keyValuePairs.end()) {
    90         ParsedContentType parsedContentType(mimeParametersIterator->value);
     90        ParsedContentType parsedContentType(mimeParametersIterator->value, Mode::Rfc2045);
    9191        mimeHeader->m_contentType = parsedContentType.mimeType();
    9292        if (!mimeHeader->isMultipart())
  • trunk/Source/WebCore/platform/network/ParsedContentType.cpp

    r239427 r240331  
    3939class DummyParsedContentType {
    4040public:
    41     void setContentType(const SubstringRange&) const { }
    42     void setContentTypeParameter(const SubstringRange&, const SubstringRange&) const { }
     41    void setContentType(const SubstringRange&, Mode) const { }
     42    void setContentTypeParameter(const String&, const String&, Mode) const { }
    4343};
    4444
     
    4949}
    5050
    51 static bool isTokenCharacter(char c)
     51static bool isQuotedStringTokenCharacter(UChar c)
     52{
     53    return (c >= ' ' && c <= '~') || (c >= 0x80 && c <= 0xFF) || c == '\t';
     54}
     55
     56static bool isTokenCharacter(UChar c)
    5257{
    5358    return isASCII(c) && c > ' ' && c != '"' && c != '(' && c != ')' && c != ',' && c != '/' && (c < ':' || c > '@') && (c < '[' || c > ']');
    5459}
    5560
    56 static Optional<SubstringRange> parseToken(const String& input, unsigned& startIndex)
     61using CharacterMeetsCondition = bool (*)(UChar);
     62
     63static Optional<SubstringRange> parseToken(const String& input, unsigned& startIndex, CharacterMeetsCondition characterMeetsCondition, Mode mode, bool skipTrailingWhitespace = false)
    5764{
    5865    unsigned inputLength = input.length();
     
    6370        return WTF::nullopt;
    6471
    65     while (tokenEnd < inputLength) {
    66         if (!isTokenCharacter(input[tokenEnd]))
     72    while (tokenEnd < inputLength && characterMeetsCondition(input[tokenEnd])) {
     73        if (mode == Mode::Rfc2045 && !isTokenCharacter(input[tokenEnd]))
    6774            break;
    6875        ++tokenEnd;
     
    7178    if (tokenEnd == tokenStart)
    7279        return WTF::nullopt;
     80    if (skipTrailingWhitespace) {
     81        while (input[tokenEnd - 1] == ' ')
     82            --tokenEnd;
     83    }
    7384    return SubstringRange(tokenStart, tokenEnd - tokenStart);
    7485}
    7586
    76 static Optional<SubstringRange> parseQuotedString(const String& input, unsigned& startIndex)
     87static bool containsNonTokenCharacters(const String& input, SubstringRange range)
     88{
     89    for (unsigned index = 0; index < range.second; ++index) {
     90        if (!isTokenCharacter(input[range.first + index]))
     91            return true;
     92    }
     93    return false;
     94}
     95
     96static Optional<SubstringRange> parseQuotedString(const String& input, unsigned& startIndex, Mode mode)
    7797{
    7898    unsigned inputLength = input.length();
     
    89109    char currentCharacter;
    90110    while ((currentCharacter = input[quotedStringEnd++]) != '"' || lastCharacterWasBackslash) {
    91         if (quotedStringEnd >= inputLength)
    92             return WTF::nullopt;
     111        if (quotedStringEnd >= inputLength) {
     112            if (mode == Mode::Rfc2045)
     113                return WTF::nullopt;
     114            break;
     115        }
    93116        if (currentCharacter == '\\' && !lastCharacterWasBackslash) {
    94117            lastCharacterWasBackslash = true;
     
    152175//               ; to use within parameter values
    153176
     177static bool isNotForwardSlash(UChar ch)
     178{
     179    return ch != '/';
     180}
     181
     182static bool isNotSemicolon(UChar ch)
     183{
     184    return ch != ';';
     185}
     186
     187static bool isNotSemicolonOrEqualSign(UChar ch)
     188{
     189    return ch != ';' && ch != '=';
     190}
     191
    154192template <class ReceiverType>
    155 bool parseContentType(const String& contentType, ReceiverType& receiver)
     193bool parseContentType(const String& contentType, ReceiverType& receiver, Mode mode)
    156194{
    157195    unsigned index = 0;
     
    164202
    165203    unsigned contentTypeStart = index;
    166     auto typeRange = parseToken(contentType, index);
    167     if (!typeRange) {
     204    auto typeRange = parseToken(contentType, index, isNotForwardSlash, mode);
     205    if (!typeRange || containsNonTokenCharacters(contentType, *typeRange)) {
    168206        LOG_ERROR("Invalid Content-Type, invalid type value.");
    169207        return false;
     
    175213    }
    176214
    177     auto subTypeRange = parseToken(contentType, index);
    178     if (!subTypeRange) {
     215    auto subTypeRange = parseToken(contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
     216    if (!subTypeRange || containsNonTokenCharacters(contentType, *subTypeRange)) {
    179217        LOG_ERROR("Invalid Content-Type, invalid subtype value.");
    180218        return false;
     
    184222    size_t semiColonIndex = contentType.find(';', contentTypeStart);
    185223    if (semiColonIndex == notFound) {
    186         receiver.setContentType(SubstringRange(contentTypeStart, contentTypeLength - contentTypeStart));
     224        receiver.setContentType(SubstringRange(contentTypeStart, contentTypeLength - contentTypeStart), mode);
    187225        return true;
    188226    }
    189227
    190     receiver.setContentType(SubstringRange(contentTypeStart, semiColonIndex - contentTypeStart));
     228    receiver.setContentType(SubstringRange(contentTypeStart, semiColonIndex - contentTypeStart), mode);
    191229    index = semiColonIndex + 1;
    192230    while (true) {
    193231        skipSpaces(contentType, index);
    194         auto keyRange = parseToken(contentType, index);
    195         if (!keyRange || index >= contentTypeLength) {
     232        auto keyRange = parseToken(contentType, index, isNotSemicolonOrEqualSign, mode);
     233        if (mode == Mode::Rfc2045 && (!keyRange || index >= contentTypeLength)) {
    196234            LOG_ERROR("Invalid Content-Type parameter name.");
    197235            return false;
     
    199237
    200238        // Should we tolerate spaces here?
    201         if (contentType[index++] != '=' || index >= contentTypeLength) {
    202             LOG_ERROR("Invalid Content-Type malformed parameter.");
    203             return false;
    204         }
     239        if (mode == Mode::Rfc2045) {
     240            if (contentType[index++] != '=' || index >= contentTypeLength) {
     241                LOG_ERROR("Invalid Content-Type malformed parameter.");
     242                return false;
     243            }
     244        } else {
     245            if (index >= contentTypeLength)
     246                break;
     247            if (contentType[index] != '=' && contentType[index] != ';') {
     248                LOG_ERROR("Invalid Content-Type malformed parameter.");
     249                return false;
     250            }
     251            if (contentType[index++] == ';')
     252                continue;
     253        }
     254
     255        String parameterName = substringForRange(contentType, *keyRange);
    205256
    206257        // Should we tolerate spaces here?
    207         String value;
    208258        Optional<SubstringRange> valueRange;
    209         if (contentType[index] == '"')
    210             valueRange = parseQuotedString(contentType, index);
    211         else
    212             valueRange = parseToken(contentType, index);
     259        if (contentType[index] == '"') {
     260            valueRange = parseQuotedString(contentType, index, mode);
     261            if (mode == Mode::MimeSniff)
     262                parseToken(contentType, index, isNotSemicolon, mode);
     263        } else
     264            valueRange = parseToken(contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
    213265
    214266        if (!valueRange) {
     
    217269        }
    218270
     271        String parameterValue = substringForRange(contentType, *valueRange);
    219272        // Should we tolerate spaces here?
    220         if (index < contentTypeLength && contentType[index++] != ';') {
     273        if (mode == Mode::Rfc2045 && index < contentTypeLength && contentType[index++] != ';') {
    221274            LOG_ERROR("Invalid Content-Type, invalid character at the end of key/value parameter.");
    222275            return false;
    223276        }
    224277
    225         receiver.setContentTypeParameter(*keyRange, *valueRange);
     278        receiver.setContentTypeParameter(parameterName, parameterValue, mode);
    226279
    227280        if (index >= contentTypeLength)
     
    232285}
    233286
    234 bool isValidContentType(const String& contentType)
     287bool isValidContentType(const String& contentType, Mode mode)
    235288{
    236289    if (contentType.contains('\r') || contentType.contains('\n'))
     
    238291
    239292    DummyParsedContentType parsedContentType = DummyParsedContentType();
    240     return parseContentType<DummyParsedContentType>(contentType, parsedContentType);
    241 }
    242 
    243 ParsedContentType::ParsedContentType(const String& contentType)
     293    return parseContentType<DummyParsedContentType>(contentType, parsedContentType, mode);
     294}
     295
     296ParsedContentType::ParsedContentType(const String& contentType, Mode mode)
    244297    : m_contentType(contentType.stripWhiteSpace())
    245298{
    246     parseContentType<ParsedContentType>(m_contentType, *this);
     299    parseContentType<ParsedContentType>(m_contentType, *this, mode);
    247300}
    248301
     
    262315}
    263316
    264 void ParsedContentType::setContentType(const SubstringRange& contentRange)
     317void ParsedContentType::setContentType(const SubstringRange& contentRange, Mode mode)
    265318{
    266319    m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace();
    267 }
    268 
    269 void ParsedContentType::setContentTypeParameter(const SubstringRange& key, const SubstringRange& value)
    270 {
    271     m_parameters.set(substringForRange(m_contentType, key), substringForRange(m_contentType, value));
    272 }
    273 
    274 }
     320    if (mode == Mode::MimeSniff)
     321        m_mimeType.convertToASCIILowercase();
     322}
     323
     324static bool isNonTokenCharacter(UChar ch)
     325{
     326    return !isTokenCharacter(ch);
     327}
     328
     329static bool isNonQuotedStringTokenCharacter(UChar ch)
     330{
     331    return !isQuotedStringTokenCharacter(ch);
     332}
     333
     334void ParsedContentType::setContentTypeParameter(const String& keyName, const String& keyValue, Mode mode)
     335{
     336    if (mode == Mode::MimeSniff) {
     337        if (m_parameters.contains(keyName) || keyName.find(isNonTokenCharacter) != notFound || keyValue.find(isNonQuotedStringTokenCharacter) != notFound)
     338            return;
     339        keyName.convertToASCIILowercase();
     340    }
     341    m_parameters.set(keyName, keyValue);
     342}
     343
     344}
  • trunk/Source/WebCore/platform/network/ParsedContentType.h

    r238124 r240331  
    3737namespace WebCore {
    3838
     39enum class Mode {
     40    Rfc2045,
     41    MimeSniff
     42};
    3943// <index, length>
    4044typedef std::pair<unsigned, unsigned> SubstringRange;
    41 bool isValidContentType(const String&);
     45WEBCORE_EXPORT bool isValidContentType(const String&, Mode = Mode::MimeSniff);
    4246
    4347// FIXME: add support for comments.
    4448class ParsedContentType {
    4549public:
    46     explicit ParsedContentType(const String&);
     50    explicit ParsedContentType(const String&, Mode = Mode::MimeSniff);
    4751
    4852    String mimeType() const { return m_mimeType; }
     
    5559private:
    5660    template<class ReceiverType>
    57     friend bool parseContentType(const String&, ReceiverType&);
    58     void setContentType(const SubstringRange&);
    59     void setContentTypeParameter(const SubstringRange&, const SubstringRange&);
     61    friend bool parseContentType(const String&, ReceiverType&, Mode);
     62    void setContentType(const SubstringRange&, Mode);
     63    void setContentTypeParameter(const String&, const String&, Mode);
    6064
    6165    typedef HashMap<String, String> KeyValuePairs;
  • trunk/Tools/ChangeLog

    r240303 r240331  
     12019-01-23  Rob Buis  <rbuis@igalia.com>
     2
     3        Update MIME type parser
     4        https://bugs.webkit.org/show_bug.cgi?id=180526
     5
     6        Reviewed by Frédéric Wang.
     7
     8        Add unit tests for both parse modes of ParsedContentType.
     9
     10        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     11        * TestWebKitAPI/Tests/WebCore/ParsedContentType.cpp: Added.
     12        (TestWebKitAPI::TEST):
     13
    1142019-01-22  Aakash Jain  <aakash_jain@apple.com>
    215
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r240010 r240331  
    697697                A5B149DE1F5A19EA00C6DAFF /* MIMETypeRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5B149DD1F5A19DC00C6DAFF /* MIMETypeRegistry.cpp */; };
    698698                A5E2027515B21F6E00C13E14 /* WindowlessWebViewWithMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A5E2027015B2180600C13E14 /* WindowlessWebViewWithMedia.html */; };
     699                AA96CAB621C7DB5000FD2F97 /* ParsedContentType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA96CAB421C7DB4200FD2F97 /* ParsedContentType.cpp */; };
    699700                AD57AC201DA7465000FF1BDE /* DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD57AC1E1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp */; };
    700701                AD57AC211DA7465B00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD57AC1F1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp */; };
     
    19301931                A5E2027215B2181900C13E14 /* WindowlessWebViewWithMedia.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowlessWebViewWithMedia.mm; sourceTree = "<group>"; };
    19311932                A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckedArithmeticOperations.cpp; sourceTree = "<group>"; };
     1933                AA96CAB421C7DB4200FD2F97 /* ParsedContentType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParsedContentType.cpp; sourceTree = "<group>"; };
    19321934                ABF510632A19B8AC7EC40E17 /* AbortableTaskQueue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AbortableTaskQueue.cpp; sourceTree = "<group>"; };
    19331935                AD57AC1D1DA7463800FF1BDE /* many-iframes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "many-iframes.html"; sourceTree = "<group>"; };
     
    26962698                                A5B149DD1F5A19DC00C6DAFF /* MIMETypeRegistry.cpp */,
    26972699                                CD225C071C45A69200140761 /* ParsedContentRange.cpp */,
     2700                                AA96CAB421C7DB4200FD2F97 /* ParsedContentType.cpp */,
    26982701                                041A1E33216FFDBC00789E0A /* PublicSuffix.cpp */,
    26992702                                F418BE141F71B7DC001970E6 /* RoundedRectTests.cpp */,
     
    41334136                                7CCE7F091A411AE600447C4C /* ParentFrame.cpp in Sources */,
    41344137                                7C83E0511D0A641800FEBCF3 /* ParsedContentRange.cpp in Sources */,
     4138                                AA96CAB621C7DB5000FD2F97 /* ParsedContentType.cpp in Sources */,
    41354139                                F44C79FF20F9E8710014478C /* ParserYieldTokenTests.mm in Sources */,
    41364140                                7CCE7F0A1A411AE600447C4C /* PasteboardNotifications.mm in Sources */,
Note: See TracChangeset for help on using the changeset viewer.