Align with Fetch on data: URLs
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jan 2019 07:58:48 +0000 (07:58 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jan 2019 07:58:48 +0000 (07:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182325

Patch by Rob Buis <rbuis@igalia.com> on 2019-01-29
Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

Update improved test expectations.

* web-platform-tests/fetch/data-urls/processing.any-expected.txt:
* web-platform-tests/fetch/data-urls/processing.any.worker-expected.txt:
* web-platform-tests/xhr/overridemimetype-blob-expected.txt:

Source/WebCore:

Implement most remaining steps for data: URL processing [1].
Serialization is still to be implemented.

To make the code in DataURLDecoder::parseMediaType more efficient,
refactor ParsedContentType so that validation and parsing is done
in one pass.

Test: web-platform-tests/fetch/data-urls/processing.any.js

[1] https://fetch.spec.whatwg.org/#data-urls

* Modules/encryptedmedia/CDM.cpp:
(WebCore::CDM::getSupportedCapabilitiesForAudioVideoType):
* platform/network/DataURLDecoder.cpp:
(WebCore::DataURLDecoder::parseMediaType):
(WebCore::DataURLDecoder::DecodeTask::process):
* platform/network/MIMEHeader.cpp:
(WebCore::MIMEHeader::parseHeader):
* platform/network/ParsedContentType.cpp:
(WebCore::containsNewline):
(WebCore::ParsedContentType::parseContentType):
(WebCore::ParsedContentType::create):
(WebCore::isValidContentType):
(WebCore::ParsedContentType::ParsedContentType):
(WebCore::DummyParsedContentType::setContentType const): Deleted.
(WebCore::DummyParsedContentType::setContentTypeParameter const): Deleted.
(WebCore::parseContentType): Deleted.
* platform/network/ParsedContentType.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240706 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/data-urls/processing.any-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/data-urls/processing.any.worker-expected.txt
LayoutTests/imported/w3c/web-platform-tests/xhr/overridemimetype-blob-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/encryptedmedia/CDM.cpp
Source/WebCore/platform/network/DataURLDecoder.cpp
Source/WebCore/platform/network/MIMEHeader.cpp
Source/WebCore/platform/network/ParsedContentType.cpp
Source/WebCore/platform/network/ParsedContentType.h

index a6538c6..2347408 100644 (file)
@@ -1,3 +1,16 @@
+2019-01-29  Rob Buis  <rbuis@igalia.com>
+
+        Align with Fetch on data: URLs
+        https://bugs.webkit.org/show_bug.cgi?id=182325
+
+        Reviewed by Alex Christensen.
+
+        Update improved test expectations.
+
+        * web-platform-tests/fetch/data-urls/processing.any-expected.txt:
+        * web-platform-tests/fetch/data-urls/processing.any.worker-expected.txt:
+        * web-platform-tests/xhr/overridemimetype-blob-expected.txt:
+
 2019-01-29  cathie chen  <cathiechen@igalia.com>
 
         Import Resize Observer test cases from WPTs
index c878ab6..4398486 100644 (file)
@@ -3,7 +3,7 @@ CONSOLE MESSAGE: Fetch API cannot load data:text/html.
 CONSOLE MESSAGE: Fetch API cannot load data:text/html    ;charset=x.
 
 PASS Setup. 
-FAIL "data://test/,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "//test/"
+PASS "data://test/,X" 
 PASS "data://test:test/,X" 
 PASS "data:,X" 
 PASS "data:" 
@@ -13,30 +13,30 @@ PASS "data:,"
 FAIL "data:,X#X" assert_array_equals: lengths differ, expected 1 got 3
 PASS "data:,%FF" 
 PASS "data:text/plain,X" 
-FAIL "data:text/plain ,X" assert_equals: expected (string) "text/plain" but got (object) null
+PASS "data:text/plain ,X" 
 PASS "data:text/plain%20,X" 
 FAIL "data:text/plain\f,X" assert_equals: expected "text/plain%0c" but got "text/plain%0C"
 FAIL "data:text/plain%0C,X" assert_equals: expected "text/plain%0c" but got "text/plain%0C"
 FAIL "data:text/plain;,X" assert_equals: expected "text/plain" but got "text/plain;"
-FAIL "data:;x=x;charset=x,X" assert_equals: expected "text/plain;x=x;charset=x" but got ";x=x;charset=x"
-FAIL "data:;x=x,X" assert_equals: expected "text/plain;x=x" but got ";x=x"
+PASS "data:;x=x;charset=x,X" 
+PASS "data:;x=x,X" 
 PASS "data:text/plain;charset=windows-1252,%C2%B1" 
 FAIL "data:text/plain;Charset=UTF-8,%C2%B1" assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;Charset=UTF-8"
 PASS "data:image/gif,%C2%B1" 
 FAIL "data:IMAGE/gif,%C2%B1" assert_equals: expected "image/gif" but got "IMAGE/gif"
 FAIL "data:IMAGE/gif;hi=x,%C2%B1" assert_equals: expected "image/gif;hi=x" but got "IMAGE/gif;hi=x"
 FAIL "data:IMAGE/gif;CHARSET=x,%C2%B1" assert_equals: expected "image/gif;charset=x" but got "IMAGE/gif;CHARSET=x"
-FAIL "data: ,%FF" assert_equals: expected (string) "text/plain;charset=US-ASCII" but got (object) null
-FAIL "data:%20,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%20"
-FAIL "data:\f,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%0C"
-FAIL "data:%1F,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%1F"
-FAIL "data:\0,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%00"
-FAIL "data:%00,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%00"
-FAIL "data:text/html  ,X" assert_equals: expected (string) "text/html" but got (object) null
-FAIL "data:text / html,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "text / html"
-FAIL "data:†,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "%E2%80%A0"
+PASS "data: ,%FF" 
+PASS "data:%20,%FF" 
+PASS "data:\f,%FF" 
+PASS "data:%1F,%FF" 
+PASS "data:\0,%FF" 
+PASS "data:%00,%FF" 
+PASS "data:text/html  ,X" 
+PASS "data:text / html,X" 
+PASS "data:†,X" 
 FAIL "data:†/†,X" assert_equals: expected "%e2%80%a0/%e2%80%a0" but got "%E2%80%A0/%E2%80%A0"
-FAIL "data:X,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "X"
+PASS "data:X,X" 
 PASS "data:image/png,X X" 
 PASS "data:application/javascript,X X" 
 PASS "data:application/xml,X X" 
@@ -45,32 +45,32 @@ PASS "data:text/plain,X X"
 PASS "data:unknown/unknown,X X" 
 FAIL "data:text/plain;a=\",\",X" assert_equals: expected "text/plain;a=\"\"" but got "text/plain;a=\""
 PASS "data:text/plain;a=%2C,X" 
-FAIL "data:;base64;base64,WA" assert_equals: expected "text/plain" but got ";base64"
+FAIL "data:;base64;base64,WA" assert_equals: expected "text/plain" but got "text/plain;base64"
 FAIL "data:x/x;base64;base64,WA" assert_equals: expected "x/x" but got "x/x;base64"
 FAIL "data:x/x;base64;charset=x,WA" assert_equals: expected "x/x;charset=x" but got "x/x;base64;charset=x"
 FAIL "data:x/x;base64;charset=x;base64,WA" assert_equals: expected "x/x;charset=x" but got "x/x;base64;charset=x"
 FAIL "data:x/x;base64;base64x,WA" assert_equals: expected "x/x" but got "x/x;base64;base64x"
 PASS "data:;base64,W%20A" 
 PASS "data:;base64,W%0CA" 
-FAIL "data:x;base64x,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "x;base64x"
-FAIL "data:x;base64;x,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "x;base64;x"
-FAIL "data:x;base64=x,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "x;base64=x"
+PASS "data:x;base64x,WA" 
+PASS "data:x;base64;x,WA" 
+PASS "data:x;base64=x,WA" 
 FAIL "data:; base64,WA" assert_array_equals: lengths differ, expected 1 got 2
 FAIL "data:;  base64,WA" assert_array_equals: lengths differ, expected 1 got 2
 FAIL "data:  ;charset=x   ;  base64,WA" assert_array_equals: lengths differ, expected 1 got 2
-FAIL "data:;base64;,WA" assert_equals: expected "text/plain" but got ";base64;"
+FAIL "data:;base64;,WA" assert_equals: expected "text/plain" but got "text/plain;base64;"
 FAIL "data:;base64 ,WA" assert_array_equals: lengths differ, expected 1 got 2
 FAIL "data:;base64   ,WA" assert_array_equals: lengths differ, expected 1 got 2
-FAIL "data:;base 64,WA" assert_equals: expected "text/plain" but got ";base 64"
+FAIL "data:;base 64,WA" assert_equals: expected "text/plain" but got "text/plain;base 64"
 PASS "data:;BASe64,WA" 
-FAIL "data:;%62ase64,WA" assert_equals: expected "text/plain" but got ";%62ase64"
-FAIL "data:%3Bbase64,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "%3Bbase64"
-FAIL "data:;charset=x,X" assert_equals: expected "text/plain;charset=x" but got ";charset=x"
-FAIL "data:; charset=x,X" assert_equals: expected "text/plain;charset=x" but got "; charset=x"
-FAIL "data:;charset =x,X" assert_equals: expected "text/plain" but got ";charset =x"
-FAIL "data:;charset= x,X" assert_equals: expected "text/plain;charset=\" x\"" but got ";charset= x"
-FAIL "data:;charset=,X" assert_equals: expected "text/plain" but got ";charset="
-FAIL "data:;charset,X" assert_equals: expected "text/plain" but got ";charset"
-FAIL "data:;charset=\"x\",X" assert_equals: expected "text/plain;charset=x" but got ";charset=\"x\""
-FAIL "data:;CHARSET=\"X\",X" assert_equals: expected "text/plain;charset=X" but got ";CHARSET=\"X\""
+FAIL "data:;%62ase64,WA" assert_equals: expected "text/plain" but got "text/plain;%62ase64"
+PASS "data:%3Bbase64,WA" 
+PASS "data:;charset=x,X" 
+FAIL "data:; charset=x,X" assert_equals: expected "text/plain;charset=x" but got "text/plain; charset=x"
+FAIL "data:;charset =x,X" assert_equals: expected "text/plain" but got "text/plain;charset =x"
+FAIL "data:;charset= x,X" assert_equals: expected "text/plain;charset=\" x\"" but got "text/plain;charset= x"
+FAIL "data:;charset=,X" assert_equals: expected "text/plain" but got "text/plain;charset="
+FAIL "data:;charset,X" assert_equals: expected "text/plain" but got "text/plain;charset"
+FAIL "data:;charset=\"x\",X" assert_equals: expected "text/plain;charset=x" but got "text/plain;charset=\"x\""
+FAIL "data:;CHARSET=\"X\",X" assert_equals: expected "text/plain;charset=X" but got "text/plain;CHARSET=\"X\""
 
index 1c23aaa..f624ea3 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS Setup. 
-FAIL "data://test/,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "//test/"
+PASS "data://test/,X" 
 PASS "data://test:test/,X" 
 PASS "data:,X" 
 PASS "data:" 
@@ -10,30 +10,30 @@ PASS "data:,"
 FAIL "data:,X#X" assert_array_equals: lengths differ, expected 1 got 3
 PASS "data:,%FF" 
 PASS "data:text/plain,X" 
-FAIL "data:text/plain ,X" assert_equals: expected (string) "text/plain" but got (object) null
+PASS "data:text/plain ,X" 
 PASS "data:text/plain%20,X" 
 FAIL "data:text/plain\f,X" assert_equals: expected "text/plain%0c" but got "text/plain%0C"
 FAIL "data:text/plain%0C,X" assert_equals: expected "text/plain%0c" but got "text/plain%0C"
 FAIL "data:text/plain;,X" assert_equals: expected "text/plain" but got "text/plain;"
-FAIL "data:;x=x;charset=x,X" assert_equals: expected "text/plain;x=x;charset=x" but got ";x=x;charset=x"
-FAIL "data:;x=x,X" assert_equals: expected "text/plain;x=x" but got ";x=x"
+PASS "data:;x=x;charset=x,X" 
+PASS "data:;x=x,X" 
 PASS "data:text/plain;charset=windows-1252,%C2%B1" 
 FAIL "data:text/plain;Charset=UTF-8,%C2%B1" assert_equals: expected "text/plain;charset=UTF-8" but got "text/plain;Charset=UTF-8"
 PASS "data:image/gif,%C2%B1" 
 FAIL "data:IMAGE/gif,%C2%B1" assert_equals: expected "image/gif" but got "IMAGE/gif"
 FAIL "data:IMAGE/gif;hi=x,%C2%B1" assert_equals: expected "image/gif;hi=x" but got "IMAGE/gif;hi=x"
 FAIL "data:IMAGE/gif;CHARSET=x,%C2%B1" assert_equals: expected "image/gif;charset=x" but got "IMAGE/gif;CHARSET=x"
-FAIL "data: ,%FF" assert_equals: expected (string) "text/plain;charset=US-ASCII" but got (object) null
-FAIL "data:%20,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%20"
-FAIL "data:\f,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%0C"
-FAIL "data:%1F,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%1F"
-FAIL "data:\0,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%00"
-FAIL "data:%00,%FF" assert_equals: expected "text/plain;charset=US-ASCII" but got "%00"
-FAIL "data:text/html  ,X" assert_equals: expected (string) "text/html" but got (object) null
-FAIL "data:text / html,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "text / html"
-FAIL "data:†,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "%E2%80%A0"
+PASS "data: ,%FF" 
+PASS "data:%20,%FF" 
+PASS "data:\f,%FF" 
+PASS "data:%1F,%FF" 
+PASS "data:\0,%FF" 
+PASS "data:%00,%FF" 
+PASS "data:text/html  ,X" 
+PASS "data:text / html,X" 
+PASS "data:†,X" 
 FAIL "data:†/†,X" assert_equals: expected "%e2%80%a0/%e2%80%a0" but got "%E2%80%A0/%E2%80%A0"
-FAIL "data:X,X" assert_equals: expected "text/plain;charset=US-ASCII" but got "X"
+PASS "data:X,X" 
 PASS "data:image/png,X X" 
 PASS "data:application/javascript,X X" 
 PASS "data:application/xml,X X" 
@@ -42,32 +42,32 @@ PASS "data:text/plain,X X"
 PASS "data:unknown/unknown,X X" 
 FAIL "data:text/plain;a=\",\",X" assert_equals: expected "text/plain;a=\"\"" but got "text/plain;a=\""
 PASS "data:text/plain;a=%2C,X" 
-FAIL "data:;base64;base64,WA" assert_equals: expected "text/plain" but got ";base64"
+FAIL "data:;base64;base64,WA" assert_equals: expected "text/plain" but got "text/plain;base64"
 FAIL "data:x/x;base64;base64,WA" assert_equals: expected "x/x" but got "x/x;base64"
 FAIL "data:x/x;base64;charset=x,WA" assert_equals: expected "x/x;charset=x" but got "x/x;base64;charset=x"
 FAIL "data:x/x;base64;charset=x;base64,WA" assert_equals: expected "x/x;charset=x" but got "x/x;base64;charset=x"
 FAIL "data:x/x;base64;base64x,WA" assert_equals: expected "x/x" but got "x/x;base64;base64x"
 PASS "data:;base64,W%20A" 
 PASS "data:;base64,W%0CA" 
-FAIL "data:x;base64x,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "x;base64x"
-FAIL "data:x;base64;x,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "x;base64;x"
-FAIL "data:x;base64=x,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "x;base64=x"
+PASS "data:x;base64x,WA" 
+PASS "data:x;base64;x,WA" 
+PASS "data:x;base64=x,WA" 
 FAIL "data:; base64,WA" assert_array_equals: lengths differ, expected 1 got 2
 FAIL "data:;  base64,WA" assert_array_equals: lengths differ, expected 1 got 2
 FAIL "data:  ;charset=x   ;  base64,WA" assert_array_equals: lengths differ, expected 1 got 2
-FAIL "data:;base64;,WA" assert_equals: expected "text/plain" but got ";base64;"
+FAIL "data:;base64;,WA" assert_equals: expected "text/plain" but got "text/plain;base64;"
 FAIL "data:;base64 ,WA" assert_array_equals: lengths differ, expected 1 got 2
 FAIL "data:;base64   ,WA" assert_array_equals: lengths differ, expected 1 got 2
-FAIL "data:;base 64,WA" assert_equals: expected "text/plain" but got ";base 64"
+FAIL "data:;base 64,WA" assert_equals: expected "text/plain" but got "text/plain;base 64"
 PASS "data:;BASe64,WA" 
-FAIL "data:;%62ase64,WA" assert_equals: expected "text/plain" but got ";%62ase64"
-FAIL "data:%3Bbase64,WA" assert_equals: expected "text/plain;charset=US-ASCII" but got "%3Bbase64"
-FAIL "data:;charset=x,X" assert_equals: expected "text/plain;charset=x" but got ";charset=x"
-FAIL "data:; charset=x,X" assert_equals: expected "text/plain;charset=x" but got "; charset=x"
-FAIL "data:;charset =x,X" assert_equals: expected "text/plain" but got ";charset =x"
-FAIL "data:;charset= x,X" assert_equals: expected "text/plain;charset=\" x\"" but got ";charset= x"
-FAIL "data:;charset=,X" assert_equals: expected "text/plain" but got ";charset="
-FAIL "data:;charset,X" assert_equals: expected "text/plain" but got ";charset"
-FAIL "data:;charset=\"x\",X" assert_equals: expected "text/plain;charset=x" but got ";charset=\"x\""
-FAIL "data:;CHARSET=\"X\",X" assert_equals: expected "text/plain;charset=X" but got ";CHARSET=\"X\""
+FAIL "data:;%62ase64,WA" assert_equals: expected "text/plain" but got "text/plain;%62ase64"
+PASS "data:%3Bbase64,WA" 
+PASS "data:;charset=x,X" 
+FAIL "data:; charset=x,X" assert_equals: expected "text/plain;charset=x" but got "text/plain; charset=x"
+FAIL "data:;charset =x,X" assert_equals: expected "text/plain" but got "text/plain;charset =x"
+FAIL "data:;charset= x,X" assert_equals: expected "text/plain;charset=\" x\"" but got "text/plain;charset= x"
+FAIL "data:;charset=,X" assert_equals: expected "text/plain" but got "text/plain;charset="
+FAIL "data:;charset,X" assert_equals: expected "text/plain" but got "text/plain;charset"
+FAIL "data:;charset=\"x\",X" assert_equals: expected "text/plain;charset=x" but got "text/plain;charset=\"x\""
+FAIL "data:;CHARSET=\"X\",X" assert_equals: expected "text/plain;charset=X" but got "text/plain;CHARSET=\"X\""
 
index b84b5e8..a7543a3 100644 (file)
@@ -51,7 +51,7 @@ PASS 46) MIME types need to be parsed and serialized:
 PASS 47) MIME types need to be parsed and serialized: / 
 PASS 48) MIME types need to be parsed and serialized: bogus 
 PASS 49) MIME types need to be parsed and serialized: bogus/ 
-FAIL 50) MIME types need to be parsed and serialized: bogus/  assert_equals: expected "application/octet-stream" but got "bogus/"
+PASS 50) MIME types need to be parsed and serialized: bogus/  
 PASS 51) MIME types need to be parsed and serialized: bogus/bogus/; 
 PASS 52) MIME types need to be parsed and serialized: </> 
 PASS 53) MIME types need to be parsed and serialized: (/) 
index 814ad65..120c31f 100644 (file)
@@ -1,3 +1,39 @@
+2019-01-29  Rob Buis  <rbuis@igalia.com>
+
+        Align with Fetch on data: URLs
+        https://bugs.webkit.org/show_bug.cgi?id=182325
+
+        Reviewed by Alex Christensen.
+
+        Implement most remaining steps for data: URL processing [1].
+        Serialization is still to be implemented.
+
+        To make the code in DataURLDecoder::parseMediaType more efficient,
+        refactor ParsedContentType so that validation and parsing is done
+        in one pass.
+
+        Test: web-platform-tests/fetch/data-urls/processing.any.js
+
+        [1] https://fetch.spec.whatwg.org/#data-urls
+
+        * Modules/encryptedmedia/CDM.cpp:
+        (WebCore::CDM::getSupportedCapabilitiesForAudioVideoType):
+        * platform/network/DataURLDecoder.cpp:
+        (WebCore::DataURLDecoder::parseMediaType):
+        (WebCore::DataURLDecoder::DecodeTask::process):
+        * platform/network/MIMEHeader.cpp:
+        (WebCore::MIMEHeader::parseHeader):
+        * platform/network/ParsedContentType.cpp:
+        (WebCore::containsNewline):
+        (WebCore::ParsedContentType::parseContentType):
+        (WebCore::ParsedContentType::create):
+        (WebCore::isValidContentType):
+        (WebCore::ParsedContentType::ParsedContentType):
+        (WebCore::DummyParsedContentType::setContentType const): Deleted.
+        (WebCore::DummyParsedContentType::setContentTypeParameter const): Deleted.
+        (WebCore::parseContentType): Deleted.
+        * platform/network/ParsedContentType.h:
+
 2019-01-29  Eric Carlson  <eric.carlson@apple.com>
 
         [MSE] add more source buffer logging
index ebf067f..40119c8 100644 (file)
@@ -433,12 +433,12 @@ Optional<Vector<MediaKeySystemMediaCapability>> CDM::getSupportedCapabilitiesFor
             return WTF::nullopt;
 
         // 3.4. If content type is an invalid or unrecognized MIME type, continue to the next iteration.
-        if (!isValidContentType(requestedCapability.contentType, Mode::Rfc2045))
+        Optional<ParsedContentType> contentType = ParsedContentType::create(requestedCapability.contentType, Mode::Rfc2045);
+        if (!contentType)
             continue;
 
         // 3.5. Let container be the container type specified by content type.
-        ParsedContentType contentType { requestedCapability.contentType };
-        String container = contentType.mimeType();
+        String container = contentType->mimeType();
 
         // 3.6. If the user agent does not support container, continue to the next iteration. The case-sensitivity
         //      of string comparisons is determined by the appropriate RFC.
@@ -446,8 +446,8 @@ Optional<Vector<MediaKeySystemMediaCapability>> CDM::getSupportedCapabilitiesFor
         // 3.8. If the user agent does not recognize one or more parameters, continue to the next iteration.
         // 3.9. Let media types be the set of codecs and codec constraints specified by parameters. The case-sensitivity
         //      of string comparisons is determined by the appropriate RFC or other specification.
-        String codecs = contentType.parameterValueForName("codecs");
-        if (contentType.parameterCount() > (codecs.isEmpty() ? 0 : 1))
+        String codecs = contentType->parameterValueForName("codecs");
+        if (contentType->parameterCount() > (codecs.isEmpty() ? 0 : 1))
             continue;
 
         // 3.10. If media types is empty:
@@ -467,7 +467,7 @@ Optional<Vector<MediaKeySystemMediaCapability>> CDM::getSupportedCapabilitiesFor
         //       combination of container, media types, robustness and local accumulated configuration in combination
         //       with restrictions:
         MediaEngineSupportParameters parameters;
-        parameters.type = ContentType(contentType.mimeType());
+        parameters.type = ContentType(contentType->mimeType());
         if (!MediaPlayer::supportsType(parameters)) {
             // Try with Media Source:
             parameters.isMediaSource = true;
index 59ddf07..b02c8d9 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "DecodeEscapeSequences.h"
 #include "HTTPParsers.h"
+#include "ParsedContentType.h"
 #include "SharedBuffer.h"
 #include "TextEncoding.h"
 #include <wtf/MainThread.h>
@@ -47,18 +48,9 @@ static WorkQueue& decodeQueue()
 
 static Result parseMediaType(const String& mediaType)
 {
-    auto mimeType = extractMIMETypeFromMediaType(mediaType);
-    auto charset = extractCharsetFromMediaType(mediaType);
-
-    // https://tools.ietf.org/html/rfc2397
-    // If <mediatype> is omitted, it defaults to text/plain;charset=US-ASCII. As a shorthand,
-    // "text/plain" can be omitted but the charset parameter supplied.
-    if (mimeType.isEmpty()) {
-        mimeType = "text/plain"_s;
-        if (charset.isEmpty())
-            charset = "US-ASCII"_s;
-    }
-    return { mimeType, charset, !mediaType.isEmpty() ? mediaType : "text/plain;charset=US-ASCII", nullptr };
+    if (Optional<ParsedContentType> parsedContentType = ParsedContentType::create(mediaType))
+        return { parsedContentType->mimeType(), parsedContentType->charset(), mediaType, nullptr };
+    return { "text/plain"_s, "US-ASCII"_s, "text/plain;charset=US-ASCII"_s, nullptr };
 }
 
 struct DecodeTask {
@@ -87,6 +79,9 @@ public:
         auto header = StringView(urlString).substring(strlen(dataString), headerEnd - strlen(dataString));
         isBase64 = header.endsWithIgnoringASCIICase(StringView(base64String));
         auto mediaType = (isBase64 ? header.substring(0, header.length() - strlen(base64String)) : header).toString();
+        mediaType = mediaType.stripWhiteSpace();
+        if (mediaType.startsWith(';'))
+            mediaType.insert("text/plain", 0);
         result = parseMediaType(mediaType);
 
         return true;
index b1daceb..3576682 100644 (file)
@@ -87,13 +87,19 @@ RefPtr<MIMEHeader> MIMEHeader::parseHeader(SharedBufferChunkReader& buffer)
     KeyValueMap keyValuePairs = retrieveKeyValuePairs(buffer);
     KeyValueMap::iterator mimeParametersIterator = keyValuePairs.find("content-type");
     if (mimeParametersIterator != keyValuePairs.end()) {
-        ParsedContentType parsedContentType(mimeParametersIterator->value, Mode::Rfc2045);
-        mimeHeader->m_contentType = parsedContentType.mimeType();
+        String contentType, charset, multipartType, endOfPartBoundary;
+        if (auto parsedContentType = ParsedContentType::create(mimeParametersIterator->value)) {
+            contentType = parsedContentType->mimeType();
+            charset = parsedContentType->charset().stripWhiteSpace();
+            multipartType = parsedContentType->parameterValueForName("type");
+            endOfPartBoundary = parsedContentType->parameterValueForName("boundary");
+        }
+        mimeHeader->m_contentType = contentType;
         if (!mimeHeader->isMultipart())
-            mimeHeader->m_charset = parsedContentType.charset().stripWhiteSpace();
+            mimeHeader->m_charset = charset;
         else {
-            mimeHeader->m_multipartType = parsedContentType.parameterValueForName("type");
-            mimeHeader->m_endOfPartBoundary = parsedContentType.parameterValueForName("boundary");
+            mimeHeader->m_multipartType = multipartType;
+            mimeHeader->m_endOfPartBoundary = endOfPartBoundary;
             if (mimeHeader->m_endOfPartBoundary.isNull()) {
                 LOG_ERROR("No boundary found in multipart MIME header.");
                 return nullptr;
index 67a433c..ceb54a7 100644 (file)
 
 namespace WebCore {
 
-class DummyParsedContentType {
-public:
-    void setContentType(const SubstringRange&, Mode) const { }
-    void setContentTypeParameter(const String&, const String&, Mode) const { }
-};
-
 static void skipSpaces(const String& input, unsigned& startIndex)
 {
     while (startIndex < input.length() && input[startIndex] == ' ')
@@ -189,47 +183,53 @@ static bool isNotSemicolonOrEqualSign(UChar ch)
     return ch != ';' && ch != '=';
 }
 
-template <class ReceiverType>
-bool parseContentType(const String& contentType, ReceiverType& receiver, Mode mode)
+static bool containsNewline(UChar ch)
+{
+    return ch == '\r' || ch == '\n';
+}
+
+bool ParsedContentType::parseContentType(Mode mode)
 {
+    if (m_contentType.find(containsNewline) != notFound)
+        return false;
     unsigned index = 0;
-    unsigned contentTypeLength = contentType.length();
-    skipSpaces(contentType, index);
+    unsigned contentTypeLength = m_contentType.length();
+    skipSpaces(m_contentType, index);
     if (index >= contentTypeLength)  {
-        LOG_ERROR("Invalid Content-Type string '%s'", contentType.ascii().data());
+        LOG_ERROR("Invalid Content-Type string '%s'", m_contentType.ascii().data());
         return false;
     }
 
     unsigned contentTypeStart = index;
-    auto typeRange = parseToken(contentType, index, isNotForwardSlash, mode);
-    if (!typeRange || containsNonTokenCharacters(contentType, *typeRange)) {
+    auto typeRange = parseToken(m_contentType, index, isNotForwardSlash, mode);
+    if (!typeRange || containsNonTokenCharacters(m_contentType, *typeRange)) {
         LOG_ERROR("Invalid Content-Type, invalid type value.");
         return false;
     }
 
-    if (contentType[index++] != '/') {
+    if (m_contentType[index++] != '/') {
         LOG_ERROR("Invalid Content-Type, missing '/'.");
         return false;
     }
 
-    auto subTypeRange = parseToken(contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
-    if (!subTypeRange || containsNonTokenCharacters(contentType, *subTypeRange)) {
+    auto subTypeRange = parseToken(m_contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
+    if (!subTypeRange || containsNonTokenCharacters(m_contentType, *subTypeRange)) {
         LOG_ERROR("Invalid Content-Type, invalid subtype value.");
         return false;
     }
 
     // There should not be any quoted strings until we reach the parameters.
-    size_t semiColonIndex = contentType.find(';', contentTypeStart);
+    size_t semiColonIndex = m_contentType.find(';', contentTypeStart);
     if (semiColonIndex == notFound) {
-        receiver.setContentType(SubstringRange(contentTypeStart, contentTypeLength - contentTypeStart), mode);
+        setContentType(SubstringRange(contentTypeStart, contentTypeLength - contentTypeStart), mode);
         return true;
     }
 
-    receiver.setContentType(SubstringRange(contentTypeStart, semiColonIndex - contentTypeStart), mode);
+    setContentType(SubstringRange(contentTypeStart, semiColonIndex - contentTypeStart), mode);
     index = semiColonIndex + 1;
     while (true) {
-        skipSpaces(contentType, index);
-        auto keyRange = parseToken(contentType, index, isNotSemicolonOrEqualSign, mode);
+        skipSpaces(m_contentType, index);
+        auto keyRange = parseToken(m_contentType, index, isNotSemicolonOrEqualSign, mode);
         if (mode == Mode::Rfc2045 && (!keyRange || index >= contentTypeLength)) {
             LOG_ERROR("Invalid Content-Type parameter name.");
             return false;
@@ -237,31 +237,31 @@ bool parseContentType(const String& contentType, ReceiverType& receiver, Mode mo
 
         // Should we tolerate spaces here?
         if (mode == Mode::Rfc2045) {
-            if (contentType[index++] != '=' || index >= contentTypeLength) {
+            if (m_contentType[index++] != '=' || index >= contentTypeLength) {
                 LOG_ERROR("Invalid Content-Type malformed parameter.");
                 return false;
             }
         } else {
             if (index >= contentTypeLength)
                 break;
-            if (contentType[index] != '=' && contentType[index] != ';') {
+            if (m_contentType[index] != '=' && m_contentType[index] != ';') {
                 LOG_ERROR("Invalid Content-Type malformed parameter.");
                 return false;
             }
-            if (contentType[index++] == ';')
+            if (m_contentType[index++] == ';')
                 continue;
         }
 
-        String parameterName = substringForRange(contentType, *keyRange);
+        String parameterName = substringForRange(m_contentType, *keyRange);
 
         // Should we tolerate spaces here?
         Optional<SubstringRange> valueRange;
-        if (contentType[index] == '"') {
-            valueRange = parseQuotedString(contentType, index, mode);
+        if (m_contentType[index] == '"') {
+            valueRange = parseQuotedString(m_contentType, index, mode);
             if (mode == Mode::MimeSniff)
-                parseToken(contentType, index, isNotSemicolon, mode);
+                parseToken(m_contentType, index, isNotSemicolon, mode);
         } else
-            valueRange = parseToken(contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
+            valueRange = parseToken(m_contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
 
         if (!valueRange) {
             if (mode == Mode::MimeSniff)
@@ -270,14 +270,14 @@ bool parseContentType(const String& contentType, ReceiverType& receiver, Mode mo
             return false;
         }
 
-        String parameterValue = substringForRange(contentType, *valueRange);
+        String parameterValue = substringForRange(m_contentType, *valueRange);
         // Should we tolerate spaces here?
-        if (mode == Mode::Rfc2045 && index < contentTypeLength && contentType[index++] != ';') {
+        if (mode == Mode::Rfc2045 && index < contentTypeLength && m_contentType[index++] != ';') {
             LOG_ERROR("Invalid Content-Type, invalid character at the end of key/value parameter.");
             return false;
         }
 
-        receiver.setContentTypeParameter(parameterName, parameterValue, mode);
+        setContentTypeParameter(parameterName, parameterValue, mode);
 
         if (index >= contentTypeLength)
             return true;
@@ -286,19 +286,22 @@ bool parseContentType(const String& contentType, ReceiverType& receiver, Mode mo
     return true;
 }
 
-bool isValidContentType(const String& contentType, Mode mode)
+Optional<ParsedContentType> ParsedContentType::create(const String& contentType, Mode mode)
 {
-    if (contentType.contains('\r') || contentType.contains('\n'))
-        return false;
+    ParsedContentType parsedContentType(mode == Mode::Rfc2045 ? contentType : contentType.stripWhiteSpace());
+    if (!parsedContentType.parseContentType(mode))
+        return WTF::nullopt;
+    return { WTFMove(parsedContentType) };
+}
 
-    DummyParsedContentType parsedContentType = DummyParsedContentType();
-    return parseContentType<DummyParsedContentType>(contentType, parsedContentType, mode);
+bool isValidContentType(const String& contentType, Mode mode)
+{
+    return ParsedContentType::create(contentType, mode) != WTF::nullopt;
 }
 
-ParsedContentType::ParsedContentType(const String& contentType, Mode mode)
-    : m_contentType(contentType.stripWhiteSpace())
+ParsedContentType::ParsedContentType(const String& contentType)
+    : m_contentType(contentType)
 {
-    parseContentType<ParsedContentType>(m_contentType, *this, mode);
 }
 
 String ParsedContentType::charset() const
index 949010b..de7df88 100644 (file)
@@ -47,7 +47,8 @@ WEBCORE_EXPORT bool isValidContentType(const String&, Mode = Mode::MimeSniff);
 // FIXME: add support for comments.
 class ParsedContentType {
 public:
-    explicit ParsedContentType(const String&, Mode = Mode::MimeSniff);
+    static Optional<ParsedContentType> create(const String&, Mode = Mode::MimeSniff);
+    ParsedContentType(ParsedContentType&&) = default;
 
     String mimeType() const { return m_mimeType; }
     String charset() const;
@@ -57,8 +58,10 @@ public:
     size_t parameterCount() const;
 
 private:
-    template<class ReceiverType>
-    friend bool parseContentType(const String&, ReceiverType&, Mode);
+    ParsedContentType(const String&);
+    ParsedContentType(const ParsedContentType&) = delete;
+    ParsedContentType& operator=(ParsedContentType const&) = delete;
+    bool parseContentType(Mode);
     void setContentType(const SubstringRange&, Mode);
     void setContentTypeParameter(const String&, const String&, Mode);