Commit 51920a88 authored by Adam Rice's avatar Adam Rice Committed by Commit Bot

WebSocket: Check the return value from SendFrame

network::WebSocket should return immediately if the return value of
net::WebSocket::SendFrame is CHANNEL_DELETED. It was not doing so. Add
the necessary return statements.

Also add WARN_UNUSED_RESULT to SendFrame() to make sure it is checked in
future.

Tested manually. No unit tests for this change because
network::WebSocket has no unit tests.

BUG=1065704

Change-Id: I0c7e0cf57f3a98fc80461ec50df59513146eff89
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2123961Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754997}
parent baa17d04
...@@ -98,7 +98,7 @@ class NET_EXPORT WebSocketChannel { ...@@ -98,7 +98,7 @@ class NET_EXPORT WebSocketChannel {
ChannelState SendFrame(bool fin, ChannelState SendFrame(bool fin,
WebSocketFrameHeader::OpCode op_code, WebSocketFrameHeader::OpCode op_code,
scoped_refptr<IOBuffer> buffer, scoped_refptr<IOBuffer> buffer,
size_t buffer_size); size_t buffer_size) WARN_UNUSED_RESULT;
// Calls WebSocketStream::ReadFrames() with the appropriate arguments. Stops // Calls WebSocketStream::ReadFrames() with the appropriate arguments. Stops
// calling ReadFrames if no writable buffer in dataframe or WebSocketStream // calling ReadFrames if no writable buffer in dataframe or WebSocketStream
......
This diff is collapsed.
...@@ -462,8 +462,10 @@ void WebSocket::SendFrame(bool fin, ...@@ -462,8 +462,10 @@ void WebSocket::SendFrame(bool fin,
auto data_to_pass = base::MakeRefCounted<net::IOBuffer>(data.size()); auto data_to_pass = base::MakeRefCounted<net::IOBuffer>(data.size());
memcpy(data_to_pass->data(), data.data(), data.size()); memcpy(data_to_pass->data(), data.data(), data.size());
channel_->SendFrame(fin, MessageTypeToOpCode(type), std::move(data_to_pass), // It's okay to ignore the result here because we don't access |this| after
data.size()); // this point.
ignore_result(channel_->SendFrame(fin, MessageTypeToOpCode(type),
std::move(data_to_pass), data.size()));
} }
void WebSocket::SendMessage(mojom::WebSocketMessageType type, void WebSocket::SendMessage(mojom::WebSocketMessageType type,
...@@ -483,6 +485,9 @@ void WebSocket::SendMessage(mojom::WebSocketMessageType type, ...@@ -483,6 +485,9 @@ void WebSocket::SendMessage(mojom::WebSocketMessageType type,
DCHECK(IsKnownEnumValue(type)); DCHECK(IsKnownEnumValue(type));
pending_send_data_frames_.push(DataFrame(type, data_length)); pending_send_data_frames_.push(DataFrame(type, data_length));
// Safe if ReadAndSendFromDataPipe() deletes |this| because this method is
// only called from mojo.
ReadAndSendFromDataPipe(); ReadAndSendFromDataPipe();
} }
...@@ -672,6 +677,9 @@ void WebSocket::OnReadable(MojoResult result, ...@@ -672,6 +677,9 @@ void WebSocket::OnReadable(MojoResult result,
return; return;
} }
wait_for_readable_ = false; wait_for_readable_ = false;
// Safe if ReadAndSendFromDataPipe() deletes |this| because this method is
// only called from mojo.
ReadAndSendFromDataPipe(); ReadAndSendFromDataPipe();
} }
...@@ -685,8 +693,12 @@ void WebSocket::ReadAndSendFromDataPipe() { ...@@ -685,8 +693,12 @@ void WebSocket::ReadAndSendFromDataPipe() {
<< ", (data_length = " << data_frame.data_length << "))"; << ", (data_length = " << data_frame.data_length << "))";
if (data_frame.data_length == 0) { if (data_frame.data_length == 0) {
auto data_to_pass = base::MakeRefCounted<net::IOBuffer>(0); auto data_to_pass = base::MakeRefCounted<net::IOBuffer>(0);
channel_->SendFrame(true, MessageTypeToOpCode(data_frame.type), if (channel_->SendFrame(true, MessageTypeToOpCode(data_frame.type),
std::move(data_to_pass), 0); std::move(data_to_pass),
0) == net::WebSocketChannel::CHANNEL_DELETED) {
// |this| has been deleted.
return;
}
pending_send_data_frames_.pop(); pending_send_data_frames_.pop();
continue; continue;
} }
...@@ -710,8 +722,12 @@ void WebSocket::ReadAndSendFromDataPipe() { ...@@ -710,8 +722,12 @@ void WebSocket::ReadAndSendFromDataPipe() {
auto data_to_pass = base::MakeRefCounted<net::IOBuffer>(size_to_send); auto data_to_pass = base::MakeRefCounted<net::IOBuffer>(size_to_send);
const bool is_final = (size_to_send == data_frame.data_length); const bool is_final = (size_to_send == data_frame.data_length);
memcpy(data_to_pass->data(), buffer, size_to_send); memcpy(data_to_pass->data(), buffer, size_to_send);
channel_->SendFrame(is_final, MessageTypeToOpCode(data_frame.type), if (channel_->SendFrame(is_final, MessageTypeToOpCode(data_frame.type),
std::move(data_to_pass), size_to_send); std::move(data_to_pass), size_to_send) ==
net::WebSocketChannel::CHANNEL_DELETED) {
// |this| has been deleted.
return;
}
const MojoResult end_result = readable_->EndReadData(size_to_send); const MojoResult end_result = readable_->EndReadData(size_to_send);
DCHECK_EQ(end_result, MOJO_RESULT_OK); DCHECK_EQ(end_result, MOJO_RESULT_OK);
......
...@@ -161,6 +161,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket { ...@@ -161,6 +161,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
// Datapipe functions to send. // Datapipe functions to send.
void OnReadable(MojoResult result, const mojo::HandleSignalsState& state); void OnReadable(MojoResult result, const mojo::HandleSignalsState& state);
// ReadAndSendFromDataPipe() may indirectly delete |this|.
void ReadAndSendFromDataPipe(); void ReadAndSendFromDataPipe();
// |factory_| owns |this|. // |factory_| owns |this|.
......
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