Bug 1581278 part 5. Stop incorrectly rejecting promises in EME. r=bryce

Differential Revision: https://phabricator.services.mozilla.com/D46387

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Zbarsky 2019-09-20 14:20:48 +00:00
parent b544880d43
commit 013f0714ce
12 changed files with 104 additions and 87 deletions

View File

@ -232,10 +232,8 @@ already_AddRefed<Promise> MediaKeySession::GenerateRequest(
// If initDataType is the empty string, return a promise rejected
// with a newly created TypeError.
if (aInitDataType.IsEmpty()) {
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING(
"Empty initDataType passed to MediaKeySession.generateRequest()"));
promise->MaybeRejectWithTypeError(
u"Empty initDataType passed to MediaKeySession.generateRequest()");
EME_LOG(
"MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initDataType",
this, NS_ConvertUTF16toUTF8(mSessionId).get());
@ -247,10 +245,8 @@ already_AddRefed<Promise> MediaKeySession::GenerateRequest(
nsTArray<uint8_t> data;
CopyArrayBufferViewOrArrayBufferData(aInitData, data);
if (data.IsEmpty()) {
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING(
"Empty initData passed to MediaKeySession.generateRequest()"));
promise->MaybeRejectWithTypeError(
u"Empty initData passed to MediaKeySession.generateRequest()");
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initData",
this, NS_ConvertUTF16toUTF8(mSessionId).get());
return promise.forget();
@ -287,10 +283,8 @@ already_AddRefed<Promise> MediaKeySession::GenerateRequest(
if (!ValidateInitData(data, aInitDataType)) {
// If the preceding step failed, reject promise with a newly created
// TypeError.
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING("initData sanitization failed in "
"MediaKeySession.generateRequest()"));
promise->MaybeRejectWithTypeError(
u"initData sanitization failed in MediaKeySession.generateRequest()");
EME_LOG(
"MediaKeySession[%p,'%s'] GenerateRequest() initData sanitization "
"failed",
@ -359,9 +353,8 @@ already_AddRefed<Promise> MediaKeySession::Load(const nsAString& aSessionId,
// 4. If sessionId is the empty string, return a promise rejected with a newly
// created TypeError.
if (aSessionId.IsEmpty()) {
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING("Trying to load a session with empty session ID"));
promise->MaybeRejectWithTypeError(
u"Trying to load a session with empty session ID");
// "The sessionId parameter is empty."
EME_LOG("MediaKeySession[%p,''] Load() failed, no sessionId", this);
return promise.forget();
@ -371,9 +364,8 @@ already_AddRefed<Promise> MediaKeySession::Load(const nsAString& aSessionId,
// on this object's session type is false, return a promise rejected with
// a newly created TypeError.
if (mSessionType == MediaKeySessionType::Temporary) {
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING("Trying to load() into a non-persistent session"));
promise->MaybeRejectWithTypeError(
u"Trying to load() into a non-persistent session");
EME_LOG(
"MediaKeySession[%p,''] Load() failed, can't load in a non-persistent "
"session",
@ -437,10 +429,8 @@ already_AddRefed<Promise> MediaKeySession::Update(
}
CopyArrayBufferViewOrArrayBufferData(aResponse, data);
if (data.IsEmpty()) {
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING(
"Empty response buffer passed to MediaKeySession.update()"));
promise->MaybeRejectWithTypeError(
u"Empty response buffer passed to MediaKeySession.update()");
EME_LOG("MediaKeySession[%p,'%s'] Update() failed, empty response buffer",
this, NS_ConvertUTF16toUTF8(mSessionId).get());
return promise.forget();

View File

@ -73,16 +73,14 @@ void MediaKeySystemAccessManager::Request(
NS_ConvertUTF16toUTF8(aKeySystem).get());
if (aKeySystem.IsEmpty()) {
aPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING("Key system string is empty"));
aPromise->MaybeRejectWithTypeError(u"Key system string is empty");
// Don't notify DecoderDoctor, as there's nothing we or the user can
// do to fix this situation; the site is using the API wrong.
return;
}
if (aConfigs.IsEmpty()) {
aPromise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING("Candidate MediaKeySystemConfigs is empty"));
aPromise->MaybeRejectWithTypeError(
u"Candidate MediaKeySystemConfigs is empty");
// Don't notify DecoderDoctor, as there's nothing we or the user can
// do to fix this situation; the site is using the API wrong.
return;

View File

@ -185,10 +185,8 @@ already_AddRefed<DetailedPromise> MediaKeys::SetServerCertificate(
nsTArray<uint8_t> data;
CopyArrayBufferViewOrArrayBufferData(aCert, data);
if (data.IsEmpty()) {
promise->MaybeReject(
NS_ERROR_DOM_TYPE_ERR,
NS_LITERAL_CSTRING(
"Empty certificate passed to MediaKeys.setServerCertificate()"));
promise->MaybeRejectWithTypeError(
u"Empty certificate passed to MediaKeys.setServerCertificate()");
return promise.forget();
}
@ -283,7 +281,12 @@ void MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode,
}
MOZ_ASSERT(NS_FAILED(aExceptionCode));
promise->MaybeReject(aExceptionCode, aReason);
if (aExceptionCode == NS_ERROR_DOM_TYPE_ERR) {
// This is supposed to be a TypeError, not a DOMException.
promise->MaybeRejectWithTypeError(NS_ConvertUTF8toUTF16(aReason));
} else {
promise->MaybeReject(aExceptionCode, aReason);
}
if (mCreatePromiseId == aId) {
// Note: This will probably destroy the MediaKeys object!

View File

@ -15,7 +15,7 @@ function runTest(config, qualifier)
var mediaKeySession;
var messageEventFired = false;
return navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function (access) {
var p = navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function (access) {
initDataType = access.getConfiguration().initDataTypes[0];
initData = getInitData(config.content, initDataType);
return access.createMediaKeys();
@ -34,15 +34,19 @@ function runTest(config, qualifier)
+ '}]}';
messageEventFired = true;
return messageEvent.target.update(stringToUint8Array(jwkSet));
}).then(function () {
assert_unreached('Error: update() should fail because the processed message has non-ASCII character.');
}).catch(function (error) {
if(messageEventFired){
assert_equals(error.name, 'TypeError');
}
else {
assert_unreached('Error: ' + error.name);
// Ensure we reached the update() call we are trying to test.
if (!messageEventFired) {
assert_unreached(
`Failed to reach the update() call. Error: '${error.name}' '${error.message}'`);
}
// Propagate the error on through.
throw error;
});
return promise_rejects_js(
test, TypeError, p,
'update() should fail because the processed message has non-ASCII character.');
}, testname);
}
}

View File

@ -57,17 +57,16 @@ function runTest(config,qualifier) {
// with the provided initData. generateRequest() should fail with an
// TypeError. Returns a promise that is resolved
// if the error occurred and rejected otherwise.
return navigator.requestMediaKeySystemAccess(testspec.keysystem, getSimpleConfigurationForInitDataType(testspec.initDataType)).then(function(access) {
var p = navigator.requestMediaKeySystemAccess(testspec.keysystem, getSimpleConfigurationForInitDataType(testspec.initDataType)).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var mediaKeySession = mediaKeys.createSession("temporary");
return mediaKeySession.generateRequest(testspec.initDataType, testspec.initData);
}).then(test.step_func(function() {
assert_unreached('generateRequest() succeeded unexpectedly');
}), test.step_func(function(error) {
assert_equals(error.name, 'TypeError');
}));
},testspec.testname);
});
return promise_rejects_js(test, TypeError, p,
"generateRequest() should fail");
}, testspec.testname);
});
});
}

View File

@ -7,7 +7,7 @@ function runTest(config)
var invalidLicense = new Uint8Array([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]);
var messageEventFired = false;
return navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function (access) {
var p = navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function (access) {
initDataType = access.getConfiguration().initDataTypes[0];
initData = getInitData(initDataType);
return access.createMediaKeys();
@ -20,14 +20,19 @@ function runTest(config)
}).then(function (messageEvent) {
messageEventFired = true;
return messageEvent.target.update(invalidLicense);
}).then(function () {
assert_unreached('Error: update() should fail because of an invalid license.');
}).catch(function (error) {
if(messageEventFired) {
assert_equals(error.name, 'TypeError');
} else {
assert_unreached('Error: ' + error.name);
// Ensure we reached the update() call we are trying to test.
if (!messageEventFired) {
assert_unreached(
`Failed to reach the update() call. Error: '${error.name}' '${error.message}'`);
}
// Propagate the error on through.
throw error;
});
return promise_rejects_js(
test, TypeError, p,
'update() should fail because of an invalid license.');
}, 'Update with invalid Clear Key license');
}
}

View File

@ -11,11 +11,17 @@ function runTest(config, qualifier) {
modifiedtestname = testname.replace( '%audiocontenttype', audiocontenttypes ).replace( '%videocontenttype', videocontenttypes );
promise_test(function(test) {
return navigator.requestMediaKeySystemAccess(keySystem, configurations).then(function(a) {
assert_unreached('Unexpected requestMediaKeySystemAccess() success.');
}, function(e) {
assert_equals(e.name, expectedError);
});
var p = navigator.requestMediaKeySystemAccess(keySystem, configurations);
// expectedError is a string name for the error. We can differentiate
// JS Errors from DOMExceptions by checking whether
// window[expectedError] exists. If it does, expectedError is the name
// of a JS Error subclass and window[expectedError] is the constructor
// for that subclass. Otherwise it's a name for a DOMException.
if (window[expectedError]) {
return promise_rejects_js(test, window[expectedError], p);
} else {
return promise_rejects_dom(test, expectedError, p);
}
}, prefix + modifiedtestname + ' should result in ' + expectedError );
}

View File

@ -30,7 +30,8 @@ function runTest(config, qualifier) {
assert_unreached('setMediaKeys should fail when setting to wrong kind of object (Date)');
}, function(error) {
// The error should be TypeError.
assert_equals(error.name, 'TypeError', 'setMediaKeys should return a TypeError when setting to wrong kind of object (Date)');
assert_throws_js(TypeError, () => { throw error; },
'setMediaKeys should return a TypeError when setting to wrong kind of object (Date)');
return navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]);
}).then(function(access) {
assert_equals(access.keySystem, config.keysystem)

View File

@ -57,7 +57,14 @@ function runTest(config) {
func: function (mk6, type) {
return mk6.createSession().generateRequest(type, new Uint8Array(0));
}
}
},
// Using an empty type should return a 'TypeError'.
{
exception: 'TypeError',
func: function (mk7, type) {
return mk7.createSession().generateRequest('', initData);
}
},
];
function generateRequestTestExceptions(){
return new Promise(function(resolve, reject){

View File

@ -37,7 +37,7 @@ function runTest(config,qualifier) {
return;
}
assert_equals(error.name, 'TypeError' );
assert_throws_js(TypeError, () => { throw error; });
test.done();
} ) );
}).catch(onFailure);

View File

@ -21,7 +21,7 @@ function runTest(config)
return jwkSet + ',"test":"unknown"'.repeat(4000) + '}';
}
return navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function(access) {
var p = navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function(access) {
initDataType = access.getConfiguration().initDataTypes[0];
initData = getInitData(initDataType);
return access.createMediaKeys();
@ -36,10 +36,8 @@ function runTest(config)
assert_greater_than(jwkSet.length, 65536);
var jwkSetArray = stringToUint8Array(jwkSet);
return mediaKeySession.update(jwkSetArray);
}).then(function () {
assert_unreached('update() with a response longer than 64Kb succeed');
}).catch(function (error) {
assert_equals(error.name, 'TypeError');
});
return promise_rejects_js(test, TypeError, p);
}, 'update() with invalid response (longer than 64Kb characters) should fail.');
}

View File

@ -240,25 +240,31 @@ function test_exception(testCase /*...*/) {
var exception = testCase.exception;
var args = Array.prototype.slice.call(arguments, 1);
// Currently blink throws for TypeErrors rather than returning
// a rejected promise (http://crbug.com/359386).
// FIXME: Remove try/catch once they become failed promises.
try {
return func.apply(null, args).then(
function (result) {
assert_unreached(format_value(func));
},
function (error) {
assert_equals(error.name, exception, format_value(func));
assert_not_equals(error.message, "", format_value(func));
// This should really be rewritten in terms of the promise_rejects_*
// testharness utility functions, but that needs the async test involved
// passed in, and we don't have that here.
return func.apply(null, args).then(
function (result) {
assert_unreached(format_value(func));
},
function (error) {
assert_not_equals(error.message, "", format_value(func));
// `exception` is a string name for the error. We can differentiate
// JS Errors from DOMExceptions by checking whether
// window[exception] exists. If it does, expectedError is the name
// of a JS Error subclass and window[exception] is the constructor
// for that subclass. Otherwise it's a name for a DOMException.
if (window[exception]) {
assert_throws_js(window[exception],
() => { throw error; },
format_value(func));
} else {
assert_throws_dom(exception,
() => { throw error; },
format_value(func));
}
);
} catch (e) {
// Only allow 'TypeError' exceptions to be thrown.
// Everything else should be a failed promise.
assert_equals('TypeError', exception, format_value(func));
assert_equals(e.name, exception, format_value(func));
}
}
);
}
// Check that the events sequence (array of strings) matches the pattern (array of either strings, or