mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1315782 - Support sending/receiving empty strings/bytes over DataChannels. r=jesup
Differential Revision: https://phabricator.services.mozilla.com/D166008
This commit is contained in:
parent
28ce608a7f
commit
280721318e
@ -1680,7 +1680,8 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
|
||||
const char* info = "";
|
||||
|
||||
if (ppid == DATA_CHANNEL_PPID_DOMSTRING_PARTIAL ||
|
||||
ppid == DATA_CHANNEL_PPID_DOMSTRING) {
|
||||
ppid == DATA_CHANNEL_PPID_DOMSTRING ||
|
||||
ppid == DATA_CHANNEL_PPID_DOMSTRING_EMPTY) {
|
||||
is_binary = false;
|
||||
}
|
||||
if (is_binary != channel->mIsRecvBinary && !channel->mRecvBuffer.IsEmpty()) {
|
||||
@ -1736,6 +1737,8 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
|
||||
data_length, WEBRTC_DATACHANNEL_MAX_MESSAGE_SIZE_LOCAL));
|
||||
}
|
||||
|
||||
bool is_empty = false;
|
||||
|
||||
switch (ppid) {
|
||||
case DATA_CHANNEL_PPID_DOMSTRING:
|
||||
DC_DEBUG(
|
||||
@ -1750,6 +1753,18 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
|
||||
// WebSockets checks IsUTF8() here; we can try to deliver it
|
||||
break;
|
||||
|
||||
case DATA_CHANNEL_PPID_DOMSTRING_EMPTY:
|
||||
DC_DEBUG(
|
||||
("DataChannel: Received empty string message of length %u on channel "
|
||||
"%u",
|
||||
data_length, channel->mStream));
|
||||
type = DataChannelOnMessageAvailable::ON_DATA_STRING;
|
||||
if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_BUFFERED) {
|
||||
info = " (string fragmented)";
|
||||
}
|
||||
is_empty = true;
|
||||
break;
|
||||
|
||||
case DATA_CHANNEL_PPID_BINARY:
|
||||
DC_DEBUG(
|
||||
("DataChannel: Received binary message of length %u on channel id %u",
|
||||
@ -1762,6 +1777,18 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
|
||||
// else send using recvData normally
|
||||
break;
|
||||
|
||||
case DATA_CHANNEL_PPID_BINARY_EMPTY:
|
||||
DC_DEBUG(
|
||||
("DataChannel: Received empty binary message of length %u on channel "
|
||||
"id %u",
|
||||
data_length, channel->mStream));
|
||||
type = DataChannelOnMessageAvailable::ON_DATA_BINARY;
|
||||
if (bufferFlags & DATA_CHANNEL_BUFFER_MESSAGE_FLAGS_BUFFERED) {
|
||||
info = " (binary fragmented)";
|
||||
}
|
||||
is_empty = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ERROR("Unknown data PPID");
|
||||
DC_ERROR(("Unknown data PPID %" PRIu32, ppid));
|
||||
@ -1784,7 +1811,8 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
|
||||
type, this, channel, channel->mRecvBuffer));
|
||||
channel->mRecvBuffer.Truncate(0);
|
||||
} else {
|
||||
nsAutoCString recvData(buffer, data_length); // copies (<64) or allocates
|
||||
nsAutoCString recvData(is_empty ? "" : buffer,
|
||||
is_empty ? 0 : data_length); // allocates >64
|
||||
channel->SendOrQueue(
|
||||
new DataChannelOnMessageAvailable(type, this, channel, recvData));
|
||||
}
|
||||
@ -1875,8 +1903,10 @@ void DataChannelConnection::HandleMessage(const void* buffer, size_t length,
|
||||
break;
|
||||
case DATA_CHANNEL_PPID_DOMSTRING_PARTIAL:
|
||||
case DATA_CHANNEL_PPID_DOMSTRING:
|
||||
case DATA_CHANNEL_PPID_DOMSTRING_EMPTY:
|
||||
case DATA_CHANNEL_PPID_BINARY_PARTIAL:
|
||||
case DATA_CHANNEL_PPID_BINARY:
|
||||
case DATA_CHANNEL_PPID_BINARY_EMPTY:
|
||||
HandleDataMessage(buffer, length, ppid, stream, flags);
|
||||
break;
|
||||
default:
|
||||
@ -2763,7 +2793,8 @@ int DataChannelConnection::SendDataMsgInternalOrBuffer(DataChannel& channel,
|
||||
int error =
|
||||
SendMsgInternalOrBuffer(channel.mBufferedData, msg, buffered, &written);
|
||||
mDeferSend = false;
|
||||
if (written) {
|
||||
if (written && ppid != DATA_CHANNEL_PPID_DOMSTRING_EMPTY &&
|
||||
ppid != DATA_CHANNEL_PPID_BINARY_EMPTY) {
|
||||
channel.DecrementBufferedAmount(written);
|
||||
}
|
||||
|
||||
@ -2971,16 +3002,23 @@ int DataChannelConnection::SendDataMsgCommon(uint16_t stream,
|
||||
if (NS_WARN_IF(!channelPtr)) {
|
||||
return EINVAL; // TODO: Find a better error code
|
||||
}
|
||||
|
||||
bool is_empty = len == 0;
|
||||
const uint8_t byte = 0;
|
||||
if (is_empty) {
|
||||
data = &byte;
|
||||
len = 1;
|
||||
}
|
||||
auto& channel = *channelPtr;
|
||||
int err = 0;
|
||||
MutexAutoLock lock(mLock);
|
||||
if (isBinary) {
|
||||
err = SendDataMsg(channel, data, len, DATA_CHANNEL_PPID_BINARY_PARTIAL,
|
||||
DATA_CHANNEL_PPID_BINARY);
|
||||
err = SendDataMsg(
|
||||
channel, data, len, DATA_CHANNEL_PPID_BINARY_PARTIAL,
|
||||
is_empty ? DATA_CHANNEL_PPID_BINARY_EMPTY : DATA_CHANNEL_PPID_BINARY);
|
||||
} else {
|
||||
err = SendDataMsg(channel, data, len, DATA_CHANNEL_PPID_DOMSTRING_PARTIAL,
|
||||
DATA_CHANNEL_PPID_DOMSTRING);
|
||||
is_empty ? DATA_CHANNEL_PPID_DOMSTRING_EMPTY
|
||||
: DATA_CHANNEL_PPID_DOMSTRING);
|
||||
}
|
||||
if (!err) {
|
||||
channel.WithTrafficCounters([&len](DataChannel::TrafficCounters& counters) {
|
||||
|
@ -33,6 +33,8 @@
|
||||
#define DATA_CHANNEL_PPID_BINARY 53
|
||||
#define DATA_CHANNEL_PPID_DOMSTRING_PARTIAL 54
|
||||
#define DATA_CHANNEL_PPID_DOMSTRING 51
|
||||
#define DATA_CHANNEL_PPID_DOMSTRING_EMPTY 56
|
||||
#define DATA_CHANNEL_PPID_BINARY_EMPTY 57
|
||||
|
||||
#define DATA_CHANNEL_MAX_BINARY_FRAGMENT 0x4000
|
||||
|
||||
|
@ -1,24 +1,8 @@
|
||||
[RTCDataChannel-send.html]
|
||||
[Datachannel should be able to send an empty string and receive an empty string]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1315782
|
||||
expected: FAIL
|
||||
|
||||
[Datachannel should be able to send an empty ArrayBuffer message and receive as ArrayBuffer]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1315782
|
||||
expected: FAIL
|
||||
|
||||
[Datachannel send() up to max size should succeed, above max size should fail]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
|
||||
expected: FAIL
|
||||
|
||||
[Negotiated datachannel should be able to send an empty string and receive an empty string]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1315782
|
||||
expected: FAIL
|
||||
|
||||
[Negotiated datachannel should be able to send an empty ArrayBuffer message and receive as ArrayBuffer]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1315782
|
||||
expected: FAIL
|
||||
|
||||
[Negotiated datachannel send() up to max size should succeed, above max size should fail]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
|
||||
expected: FAIL
|
||||
|
@ -55,6 +55,9 @@ const helloString = 'hello';
|
||||
const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f);
|
||||
const helloBlob = new Blob([helloBuffer]);
|
||||
|
||||
const emptyBuffer = Uint8Array.of();
|
||||
const emptyBlob = new Blob([emptyBuffer]);
|
||||
|
||||
// Unicode string with multiple code units
|
||||
const unicodeString = '世界你好';
|
||||
// UTF-8 encoded buffer representation of the string
|
||||
@ -96,6 +99,17 @@ for (const options of [{}, {negotiated: true, id: 0}]) {
|
||||
}, `${mode} bufferedAmount should increase to byte length of encoded` +
|
||||
`unicode string sent`);
|
||||
|
||||
promise_test(async (t) => {
|
||||
const [dc1, dc2] = await createDataChannelPair(t, options);
|
||||
|
||||
dc1.send("");
|
||||
assert_equals(dc1.bufferedAmount, 0,
|
||||
'Expect bufferedAmount to stay at zero after sending empty string');
|
||||
|
||||
await awaitMessage(dc2);
|
||||
assert_equals(dc1.bufferedAmount, 0, 'Expect sender bufferedAmount unchanged');
|
||||
}, `${mode} bufferedAmount should stay at zero for empty string sent`);
|
||||
|
||||
/*
|
||||
6.2. send()
|
||||
3. Execute the sub step that corresponds to the type of the methods argument:
|
||||
@ -116,6 +130,18 @@ for (const options of [{}, {negotiated: true, id: 0}]) {
|
||||
'Expect sender bufferedAmount to be reduced after message is sent');
|
||||
}, `${mode} bufferedAmount should increase to byte length of buffer sent`);
|
||||
|
||||
promise_test(async (t) => {
|
||||
const [dc1, dc2] = await createDataChannelPair(t, options);
|
||||
|
||||
dc1.send(emptyBuffer.buffer);
|
||||
assert_equals(dc1.bufferedAmount, 0,
|
||||
'Expect bufferedAmount to stay at zero after sending empty buffer');
|
||||
|
||||
await awaitMessage(dc2);
|
||||
assert_equals(dc1.bufferedAmount, 0,
|
||||
'Expect sender bufferedAmount unchanged');
|
||||
}, `${mode} bufferedAmount should stay at zero for empty buffer sent`);
|
||||
|
||||
/*
|
||||
6.2. send()
|
||||
3. Execute the sub step that corresponds to the type of the methods argument:
|
||||
@ -135,6 +161,18 @@ for (const options of [{}, {negotiated: true, id: 0}]) {
|
||||
'Expect sender bufferedAmount to be reduced after message is sent');
|
||||
}, `${mode} bufferedAmount should increase to size of blob sent`);
|
||||
|
||||
promise_test(async (t) => {
|
||||
const [dc1, dc2] = await createDataChannelPair(t, options);
|
||||
|
||||
dc1.send(emptyBlob);
|
||||
assert_equals(dc1.bufferedAmount, 0,
|
||||
'Expect bufferedAmount to stay at zero after sending empty blob');
|
||||
|
||||
await awaitMessage(dc2);
|
||||
assert_equals(dc1.bufferedAmount, 0,
|
||||
'Expect sender bufferedAmount unchanged');
|
||||
}, `${mode} bufferedAmount should stay at zero for empty blob sent`);
|
||||
|
||||
// Test sending 3 messages: helloBuffer, unicodeString, helloBlob
|
||||
promise_test(async (t) => {
|
||||
const resolver = new Resolver();
|
||||
|
Loading…
Reference in New Issue
Block a user