Bug 1235183. Part 4 - create channel asynchronously.
MozReview-Commit-ID: 9JVuHhhMFoa
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -464,18 +464,21 @@ void HTMLMediaElement::ReportLoadError(c
aParams,
aParamCount);
}
class HTMLMediaElement::ChannelLoader final {
public:
NS_INLINE_DECL_REFCOUNTING(ChannelLoader);
- nsresult Load(HTMLMediaElement* aElement)
+ void LoadInternal(HTMLMediaElement* aElement)
{
+ if (mCancelled) {
+ return;
+ }
// determine what security checks need to be performed in AsyncOpen2().
nsSecurityFlags securityFlags = aElement->ShouldCheckAllowOrigin()
? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS :
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
if (aElement->GetCORSMode() == CORS_USE_CREDENTIALS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
@@ -506,17 +509,19 @@ public:
loadGroup,
nullptr, // aCallbacks
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
nsIChannel::LOAD_CLASSIFY_URI |
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
if (NS_FAILED(rv)) {
- return rv;
+ // Notify load error so the element will try next resource candidate.
+ aElement->NotifyLoadError();
+ return;
}
// This is a workaround and it will be fix in bug 1264230.
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
if (loadInfo) {
NeckoOriginAttributes originAttrs;
NS_GetOriginAttributes(channel, originAttrs);
loadInfo->SetOriginAttributes(originAttrs);
@@ -540,37 +545,50 @@ public:
hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
NS_LITERAL_CSTRING("bytes=0-"),
false);
aElement->SetRequestHeaders(hc);
}
rv = channel->AsyncOpen2(loadListener);
if (NS_FAILED(rv)) {
- return rv;
+ // Notify load error so the element will try next resource candidate.
+ aElement->NotifyLoadError();
+ return;
}
// Else the channel must be open and starting to download. If it encounters
// a non-catastrophic failure, it will set a new task to continue loading
// another candidate. It's safe to set it as mChannel now.
mChannel = channel;
// loadListener will be unregistered either on shutdown or when
// OnStartRequest for the channel we just opened fires.
nsContentUtils::RegisterShutdownObserver(loadListener);
- return NS_OK;
+ }
+
+ nsresult Load(HTMLMediaElement* aElement)
+ {
+ // Per bug 1235183 comment 8, we can't spin the event loop from stable
+ // state. Defer NS_NewChannel() to a new regular runnable.
+ return NS_DispatchToMainThread(NewRunnableMethod<HTMLMediaElement*>(
+ this, &ChannelLoader::LoadInternal, aElement));
}
void Cancel()
{
- mChannel->Cancel(NS_BINDING_ABORTED);
- mChannel = nullptr;
+ mCancelled = true;
+ if (mChannel) {
+ mChannel->Cancel(NS_BINDING_ABORTED);
+ mChannel = nullptr;
+ }
}
void Done() {
+ MOZ_ASSERT(mChannel);
// Decoder successfully created, the decoder now owns the MediaResource
// which owns the channel.
mChannel = nullptr;
}
nsresult Redirect(nsIChannel* aChannel,
nsIChannel* aNewChannel,
uint32_t aFlags)
@@ -604,16 +622,18 @@ private:
{
MOZ_ASSERT(!mChannel);
}
// Holds a reference to the first channel we open to the media resource.
// Once the decoder is created, control over the channel passes to the
// decoder, and we null out this reference. We must store this in case
// we need to cancel the channel before control of it passes to the decoder.
nsCOMPtr<nsIChannel> mChannel;
+
+ bool mCancelled = false;
};
NS_IMPL_ADDREF_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
NS_IMPL_RELEASE_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLMediaElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)