Home | History | Annotate | Download | only in child
      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 // An implementation of WebSocketStreamHandle.
      6 
      7 #include "content/child/web_socket_stream_handle_impl.h"
      8 
      9 #include <vector>
     10 
     11 #include "base/compiler_specific.h"
     12 #include "base/logging.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/strings/string16.h"
     16 #include "content/child/child_thread.h"
     17 #include "content/child/socket_stream_dispatcher.h"
     18 #include "content/child/web_socket_stream_handle_bridge.h"
     19 #include "content/child/web_socket_stream_handle_delegate.h"
     20 #include "third_party/WebKit/public/platform/WebData.h"
     21 #include "third_party/WebKit/public/platform/WebSocketStreamError.h"
     22 #include "third_party/WebKit/public/platform/WebSocketStreamHandleClient.h"
     23 #include "third_party/WebKit/public/platform/WebURL.h"
     24 
     25 using blink::WebData;
     26 using blink::WebSocketStreamError;
     27 using blink::WebSocketStreamHandle;
     28 using blink::WebSocketStreamHandleClient;
     29 using blink::WebURL;
     30 
     31 namespace content {
     32 
     33 // WebSocketStreamHandleImpl::Context -----------------------------------------
     34 
     35 class WebSocketStreamHandleImpl::Context
     36     : public base::RefCounted<Context>,
     37       public WebSocketStreamHandleDelegate {
     38  public:
     39   explicit Context(WebSocketStreamHandleImpl* handle);
     40 
     41   WebSocketStreamHandleClient* client() const { return client_; }
     42   void set_client(WebSocketStreamHandleClient* client) {
     43     client_ = client;
     44   }
     45 
     46   void Connect(const WebURL& url);
     47   bool Send(const WebData& data);
     48   void Close();
     49 
     50   // Must be called before |handle_| or |client_| is deleted.
     51   // Once detached, it never calls |client_| back.
     52   void Detach();
     53 
     54   // WebSocketStreamHandleDelegate methods:
     55   virtual void DidOpenStream(WebSocketStreamHandle*, int) OVERRIDE;
     56   virtual void DidSendData(WebSocketStreamHandle*, int) OVERRIDE;
     57   virtual void DidReceiveData(WebSocketStreamHandle*,
     58                               const char*,
     59                               int) OVERRIDE;
     60   virtual void DidClose(WebSocketStreamHandle*) OVERRIDE;
     61   virtual void DidFail(WebSocketStreamHandle*,
     62                        int,
     63                        const base::string16&) OVERRIDE;
     64 
     65  private:
     66   friend class base::RefCounted<Context>;
     67   virtual ~Context() {
     68     DCHECK(!handle_);
     69     DCHECK(!client_);
     70     DCHECK(!bridge_.get());
     71   }
     72 
     73   WebSocketStreamHandleImpl* handle_;
     74   WebSocketStreamHandleClient* client_;
     75   // |bridge_| is alive from Connect to DidClose, so Context must be alive
     76   // in the time period.
     77   scoped_refptr<WebSocketStreamHandleBridge> bridge_;
     78 
     79   DISALLOW_COPY_AND_ASSIGN(Context);
     80 };
     81 
     82 WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle)
     83     : handle_(handle),
     84       client_(NULL) {
     85 }
     86 
     87 void WebSocketStreamHandleImpl::Context::Connect(const WebURL& url) {
     88   VLOG(1) << "Connect url=" << url;
     89   DCHECK(!bridge_.get());
     90 
     91   SocketStreamDispatcher* dispatcher =
     92       ChildThread::current()->socket_stream_dispatcher();
     93   bridge_ = dispatcher->CreateBridge(handle_, this);
     94 
     95   AddRef();  // Will be released by DidClose().
     96   bridge_->Connect(url);
     97 }
     98 
     99 bool WebSocketStreamHandleImpl::Context::Send(const WebData& data) {
    100   VLOG(1) << "Send data.size=" << data.size();
    101   DCHECK(bridge_.get());
    102   return bridge_->Send(
    103       std::vector<char>(data.data(), data.data() + data.size()));
    104 }
    105 
    106 void WebSocketStreamHandleImpl::Context::Close() {
    107   VLOG(1) << "Close";
    108   if (bridge_.get())
    109     bridge_->Close();
    110 }
    111 
    112 void WebSocketStreamHandleImpl::Context::Detach() {
    113   handle_ = NULL;
    114   client_ = NULL;
    115   // If Connect was called, |bridge_| is not NULL, so that this Context closes
    116   // the |bridge_| here.  Then |bridge_| will call back DidClose, and will
    117   // be released by itself.
    118   // Otherwise, |bridge_| is NULL.
    119   if (bridge_.get())
    120     bridge_->Close();
    121 }
    122 
    123 void WebSocketStreamHandleImpl::Context::DidOpenStream(
    124     WebSocketStreamHandle* web_handle, int max_amount_send_allowed) {
    125   VLOG(1) << "DidOpen";
    126   if (client_)
    127     client_->didOpenStream(handle_, max_amount_send_allowed);
    128 }
    129 
    130 void WebSocketStreamHandleImpl::Context::DidSendData(
    131     WebSocketStreamHandle* web_handle, int amount_sent) {
    132   if (client_)
    133     client_->didSendData(handle_, amount_sent);
    134 }
    135 
    136 void WebSocketStreamHandleImpl::Context::DidReceiveData(
    137     WebSocketStreamHandle* web_handle, const char* data, int size) {
    138   if (client_)
    139     client_->didReceiveData(handle_, WebData(data, size));
    140 }
    141 
    142 void WebSocketStreamHandleImpl::Context::DidClose(
    143     WebSocketStreamHandle* web_handle) {
    144   VLOG(1) << "DidClose";
    145   bridge_ = NULL;
    146   WebSocketStreamHandleImpl* handle = handle_;
    147   handle_ = NULL;
    148   if (client_) {
    149     WebSocketStreamHandleClient* client = client_;
    150     client_ = NULL;
    151     client->didClose(handle);
    152   }
    153   Release();
    154 }
    155 
    156 void WebSocketStreamHandleImpl::Context::DidFail(
    157     WebSocketStreamHandle* web_handle,
    158     int error_code,
    159     const base::string16& error_msg) {
    160   VLOG(1) << "DidFail";
    161   if (client_) {
    162     client_->didFail(
    163         handle_,
    164         WebSocketStreamError(error_code, error_msg));
    165   }
    166 }
    167 
    168 // WebSocketStreamHandleImpl ------------------------------------------------
    169 
    170 WebSocketStreamHandleImpl::WebSocketStreamHandleImpl()
    171     : context_(new Context(this)) {
    172 }
    173 
    174 WebSocketStreamHandleImpl::~WebSocketStreamHandleImpl() {
    175   // We won't receive any events from |context_|.
    176   // |context_| is ref counted, and will be released when it received
    177   // DidClose.
    178   context_->Detach();
    179 }
    180 
    181 void WebSocketStreamHandleImpl::connect(
    182     const WebURL& url, WebSocketStreamHandleClient* client) {
    183   VLOG(1) << "connect url=" << url;
    184   DCHECK(!context_->client());
    185   context_->set_client(client);
    186 
    187   context_->Connect(url);
    188 }
    189 
    190 bool WebSocketStreamHandleImpl::send(const WebData& data) {
    191   return context_->Send(data);
    192 }
    193 
    194 void WebSocketStreamHandleImpl::close() {
    195   context_->Close();
    196 }
    197 
    198 }  // namespace content
    199