Bug 966439 - BroadcastChannel API - patch 2 - close() method, r=smaug

This commit is contained in:
Andrea Marchesini 2015-01-14 11:50:34 +00:00
parent 65afdf13d8
commit 9a3e22bc9c
5 changed files with 112 additions and 3 deletions

View File

@ -219,6 +219,7 @@ BroadcastChannel::BroadcastChannel(nsPIDOMWindow* aWindow,
, mChannel(aChannel) , mChannel(aChannel)
, mIsKeptAlive(false) , mIsKeptAlive(false)
, mInnerID(0) , mInnerID(0)
, mState(StateActive)
{ {
// Window can be null in workers // Window can be null in workers
} }
@ -322,7 +323,18 @@ BroadcastChannel::Constructor(const GlobalObject& aGlobal,
} }
void void
BroadcastChannel::PostMessage(const nsAString& aMessage) BroadcastChannel::PostMessage(const nsAString& aMessage, ErrorResult& aRv)
{
if (mState != StateActive) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
PostMessageInternal(aMessage);
}
void
BroadcastChannel::PostMessageInternal(const nsAString& aMessage)
{ {
if (mActor) { if (mActor) {
nsRefPtr<PostMessageRunnable> runnable = nsRefPtr<PostMessageRunnable> runnable =
@ -338,6 +350,21 @@ BroadcastChannel::PostMessage(const nsAString& aMessage)
mPendingMessages.AppendElement(aMessage); mPendingMessages.AppendElement(aMessage);
} }
void
BroadcastChannel::Close()
{
if (mState != StateActive) {
return;
}
if (mPendingMessages.IsEmpty()) {
Shutdown();
} else {
MOZ_ASSERT(!mActor);
mState = StateClosing;
}
}
void void
BroadcastChannel::ActorFailed() BroadcastChannel::ActorFailed()
{ {
@ -349,6 +376,10 @@ BroadcastChannel::ActorCreated(ipc::PBackgroundChild* aActor)
{ {
MOZ_ASSERT(aActor); MOZ_ASSERT(aActor);
if (mState == StateClosed) {
return;
}
PBroadcastChannelChild* actor = PBroadcastChannelChild* actor =
aActor->SendPBroadcastChannelConstructor(mPrincipalInfo, mOrigin, mChannel); aActor->SendPBroadcastChannelConstructor(mPrincipalInfo, mOrigin, mChannel);
@ -359,15 +390,21 @@ BroadcastChannel::ActorCreated(ipc::PBackgroundChild* aActor)
// Flush pending messages. // Flush pending messages.
for (uint32_t i = 0; i < mPendingMessages.Length(); ++i) { for (uint32_t i = 0; i < mPendingMessages.Length(); ++i) {
PostMessage(mPendingMessages[i]); PostMessageInternal(mPendingMessages[i]);
} }
mPendingMessages.Clear(); mPendingMessages.Clear();
if (mState == StateClosing) {
Shutdown();
}
} }
void void
BroadcastChannel::Shutdown() BroadcastChannel::Shutdown()
{ {
mState = StateClosed;
// If shutdown() is called we have to release the reference if we still keep // If shutdown() is called we have to release the reference if we still keep
// it. // it.
if (mIsKeptAlive) { if (mIsKeptAlive) {

View File

@ -53,7 +53,9 @@ public:
aName = mChannel; aName = mChannel;
} }
void PostMessage(const nsAString& aMessage); void PostMessage(const nsAString& aMessage, ErrorResult& aRv);
void Close();
EventHandlerNonNull* GetOnmessage(); EventHandlerNonNull* GetOnmessage();
void SetOnmessage(EventHandlerNonNull* aCallback); void SetOnmessage(EventHandlerNonNull* aCallback);
@ -81,6 +83,8 @@ private:
~BroadcastChannel(); ~BroadcastChannel();
void PostMessageInternal(const nsAString& aMessage);
void UpdateMustKeepAlive(); void UpdateMustKeepAlive();
nsRefPtr<BroadcastChannelChild> mActor; nsRefPtr<BroadcastChannelChild> mActor;
@ -95,6 +99,12 @@ private:
bool mIsKeptAlive; bool mIsKeptAlive;
uint64_t mInnerID; uint64_t mInnerID;
enum {
StateActive,
StateClosing,
StateClosed
} mState;
}; };
} // namespace dom } // namespace dom

View File

@ -6,3 +6,4 @@ support-files =
[test_broadcastchannel_basic.html] [test_broadcastchannel_basic.html]
[test_broadcastchannel_self.html] [test_broadcastchannel_self.html]
[test_broadcastchannel_worker.html] [test_broadcastchannel_worker.html]
[test_broadcastchannel_close.html]

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for BroadcastChannel</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="content"></div>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var receiver = new BroadcastChannel('foo');
var sequence = [ '2', 'done' ];
receiver.onmessage = function(e) {
if (!sequence.length) {
ok (false, 'No more data is expected');
return;
}
var data = sequence.shift();
is(e.data, data);
if (!sequence.length) {
SimpleTest.executeSoon(function() {
SimpleTest.finish();
});
}
}
var x = new BroadcastChannel('foo');
x.close();
try {
x.postMessage('1');
ok(false, "PostMessage should throw if called after a close().");
} catch(e) {
ok(true, "PostMessage should throw if called after a close().");
}
var y = new BroadcastChannel('foo');
y.postMessage('2');
y.close();
try {
y.postMessage('3');
ok(false, "PostMessage should throw if called after a close().");
} catch(e) {
ok(true, "PostMessage should throw if called after a close().");
}
var z = new BroadcastChannel('foo');
z.postMessage('done');
</script>
</body>
</html>

View File

@ -12,7 +12,10 @@
interface BroadcastChannel : EventTarget { interface BroadcastChannel : EventTarget {
readonly attribute DOMString name; readonly attribute DOMString name;
[Throws]
void postMessage(DOMString message); void postMessage(DOMString message);
void close();
attribute EventHandler onmessage; attribute EventHandler onmessage;
}; };