Chromium Code Reviews| 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 5551e9643bf2de32a906f1558bdfdcd88d5ab1bb..23f0d7227067869a51b8e3140998e2601185130a 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" |
|
yhirano
2016/01/25 10:52:23
Can you tell me why you stopped including weak_ptr
Adam Rice
2016/01/25 23:04:01
It is included in websocket_host.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,39 @@ ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) { |
| return static_cast<ChannelState>(host_state); |
| } |
| +// Implementation of WebSocketBlobSender::Channel |
| +class SendChannelImpl : public WebSocketBlobSender::Channel { |
| + public: |
| + explicit SendChannelImpl(net::WebSocketChannel* channel) |
| + : channel_(channel) {} |
| + |
| + // Implementation of WebSocketBlobSender::Channel |
| + int GetSendQuota() const override { return 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 |
| + : public net::WebSocketEventInterface { |
| public: |
| WebSocketEventHandler(WebSocketDispatcherHost* dispatcher, |
| + WebSocketHost* host, |
| int routing_id, |
| int render_frame_id); |
| ~WebSocketEventHandler() override; |
| @@ -140,6 +176,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 +184,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 +210,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 +218,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 +251,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 +279,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 +305,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 +326,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 +348,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 +379,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 +426,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 +448,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 +491,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 +525,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 |