Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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 "webkit/glue/websocketstreamhandle_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 "third_party/WebKit/Source/WebKit/chromium/public/WebData.h"
     16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
     17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSocketStreamHandleClient.h"
     18 #include "webkit/glue/websocketstreamhandle_bridge.h"
     19 #include "webkit/glue/websocketstreamhandle_delegate.h"
     20 
     21 namespace webkit_glue {
     22 
     23 // WebSocketStreamHandleImpl::Context -----------------------------------------
     24 
     25 class WebSocketStreamHandleImpl::Context
     26     : public base::RefCounted<Context>,
     27       public WebSocketStreamHandleDelegate {
     28  public:
     29   explicit Context(WebSocketStreamHandleImpl* handle);
     30 
     31   WebKit::WebSocketStreamHandleClient* client() const { return client_; }
     32   void set_client(WebKit::WebSocketStreamHandleClient* client) {
     33     client_ = client;
     34   }
     35 
     36   void Connect(const WebKit::WebURL& url);
     37   bool Send(const WebKit::WebData& data);
     38   void Close();
     39 
     40   // Must be called before |handle_| or |client_| is deleted.
     41   // Once detached, it never calls |client_| back.
     42   void Detach();
     43 
     44   // WebSocketStreamHandleDelegate methods:
     45   virtual void DidOpenStream(WebKit::WebSocketStreamHandle*, int);
     46   virtual void DidSendData(WebKit::WebSocketStreamHandle*, int);
     47   virtual void DidReceiveData(
     48       WebKit::WebSocketStreamHandle*, const char*, int);
     49   virtual void DidClose(WebKit::WebSocketStreamHandle*);
     50 
     51  private:
     52   friend class base::RefCounted<Context>;
     53   ~Context() {
     54     DCHECK(!handle_);
     55     DCHECK(!client_);
     56     DCHECK(!bridge_);
     57   }
     58 
     59   WebSocketStreamHandleImpl* handle_;
     60   WebKit::WebSocketStreamHandleClient* client_;
     61   // |bridge_| is alive from Connect to DidClose, so Context must be alive
     62   // in the time period.
     63   scoped_refptr<WebSocketStreamHandleBridge> bridge_;
     64 
     65   DISALLOW_COPY_AND_ASSIGN(Context);
     66 };
     67 
     68 WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle)
     69     : handle_(handle),
     70       client_(NULL),
     71       bridge_(NULL) {
     72 }
     73 
     74 void WebSocketStreamHandleImpl::Context::Connect(const WebKit::WebURL& url) {
     75   VLOG(1) << "Connect url=" << url;
     76   DCHECK(!bridge_);
     77   bridge_ = WebSocketStreamHandleBridge::Create(handle_, this);
     78   AddRef();  // Will be released by DidClose().
     79   bridge_->Connect(url);
     80 }
     81 
     82 bool WebSocketStreamHandleImpl::Context::Send(const WebKit::WebData& data) {
     83   VLOG(1) << "Send data.size=" << data.size();
     84   DCHECK(bridge_);
     85   return bridge_->Send(
     86       std::vector<char>(data.data(), data.data() + data.size()));
     87 }
     88 
     89 void WebSocketStreamHandleImpl::Context::Close() {
     90   VLOG(1) << "Close";
     91   if (bridge_)
     92     bridge_->Close();
     93 }
     94 
     95 void WebSocketStreamHandleImpl::Context::Detach() {
     96   handle_ = NULL;
     97   client_ = NULL;
     98   // If Connect was called, |bridge_| is not NULL, so that this Context closes
     99   // the |bridge_| here.  Then |bridge_| will call back DidClose, and will
    100   // be released by itself.
    101   // Otherwise, |bridge_| is NULL.
    102   if (bridge_)
    103     bridge_->Close();
    104 }
    105 
    106 void WebSocketStreamHandleImpl::Context::DidOpenStream(
    107     WebKit::WebSocketStreamHandle* web_handle, int max_amount_send_allowed) {
    108   VLOG(1) << "DidOpen";
    109   if (client_)
    110     client_->didOpenStream(handle_, max_amount_send_allowed);
    111 }
    112 
    113 void WebSocketStreamHandleImpl::Context::DidSendData(
    114     WebKit::WebSocketStreamHandle* web_handle, int amount_sent) {
    115   if (client_)
    116     client_->didSendData(handle_, amount_sent);
    117 }
    118 
    119 void WebSocketStreamHandleImpl::Context::DidReceiveData(
    120     WebKit::WebSocketStreamHandle* web_handle, const char* data, int size) {
    121   if (client_)
    122     client_->didReceiveData(handle_, WebKit::WebData(data, size));
    123 }
    124 
    125 void WebSocketStreamHandleImpl::Context::DidClose(
    126     WebKit::WebSocketStreamHandle* web_handle) {
    127   VLOG(1) << "DidClose";
    128   bridge_ = NULL;
    129   WebSocketStreamHandleImpl* handle = handle_;
    130   handle_ = NULL;
    131   if (client_) {
    132     WebKit::WebSocketStreamHandleClient* client = client_;
    133     client_ = NULL;
    134     client->didClose(handle);
    135   }
    136   Release();
    137 }
    138 
    139 // WebSocketStreamHandleImpl ------------------------------------------------
    140 
    141 WebSocketStreamHandleImpl::WebSocketStreamHandleImpl()
    142     : ALLOW_THIS_IN_INITIALIZER_LIST(context_(new Context(this))) {
    143 }
    144 
    145 WebSocketStreamHandleImpl::~WebSocketStreamHandleImpl() {
    146   // We won't receive any events from |context_|.
    147   // |context_| is ref counted, and will be released when it received
    148   // DidClose.
    149   context_->Detach();
    150 }
    151 
    152 void WebSocketStreamHandleImpl::connect(
    153     const WebKit::WebURL& url, WebKit::WebSocketStreamHandleClient* client) {
    154   VLOG(1) << "connect url=" << url;
    155   DCHECK(!context_->client());
    156   context_->set_client(client);
    157 
    158   context_->Connect(url);
    159 }
    160 
    161 bool WebSocketStreamHandleImpl::send(const WebKit::WebData& data) {
    162   return context_->Send(data);
    163 }
    164 
    165 void WebSocketStreamHandleImpl::close() {
    166   context_->Close();
    167 }
    168 
    169 }  // namespace webkit_glue
    170