diff --git a/lib/MimeType.php b/lib/MimeType.php index ca67374..420d655 100644 --- a/lib/MimeType.php +++ b/lib/MimeType.php @@ -8,7 +8,7 @@ namespace MensBeam\Lax; /** {@inheritDoc} */ class MimeType extends \MensBeam\Mime\MimeType { - protected const MEDIUM_PATTERN = '<^[\t\r\n ]*(audio|video|image|text|application|document|executable)(?:$|[\t\r\n ;])>i'; + protected const LOOSE_TYPE_PATTERN = '<^[\t\r\n ]*([^;\t\r\n ]+)(?:$|[\t\r\n ]*(?:;.*)?)$>is'; protected const ATOM_TYPE_PATTERN = '<^\s*(|text|x?html)\s*$>i'; protected static $mime; @@ -17,7 +17,7 @@ class MimeType extends \MensBeam\Mime\MimeType { public static function parseLoose(string $type, ?Url $url = null): ?self { if ($normalized = self::parse($type)) { return $normalized; - } elseif (preg_match(self::MEDIUM_PATTERN, $type, $match)) { + } elseif (preg_match(self::LOOSE_TYPE_PATTERN, $type, $match) && preg_match(self::TOKEN_PATTERN, $match[1])) { $type = strtolower($match[1]); $type = ['document' => "text", 'executable' => "application"][$type] ?? $type; return new self($type); @@ -47,7 +47,7 @@ class MimeType extends \MensBeam\Mime\MimeType { */ public static function parseAtom(string $type): self { if (preg_match(self::ATOM_TYPE_PATTERN, $type, $match)) { - $type = ['' => "text/plain", 'text' => "text/plain", 'html' => "text/html", 'xhtml' => "application/xhtml+xml"][$match[1]] ?? null; + $type = ['' => "text/plain", 'text' => "text/plain", 'html' => "text/html", 'xhtml' => "application/xhtml+xml"][strtolower($match[1])] ?? null; assert(!is_null($type)); } return self::parse($type) ?? self::parse("unknown/unknown"); diff --git a/tests/cases/Util/MimeTypeTest.php b/tests/cases/Util/MimeTypeTest.php index 0cc0c44..37ae022 100644 --- a/tests/cases/Util/MimeTypeTest.php +++ b/tests/cases/Util/MimeTypeTest.php @@ -16,7 +16,7 @@ class MimeTypeTest extends \PHPUnit\Framework\TestCase { if ($exp) { $act = MimeType::parseLoose($input, $url); $this->assertInstanceOf(MimeType::class, $act); - $this->assertSame($exp, (string) $exp); + $this->assertSame($exp, (string) $act); } else { $this->assertNull(MimeType::parseLoose($input, $url)); } @@ -24,7 +24,48 @@ class MimeTypeTest extends \PHPUnit\Framework\TestCase { public function provideLooseParsings(): iterable { return [ - 'Sanity check' => ["text/html;charset=utf-8", 'TEXT/HTML ; CHARSET="utf-\8"; ook=', null], + 'Sanity check' => ["text/html;charset=utf-8", 'TEXT/HTML ; CHARSET="utf-\8"; ook=', null], + 'Major type only' => ["text", " text\t", null], + 'Document medium' => ["text", " document\t", null], + 'Executable medium' => ["application", " EXECUTABLE\t", null], + 'Arbitrary major type' => ["ook", " OOK\t", null], + 'Major type with parameters' => ["ook", " OOK; charset=utf-8", null], + 'Bogus major type' => [null, " OOK EEK", null], + 'Guessed type' => ["text/plain", "", new Url("http://example.com/blah.txt?q=abc")], + 'Medium preferrable to guess' => ["text", "text", new Url("http://example.com/blah.txt?q=abc")], + 'Data URI with type' => ["text/css", "", new Url("data:text/css;base64,")], + 'Data URI without type' => ["text/plain", "", new Url("data:,")], + 'Data URI with bogus type' => ["text/plain", "", new Url("data:/,")], ]; } + + /** @dataProvider provideAtomParsings */ + public function testParseAnAtomType(string $input, ?string $exp): void { + $act = MimeType::parseAtom($input); + $this->assertInstanceOf(MimeType::class, $act); + $this->assertSame($exp ?? "unknown/unknown", (string) $act); + } + + public function provideAtomParsings(): iterable { + return [ + 'Sanity check' => ['TEXT/HTML; CHARSET="utf-\8"; ook=', "text/html;charset=utf-8"], + 'Plain text' => ['text', "text/plain"], + 'Plain text UC' => ['TEXT', "text/plain"], + 'HTML' => ['html', "text/html"], + 'HTML UC' => ['HTML', "text/html"], + 'XHTML' => ['xhtml', "application/xhtml+xml"], + 'XHTML UC' => ['XHTML', "application/xhtml+xml"], + 'Blank type' => ['', "text/plain"], + 'Bogus type' => ['image', null], + 'arbitrary type' => ['FONT/TTF', "font/ttf"], + ]; + } + + public function testManipulateAnIncompleteType():void { + $t = MimeType::parseLoose("text; charset=utf-8"); + $this->assertSame("text", $t->type); + $this->assertSame("", $t->subtype); + $this->assertSame("text", $t->essence); + $this->assertSame([], $t->params); + } }