• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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