Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Unified Diff: content/browser/renderer_host/websocket_host.cc

Issue 1568523002: Implement content::WebSocketBlobSender (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@websocket_blob_send_ipcs
Patch Set: Rebase. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/websocket_host.cc
diff --git a/content/browser/renderer_host/websocket_host.cc b/content/browser/renderer_host/websocket_host.cc
index d57814512e595d57696089aa6ffdc991b6bf20b1..88c333a77e98e779266cff49dfd21ff695b12bd3 100644
--- a/content/browser/renderer_host/websocket_host.cc
+++ b/content/browser/renderer_host/websocket_host.cc
@@ -4,20 +4,29 @@
#include "content/browser/renderer_host/websocket_host.h"
+#include <inttypes.h>
#include <utility>
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/thread_task_runner_handle.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/renderer_host/websocket_blob_sender.h"
#include "content/browser/renderer_host/websocket_dispatcher_host.h"
#include "content/browser/ssl/ssl_error_handler.h"
#include "content/browser/ssl/ssl_manager.h"
#include "content/common/websocket_messages.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/storage_partition.h"
#include "ipc/ipc_message_macros.h"
+#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
@@ -86,12 +95,41 @@ ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) {
return static_cast<ChannelState>(host_state);
}
+// Implementation of WebSocketBlobSender::Channel
+class SendChannelImpl final : public WebSocketBlobSender::Channel {
+ public:
+ explicit SendChannelImpl(net::WebSocketChannel* channel)
+ : channel_(channel) {}
+
+ // Implementation of WebSocketBlobSender::Channel
+ size_t GetSendQuota() const override {
+ return static_cast<size_t>(channel_->current_send_quota());
+ }
+
+ ChannelState SendFrame(bool fin, const std::vector<char>& data) override {
+ int opcode = first_frame_ ? net::WebSocketFrameHeader::kOpCodeBinary
+ : net::WebSocketFrameHeader::kOpCodeContinuation;
+ first_frame_ = false;
+ return channel_->SendFrame(fin, opcode, data);
+ }
+
+ private:
+ net::WebSocketChannel* channel_;
+ bool first_frame_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(SendChannelImpl);
+};
+
+} // namespace
+
// Implementation of net::WebSocketEventInterface. Receives events from our
// WebSocketChannel object. Each event is translated to an IPC and sent to the
// renderer or child process via WebSocketDispatcherHost.
-class WebSocketEventHandler : public net::WebSocketEventInterface {
+class WebSocketHost::WebSocketEventHandler final
+ : public net::WebSocketEventInterface {
public:
WebSocketEventHandler(WebSocketDispatcherHost* dispatcher,
+ WebSocketHost* host,
int routing_id,
int render_frame_id);
~WebSocketEventHandler() override;
@@ -120,7 +158,7 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
bool fatal) override;
private:
- class SSLErrorHandlerDelegate : public SSLErrorHandler::Delegate {
+ class SSLErrorHandlerDelegate final : public SSLErrorHandler::Delegate {
public:
SSLErrorHandlerDelegate(
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks);
@@ -140,6 +178,7 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
};
WebSocketDispatcherHost* const dispatcher_;
+ WebSocketHost* const host_;
const int routing_id_;
const int render_frame_id_;
scoped_ptr<SSLErrorHandlerDelegate> ssl_error_handler_delegate_;
@@ -147,20 +186,21 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler);
};
-WebSocketEventHandler::WebSocketEventHandler(
+WebSocketHost::WebSocketEventHandler::WebSocketEventHandler(
WebSocketDispatcherHost* dispatcher,
+ WebSocketHost* host,
int routing_id,
int render_frame_id)
: dispatcher_(dispatcher),
+ host_(host),
routing_id_(routing_id),
- render_frame_id_(render_frame_id) {
-}
+ render_frame_id_(render_frame_id) {}
-WebSocketEventHandler::~WebSocketEventHandler() {
+WebSocketHost::WebSocketEventHandler::~WebSocketEventHandler() {
DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_;
}
-ChannelState WebSocketEventHandler::OnAddChannelResponse(
+ChannelState WebSocketHost::WebSocketEventHandler::OnAddChannelResponse(
const std::string& selected_protocol,
const std::string& extensions) {
DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse"
@@ -172,7 +212,7 @@ ChannelState WebSocketEventHandler::OnAddChannelResponse(
routing_id_, selected_protocol, extensions));
}
-ChannelState WebSocketEventHandler::OnDataFrame(
+ChannelState WebSocketHost::WebSocketEventHandler::OnDataFrame(
bool fin,
net::WebSocketFrameHeader::OpCode type,
const std::vector<char>& data) {
@@ -180,27 +220,31 @@ ChannelState WebSocketEventHandler::OnDataFrame(
<< " routing_id=" << routing_id_ << " fin=" << fin
<< " type=" << type << " data is " << data.size() << " bytes";
- return StateCast(dispatcher_->SendFrame(
- routing_id_, fin, OpCodeToMessageType(type), data));
+ return StateCast(dispatcher_->SendFrame(routing_id_, fin,
+ OpCodeToMessageType(type), data));
}
-ChannelState WebSocketEventHandler::OnClosingHandshake() {
+ChannelState WebSocketHost::WebSocketEventHandler::OnClosingHandshake() {
DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake"
<< " routing_id=" << routing_id_;
return StateCast(dispatcher_->NotifyClosingHandshake(routing_id_));
}
-ChannelState WebSocketEventHandler::OnFlowControl(int64_t quota) {
+ChannelState WebSocketHost::WebSocketEventHandler::OnFlowControl(
+ int64_t quota) {
DVLOG(3) << "WebSocketEventHandler::OnFlowControl"
<< " routing_id=" << routing_id_ << " quota=" << quota;
+ if (host_->blob_sender_)
+ host_->blob_sender_->OnNewSendQuota();
return StateCast(dispatcher_->SendFlowControl(routing_id_, quota));
}
-ChannelState WebSocketEventHandler::OnDropChannel(bool was_clean,
- uint16_t code,
- const std::string& reason) {
+ChannelState WebSocketHost::WebSocketEventHandler::OnDropChannel(
+ bool was_clean,
+ uint16_t code,
+ const std::string& reason) {
DVLOG(3) << "WebSocketEventHandler::OnDropChannel"
<< " routing_id=" << routing_id_ << " was_clean=" << was_clean
<< " code=" << code << " reason=\"" << reason << "\"";
@@ -209,15 +253,15 @@ ChannelState WebSocketEventHandler::OnDropChannel(bool was_clean,
dispatcher_->DoDropChannel(routing_id_, was_clean, code, reason));
}
-ChannelState WebSocketEventHandler::OnFailChannel(const std::string& message) {
+ChannelState WebSocketHost::WebSocketEventHandler::OnFailChannel(
+ const std::string& message) {
DVLOG(3) << "WebSocketEventHandler::OnFailChannel"
- << " routing_id=" << routing_id_
- << " message=\"" << message << "\"";
+ << " routing_id=" << routing_id_ << " message=\"" << message << "\"";
return StateCast(dispatcher_->NotifyFailure(routing_id_, message));
}
-ChannelState WebSocketEventHandler::OnStartOpeningHandshake(
+ChannelState WebSocketHost::WebSocketEventHandler::OnStartOpeningHandshake(
scoped_ptr<net::WebSocketHandshakeRequestInfo> request) {
bool should_send = dispatcher_->CanReadRawCookies();
DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake "
@@ -237,11 +281,11 @@ ChannelState WebSocketEventHandler::OnStartOpeningHandshake(
request->headers.ToString();
request_to_pass.request_time = request->request_time;
- return StateCast(dispatcher_->NotifyStartOpeningHandshake(routing_id_,
- request_to_pass));
+ return StateCast(
+ dispatcher_->NotifyStartOpeningHandshake(routing_id_, request_to_pass));
}
-ChannelState WebSocketEventHandler::OnFinishOpeningHandshake(
+ChannelState WebSocketHost::WebSocketEventHandler::OnFinishOpeningHandshake(
scoped_ptr<net::WebSocketHandshakeResponseInfo> response) {
bool should_send = dispatcher_->CanReadRawCookies();
DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake "
@@ -263,11 +307,11 @@ ChannelState WebSocketEventHandler::OnFinishOpeningHandshake(
response->headers->raw_headers());
response_to_pass.response_time = response->response_time;
- return StateCast(dispatcher_->NotifyFinishOpeningHandshake(routing_id_,
- response_to_pass));
+ return StateCast(
+ dispatcher_->NotifyFinishOpeningHandshake(routing_id_, response_to_pass));
}
-ChannelState WebSocketEventHandler::OnSSLCertificateError(
+ChannelState WebSocketHost::WebSocketEventHandler::OnSSLCertificateError(
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks,
const GURL& url,
const net::SSLInfo& ssl_info,
@@ -284,20 +328,21 @@ ChannelState WebSocketEventHandler::OnSSLCertificateError(
return WebSocketEventInterface::CHANNEL_ALIVE;
}
-WebSocketEventHandler::SSLErrorHandlerDelegate::SSLErrorHandlerDelegate(
- scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks)
+WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ SSLErrorHandlerDelegate(
+ scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks)
: callbacks_(std::move(callbacks)), weak_ptr_factory_(this) {}
-WebSocketEventHandler::SSLErrorHandlerDelegate::~SSLErrorHandlerDelegate() {}
+WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ ~SSLErrorHandlerDelegate() {}
base::WeakPtr<SSLErrorHandler::Delegate>
-WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
+WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-void WebSocketEventHandler::SSLErrorHandlerDelegate::CancelSSLRequest(
- int error,
- const net::SSLInfo* ssl_info) {
+void WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ CancelSSLRequest(int error, const net::SSLInfo* ssl_info) {
DVLOG(3) << "SSLErrorHandlerDelegate::CancelSSLRequest"
<< " error=" << error
<< " cert_status=" << (ssl_info ? ssl_info->cert_status
@@ -305,13 +350,12 @@ void WebSocketEventHandler::SSLErrorHandlerDelegate::CancelSSLRequest(
callbacks_->CancelSSLRequest(error, ssl_info);
}
-void WebSocketEventHandler::SSLErrorHandlerDelegate::ContinueSSLRequest() {
+void WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ ContinueSSLRequest() {
DVLOG(3) << "SSLErrorHandlerDelegate::ContinueSSLRequest";
callbacks_->ContinueSSLRequest();
}
-} // namespace
-
WebSocketHost::WebSocketHost(int routing_id,
WebSocketDispatcherHost* dispatcher,
net::URLRequestContext* url_request_context,
@@ -337,6 +381,7 @@ bool WebSocketHost::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebSocketHost, message)
IPC_MESSAGE_HANDLER(WebSocketHostMsg_AddChannelRequest, OnAddChannelRequest)
+ IPC_MESSAGE_HANDLER(WebSocketHostMsg_SendBlob, OnSendBlob)
IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, OnSendFrame)
IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, OnFlowControl)
IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, OnDropChannel)
@@ -383,7 +428,8 @@ void WebSocketHost::AddChannel(
DCHECK(!channel_);
scoped_ptr<net::WebSocketEventInterface> event_interface(
- new WebSocketEventHandler(dispatcher_, routing_id_, render_frame_id));
+ new WebSocketEventHandler(dispatcher_, this, routing_id_,
+ render_frame_id));
channel_.reset(new net::WebSocketChannel(std::move(event_interface),
url_request_context_));
@@ -404,6 +450,41 @@ void WebSocketHost::AddChannel(
// |this| may have been deleted here.
}
+void WebSocketHost::OnSendBlob(const std::string& uuid,
+ uint64_t expected_size) {
+ DVLOG(3) << "WebSocketHost::OnSendBlob"
+ << " routing_id=" << routing_id_ << " uuid=" << uuid
+ << " expected_size=" << expected_size;
+
+ DCHECK(channel_);
+ if (blob_sender_) {
+ bad_message::ReceivedBadMessage(
+ dispatcher_, bad_message::WSH_SEND_BLOB_DURING_BLOB_SEND);
+ return;
+ }
+ blob_sender_.reset(new WebSocketBlobSender(
+ make_scoped_ptr(new SendChannelImpl(channel_.get()))));
+ StoragePartition* partition = dispatcher_->storage_partition();
+ storage::FileSystemContext* file_system_context =
+ partition->GetFileSystemContext();
+
+ net::WebSocketEventInterface::ChannelState channel_state =
+ net::WebSocketEventInterface::CHANNEL_ALIVE;
+
+ // This use of base::Unretained is safe because the WebSocketBlobSender object
+ // is owned by this object and will not call it back after destruction.
+ int rv = blob_sender_->Start(
+ uuid, expected_size, dispatcher_->blob_storage_context(),
+ file_system_context,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
+ &channel_state,
+ base::Bind(&WebSocketHost::BlobSendComplete, base::Unretained(this)));
+ if (channel_state == net::WebSocketEventInterface::CHANNEL_ALIVE &&
+ rv != net::ERR_IO_PENDING)
+ BlobSendComplete(rv);
+ // |this| may be destroyed here.
+}
+
void WebSocketHost::OnSendFrame(bool fin,
WebSocketMessageType type,
const std::vector<char>& data) {
@@ -412,6 +493,11 @@ void WebSocketHost::OnSendFrame(bool fin,
<< " type=" << type << " data is " << data.size() << " bytes";
DCHECK(channel_);
+ if (blob_sender_) {
+ bad_message::ReceivedBadMessage(
+ dispatcher_, bad_message::WSH_SEND_FRAME_DURING_BLOB_SEND);
+ return;
+ }
channel_->SendFrame(fin, MessageTypeToOpCode(type), data);
}
@@ -441,16 +527,52 @@ void WebSocketHost::OnDropChannel(bool was_clean,
// WebSocketChannel is not yet created due to the delay introduced by
// per-renderer WebSocket throttling.
WebSocketDispatcherHost::WebSocketHostState result =
- dispatcher_->DoDropChannel(routing_id_,
- false,
- net::kWebSocketErrorAbnormalClosure,
- "");
+ dispatcher_->DoDropChannel(routing_id_, false,
+ net::kWebSocketErrorAbnormalClosure, "");
DCHECK_EQ(WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED, result);
return;
}
+ blob_sender_.reset();
// TODO(yhirano): Handle |was_clean| appropriately.
channel_->StartClosingHandshake(code, reason);
}
+void WebSocketHost::BlobSendComplete(int result) {
+ DVLOG(3) << "WebSocketHost::BlobSendComplete"
+ << " routing_id=" << routing_id_
+ << " result=" << net::ErrorToString(result);
+
+ // All paths through this method must reset blob_sender_, so take ownership
+ // at the beginning.
+ scoped_ptr<WebSocketBlobSender> blob_sender(std::move(blob_sender_));
+ switch (result) {
+ case net::OK:
+ ignore_result(dispatcher_->BlobSendComplete(routing_id_));
+ // |this| may be destroyed here.
+ return;
+
+ case net::ERR_UPLOAD_FILE_CHANGED: {
+ uint64_t expected_size = blob_sender->expected_size();
+ uint64_t actual_size = blob_sender->ActualSize();
+ if (expected_size != actual_size) {
+ ignore_result(dispatcher_->NotifyFailure(
+ routing_id_,
+ base::StringPrintf("Blob size mismatch; renderer size = %" PRIu64
+ ", browser size = %" PRIu64,
+ expected_size, actual_size)));
+ // |this| is destroyed here.
+ return;
+ } // else fallthrough
+ }
+
+ default:
+ ignore_result(dispatcher_->NotifyFailure(
+ routing_id_,
+ "Failed to load Blob: error code = " + net::ErrorToString(result)));
+ // |this| is destroyed here.
+ return;
+ }
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698