diff --git a/dom/base/MimeType.cpp b/dom/base/MimeType.cpp new file mode 100644 index 000000000000..0bff692cf8f2 --- /dev/null +++ b/dom/base/MimeType.cpp @@ -0,0 +1,256 @@ +#include "MimeType.h" +#include "nsUnicharUtils.h" + +namespace { + static inline bool IsHTTPTokenPoint(const char16_t c) { + return c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || + c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' || + c == '^' || c == '_' || c == '`' || c == '|' || c == '~' || + mozilla::IsAsciiAlphanumeric(c); + } + + static inline bool IsHTTPQuotedStringTokenPoint(const char16_t c) { + return c == 0x9 || (c >= ' ' && c <= '~') || (c >= 0x80 && c <= 0xFF); + } +} + +/* static */ mozilla::UniquePtr +MimeType::Parse(const nsAString& aMimeType) +{ + // See https://mimesniff.spec.whatwg.org/#parsing-a-mime-type + + // Steps 1-2 + const char16_t* pos = aMimeType.BeginReading(); + const char16_t* end = aMimeType.EndReading(); + while (pos < end && mozilla::IsAsciiWhitespace(*pos)) { + ++pos; + } + if (pos == end) { + return nullptr; + } + while (end > pos && mozilla::IsAsciiWhitespace(*(end - 1))) { + --end; + } + + // Steps 3-4 + const char16_t* typeStart = pos; + while (pos < end && *pos != '/') { + if (!IsHTTPTokenPoint(*pos)) { + return nullptr; + } + ++pos; + } + const char16_t* typeEnd = pos; + if (typeStart == typeEnd) { + return nullptr; + } + + // Step 5 + if (pos == end) { + return nullptr; + } + + // Step 6 + ++pos; + + // Step 7-9 + const char16_t* subtypeStart = pos; + const char16_t* subtypeEnd = nullptr; + while (pos < end && *pos != ';') { + if (!IsHTTPTokenPoint(*pos)) { + // If we hit a whitespace, check that the rest of + // the subtype is whitespace, otherwise fail. + if (mozilla::IsAsciiWhitespace(*pos)) { + subtypeEnd = pos; + ++pos; + while (pos < end && *pos != ';') { + if (!mozilla::IsAsciiWhitespace(*pos)) { + return nullptr; + } + ++pos; + } + break; + } else { + return nullptr; + } + } + ++pos; + } + if (subtypeEnd == nullptr) { + subtypeEnd = pos; + } + if (subtypeStart == subtypeEnd) { + return nullptr; + } + + // Step 10 + nsString type; + nsString subtype; + for (const char16_t* c = typeStart; c < typeEnd; ++c) { + type.Append(ToLowerCaseASCII(*c)); + } + for (const char16_t* c = subtypeStart; c < subtypeEnd; ++c) { + subtype.Append(ToLowerCaseASCII(*c)); + } + mozilla::UniquePtr mimeType(mozilla::MakeUnique(type, subtype)); + + // Step 11 + while (pos < end) { + // Step 11.1 + ++pos; + + // Step 11.2 + while (pos < end && mozilla::IsAsciiWhitespace(*pos)) { + ++pos; + } + + // Steps 11.3 and 11.4 + nsString paramName; + bool paramNameHadInvalidChars = false; + while (pos < end && *pos != ';' && *pos != '=') { + if (!IsHTTPTokenPoint(*pos)) { + paramNameHadInvalidChars = true; + } + paramName.Append(ToLowerCaseASCII(*pos)); + ++pos; + } + + // Step 11.5 + if (pos < end) { + if (*pos == ';') { + continue; + } + ++pos; + } + + // Step 11.6 + ParameterValue paramValue; + bool paramValueHadInvalidChars = false; + + // Step 11.7 + if (pos < end) { + + // Step 11.7.1 + if (*pos == '"') { + + // Step 11.7.1.1 + ++pos; + + // Step 11.7.1.2 + while (true) { + + // Step 11.7.1.2.1 + while (pos < end && *pos != '"' && *pos != '\\') { + if (!IsHTTPQuotedStringTokenPoint(*pos)) { + paramValueHadInvalidChars = true; + } + if (!IsHTTPTokenPoint(*pos)) { + paramValue.mRequiresQuoting = true; + } + paramValue.Append(*pos); + ++pos; + } + + // Step 11.7.1.2.2 + if (pos < end && *pos == '\\') { + // Step 11.7.1.2.2.1 + ++pos; + + // Step 11.7.1.2.2.2 + if (pos < end) { + if (!IsHTTPQuotedStringTokenPoint(*pos)) { + paramValueHadInvalidChars = true; + } + if (!IsHTTPTokenPoint(*pos)) { + paramValue.mRequiresQuoting = true; + } + paramValue.Append(*pos); + ++pos; + continue; + } + + // Step 11.7.1.2.2.3 + paramValue.Append('\\'); + paramValue.mRequiresQuoting = true; + break; + } else { + // Step 11.7.1.2.3 + break; + } + } + + // Step 11.7.1.3 + while (pos < end && *pos != ';') { + ++pos; + } + + } else { + + const char16_t* paramValueStart = pos; + + // Step 11.7.2.1 + while (pos < end && *pos != ';') { + if (!IsHTTPQuotedStringTokenPoint(*pos)) { + paramValueHadInvalidChars = true; + } + if (!IsHTTPTokenPoint(*pos)) { + paramValue.mRequiresQuoting = true; + } + ++pos; + } + + // Step 11.7.2.2 + const char16_t* paramValueEnd = pos - 1; + while (paramValueEnd >= paramValueStart && + mozilla::IsAsciiWhitespace(*paramValueEnd)) { + --paramValueEnd; + } + + for (const char16_t* c = paramValueStart; c <= paramValueEnd; ++c) { + paramValue.Append(*c); + } + } + + // Step 11.8 + if (!paramName.IsEmpty() && !paramValue.IsEmpty() && + !paramNameHadInvalidChars && !paramValueHadInvalidChars && + !mimeType->mParameters.Get(paramName, ¶mValue)) { + mimeType->mParameters.Put(paramName, paramValue); + mimeType->mParameterNames.AppendElement(paramName); + } + } + } + + return mimeType; +} + +void +MimeType::Serialize(nsAString& aOutput) const +{ + aOutput.Assign(mType); + aOutput.AppendLiteral("/"); + aOutput.Append(mSubtype); + for (uint32_t i = 0; i < mParameterNames.Length(); i++) { + auto name = mParameterNames[i]; + ParameterValue value; + mParameters.Get(name, &value); + aOutput.AppendLiteral(";"); + aOutput.Append(name); + aOutput.AppendLiteral("="); + if (value.mRequiresQuoting) { + aOutput.AppendLiteral("\""); + const char16_t* vcur = value.BeginReading(); + const char16_t* vend = value.EndReading(); + while (vcur < vend) { + if (*vcur == '"' || *vcur == '\\') { + aOutput.AppendLiteral("\\"); + } + aOutput.Append(*vcur); + vcur++; + } + aOutput.AppendLiteral("\""); + } else { + aOutput.Append(value); + } + } +} diff --git a/dom/base/MimeType.h b/dom/base/MimeType.h new file mode 100644 index 000000000000..6d08a144b7c5 --- /dev/null +++ b/dom/base/MimeType.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_MimeType_h +#define mozilla_dom_MimeType_h + +#include "mozilla/TextUtils.h" +#include "mozilla/UniquePtr.h" +#include "nsDataHashtable.h" +#include "nsTArray.h" + +class MimeType final +{ +private: + class ParameterValue : public nsString + { + public: + bool mRequiresQuoting; + + ParameterValue() + : mRequiresQuoting(false) + {} + }; + + nsString mType; + nsString mSubtype; + nsDataHashtable mParameters; + nsTArray mParameterNames; + +public: + MimeType(const nsAString& aType, const nsAString& aSubtype) + : mType(aType), mSubtype(aSubtype) + {} + + static mozilla::UniquePtr Parse(const nsAString& aStr); + void Serialize(nsAString& aStr) const; +}; + +#endif // mozilla_dom_MimeType_h diff --git a/dom/base/moz.build b/dom/base/moz.build index 7b10df632fa2..1c6e23cd5b88 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -194,6 +194,7 @@ EXPORTS.mozilla.dom += [ 'MessageListenerManager.h', 'MessageManagerGlobal.h', 'MessageSender.h', + 'MimeType.h', 'MozQueryInterface.h', 'NameSpaceConstants.h', 'Navigator.h', @@ -288,6 +289,7 @@ UNIFIED_SOURCES += [ 'MessageListenerManager.cpp', 'MessageManagerGlobal.cpp', 'MessageSender.cpp', + 'MimeType.cpp', 'MozQueryInterface.cpp', 'Navigator.cpp', 'NodeInfo.cpp', diff --git a/dom/base/test/gtest/TestMimeType.cpp b/dom/base/test/gtest/TestMimeType.cpp new file mode 100644 index 000000000000..e2bbfe5a39cb --- /dev/null +++ b/dom/base/test/gtest/TestMimeType.cpp @@ -0,0 +1,708 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" + +#include "MimeType.h" +#include "nsString.h" + +using mozilla::UniquePtr; + +TEST(MimeType, EmptyString) +{ + const auto in = NS_LITERAL_STRING(""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Empty string"; +} + +TEST(MimeType, JustWhitespace) +{ + const auto in = NS_LITERAL_STRING(" \t\r\n "); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Just whitespace"; +} + +TEST(MimeType, JustBackslash) +{ + const auto in = NS_LITERAL_STRING("\\"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Just backslash"; +} + +TEST(MimeType, JustForwardslash) +{ + const auto in = NS_LITERAL_STRING("/"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Just forward slash"; +} + +TEST(MimeType, MissingType1) +{ + const auto in = NS_LITERAL_STRING("/bogus"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Missing type #1"; +} + +TEST(MimeType, MissingType2) +{ + const auto in = NS_LITERAL_STRING(" \r\n\t/bogus"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Missing type #2"; +} + +TEST(MimeType, MissingSubtype1) +{ + const auto in = NS_LITERAL_STRING("bogus"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Missing subtype #1"; +} + +TEST(MimeType, MissingSubType2) +{ + const auto in = NS_LITERAL_STRING("bogus/"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Missing subtype #2"; +} + +TEST(MimeType, MissingSubType3) +{ + const auto in = NS_LITERAL_STRING("bogus;"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Missing subtype #3"; +} + +TEST(MimeType, MissingSubType4) +{ + const auto in = NS_LITERAL_STRING("bogus; \r\n\t"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Missing subtype #3"; +} + +TEST(MimeType, ExtraForwardSlash) +{ + const auto in = NS_LITERAL_STRING("bogus/bogus/;"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Extra forward slash"; +} + +TEST(MimeType, WhitespaceInType) +{ + const auto in = NS_LITERAL_STRING("t\re\nx\tt /html"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Type with whitespace"; +} + +TEST(MimeType, WhitespaceInSubtype) +{ + const auto in = NS_LITERAL_STRING("text/ h\rt\nm\tl"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Subtype with whitespace"; +} + +TEST(MimeType, NonAlphanumericMediaType1) +{ + const auto in = NS_LITERAL_STRING(""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-alphanumeric media type #1"; +} + +TEST(MimeType, NonAlphanumericMediaType2) +{ + const auto in = NS_LITERAL_STRING("(/)"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-alphanumeric media type #2"; +} + +TEST(MimeType, NonAlphanumericMediaType3) +{ + const auto in = NS_LITERAL_STRING("{/}"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-alphanumeric media type #3"; +} + +TEST(MimeType, NonAlphanumericMediaType4) +{ + const auto in = NS_LITERAL_STRING("\"/\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-alphanumeric media type #4"; +} + +TEST(MimeType, NonAlphanumericMediaType5) +{ + const auto in = NS_LITERAL_STRING("\0/\0"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-alphanumeric media type #5"; +} + +TEST(MimeType, NonAlphanumericMediaType6) +{ + const auto in = NS_LITERAL_STRING("text/html(;doesnot=matter"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-alphanumeric media type #6"; +} + +TEST(MimeType, NonLatin1MediaType1) +{ + const auto in = NS_LITERAL_STRING("ÿ/ÿ"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-latin1 media type #1"; +} + +TEST(MimeType, NonLatin1MediaType2) +{ + const auto in = NS_LITERAL_STRING("\x0100/\x0100"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_FALSE(parsed) << + "Non-latin1 media type #2"; +} + +TEST(MimeType, MultipleParameters) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=gbk;no=1;charset_=gbk_;yes=2"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(NS_LITERAL_STRING("text/html;charset=gbk;no=1;charset_=gbk_;yes=2"))) << + "Multiple parameters"; +} + +TEST(MimeType, DuplicateParameter1) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=gbk;charset=windows-1255"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(NS_LITERAL_STRING("text/html;charset=gbk"))) << + "Duplicate parameter #1"; +} + +TEST(MimeType, DuplicateParameter2) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=();charset=GBK"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(NS_LITERAL_STRING("text/html;charset=\"()\""))) << + "Duplicate parameter #2"; +} + +TEST(MimeType, NonAlphanumericParametersAreQuoted) +{ + const auto in = NS_LITERAL_STRING("text/html;test=\x00FF\\;charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(NS_LITERAL_STRING("text/html;test=\"\x00FF\\\\\";charset=gbk"))) << + "Non-alphanumeric parameters are quoted"; +} + +TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace1) +{ + const auto in = NS_LITERAL_STRING("text/html;charset= g\\\"bk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" g\\\\\\\"bk\"")) << + "Parameter is quoted if has leading whitespace #1"; +} + +TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace2) +{ + const auto in = NS_LITERAL_STRING("text/html;charset= \"g\\bk\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" \\\"g\\\\bk\\\"\"")) << + "Parameter is quoted if has leading whitespace #2"; +} + +TEST(MimeType, ParameterQuotedIfHasInternalWhitespace) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=g \\b\"k"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"g \\\\b\\\"k\"")) << + "Parameter is quoted if has internal whitespace"; +} + +TEST(MimeType, ImproperlyQuotedParameter1) +{ + const auto in = NS_LITERAL_STRING("x/x;test=\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x")) << + "Improperly-quoted parameter is handled properly #1"; +} + +TEST(MimeType, ImproperlyQuotedParameter2) +{ + const auto in = NS_LITERAL_STRING("x/x;test=\"\\"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x;test=\"\\\\\"")) << + "Improperly-quoted parameter is handled properly #2"; +} + +TEST(MimeType, NonLatin1ParameterIgnored) +{ + const auto in = NS_LITERAL_STRING("x/x;test=\xFFFD;x=x"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x;x=x")) << + "Non latin-1 parameters are ignored"; +} + +TEST(MimeType, ParameterIgnoredIfWhitespaceInName1) +{ + const auto in = NS_LITERAL_STRING("text/html;charset =gbk;charset=123"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=123")) << + "Parameter ignored if whitespace in name #1"; +} + +TEST(MimeType, ParameterIgnoredIfWhitespaceInName2) +{ + const auto in = NS_LITERAL_STRING("text/html;cha rset =gbk;charset=123"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=123")) << + "Parameter ignored if whitespace in name #2"; +} + +TEST(MimeType, WhitespaceTrimmed) +{ + const auto in = NS_LITERAL_STRING("\n\r\t text/plain\n\r\t ;\n\r\t charset=123\n\r\t "); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/plain;charset=123")) << + "Whitespace appropriately ignored"; +} + +TEST(MimeType, WhitespaceOnlyParameterIgnored) +{ + const auto in = NS_LITERAL_STRING("x/x;x= \r\n\t"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x")) << + "Whitespace-only parameter is ignored"; +} + +TEST(MimeType, IncompleteParameterIgnored1) +{ + const auto in = NS_LITERAL_STRING("x/x;test"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x")) << + "Incomplete parameter is ignored #1"; +} + +TEST(MimeType, IncompleteParameterIgnored2) +{ + const auto in = NS_LITERAL_STRING("x/x;test="); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x")) << + "Incomplete parameter is ignored #2"; +} + +TEST(MimeType, IncompleteParameterIgnored3) +{ + const auto in = NS_LITERAL_STRING("x/x;test= \r\n\t"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("x/x")) << + "Incomplete parameter is ignored #3"; +} + +TEST(MimeType, IncompleteParameterIgnored4) +{ + const auto in = NS_LITERAL_STRING("text/html;test;charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Incomplete parameter is ignored #4"; +} + +TEST(MimeType, IncompleteParameterIgnored5) +{ + const auto in = NS_LITERAL_STRING("text/html;test=;charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Incomplete parameter is ignored #5"; +} + +TEST(MimeType, EmptyParameterIgnored1) +{ + const auto in = NS_LITERAL_STRING("text/html ; ; charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Empty parameter ignored #1"; +} + +TEST(MimeType, EmptyParameterIgnored2) +{ + const auto in = NS_LITERAL_STRING("text/html;;;;charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Empty parameter ignored #2"; +} + +TEST(MimeType, InvalidParameterIgnored1) +{ + const auto in = NS_LITERAL_STRING("text/html;';charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Invalid parameter ignored #1"; +} + +TEST(MimeType, InvalidParameterIgnored2) +{ + const auto in = NS_LITERAL_STRING("text/html;\";charset=gbk;=123; =321"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Invalid parameter ignored #2"; +} + +TEST(MimeType, InvalidParameterIgnored3) +{ + const auto in = NS_LITERAL_STRING("text/html;charset= \"\u007F;charset=GBK"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=GBK")) << + "Invalid parameter ignored #3"; +} + +TEST(MimeType, InvalidParameterIgnored4) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"\u007F;charset=foo\";charset=GBK;charset="); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=GBK")) << + "Invalid parameter ignored #4"; +} + +TEST(MimeType, SingleQuotes1) +{ + const auto in = NS_LITERAL_STRING("text/html;charset='gbk'"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset='gbk'")) << + "Single quotes handled properly #1"; +} + +TEST(MimeType, SingleQuotes2) +{ + const auto in = NS_LITERAL_STRING("text/html;charset='gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset='gbk")) << + "Single quotes handled properly #2"; +} + +TEST(MimeType, SingleQuotes3) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=gbk'"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk'")) << + "Single quotes handled properly #3"; +} + +TEST(MimeType, SingleQuotes4) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=';charset=GBK"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset='")) << + "Single quotes handled properly #4"; +} + +TEST(MimeType, SingleQuotes5) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=''';charset=GBK"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset='''")) << + "Single quotes handled properly #5"; +} + +TEST(MimeType, DoubleQuotes1) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"gbk\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Double quotes handled properly #1"; +} + +TEST(MimeType, DoubleQuotes2) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Double quotes handled properly #2"; +} + +TEST(MimeType, DoubleQuotes3) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=gbk\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"gbk\\\"\"")) << + "Double quotes handled properly #3"; +} + +TEST(MimeType, DoubleQuotes4) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\" gbk\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" gbk\"")) << + "Double quotes handled properly #4"; +} + +TEST(MimeType, DoubleQuotes5) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"gbk \""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"gbk \"")) << + "Double quotes handled properly #5"; +} + +TEST(MimeType, DoubleQuotes6) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"\\ gbk\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" gbk\"")) << + "Double quotes handled properly #6"; +} + +TEST(MimeType, DoubleQuotes7) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"\\g\\b\\k\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Double quotes handled properly #7"; +} + +TEST(MimeType, DoubleQuotes8) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"gbk\"x"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk")) << + "Double quotes handled properly #8"; +} + +TEST(MimeType, DoubleQuotes9) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\"\";charset=GBK"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=GBK")) << + "Double quotes handled properly #9"; +} + +TEST(MimeType, DoubleQuotes10) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=\";charset=GBK"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\";charset=GBK\"")) << + "Double quotes handled properly #10"; +} + +TEST(MimeType, UnexpectedCodePoints) +{ + const auto in = NS_LITERAL_STRING("text/html;charset={gbk}"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"{gbk}\"")) << + "Unexpected code points handled properly"; +} + +TEST(MimeType, LongTypesSubtypesAccepted) +{ + const auto in = NS_LITERAL_STRING("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(in)) << + "Long type/subtype accepted"; +} + +TEST(MimeType, LongParametersAccepted) +{ + const auto in = NS_LITERAL_STRING("text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(in)) << + "Long parameters accepted"; +} + +TEST(MimeType, AllValidCharactersAccepted1) +{ + const auto in = NS_LITERAL_STRING("x/x;x=\"\t !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E\u009F\u00A0\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A8\u00A9\u00AA\u00AB\u00AC\u00AD\u00AE\u00AF\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6\u00B7\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF\""); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.Equals(in)) << + "All valid characters accepted #1"; +} + +TEST(MimeType, CaseNormalization1) +{ + const auto in = NS_LITERAL_STRING("TEXT/PLAIN;CHARSET=TEST"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/plain;charset=TEST")) << + "Case normalized properly #1"; +} + +TEST(MimeType, CaseNormalization2) +{ + const auto in = NS_LITERAL_STRING("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) << + "Case normalized properly #2"; +} + +TEST(MimeType, LegacyCommentSyntax1) +{ + const auto in = NS_LITERAL_STRING("text/html;charset=gbk("); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"gbk(\"")) << + "Legacy comment syntax #1"; +} + +TEST(MimeType, LegacyCommentSyntax2) +{ + const auto in = NS_LITERAL_STRING("text/html;x=(;charset=gbk"); + UniquePtr parsed = MimeType::Parse(in); + ASSERT_TRUE(parsed) << "Parsing succeeded"; + nsAutoString out; + parsed->Serialize(out); + ASSERT_TRUE(out.EqualsLiteral("text/html;x=\"(\";charset=gbk")) << + "Legacy comment syntax #2"; +} diff --git a/dom/base/test/gtest/moz.build b/dom/base/test/gtest/moz.build index cdeb42eb15a7..016984257702 100644 --- a/dom/base/test/gtest/moz.build +++ b/dom/base/test/gtest/moz.build @@ -6,6 +6,7 @@ UNIFIED_SOURCES += [ 'TestContentUtils.cpp', + 'TestMimeType.cpp', 'TestPlainTextSerializer.cpp', 'TestXPathGenerator.cpp', ] diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index bb77b7ce0687..0c21a6475b77 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -2172,7 +2172,11 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt, // Smaller files may be written in cache map instead of separate files. // Also, no-store response cannot be written in persistent cache. nsAutoCString contentType; - mChannel->GetContentType(contentType); + if (!mOverrideMimeType.IsEmpty()) { + contentType.Assign(NS_ConvertUTF16toUTF8(mOverrideMimeType)); + } else { + mChannel->GetContentType(contentType); + } // mBlobStorage can be null if the channel is non-file non-cacheable // and if the response length is zero. @@ -3135,7 +3139,12 @@ XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType, return; } - mOverrideMimeType = aMimeType; + UniquePtr parsed = MimeType::Parse(aMimeType); + if (parsed) { + parsed->Serialize(mOverrideMimeType); + } else { + mOverrideMimeType.AssignLiteral(APPLICATION_OCTET_STREAM); + } } bool diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index a2781ea83a90..24a6f0519606 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -39,6 +39,7 @@ #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FormData.h" +#include "mozilla/dom/MimeType.h" #include "mozilla/dom/PerformanceStorage.h" #include "mozilla/dom/ServiceWorkerDescriptor.h" #include "mozilla/dom/URLSearchParams.h" diff --git a/intl/unicharutil/util/nsUnicharUtils.cpp b/intl/unicharutil/util/nsUnicharUtils.cpp index 996cec85344c..c35af8281e51 100644 --- a/intl/unicharutil/util/nsUnicharUtils.cpp +++ b/intl/unicharutil/util/nsUnicharUtils.cpp @@ -59,6 +59,33 @@ ToLowerCaseASCII(nsAString& aString) ToLowerCaseASCII(buf, buf, aString.Length()); } +char +ToLowerCaseASCII(char aChar) +{ + if (aChar >= 'A' && aChar <= 'Z') { + return aChar + 0x20; + } + return aChar; +} + +char16_t +ToLowerCaseASCII(char16_t aChar) +{ + if (aChar >= 'A' && aChar <= 'Z') { + return aChar + 0x20; + } + return aChar; +} + +char32_t +ToLowerCaseASCII(char32_t aChar) +{ + if (aChar >= 'A' && aChar <= 'Z') { + return aChar + 0x20; + } + return aChar; +} + void ToLowerCase(const nsAString& aSource, nsAString& aDest) diff --git a/intl/unicharutil/util/nsUnicharUtils.h b/intl/unicharutil/util/nsUnicharUtils.h index 9d0f813e41be..3f80ace65b46 100644 --- a/intl/unicharutil/util/nsUnicharUtils.h +++ b/intl/unicharutil/util/nsUnicharUtils.h @@ -40,6 +40,10 @@ void ToLowerCase(const char16_t *aIn, char16_t *aOut, uint32_t aLen); void ToLowerCaseASCII(const char16_t *aIn, char16_t *aOut, uint32_t aLen); void ToUpperCase(const char16_t *aIn, char16_t *aOut, uint32_t aLen); +char ToLowerCaseASCII(const char aChar); +char16_t ToLowerCaseASCII(const char16_t aChar); +char32_t ToLowerCaseASCII(const char32_t aChar); + inline bool IsUpperCase(uint32_t c) { return ToLowerCase(c) != c; } diff --git a/mfbt/TextUtils.h b/mfbt/TextUtils.h index ca68778db446..3134e11637ea 100644 --- a/mfbt/TextUtils.h +++ b/mfbt/TextUtils.h @@ -47,6 +47,21 @@ IsAscii(Char aChar) return uc < 0x80; } +/** + * Returns true iff |aChar| matches Ascii Whitespace. + * + * This function is intended to match the Infra standard + * (https://infra.spec.whatwg.org/#ascii-whitespace) + */ +template +constexpr bool +IsAsciiWhitespace(Char aChar) +{ + using UnsignedChar = typename detail::MakeUnsignedChar::Type; + auto uc = static_cast(aChar); + return uc == 0x9 || uc == 0xA || uc == 0xC || uc == 0xD || uc == 0x20; +} + /** * Returns true iff |aChar| matches [a-z]. * diff --git a/testing/web-platform/meta/xhr/overridemimetype-blob.html.ini b/testing/web-platform/meta/xhr/overridemimetype-blob.html.ini deleted file mode 100644 index 0a70e7dcbb97..000000000000 --- a/testing/web-platform/meta/xhr/overridemimetype-blob.html.ini +++ /dev/null @@ -1,286 +0,0 @@ -[overridemimetype-blob.html] - [Bogus MIME type should end up as application/octet-stream, 2] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream, 3] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream, 4] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream, 5] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream, 6] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream, 7] - expected: FAIL - - [Bogus MIME type should end up as application/octet-stream, 9] - expected: FAIL - - [Valid MIME types need to be parsed and serialized 1] - expected: FAIL - - [Valid MIME types need to be parsed and serialized 4] - expected: FAIL - - [Valid MIME types need to be parsed and serialized 5] - expected: FAIL - - [1) MIME types need to be parsed and serialized: text/html;charset=gbk] - expected: FAIL - - [2) MIME types need to be parsed and serialized: TEXT/HTML;CHARSET=GBK] - expected: FAIL - - [3) MIME types need to be parsed and serialized: text/html;charset=gbk(] - expected: FAIL - - [4) MIME types need to be parsed and serialized: text/html;x=(;charset=gbk] - expected: FAIL - - [5) MIME types need to be parsed and serialized: text/html;charset=gbk;charset=windows-1255] - expected: FAIL - - [7) MIME types need to be parsed and serialized: text/html ;charset=gbk] - expected: FAIL - - [8) MIME types need to be parsed and serialized: text/html; charset=gbk] - expected: FAIL - - [9) MIME types need to be parsed and serialized: text/html;charset= gbk] - expected: FAIL - - [10) MIME types need to be parsed and serialized: text/html;charset='gbk'] - expected: FAIL - - [11) MIME types need to be parsed and serialized: text/html;charset='gbk] - expected: FAIL - - [12) MIME types need to be parsed and serialized: text/html;charset=gbk'] - expected: FAIL - - [13) MIME types need to be parsed and serialized: text/html;test;charset=gbk] - expected: FAIL - - [14) MIME types need to be parsed and serialized: text/html;test=;charset=gbk] - expected: FAIL - - [15) MIME types need to be parsed and serialized: text/html;';charset=gbk] - expected: FAIL - - [16) MIME types need to be parsed and serialized: text/html;";charset=gbk] - expected: FAIL - - [17) MIME types need to be parsed and serialized: text/html ; ; charset=gbk] - expected: FAIL - - [18) MIME types need to be parsed and serialized: text/html;;;;charset=gbk] - expected: FAIL - - [19) MIME types need to be parsed and serialized: text/html;charset="gbk"] - expected: FAIL - - [20) MIME types need to be parsed and serialized: text/html;charset="gbk] - expected: FAIL - - [21) MIME types need to be parsed and serialized: text/html;charset=gbk"] - expected: FAIL - - [22) MIME types need to be parsed and serialized: text/html;charset=" gbk"] - expected: FAIL - - [23) MIME types need to be parsed and serialized: text/html;charset="\\ gbk"] - expected: FAIL - - [24) MIME types need to be parsed and serialized: text/html;charset="\\g\\b\\k"] - expected: FAIL - - [25) MIME types need to be parsed and serialized: text/html;charset="gbk"x] - expected: FAIL - - [26) MIME types need to be parsed and serialized: text/html;charset={gbk}] - expected: FAIL - - [27) MIME types need to be parsed and serialized: text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk] - expected: FAIL - - [29) MIME types need to be parsed and serialized: !#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz] - expected: FAIL - - [30) MIME types need to be parsed and serialized: x/x;x="\t !\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"] - expected: FAIL - - [32) MIME types need to be parsed and serialized: x/x;test="\\] - expected: FAIL - - [35) MIME types need to be parsed and serialized: text/html;test=ÿ;charset=gbk] - expected: FAIL - - [36) MIME types need to be parsed and serialized: x/x;test=�;x=x] - expected: FAIL - - [37) MIME types need to be parsed and serialized: ] - expected: FAIL - - [39) MIME types need to be parsed and serialized: /] - expected: FAIL - - [41) MIME types need to be parsed and serialized: bogus/] - expected: FAIL - - [42) MIME types need to be parsed and serialized: bogus/ ] - expected: FAIL - - [43) MIME types need to be parsed and serialized: bogus/bogus/;] - expected: FAIL - - [44) MIME types need to be parsed and serialized: ] - expected: FAIL - - [46) MIME types need to be parsed and serialized: ÿ/ÿ] - expected: FAIL - - [47) MIME types need to be parsed and serialized: text/html(;doesnot=matter] - expected: FAIL - - [48) MIME types need to be parsed and serialized: {/}] - expected: FAIL - - [49) MIME types need to be parsed and serialized: Ā/Ā] - expected: FAIL - - [6) MIME types need to be parsed and serialized: text/html;charset=();charset=GBK] - expected: FAIL - - [8) MIME types need to be parsed and serialized: text/html ;charset=gbk] - expected: FAIL - - [9) MIME types need to be parsed and serialized: text/html; charset=gbk] - expected: FAIL - - [10) MIME types need to be parsed and serialized: text/html;charset= gbk] - expected: FAIL - - [11) MIME types need to be parsed and serialized: text/html;charset= "gbk"] - expected: FAIL - - [12) MIME types need to be parsed and serialized: text/html;charset='gbk'] - expected: FAIL - - [13) MIME types need to be parsed and serialized: text/html;charset='gbk] - expected: FAIL - - [14) MIME types need to be parsed and serialized: text/html;charset=gbk'] - expected: FAIL - - [15) MIME types need to be parsed and serialized: text/html;charset=';charset=GBK] - expected: FAIL - - [16) MIME types need to be parsed and serialized: text/html;test;charset=gbk] - expected: FAIL - - [17) MIME types need to be parsed and serialized: text/html;test=;charset=gbk] - expected: FAIL - - [18) MIME types need to be parsed and serialized: text/html;';charset=gbk] - expected: FAIL - - [19) MIME types need to be parsed and serialized: text/html;";charset=gbk] - expected: FAIL - - [20) MIME types need to be parsed and serialized: text/html ; ; charset=gbk] - expected: FAIL - - [21) MIME types need to be parsed and serialized: text/html;;;;charset=gbk] - expected: FAIL - - [22) MIME types need to be parsed and serialized: text/html;charset= ";charset=GBK] - expected: FAIL - - [23) MIME types need to be parsed and serialized: text/html;charset=";charset=foo";charset=GBK] - expected: FAIL - - [24) MIME types need to be parsed and serialized: text/html;charset="gbk"] - expected: FAIL - - [25) MIME types need to be parsed and serialized: text/html;charset="gbk] - expected: FAIL - - [26) MIME types need to be parsed and serialized: text/html;charset=gbk"] - expected: FAIL - - [27) MIME types need to be parsed and serialized: text/html;charset=" gbk"] - expected: FAIL - - [28) MIME types need to be parsed and serialized: text/html;charset="gbk "] - expected: FAIL - - [29) MIME types need to be parsed and serialized: text/html;charset="\\ gbk"] - expected: FAIL - - [30) MIME types need to be parsed and serialized: text/html;charset="\\g\\b\\k"] - expected: FAIL - - [31) MIME types need to be parsed and serialized: text/html;charset="gbk"x] - expected: FAIL - - [32) MIME types need to be parsed and serialized: text/html;charset="";charset=GBK] - expected: FAIL - - [33) MIME types need to be parsed and serialized: text/html;charset=";charset=GBK] - expected: FAIL - - [34) MIME types need to be parsed and serialized: text/html;charset={gbk}] - expected: FAIL - - [35) MIME types need to be parsed and serialized: text/html;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789=x;charset=gbk] - expected: FAIL - - [37) MIME types need to be parsed and serialized: !#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz] - expected: FAIL - - [38) MIME types need to be parsed and serialized: x/x;x="\t !\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"] - expected: FAIL - - [40) MIME types need to be parsed and serialized: x/x;test="\\] - expected: FAIL - - [43) MIME types need to be parsed and serialized: text/html;test=ÿ;charset=gbk] - expected: FAIL - - [44) MIME types need to be parsed and serialized: x/x;test=�;x=x] - expected: FAIL - - [45) MIME types need to be parsed and serialized: ] - expected: FAIL - - [47) MIME types need to be parsed and serialized: /] - expected: FAIL - - [49) MIME types need to be parsed and serialized: bogus/] - expected: FAIL - - [50) MIME types need to be parsed and serialized: bogus/ ] - expected: FAIL - - [51) MIME types need to be parsed and serialized: bogus/bogus/;] - expected: FAIL - - [52) MIME types need to be parsed and serialized: ] - expected: FAIL - - [54) MIME types need to be parsed and serialized: ÿ/ÿ] - expected: FAIL - - [55) MIME types need to be parsed and serialized: text/html(;doesnot=matter] - expected: FAIL - - [56) MIME types need to be parsed and serialized: {/}] - expected: FAIL - - [57) MIME types need to be parsed and serialized: Ā/Ā] - expected: FAIL -