1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "mojo/services/html_viewer/websockethandle_impl.h" 6 7#include <vector> 8 9#include "base/bind.h" 10#include "base/memory/scoped_vector.h" 11#include "mojo/services/html_viewer/blink_basic_type_converters.h" 12#include "mojo/services/public/cpp/network/web_socket_read_queue.h" 13#include "mojo/services/public/cpp/network/web_socket_write_queue.h" 14#include "mojo/services/public/interfaces/network/network_service.mojom.h" 15#include "third_party/WebKit/public/platform/WebSerializedOrigin.h" 16#include "third_party/WebKit/public/platform/WebSocketHandleClient.h" 17#include "third_party/WebKit/public/platform/WebString.h" 18#include "third_party/WebKit/public/platform/WebURL.h" 19#include "third_party/WebKit/public/platform/WebVector.h" 20 21using blink::WebSerializedOrigin; 22using blink::WebSocketHandle; 23using blink::WebSocketHandleClient; 24using blink::WebString; 25using blink::WebURL; 26using blink::WebVector; 27 28namespace mojo { 29 30template<> 31struct TypeConverter<WebSocket::MessageType, WebSocketHandle::MessageType> { 32 static WebSocket::MessageType Convert(WebSocketHandle::MessageType type) { 33 DCHECK(type == WebSocketHandle::MessageTypeContinuation || 34 type == WebSocketHandle::MessageTypeText || 35 type == WebSocketHandle::MessageTypeBinary); 36 typedef WebSocket::MessageType MessageType; 37 COMPILE_ASSERT( 38 static_cast<MessageType>(WebSocketHandle::MessageTypeContinuation) == 39 WebSocket::MESSAGE_TYPE_CONTINUATION, 40 enum_values_must_match_for_message_type); 41 COMPILE_ASSERT( 42 static_cast<MessageType>(WebSocketHandle::MessageTypeText) == 43 WebSocket::MESSAGE_TYPE_TEXT, 44 enum_values_must_match_for_message_type); 45 COMPILE_ASSERT( 46 static_cast<MessageType>(WebSocketHandle::MessageTypeBinary) == 47 WebSocket::MESSAGE_TYPE_BINARY, 48 enum_values_must_match_for_message_type); 49 return static_cast<WebSocket::MessageType>(type); 50 } 51}; 52 53template<> 54struct TypeConverter<WebSocketHandle::MessageType, WebSocket::MessageType> { 55 static WebSocketHandle::MessageType Convert(WebSocket::MessageType type) { 56 DCHECK(type == WebSocket::MESSAGE_TYPE_CONTINUATION || 57 type == WebSocket::MESSAGE_TYPE_TEXT || 58 type == WebSocket::MESSAGE_TYPE_BINARY); 59 return static_cast<WebSocketHandle::MessageType>(type); 60 } 61}; 62 63// This class forms a bridge from the mojo WebSocketClient interface and the 64// Blink WebSocketHandleClient interface. 65class WebSocketClientImpl : public InterfaceImpl<WebSocketClient> { 66 public: 67 explicit WebSocketClientImpl(WebSocketHandleImpl* handle, 68 blink::WebSocketHandleClient* client) 69 : handle_(handle), client_(client) {} 70 virtual ~WebSocketClientImpl() {} 71 72 private: 73 // WebSocketClient methods: 74 virtual void DidConnect(bool fail, 75 const String& selected_subprotocol, 76 const String& extensions, 77 ScopedDataPipeConsumerHandle receive_stream) 78 OVERRIDE { 79 blink::WebSocketHandleClient* client = client_; 80 WebSocketHandleImpl* handle = handle_; 81 receive_stream_ = receive_stream.Pass(); 82 read_queue_.reset(new WebSocketReadQueue(receive_stream_.get())); 83 if (fail) 84 handle->Disconnect(); // deletes |this| 85 client->didConnect(handle, 86 fail, 87 selected_subprotocol.To<WebString>(), 88 extensions.To<WebString>()); 89 // |handle| can be deleted here. 90 } 91 92 virtual void DidReceiveData(bool fin, 93 WebSocket::MessageType type, 94 uint32_t num_bytes) OVERRIDE { 95 read_queue_->Read(num_bytes, 96 base::Bind(&WebSocketClientImpl::DidReadFromReceiveStream, 97 base::Unretained(this), 98 fin, type, num_bytes)); 99 } 100 101 virtual void DidReceiveFlowControl(int64_t quota) OVERRIDE { 102 client_->didReceiveFlowControl(handle_, quota); 103 // |handle| can be deleted here. 104 } 105 106 virtual void DidFail(const String& message) OVERRIDE { 107 blink::WebSocketHandleClient* client = client_; 108 WebSocketHandleImpl* handle = handle_; 109 handle->Disconnect(); // deletes |this| 110 client->didFail(handle, message.To<WebString>()); 111 // |handle| can be deleted here. 112 } 113 114 virtual void DidClose(bool was_clean, 115 uint16_t code, 116 const String& reason) OVERRIDE { 117 blink::WebSocketHandleClient* client = client_; 118 WebSocketHandleImpl* handle = handle_; 119 handle->Disconnect(); // deletes |this| 120 client->didClose(handle, was_clean, code, reason.To<WebString>()); 121 // |handle| can be deleted here. 122 } 123 124 void DidReadFromReceiveStream(bool fin, 125 WebSocket::MessageType type, 126 uint32_t num_bytes, 127 const char* data) { 128 client_->didReceiveData(handle_, 129 fin, 130 ConvertTo<WebSocketHandle::MessageType>(type), 131 data, 132 num_bytes); 133 // |handle_| can be deleted here. 134 } 135 136 // |handle_| owns this object, so it is guaranteed to outlive us. 137 WebSocketHandleImpl* handle_; 138 blink::WebSocketHandleClient* client_; 139 ScopedDataPipeConsumerHandle receive_stream_; 140 scoped_ptr<WebSocketReadQueue> read_queue_; 141 142 DISALLOW_COPY_AND_ASSIGN(WebSocketClientImpl); 143}; 144 145WebSocketHandleImpl::WebSocketHandleImpl(NetworkService* network_service) 146 : did_close_(false) { 147 network_service->CreateWebSocket(Get(&web_socket_)); 148} 149 150WebSocketHandleImpl::~WebSocketHandleImpl() { 151 if (!did_close_) { 152 // The connection is abruptly disconnected by the renderer without 153 // closing handshake. 154 web_socket_->Close(WebSocket::kAbnormalCloseCode, String()); 155 } 156} 157 158void WebSocketHandleImpl::connect(const WebURL& url, 159 const WebVector<WebString>& protocols, 160 const WebSerializedOrigin& origin, 161 WebSocketHandleClient* client) { 162 client_.reset(new WebSocketClientImpl(this, client)); 163 WebSocketClientPtr client_ptr; 164 // TODO(mpcomplete): Is this the right ownership model? Or should mojo own 165 // |client_|? 166 WeakBindToProxy(client_.get(), &client_ptr); 167 168 DataPipe data_pipe; 169 send_stream_ = data_pipe.producer_handle.Pass(); 170 write_queue_.reset(new WebSocketWriteQueue(send_stream_.get())); 171 web_socket_->Connect(url.string().utf8(), 172 Array<String>::From(protocols), 173 origin.string().utf8(), 174 data_pipe.consumer_handle.Pass(), 175 client_ptr.Pass()); 176} 177 178void WebSocketHandleImpl::send(bool fin, 179 WebSocketHandle::MessageType type, 180 const char* data, 181 size_t size) { 182 if (!client_) 183 return; 184 185 uint32_t size32 = static_cast<uint32_t>(size); 186 write_queue_->Write( 187 data, size32, 188 base::Bind(&WebSocketHandleImpl::DidWriteToSendStream, 189 base::Unretained(this), 190 fin, type, size32)); 191} 192 193void WebSocketHandleImpl::flowControl(int64_t quota) { 194 if (!client_) 195 return; 196 197 web_socket_->FlowControl(quota); 198} 199 200void WebSocketHandleImpl::close(unsigned short code, const WebString& reason) { 201 web_socket_->Close(code, reason.utf8()); 202} 203 204void WebSocketHandleImpl::DidWriteToSendStream( 205 bool fin, 206 WebSocketHandle::MessageType type, 207 uint32_t num_bytes, 208 const char* data) { 209 web_socket_->Send(fin, ConvertTo<WebSocket::MessageType>(type), num_bytes); 210} 211 212void WebSocketHandleImpl::Disconnect() { 213 did_close_ = true; 214 client_.reset(); 215} 216 217} // namespace mojo 218