Bug 476731 - Media element should fire error event when src is a 404 - r=doublec sr=roc

This commit is contained in:
Chris Pearce 2009-02-09 14:04:10 +13:00
parent 0757196440
commit 8d5bc5908a
23 changed files with 194 additions and 64 deletions

View File

@ -213,6 +213,12 @@ protected:
*/
nsresult NewURIFromString(const nsAutoString& aURISpec, nsIURI** aURI);
/**
* Does step 12 of the media load() algorithm, sends error/emptied events to
* to the media element, and reset network/begun state.
*/
void NoSupportedMediaError();
nsRefPtr<nsMediaDecoder> mDecoder;
nsCOMPtr<nsIChannel> mChannel;

View File

@ -138,6 +138,8 @@ NS_IMETHODIMP nsHTMLMediaElement::nsMediaLoadListener::OnStartRequest(nsIRequest
// the connection since we aren't interested in keeping the channel
// alive ourselves.
rv = NS_BINDING_ABORTED;
if (mElement)
mElement->NetworkError();
}
// The element is only needed until we've had a chance to call
@ -243,16 +245,31 @@ PRBool nsHTMLMediaElement::AbortExistingLoads()
return PR_FALSE;
}
void nsHTMLMediaElement::NoSupportedMediaError()
{
mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_NONE_SUPPORTED);
mBegun = PR_FALSE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
}
/* void load (); */
NS_IMETHODIMP nsHTMLMediaElement::Load()
{
if (AbortExistingLoads())
return NS_OK;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
mBegun = PR_TRUE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
nsCOMPtr<nsIURI> uri;
nsresult rv = PickMediaElement(getter_AddRefs(uri));
if (NS_FAILED(rv))
if (NS_FAILED(rv)) {
NoSupportedMediaError();
return rv;
}
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
@ -270,6 +287,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
NoSupportedMediaError();
return NS_ERROR_CONTENT_BLOCKED;
}
@ -279,8 +297,10 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
nsnull,
nsnull,
nsIRequest::LOAD_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
NetworkError();
return rv;
}
// The listener holds a strong reference to us. This creates a reference
// cycle which is manually broken in the listener's OnStartRequest method
// after it is finished with the element.
@ -295,14 +315,19 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
PR_FALSE,
&rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
NoSupportedMediaError();
return rv;
}
} else {
rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(NodePrincipal(),
uri,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
NoSupportedMediaError();
return rv;
}
listener = loadListener;
}
@ -325,14 +350,10 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
// and is useless now anyway, so drop our reference to it to allow it to
// be destroyed.
mChannel = nsnull;
NetworkError();
return rv;
}
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
mBegun = PR_TRUE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
return NS_OK;
}
@ -1163,9 +1184,6 @@ nsresult nsHTMLMediaElement::DispatchAsyncProgressEvent(const nsAString& aName)
nsresult nsHTMLMediaElement::DispatchProgressEvent(const nsAString& aName)
{
if (!mDecoder)
return NS_OK;
nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(GetOwnerDoc()));
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(static_cast<nsIContent*>(this)));
NS_ENSURE_TRUE(docEvent && target, NS_ERROR_INVALID_ARG);
@ -1177,9 +1195,15 @@ nsresult nsHTMLMediaElement::DispatchProgressEvent(const nsAString& aName)
nsCOMPtr<nsIDOMProgressEvent> progressEvent(do_QueryInterface(event));
NS_ENSURE_TRUE(progressEvent, NS_ERROR_FAILURE);
nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
PRInt64 totalBytes = 0;
PRUint64 downloadPosition = 0;
if (mDecoder) {
nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
totalBytes = stats.mTotalBytes;
downloadPosition = stats.mDownloadPosition;
}
rv = progressEvent->InitProgressEvent(aName, PR_TRUE, PR_TRUE,
stats.mTotalBytes >= 0, stats.mDownloadPosition, stats.mTotalBytes);
totalBytes >= 0, downloadPosition, totalBytes);
NS_ENSURE_SUCCESS(rv, rv);
PRBool dummy;

View File

@ -74,6 +74,7 @@ _TEST_FILES += \
test_duration1.html \
test_ended1.html \
test_ended2.html \
test_error_on_404.html \
test_onloadedmetadata.html \
test_progress1.html \
test_progress3.html \

View File

@ -1,5 +1,7 @@
<html>
<head>
</head>
<body onload="setTimeout(load, 0);" onunload="done()">
<script>
// Page URL: http://example.org/tests/content/media/video/test/file_access_controls.html
@ -86,7 +88,15 @@ function load() {
opener.ok(branch!=null, "Get media pref branch");
gOldPref = branch.getBoolPref("enforce_same_site_origin");
branch.setBoolPref("enforce_same_site_origin", true);
video = document.createElement('video');
video.addEventListener('loadeddata', function(){result('loaded');}, false);
video.addEventListener('error', function(){result('error');}, false);
video.id = 'video';
nextTest();
document.body.appendChild(video);
}
function nextTest() {
@ -122,16 +132,6 @@ function done() {
}
</script>
</head>
<body onload="load();" onunload="done()">
<!-- Change onloadedfirstframe to onloadeddata after bug 462570 lands -->
<video id="video"
onloadeddata="result('loaded');"
onerror="result('error');">
</video>
</body>
</html>

View File

@ -7,8 +7,8 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v2' autoplay></video><audio id='a2' autoplay></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<video id='v2' onerror="event.stopPropagation();" autoplay></video><audio id='a2' onerror="event.stopPropagation();"autoplay></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById('v1');

View File

@ -13,10 +13,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=463162
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=463162">Mozilla Bug 463162</a>
<audio id='a1'><sauce type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a2'><source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a3'><html:source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a4'><svg:source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a1' onerror="event.stopPropagation();"><sauce type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a2' onerror="event.stopPropagation();"><source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a3' onerror="event.stopPropagation();"><html:source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<audio id='a4' onerror="event.stopPropagation();"><svg:source type="audio/x-wav" src="r11025_s16_c1.wav"/></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[

View File

@ -16,7 +16,7 @@ a Bug 469247</a>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<video id="v" onerror="event.stopPropagation();"></video>
<pre id="test">
<script type="application/javascript">

View File

@ -16,7 +16,7 @@ a Bug 469247</a>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<video id="v" onerror="event.stopPropagation();"></video>
<pre id="test">
<script src="can_play_type_ogg.js"></script>

View File

@ -16,7 +16,7 @@ a Bug 469247</a>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<video id="v" onerror="event.stopPropagation();"></video>
<pre id="test">
<script src="can_play_type_wave.js"></script>

View File

@ -16,7 +16,7 @@ a Bug 469247</a>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<video id="v" onerror="event.stopPropagation();"></video>
<pre id="test">
<script src="can_play_type_ogg.js"></script>

View File

@ -16,7 +16,7 @@ a Bug 469247</a>
<div id="content" style="display: none">
</div>
<video id="v"></video>
<video id="v" onerror="event.stopPropagation();"></video>
<pre id="test">
<script src="can_play_type_wave.js"></script>

View File

@ -11,7 +11,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video><source></video><audio><source></audio>
<video onerror="event.stopPropagation();"><source></video><audio onerror="event.stopPropagation();"><source></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
is(HTMLElement.NETWORK_EMPTY, undefined);

View File

@ -7,8 +7,8 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v2' controls></video><audio id='a2' controls></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<video id='v2' onerror="event.stopPropagation();" controls></video><audio id='a2' onerror="event.stopPropagation();" controls></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById('v1');

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById('v1');

View File

@ -28,25 +28,25 @@ var gOldWavePref = branch.getBoolPref("wave.enabled");
branch.setBoolPref("ogg.enabled", false);
branch.setBoolPref("wave.enabled", false);
</script>
var gLoadError = new Object();
<video id="video1">
<source type="video/ogg" src="320x240.ogv"/>
<source type="audio/wave" src="r11025_u8_c1.wav"/>
</video>
gLoadError['video1'] = 0;
gLoadError['video2'] = 0;
gLoadError['video3'] = 0;
<video id="video2" src="320x240.ogv"></video>
<video id="video3" src="r11025_u8_c1.wav"></video>
<script>
var gErrorCount = 0;
SimpleTest.waitForExplicitFinish();
function doTest() {
is(document.getElementById('video1').currentSrc, "");
is(document.getElementById('video2').currentSrc, "");
is(document.getElementById('video3').currentSrc, "");
function finishTest() {
is(document.getElementById('video1').currentSrc, "", 'video1.currentSrc==""');
is(document.getElementById('video2').currentSrc, "", 'video2.currentSrc==""');
is(document.getElementById('video3').currentSrc, "", 'video3.currentSrc==""');
is(gLoadError['video1'], 1, "Load error on video1");
is(gLoadError['video2'], 1, "Load error on video2");
is(gLoadError['video3'], 1, "Load error on video3");
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
branch.setBoolPref("ogg.enabled", gOldOggPref);
@ -55,12 +55,26 @@ function doTest() {
SimpleTest.finish();
}
// Using a timeout here sucks, but we currently have no way
// to be notified that the element couldn't load. At least if this timeout
// happens "too early", the test will pass instead of failing.
setTimeout(doTest, 1000);
function videoError(event, id) {
event.stopPropagation();
gLoadError[id]++;
gErrorCount++;
if (gErrorCount == 3) {
finishTest();
}
}
</script>
<video id="video1" onerror="videoError(event, 'video1');">
<source type="video/ogg" src="320x240.ogv"/>
<source type="audio/wave" src="r11025_u8_c1.wav"/>
</video>
<video id="video2" src="320x240.ogv" onerror="videoError(event, 'video2');"></video>
<video id="video3" src="r11025_u8_c1.wav" onerror="videoError(event, 'video3');"></video>
</pre>
</body>
</html>

View File

@ -0,0 +1,80 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=476731
-->
<head>
<title>Test for Bug 476731</title>
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=476731">Mozilla Bug </a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug **/
var gLoadedData = new Object();
var gLoadStart = new Object();
var gLoadError = new Object();
gLoadedData['v'] = false;
gLoadedData['a'] = false;
gLoadStart['v'] = false;
gLoadStart['a'] = false;
gLoadError['v'] = false;
gLoadError['a'] = false;
function loadError(evt, id) {
// Prevent mochitest's onerror handler catching the 'error' event on bubble.
evt.stopPropagation();
is(gLoadError[id], false, "Shouldn't have more than one error for each media element");
gLoadError[id] = true;
is(gLoadStart[id], true, "Should have started load");
is(gLoadedData[id], false, "Shouldn't have finished load.");
if (gLoadError['a'] && gLoadError['v'])
SimpleTest.finish();
}
function loadedData(evt, id) {
gLoadedData[id] = true;
}
function loadStart(evt, id) {
gLoadStart[id] = true;
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<video id="v"
onerror="loadError(event, 'v');"
onloadstart="loadStart(event, 'v');"
onloadeddata="loadedData(event, 'v');"
src="404.ogg">
</video>
<audio id="a"
onerror="loadError(event, 'a');"
onloadstart="loadStart(event, 'a');"
onloadeddata="loadedData(event, 'a');"
src="404.wav">
</audio>
</body>
</html>

View File

@ -15,6 +15,8 @@ function maketest(expect_load, attach_media, name, type, check_metadata) {
return function (testNum) {
var e = document.createElement('video');
e.addEventListener('error', function(e) { e.stopPropagation();}, false);
if (expect_load) {
// this could be loadedmetadata, but needs bug 466410 fixed
e.addEventListener('loadeddata', function () {

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById('v1');

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById('v1');

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">
var v1 = document.getElementById('v1');

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<video id='v'></video>
<video id='v' onerror="event.stopPropagation();"></video>
<pre id="test">
<script class="testbody" type="text/javascript">
// http://www.whatwg.org/specs/web-apps/current-work/#dom-media-seek

View File

@ -8,7 +8,7 @@
</head>
<body>
<video id='v1'></video><audio id='a1'></audio>
<video id='v1' onerror="event.stopPropagation();"></video><audio id='a1' onerror="event.stopPropagation();"></audio>
<pre id="test">
<script class="testbody" type="text/javascript">

View File

@ -37,7 +37,7 @@
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
[scriptable, uuid(9BEA222F-13CF-42AD-A14E-E01F4F66B833)]
[scriptable, uuid(7bd8c29f-8a76-453f-9373-79f820f2dc01)]
interface nsIDOMHTMLMediaError : nsISupports
{
/* The download of the media resource was aborted by
@ -52,5 +52,8 @@ interface nsIDOMHTMLMediaError : nsISupports
the media resource */
const unsigned short MEDIA_ERR_DECODE = 3;
/* No suitable media resource could be found */
const unsigned short MEDIA_ERR_NONE_SUPPORTED = 4;
readonly attribute unsigned short code;
};