Bug 1845006 - store the fully-serialized MimeType on data url channels so XHR and fetch may use it for content-type response headers, and clean up the data url parsing code to better match the spec. r=kershaw,sunil,necko-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D184713
This commit is contained in:
Thomas Wisniewski 2023-08-02 13:39:48 +00:00
Родитель 173c3a000a
Коммит 6948e36567
11 изменённых файлов: 202 добавлений и 216 удалений

Просмотреть файл

@ -5,34 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MimeType.h"
#include "nsNetUtil.h"
#include "nsUnicharUtils.h"
namespace {
template <typename Char>
constexpr bool IsHTTPTokenPoint(Char aChar) {
using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
auto c = static_cast<UnsignedChar>(aChar);
return c == '!' || c == '#' || c == '$' || c == '%' || c == '&' ||
c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' ||
c == '^' || c == '_' || c == '`' || c == '|' || c == '~' ||
mozilla::IsAsciiAlphanumeric(c);
}
template <typename Char>
constexpr bool IsHTTPQuotedStringTokenPoint(Char aChar) {
using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
auto c = static_cast<UnsignedChar>(aChar);
return c == 0x9 || (c >= ' ' && c <= '~') || mozilla::IsNonAsciiLatin1(c);
}
template <typename Char>
constexpr bool IsHTTPWhitespace(Char aChar) {
using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
auto c = static_cast<UnsignedChar>(aChar);
return c == 0x9 || c == 0xA || c == 0xD || c == 0x20;
}
} // namespace
template <typename char_type>
/* static */ mozilla::UniquePtr<TMimeType<char_type>>
TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
@ -41,20 +16,20 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
// Steps 1-2
const char_type* pos = aMimeType.BeginReading();
const char_type* end = aMimeType.EndReading();
while (pos < end && IsHTTPWhitespace(*pos)) {
while (pos < end && NS_IsHTTPWhitespace(*pos)) {
++pos;
}
if (pos == end) {
return nullptr;
}
while (end > pos && IsHTTPWhitespace(*(end - 1))) {
while (end > pos && NS_IsHTTPWhitespace(*(end - 1))) {
--end;
}
// Steps 3-4
const char_type* typeStart = pos;
while (pos < end && *pos != '/') {
if (!IsHTTPTokenPoint(*pos)) {
if (!NS_IsHTTPTokenPoint(*pos)) {
return nullptr;
}
++pos;
@ -76,14 +51,14 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
const char_type* subtypeStart = pos;
const char_type* subtypeEnd = nullptr;
while (pos < end && *pos != ';') {
if (!IsHTTPTokenPoint(*pos)) {
if (!NS_IsHTTPTokenPoint(*pos)) {
// If we hit a whitespace, check that the rest of
// the subtype is whitespace, otherwise fail.
if (IsHTTPWhitespace(*pos)) {
if (NS_IsHTTPWhitespace(*pos)) {
subtypeEnd = pos;
++pos;
while (pos < end && *pos != ';') {
if (!IsHTTPWhitespace(*pos)) {
if (!NS_IsHTTPWhitespace(*pos)) {
return nullptr;
}
++pos;
@ -119,21 +94,41 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
++pos;
// Step 11.2
while (pos < end && IsHTTPWhitespace(*pos)) {
while (pos < end && NS_IsHTTPWhitespace(*pos)) {
++pos;
}
const char_type* namePos = pos;
// Steps 11.3 and 11.4
nsTString<char_type> paramName;
bool paramNameHadInvalidChars = false;
while (pos < end && *pos != ';' && *pos != '=') {
if (!IsHTTPTokenPoint(*pos)) {
if (!NS_IsHTTPTokenPoint(*pos)) {
paramNameHadInvalidChars = true;
}
paramName.Append(ToLowerCaseASCII(*pos));
++pos;
}
// Might as well check for base64 now
if (*pos != '=') {
// trim leading and trailing spaces
while (namePos < pos && NS_IsHTTPWhitespace(*namePos)) {
++namePos;
}
if (namePos < pos && ToLowerCaseASCII(*namePos) == 'b' &&
++namePos < pos && ToLowerCaseASCII(*namePos) == 'a' &&
++namePos < pos && ToLowerCaseASCII(*namePos) == 's' &&
++namePos < pos && ToLowerCaseASCII(*namePos) == 'e' &&
++namePos < pos && ToLowerCaseASCII(*namePos) == '6' &&
++namePos < pos && ToLowerCaseASCII(*namePos) == '4') {
while (++namePos < pos && NS_IsHTTPWhitespace(*namePos)) {
}
mimeType->mIsBase64 = namePos == pos;
}
}
// Step 11.5
if (pos < end) {
if (*pos == ';') {
@ -160,10 +155,10 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
while (true) {
// Step 11.8.2.1
while (pos < end && *pos != '"' && *pos != '\\') {
if (!IsHTTPQuotedStringTokenPoint(*pos)) {
if (!NS_IsHTTPQuotedStringTokenPoint(*pos)) {
paramValueHadInvalidChars = true;
}
if (!IsHTTPTokenPoint(*pos)) {
if (!NS_IsHTTPTokenPoint(*pos)) {
paramValue.mRequiresQuoting = true;
}
paramValue.Append(*pos);
@ -177,10 +172,10 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
// Step 11.8.2.2.2
if (pos < end) {
if (!IsHTTPQuotedStringTokenPoint(*pos)) {
if (!NS_IsHTTPQuotedStringTokenPoint(*pos)) {
paramValueHadInvalidChars = true;
}
if (!IsHTTPTokenPoint(*pos)) {
if (!NS_IsHTTPTokenPoint(*pos)) {
paramValue.mRequiresQuoting = true;
}
paramValue.Append(*pos);
@ -213,7 +208,7 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
// Step 11.9.2
const char_type* paramValueLastChar = pos - 1;
while (paramValueLastChar >= paramValueStart &&
IsHTTPWhitespace(*paramValueLastChar)) {
NS_IsHTTPWhitespace(*paramValueLastChar)) {
--paramValueLastChar;
}
@ -223,10 +218,10 @@ TMimeType<char_type>::Parse(const nsTSubstring<char_type>& aMimeType) {
}
for (const char_type* c = paramValueStart; c <= paramValueLastChar; ++c) {
if (!IsHTTPQuotedStringTokenPoint(*c)) {
if (!NS_IsHTTPQuotedStringTokenPoint(*c)) {
paramValueHadInvalidChars = true;
}
if (!IsHTTPTokenPoint(*c)) {
if (!NS_IsHTTPTokenPoint(*c)) {
paramValue.mRequiresQuoting = true;
}
paramValue.Append(*c);

Просмотреть файл

@ -33,6 +33,7 @@ class TMimeType final {
ParameterValue() : mRequiresQuoting(false) {}
};
bool mIsBase64{false};
nsTString<char_type> mType;
nsTString<char_type> mSubtype;
nsTHashMap<typename HashKeyType<char_type>::HashType, ParameterValue>
@ -52,6 +53,8 @@ class TMimeType final {
// Returns the `<mType>/<mSubtype>`
void GetFullType(nsTSubstring<char_type>& aStr) const;
bool IsBase64() const { return mIsBase64; }
// @param aName - the name of the parameter
// @return true if the parameter name is found, false otherwise.
bool HasParameter(const nsTSubstring<char_type>& aName) const;

Просмотреть файл

@ -29,6 +29,7 @@
#include "nsBaseChannel.h"
#include "nsContentPolicyUtils.h"
#include "nsDataChannel.h"
#include "nsDataHandler.h"
#include "nsNetUtil.h"
#include "nsPrintfCString.h"
@ -1017,7 +1018,6 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
bool foundOpaqueRedirect = false;
nsAutoCString contentType;
channel->GetContentType(contentType);
int64_t contentLength = InternalResponse::UNKNOWN_BODY_SIZE;
rv = channel->GetContentLength(&contentLength);
@ -1025,6 +1025,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
contentLength == InternalResponse::UNKNOWN_BODY_SIZE);
if (httpChannel) {
channel->GetContentType(contentType);
uint32_t responseStatus = 0;
rv = httpChannel->GetResponseStatus(&responseStatus);
if (NS_FAILED(rv)) {
@ -1098,11 +1100,20 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
MOZ_ASSERT(!result.Failed());
}
if (!contentType.IsEmpty()) {
nsAutoCString contentCharset;
channel->GetContentCharset(contentCharset);
if (NS_SUCCEEDED(rv) && !contentCharset.IsEmpty()) {
contentType += ";charset="_ns + contentCharset;
nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(channel->GetURI(getter_AddRefs(uri))) &&
uri->SchemeIs("data")) {
nsDataChannel* dchan = static_cast<nsDataChannel*>(channel.get());
MOZ_ASSERT(dchan);
contentType.Assign(dchan->MimeType());
} else {
channel->GetContentType(contentType);
if (!contentType.IsEmpty()) {
nsAutoCString contentCharset;
channel->GetContentCharset(contentCharset);
if (NS_SUCCEEDED(rv) && !contentCharset.IsEmpty()) {
contentType += ";charset="_ns + contentCharset;
}
}
}

Просмотреть файл

@ -46,6 +46,7 @@
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/dom/ProgressEvent.h"
#include "nsDataChannel.h"
#include "nsIJARChannel.h"
#include "nsIJARURI.h"
#include "nsLayoutCID.h"
@ -1144,6 +1145,26 @@ bool XMLHttpRequestMainThread::IsSafeHeader(
return isSafe;
}
bool XMLHttpRequestMainThread::GetContentType(nsACString& aValue) const {
MOZ_ASSERT(mChannel);
nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(mChannel->GetURI(getter_AddRefs(uri))) &&
uri->SchemeIs("data")) {
nsDataChannel* dchan = static_cast<nsDataChannel*>(mChannel.get());
MOZ_ASSERT(dchan);
aValue.Assign(dchan->MimeType());
return true;
}
if (NS_SUCCEEDED(mChannel->GetContentType(aValue))) {
nsCString value;
if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) && !value.IsEmpty()) {
aValue.AppendLiteral(";charset=");
aValue.Append(value);
}
return true;
}
return false;
}
void XMLHttpRequestMainThread::GetAllResponseHeaders(
nsACString& aResponseHeaders, ErrorResult& aRv) {
NOT_CALLABLE_IN_SYNC_SEND_RV
@ -1176,13 +1197,9 @@ void XMLHttpRequestMainThread::GetAllResponseHeaders(
// Even non-http channels supply content type.
nsAutoCString value;
if (NS_SUCCEEDED(mChannel->GetContentType(value))) {
if (GetContentType(value)) {
aResponseHeaders.AppendLiteral("Content-Type: ");
aResponseHeaders.Append(value);
if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) && !value.IsEmpty()) {
aResponseHeaders.AppendLiteral(";charset=");
aResponseHeaders.Append(value);
}
aResponseHeaders.AppendLiteral("\r\n");
}
@ -1240,18 +1257,11 @@ void XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
// Content Type:
if (header.LowerCaseEqualsASCII("content-type")) {
if (NS_FAILED(mChannel->GetContentType(_retval))) {
if (!GetContentType(_retval)) {
// Means no content type
_retval.SetIsVoid(true);
return;
}
nsCString value;
if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) &&
!value.IsEmpty()) {
_retval.AppendLiteral(";charset=");
_retval.Append(value);
}
}
// Content Length:

Просмотреть файл

@ -477,6 +477,9 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
// set to "text/xml".
void EnsureChannelContentType();
// Gets the value of the final content-type header from the channel.
bool GetContentType(nsACString& aValue) const;
already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
already_AddRefed<nsIJARChannel> GetCurrentJARChannel();

Просмотреть файл

@ -903,6 +903,30 @@ bool NS_IsValidHTTPToken(const nsACString& aToken);
*/
void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest);
template <typename Char>
constexpr bool NS_IsHTTPTokenPoint(Char aChar) {
using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
auto c = static_cast<UnsignedChar>(aChar);
return c == '!' || c == '#' || c == '$' || c == '%' || c == '&' ||
c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' ||
c == '^' || c == '_' || c == '`' || c == '|' || c == '~' ||
mozilla::IsAsciiAlphanumeric(c);
}
template <typename Char>
constexpr bool NS_IsHTTPQuotedStringTokenPoint(Char aChar) {
using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
auto c = static_cast<UnsignedChar>(aChar);
return c == 0x9 || (c >= ' ' && c <= '~') || mozilla::IsNonAsciiLatin1(c);
}
template <typename Char>
constexpr bool NS_IsHTTPWhitespace(Char aChar) {
using UnsignedChar = typename mozilla::detail::MakeUnsignedChar<Char>::Type;
auto c = static_cast<UnsignedChar>(aChar);
return c == 0x9 || c == 0xA || c == 0xD || c == 0x20;
}
/**
* Return true if the given request must be upgraded to HTTPS.
* If |aResultCallback| is provided and the storage is not ready to read, the

Просмотреть файл

@ -59,7 +59,7 @@ nsresult nsDataChannel::OpenContentStream(bool async, nsIInputStream** result,
nsDependentCSubstring dataRange;
bool lBase64;
rv = nsDataHandler::ParsePathWithoutRef(path, contentType, &contentCharset,
lBase64, &dataRange);
lBase64, &dataRange, &mMimeType);
if (NS_FAILED(rv)) return rv;
// This will avoid a copy if nothing needs to be unescaped.

Просмотреть файл

@ -16,9 +16,13 @@ class nsDataChannel : public nsBaseChannel {
public:
explicit nsDataChannel(nsIURI* uri) { SetURI(uri); }
const nsACString& MimeType() const { return mMimeType; }
protected:
[[nodiscard]] virtual nsresult OpenContentStream(
bool async, nsIInputStream** result, nsIChannel** channel) override;
nsCString mMimeType;
};
#endif /* nsDataChannel_h___ */

Просмотреть файл

@ -9,7 +9,9 @@
#include "nsError.h"
#include "nsIOService.h"
#include "DataChannelChild.h"
#include "nsNetUtil.h"
#include "nsSimpleURI.h"
#include "nsUnicharUtils.h"
#include "mozilla/dom/MimeType.h"
#include "mozilla/StaticPrefs_network.h"
@ -92,37 +94,68 @@ nsDataHandler::AllowPort(int32_t port, const char* scheme, bool* _retval) {
return NS_OK;
}
/**
* Helper that performs a case insensitive match to find the offset of a given
* pattern in a nsACString.
* The search is performed starting from the end of the string; if the string
* contains more than one match, the rightmost (last) match will be returned.
*/
static bool FindOffsetOf(const nsACString& aPattern, const nsACString& aSrc,
nsACString::size_type& aOffset) {
nsACString::const_iterator begin, end;
aSrc.BeginReading(begin);
aSrc.EndReading(end);
if (!RFindInReadable(aPattern, begin, end,
nsCaseInsensitiveCStringComparator)) {
namespace {
constexpr bool TrimSpacesAndBase64(nsACString& aMimeType) {
const char* beg = aMimeType.BeginReading();
const char* end = aMimeType.EndReading();
// trim leading and trailing spaces
while (beg < end && NS_IsHTTPWhitespace(*beg)) {
++beg;
}
if (beg == end) {
aMimeType.Truncate();
return false;
}
while (end > beg && NS_IsHTTPWhitespace(*(end - 1))) {
--end;
}
if (beg == end) {
aMimeType.Truncate();
return false;
}
// FindInReadable updates |begin| and |end| to the match coordinates.
aOffset = nsACString::size_type(begin.get() - aSrc.Data());
return true;
// trim trailing `; base64` (if any) and remember it
const char* pos = end - 1;
bool foundBase64 = false;
if (pos > beg && *pos == '4' && --pos > beg && *pos == '6' && --pos > beg &&
ToLowerCaseASCII(*pos) == 'e' && --pos > beg &&
ToLowerCaseASCII(*pos) == 's' && --pos > beg &&
ToLowerCaseASCII(*pos) == 'a' && --pos > beg &&
ToLowerCaseASCII(*pos) == 'b') {
while (--pos > beg && NS_IsHTTPWhitespace(*pos)) {
}
if (pos >= beg && *pos == ';') {
end = pos;
foundBase64 = true;
}
}
// actually trim off the spaces and trailing base64, returning if we found it.
const char* s = aMimeType.BeginReading();
aMimeType.Assign(Substring(aMimeType, beg - s, end - s));
return foundBase64;
}
nsresult nsDataHandler::ParsePathWithoutRef(
const nsACString& aPath, nsCString& aContentType,
nsCString* aContentCharset, bool& aIsBase64,
nsDependentCSubstring* aDataBuffer) {
static constexpr auto kBase64 = "base64"_ns;
} // namespace
nsresult nsDataHandler::ParsePathWithoutRef(const nsACString& aPath,
nsCString& aContentType,
nsCString* aContentCharset,
bool& aIsBase64,
nsDependentCSubstring* aDataBuffer,
nsCString* aMimeType) {
static constexpr auto kCharset = "charset"_ns;
// This implements https://fetch.spec.whatwg.org/#data-url-processor
// It also returns the full mimeType in aMimeType so fetch/XHR may access it
// for content-length headers. The contentType and charset parameters retain
// our legacy behavior, as much Gecko code generally expects GetContentType
// to yield only the MimeType's essence, not its full value with parameters.
aIsBase64 = false;
// First, find the start of the data
int32_t commaIdx = aPath.FindChar(',');
// This is a hack! When creating a URL using the DOM API we want to ignore
@ -132,70 +165,45 @@ nsresult nsDataHandler::ParsePathWithoutRef(
if (aContentCharset && commaIdx == kNotFound) {
return NS_ERROR_MALFORMED_URI;
}
if (commaIdx == 0 || commaIdx == kNotFound) {
// Nothing but data.
// "Let mimeType be the result of collecting a sequence of code points that
// are not equal to U+002C (,), given position."
nsCString mimeType(Substring(aPath, 0, commaIdx));
// "Strip leading and trailing ASCII whitespace from mimeType."
// "If mimeType ends with U+003B (;), followed by zero or more U+0020 SPACE,
// followed by an ASCII case-insensitive match for "base64", then ..."
aIsBase64 = TrimSpacesAndBase64(mimeType);
// "If mimeType starts with ";", then prepend "text/plain" to mimeType."
if (mimeType.Length() > 0 && mimeType.CharAt(0) == ';') {
mimeType = "text/plain"_ns + mimeType;
}
// "Let mimeTypeRecord be the result of parsing mimeType."
// This also checks for instances of ;base64 in the middle of the MimeType.
// This is against the current spec, but we're doing it because we have
// historically seen webcompat issues relying on this (see bug 781693).
if (mozilla::UniquePtr<CMimeType> parsed = CMimeType::Parse(mimeType)) {
parsed->GetFullType(aContentType);
if (aContentCharset) {
parsed->GetParameterValue(kCharset, *aContentCharset);
}
if (aMimeType) {
parsed->Serialize(*aMimeType);
}
if (parsed->IsBase64()) {
aIsBase64 = true;
}
} else {
// "If mimeTypeRecord is failure, then set mimeTypeRecord to
// text/plain;charset=US-ASCII."
aContentType.AssignLiteral("text/plain");
if (aContentCharset) {
aContentCharset->AssignLiteral("US-ASCII");
}
} else {
auto mediaType = Substring(aPath, 0, commaIdx);
// Determine if the data is base64 encoded.
nsACString::size_type base64;
if (FindOffsetOf(kBase64, mediaType, base64) && base64 > 0) {
nsACString::size_type offset = base64 + kBase64.Length();
// Per the RFC 2397 grammar, "base64" MUST be at the end of the
// non-data part.
//
// But we also allow it in between parameters so a subsequent ";"
// is ok as well (this deals with *broken* data URIs, see bug
// 781693 for an example). Anything after "base64" in the non-data
// part will be discarded in this case, however.
if (offset == mediaType.Length() || mediaType[offset] == ';' ||
mediaType[offset] == ' ') {
MOZ_DIAGNOSTIC_ASSERT(base64 > 0, "Did someone remove the check?");
// Index is on the first character of matched "base64" so we
// move to the preceding character
base64--;
// Skip any preceding spaces, searching for a semicolon
while (base64 > 0 && mediaType[base64] == ' ') {
base64--;
}
if (mediaType[base64] == ';') {
aIsBase64 = true;
// Trim the base64 part off.
mediaType.Rebind(aPath, 0, base64);
}
}
}
// Skip any leading spaces
nsACString::size_type startIndex = 0;
while (startIndex < mediaType.Length() && mediaType[startIndex] == ' ') {
startIndex++;
}
nsAutoCString mediaTypeBuf;
// If the mimetype starts with ';' we assume text/plain
if (startIndex < mediaType.Length() && mediaType[startIndex] == ';') {
mediaTypeBuf.AssignLiteral("text/plain");
mediaTypeBuf.Append(mediaType);
mediaType.Rebind(mediaTypeBuf, 0, mediaTypeBuf.Length());
}
// Everything else is content type.
if (mozilla::UniquePtr<CMimeType> parsed = CMimeType::Parse(mediaType)) {
parsed->GetFullType(aContentType);
if (aContentCharset) {
parsed->GetParameterValue(kCharset, *aContentCharset);
}
} else {
// Mime Type parsing failed
aContentType.AssignLiteral("text/plain");
if (aContentCharset) {
aContentCharset->AssignLiteral("US-ASCII");
}
if (aMimeType) {
aMimeType->AssignLiteral("text/plain;charset=US-ASCII");
}
}

Просмотреть файл

@ -50,7 +50,7 @@ class nsDataHandler : public nsIProtocolHandler,
[[nodiscard]] static nsresult ParsePathWithoutRef(
const nsACString& aPath, nsCString& aContentType,
nsCString* aContentCharset, bool& aIsBase64,
nsDependentCSubstring* aDataBuffer);
nsDependentCSubstring* aDataBuffer, nsCString* aMimeType = nullptr);
};
#endif /* nsDataHandler_h___ */

Просмотреть файл

@ -4,30 +4,12 @@
["data://test:test/,X"]
expected: FAIL
["data:;x=x;charset=x,X"]
expected: FAIL
["data:;x=x,X"]
expected: FAIL
["data:IMAGE/gif;hi=x,%C2%B1"]
expected: FAIL
["data:text/plain;a=%2C,X"]
expected: FAIL
["data:x/x;base64;charset=x,WA"]
expected: FAIL
["data:x;base64;x,WA"]
expected: FAIL
["data:;base64;,WA"]
expected: FAIL
["data:text/plain;a=\\",\\",X"]
expected: FAIL
[processing.any.worker.html]
expected:
@ -35,55 +17,19 @@
["data://test:test/,X"]
expected: FAIL
["data:;x=x;charset=x,X"]
expected: FAIL
["data:;x=x,X"]
expected: FAIL
["data:IMAGE/gif;hi=x,%C2%B1"]
expected: FAIL
["data:text/plain;a=%2C,X"]
expected: FAIL
["data:x/x;base64;charset=x,WA"]
expected: FAIL
["data:x;base64;x,WA"]
expected: FAIL
["data:;base64;,WA"]
expected: FAIL
["data:text/plain;a=\\",\\",X"]
expected: FAIL
[processing.any.serviceworker.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
["data:;x=x;charset=x,X"]
expected: FAIL
["data:text/plain;a=\\",\\",X"]
expected: FAIL
["data://test:test/,X"]
expected: FAIL
["data:;x=x,X"]
expected: FAIL
["data:text/plain;a=%2C,X"]
expected: FAIL
["data:x;base64;x,WA"]
expected: FAIL
["data:IMAGE/gif;hi=x,%C2%B1"]
expected: FAIL
["data:x/x;base64;charset=x,WA"]
expected: FAIL
@ -94,27 +40,9 @@
[processing.any.sharedworker.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
["data:;x=x;charset=x,X"]
expected: FAIL
["data:text/plain;a=\\",\\",X"]
expected: FAIL
["data://test:test/,X"]
expected: FAIL
["data:;x=x,X"]
expected: FAIL
["data:text/plain;a=%2C,X"]
expected: FAIL
["data:x;base64;x,WA"]
expected: FAIL
["data:IMAGE/gif;hi=x,%C2%B1"]
expected: FAIL
["data:x/x;base64;charset=x,WA"]
expected: FAIL