Home | History | Annotate | Download | only in html_viewer
      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> {
     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 
     53 template<>
     54 struct 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.
     65 class 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 
    145 WebSocketHandleImpl::WebSocketHandleImpl(NetworkService* network_service)
    146     : did_close_(false) {
    147   network_service->CreateWebSocket(Get(&web_socket_));
    148 }
    149 
    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 
    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 
    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 
    193 void WebSocketHandleImpl::flowControl(int64_t quota) {
    194   if (!client_)
    195     return;
    196 
    197   web_socket_->FlowControl(quota);
    198 }
    199 
    200 void WebSocketHandleImpl::close(unsigned short code, const WebString& reason) {
    201   web_socket_->Close(code, reason.utf8());
    202 }
    203 
    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 
    212 void WebSocketHandleImpl::Disconnect() {
    213   did_close_ = true;
    214   client_.reset();
    215 }
    216 
    217 }  // namespace mojo
    218