Commit 5882ee35 authored by Harald Alvestrand's avatar Harald Alvestrand Committed by Commit Bot

Implement datachannel.onclosing event

Bug: chromium:1040584
Change-Id: Ic78ea01897ee3f8dd120ed6d638a1f70a288c26c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1991571
Auto-Submit: Harald Alvestrand <hta@chromium.org>
Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Reviewed-by: default avatarSteve Anton <steveanton@chromium.org>
Commit-Queue: Harald Alvestrand <hta@chromium.org>
Cr-Commit-Position: refs/heads/master@{#732632}
parent be9ead6f
......@@ -69,6 +69,7 @@
"checking",
"click",
"close",
"closing",
"complete",
"compositionend",
"compositionstart",
......
......@@ -222,6 +222,7 @@ RTCDataChannel::RTCDataChannel(
buffered_amount_low_threshold_(0U),
buffered_amount_(0U),
stopped_(false),
closed_from_owner_(false),
observer_(base::MakeRefCounted<Observer>(
context->GetTaskRunner(TaskType::kNetworking),
this,
......@@ -427,6 +428,7 @@ void RTCDataChannel::send(Blob* data, ExceptionState& exception_state) {
void RTCDataChannel::close() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
closed_from_owner_ = true;
if (observer_)
channel()->Close();
// Note that even though Close() will run synchronously, the readyState has
......@@ -459,9 +461,10 @@ bool RTCDataChannel::HasPendingActivity() const {
// A RTCDataChannel object must not be garbage collected if its
// * readyState is connecting and at least one event listener is registered
// for open events, message events, error events, or close events.
// for open events, message events, error events, closing events
// or close events.
// * readyState is open and at least one event listener is registered for
// message events, error events, or close events.
// message events, error events, closing events, or close events.
// * readyState is closing and at least one event listener is registered for
// error events, or close events.
// * underlying data transport is established and data is queued to be
......@@ -472,7 +475,8 @@ bool RTCDataChannel::HasPendingActivity() const {
has_valid_listeners |= HasEventListeners(event_type_names::kOpen);
FALLTHROUGH;
case webrtc::DataChannelInterface::kOpen:
has_valid_listeners |= HasEventListeners(event_type_names::kMessage);
has_valid_listeners |= HasEventListeners(event_type_names::kMessage) ||
HasEventListeners(event_type_names::kClosing);
FALLTHROUGH;
case webrtc::DataChannelInterface::kClosing:
has_valid_listeners |= HasEventListeners(event_type_names::kError) ||
......@@ -509,6 +513,11 @@ void RTCDataChannel::OnStateChange(
IncrementCounter(DataChannelCounters::kOpened);
ScheduleDispatchEvent(Event::Create(event_type_names::kOpen));
break;
case webrtc::DataChannelInterface::kClosing:
if (!closed_from_owner_) {
ScheduleDispatchEvent(Event::Create(event_type_names::kClosing));
}
break;
case webrtc::DataChannelInterface::kClosed:
if (!channel()->error().ok()) {
ScheduleDispatchEvent(MakeGarbageCollected<RTCErrorEvent>(
......
......@@ -91,6 +91,7 @@ class MODULES_EXPORT RTCDataChannel final
DEFINE_ATTRIBUTE_EVENT_LISTENER(bufferedamountlow, kBufferedamountlow)
DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError)
DEFINE_ATTRIBUTE_EVENT_LISTENER(close, kClose)
DEFINE_ATTRIBUTE_EVENT_LISTENER(closing, kClosing)
DEFINE_ATTRIBUTE_EVENT_LISTENER(message, kMessage)
// EventTarget
......@@ -174,6 +175,7 @@ class MODULES_EXPORT RTCDataChannel final
unsigned buffered_amount_low_threshold_;
unsigned buffered_amount_;
bool stopped_;
bool closed_from_owner_;
scoped_refptr<Observer> observer_;
THREAD_CHECKER(thread_checker_);
};
......
......@@ -51,6 +51,7 @@ enum RTCDataChannelState {
attribute EventHandler onopen;
attribute EventHandler onbufferedamountlow;
attribute EventHandler onerror;
attribute EventHandler onclosing;
attribute EventHandler onclose;
void close();
attribute EventHandler onmessage;
......
......@@ -12,15 +12,23 @@ promise_test(async t => {
let pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
let [channel1, channel2] = await createDataChannelPair(pc1);
let close_handler = new Promise(resolve => {
let closeHandler = new Promise(resolve => {
channel2.onclose = event => {
resolve();
};
});
let closingSeen = false;
channel1.onclosing = t.unreached_func();
channel2.onclosing = event => {
assert_equals(channel2.readyState, 'closing');
closingSeen = true;
}
channel2.addEventListener('error', t.unreached_func());
channel1.close();
await close_handler;
}, 'Close datachannel causes onclose to be called');
await closeHandler;
assert_equals(channel2.readyState, 'closed');
assert_true(closingSeen, 'Closing event was seen');
}, 'Close datachannel causes onclosing and onclose to be called');
promise_test(async t => {
// This is the same test as above, but using addEventListener
......@@ -28,15 +36,23 @@ promise_test(async t => {
let pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
let [channel1, channel2] = await createDataChannelPair(pc1);
let close_handler = new Promise(resolve => {
let closeHandler = new Promise(resolve => {
channel2.addEventListener('close', event => {
resolve();
});
});
let closingSeen = false;
channel1.addEventListener('closing', t.unreached_func());
channel2.addEventListener('closing', event => {
assert_equals(channel2.readyState, 'closing');
closingSeen = true;
});
channel2.addEventListener('error', t.unreached_func());
channel1.close();
await close_handler;
}, 'Close datachannel causes close event to be called');
await closeHandler;
assert_equals(channel2.readyState, 'closed');
assert_true(closingSeen, 'Closing event was seen');
}, 'Close datachannel causes closing and close event to be called');
promise_test(async t => {
let pc1 = new RTCPeerConnection();
......@@ -44,13 +60,13 @@ promise_test(async t => {
let [channel1, channel2] = await createDataChannelPair(pc1);
let events = [];
let error = null;
let close_handler = new Promise(resolve => {
let closeHandler = new Promise(resolve => {
channel2.addEventListener('close', event => {
events.push('close');
resolve();
});
});
let error_handler = new Promise((resolve, reject) => {
let errorHandler = new Promise((resolve, reject) => {
channel2.addEventListener('error', event => {
events.push('error');
try {
......@@ -64,8 +80,8 @@ promise_test(async t => {
});
});
pc1.close();
await error_handler;
await close_handler;
await errorHandler;
await closeHandler;
// Error should fire before close.
assert_array_equals(['error', 'close'], events);
assert_true(error instanceof RTCError);
......
This is a testharness.js-based test.
Found 496 tests; 466 PASS, 30 FAIL, 0 TIMEOUT, 0 NOTRUN.
Found 496 tests; 468 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS idl_test setup
PASS idl_test validation
PASS Test driver for asyncInitCertificate
......@@ -407,7 +407,7 @@ PASS RTCDataChannel interface: attribute bufferedAmountLowThreshold
PASS RTCDataChannel interface: attribute onopen
PASS RTCDataChannel interface: attribute onbufferedamountlow
PASS RTCDataChannel interface: attribute onerror
FAIL RTCDataChannel interface: attribute onclosing assert_true: The prototype object must have a property "onclosing" expected true got false
PASS RTCDataChannel interface: attribute onclosing
PASS RTCDataChannel interface: attribute onclose
PASS RTCDataChannel interface: operation close()
PASS RTCDataChannel interface: attribute onmessage
......@@ -431,7 +431,7 @@ PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') mus
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onopen" with the proper type
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onbufferedamountlow" with the proper type
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onerror" with the proper type
FAIL RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclosing" with the proper type assert_inherits: property "onclosing" not found in prototype chain
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclosing" with the proper type
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onclose" with the proper type
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "close()" with the proper type
PASS RTCDataChannel interface: new RTCPeerConnection().createDataChannel('') must inherit property "onmessage" with the proper type
......
......@@ -5106,6 +5106,7 @@ interface RTCDataChannel : EventTarget
getter negotiated
getter onbufferedamountlow
getter onclose
getter onclosing
getter onerror
getter onmessage
getter onopen
......@@ -5120,6 +5121,7 @@ interface RTCDataChannel : EventTarget
setter bufferedAmountLowThreshold
setter onbufferedamountlow
setter onclose
setter onclosing
setter onerror
setter onmessage
setter onopen
......
......@@ -6234,6 +6234,7 @@ interface RTCDataChannel : EventTarget
getter negotiated
getter onbufferedamountlow
getter onclose
getter onclosing
getter onerror
getter onmessage
getter onopen
......@@ -6248,6 +6249,7 @@ interface RTCDataChannel : EventTarget
setter bufferedAmountLowThreshold
setter onbufferedamountlow
setter onclose
setter onclosing
setter onerror
setter onmessage
setter onopen
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment