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
21 using blink::WebSerializedOrigin;
22 using blink::WebSocketHandle;
23 using blink::WebSocketHandleClient;
24 using blink::WebString;
25 using blink::WebURL;
26 using blink::WebVector;
27
28 namespace mojo {
29
30 template<>
31 struct TypeConverter<WebSocket::MessageType, WebSocketHandle::MessageType> {
Convertmojo::TypeConverter32 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
53 template<>
54 struct TypeConverter<WebSocketHandle::MessageType, WebSocket::MessageType> {
Convertmojo::TypeConverter55 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.
65 class WebSocketClientImpl : public InterfaceImpl<WebSocketClient> {
66 public:
WebSocketClientImpl(WebSocketHandleImpl * handle,blink::WebSocketHandleClient * client)67 explicit WebSocketClientImpl(WebSocketHandleImpl* handle,
68 blink::WebSocketHandleClient* client)
69 : handle_(handle), client_(client) {}
~WebSocketClientImpl()70 virtual ~WebSocketClientImpl() {}
71
72 private:
73 // WebSocketClient methods:
DidConnect(bool fail,const String & selected_subprotocol,const String & extensions,ScopedDataPipeConsumerHandle receive_stream)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
DidReceiveData(bool fin,WebSocket::MessageType type,uint32_t num_bytes)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
DidReceiveFlowControl(int64_t quota)101 virtual void DidReceiveFlowControl(int64_t quota) OVERRIDE {
102 client_->didReceiveFlowControl(handle_, quota);
103 // |handle| can be deleted here.
104 }
105
DidFail(const String & message)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
DidClose(bool was_clean,uint16_t code,const String & reason)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
DidReadFromReceiveStream(bool fin,WebSocket::MessageType type,uint32_t num_bytes,const char * data)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
WebSocketHandleImpl(NetworkService * network_service)145 WebSocketHandleImpl::WebSocketHandleImpl(NetworkService* network_service)
146 : did_close_(false) {
147 network_service->CreateWebSocket(Get(&web_socket_));
148 }
149
~WebSocketHandleImpl()150 WebSocketHandleImpl::~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
connect(const WebURL & url,const WebVector<WebString> & protocols,const WebSerializedOrigin & origin,WebSocketHandleClient * client)158 void 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
send(bool fin,WebSocketHandle::MessageType type,const char * data,size_t size)178 void 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
flowControl(int64_t quota)193 void WebSocketHandleImpl::flowControl(int64_t quota) {
194 if (!client_)
195 return;
196
197 web_socket_->FlowControl(quota);
198 }
199
close(unsigned short code,const WebString & reason)200 void WebSocketHandleImpl::close(unsigned short code, const WebString& reason) {
201 web_socket_->Close(code, reason.utf8());
202 }
203
DidWriteToSendStream(bool fin,WebSocketHandle::MessageType type,uint32_t num_bytes,const char * data)204 void 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
Disconnect()212 void WebSocketHandleImpl::Disconnect() {
213 did_close_ = true;
214 client_.reset();
215 }
216
217 } // namespace mojo
218