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.
5 #include "components/html_viewer/web_socket_handle_impl.h"
10 #include "base/macros.h"
11 #include "components/html_viewer/blink_basic_type_converters.h"
12 #include "mojo/services/network/public/cpp/web_socket_read_queue.h"
13 #include "mojo/services/network/public/cpp/web_socket_write_queue.h"
14 #include "mojo/services/network/public/interfaces/web_socket_factory.mojom.h"
15 #include "third_party/WebKit/public/platform/WebSecurityOrigin.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 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
22 using blink::WebSecurityOrigin
;
23 using blink::WebSocketHandle
;
24 using blink::WebSocketHandleClient
;
25 using blink::WebString
;
27 using blink::WebVector
;
29 using mojo::ConvertTo
;
31 using mojo::WebSocket
;
32 using mojo::WebSocketReadQueue
;
37 struct TypeConverter
<WebSocket::MessageType
, WebSocketHandle::MessageType
> {
38 static WebSocket::MessageType
Convert(WebSocketHandle::MessageType type
) {
39 DCHECK(type
== WebSocketHandle::MessageTypeContinuation
||
40 type
== WebSocketHandle::MessageTypeText
||
41 type
== WebSocketHandle::MessageTypeBinary
);
42 typedef WebSocket::MessageType MessageType
;
44 static_cast<MessageType
>(WebSocketHandle::MessageTypeContinuation
) ==
45 WebSocket::MESSAGE_TYPE_CONTINUATION
,
46 enum_values_must_match_for_message_type
);
48 static_cast<MessageType
>(WebSocketHandle::MessageTypeText
) ==
49 WebSocket::MESSAGE_TYPE_TEXT
,
50 enum_values_must_match_for_message_type
);
52 static_cast<MessageType
>(WebSocketHandle::MessageTypeBinary
) ==
53 WebSocket::MESSAGE_TYPE_BINARY
,
54 enum_values_must_match_for_message_type
);
55 return static_cast<WebSocket::MessageType
>(type
);
60 struct TypeConverter
<WebSocketHandle::MessageType
, WebSocket::MessageType
> {
61 static WebSocketHandle::MessageType
Convert(WebSocket::MessageType type
) {
62 DCHECK(type
== WebSocket::MESSAGE_TYPE_CONTINUATION
||
63 type
== WebSocket::MESSAGE_TYPE_TEXT
||
64 type
== WebSocket::MESSAGE_TYPE_BINARY
);
65 return static_cast<WebSocketHandle::MessageType
>(type
);
71 namespace html_viewer
{
73 // This class forms a bridge from the mojo WebSocketClient interface and the
74 // Blink WebSocketHandleClient interface.
75 class WebSocketClientImpl
: public mojo::WebSocketClient
{
77 WebSocketClientImpl(WebSocketHandleImpl
* handle
,
78 blink::WebSocketHandleClient
* client
,
79 mojo::InterfaceRequest
<mojo::WebSocketClient
> request
)
80 : handle_(handle
), client_(client
), binding_(this, request
.Pass()) {}
81 ~WebSocketClientImpl() override
{}
84 // WebSocketClient methods:
85 void DidConnect(const String
& selected_subprotocol
,
86 const String
& extensions
,
87 mojo::ScopedDataPipeConsumerHandle receive_stream
) override
{
88 blink::WebSocketHandleClient
* client
= client_
;
89 WebSocketHandleImpl
* handle
= handle_
;
90 receive_stream_
= receive_stream
.Pass();
91 read_queue_
.reset(new WebSocketReadQueue(receive_stream_
.get()));
92 client
->didConnect(handle
,
93 selected_subprotocol
.To
<WebString
>(),
94 extensions
.To
<WebString
>());
95 // |handle| can be deleted here.
98 void DidReceiveData(bool fin
,
99 WebSocket::MessageType type
,
100 uint32_t num_bytes
) override
{
101 read_queue_
->Read(num_bytes
,
102 base::Bind(&WebSocketClientImpl::DidReadFromReceiveStream
,
103 base::Unretained(this),
104 fin
, type
, num_bytes
));
107 void DidReceiveFlowControl(int64_t quota
) override
{
108 client_
->didReceiveFlowControl(handle_
, quota
);
109 // |handle| can be deleted here.
112 void DidFail(const String
& message
) override
{
113 blink::WebSocketHandleClient
* client
= client_
;
114 WebSocketHandleImpl
* handle
= handle_
;
115 handle
->Disconnect(); // deletes |this|
116 client
->didFail(handle
, message
.To
<WebString
>());
117 // |handle| can be deleted here.
120 void DidClose(bool was_clean
, uint16_t code
, const String
& reason
) override
{
121 blink::WebSocketHandleClient
* client
= client_
;
122 WebSocketHandleImpl
* handle
= handle_
;
123 handle
->Disconnect(); // deletes |this|
124 client
->didClose(handle
, was_clean
, code
, reason
.To
<WebString
>());
125 // |handle| can be deleted here.
128 void DidReadFromReceiveStream(bool fin
,
129 WebSocket::MessageType type
,
132 client_
->didReceiveData(handle_
,
134 ConvertTo
<WebSocketHandle::MessageType
>(type
),
137 // |handle_| can be deleted here.
140 // |handle_| owns this object, so it is guaranteed to outlive us.
141 WebSocketHandleImpl
* handle_
;
142 blink::WebSocketHandleClient
* client_
;
143 mojo::ScopedDataPipeConsumerHandle receive_stream_
;
144 scoped_ptr
<WebSocketReadQueue
> read_queue_
;
145 mojo::Binding
<mojo::WebSocketClient
> binding_
;
147 DISALLOW_COPY_AND_ASSIGN(WebSocketClientImpl
);
150 WebSocketHandleImpl::WebSocketHandleImpl(mojo::WebSocketFactory
* factory
)
151 : did_close_(false) {
152 factory
->CreateWebSocket(GetProxy(&web_socket_
));
155 WebSocketHandleImpl::~WebSocketHandleImpl() {
157 // The connection is abruptly disconnected by the renderer without
158 // closing handshake.
159 web_socket_
->Close(WebSocket::kAbnormalCloseCode
, String());
163 void WebSocketHandleImpl::connect(const WebURL
& url
,
164 const WebVector
<WebString
>& protocols
,
165 const WebSecurityOrigin
& origin
,
166 WebSocketHandleClient
* client
) {
167 // TODO(mpcomplete): Is this the right ownership model? Or should mojo own
169 mojo::WebSocketClientPtr client_ptr
;
170 mojo::MessagePipe pipe
;
172 mojo::InterfacePtrInfo
<mojo::WebSocketClient
>(pipe
.handle0
.Pass(), 0u));
173 mojo::InterfaceRequest
<mojo::WebSocketClient
> request
;
174 request
.Bind(pipe
.handle1
.Pass());
175 client_
.reset(new WebSocketClientImpl(this, client
, request
.Pass()));
177 mojo::DataPipe data_pipe
;
178 send_stream_
= data_pipe
.producer_handle
.Pass();
179 write_queue_
.reset(new mojo::WebSocketWriteQueue(send_stream_
.get()));
180 web_socket_
->Connect(url
.string().utf8(),
181 mojo::Array
<String
>::From(protocols
),
182 origin
.toString().utf8(),
183 data_pipe
.consumer_handle
.Pass(), client_ptr
.Pass());
186 void WebSocketHandleImpl::send(bool fin
,
187 WebSocketHandle::MessageType type
,
193 uint32_t size32
= static_cast<uint32_t>(size
);
196 base::Bind(&WebSocketHandleImpl::DidWriteToSendStream
,
197 base::Unretained(this),
201 void WebSocketHandleImpl::flowControl(int64_t quota
) {
205 web_socket_
->FlowControl(quota
);
208 void WebSocketHandleImpl::close(unsigned short code
, const WebString
& reason
) {
209 web_socket_
->Close(code
, reason
.utf8());
212 void WebSocketHandleImpl::DidWriteToSendStream(
214 WebSocketHandle::MessageType type
,
217 web_socket_
->Send(fin
, ConvertTo
<WebSocket::MessageType
>(type
), num_bytes
);
220 void WebSocketHandleImpl::Disconnect() {
225 } // namespace html_viewer