• 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 // 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 
client() const41   WebSocketStreamHandleClient* client() const { return client_; }
set_client(WebSocketStreamHandleClient * 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>;
~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 
Context(WebSocketStreamHandleImpl * handle)82 WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle)
83     : handle_(handle),
84       client_(NULL) {
85 }
86 
Connect(const WebURL & url)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 
Send(const WebData & data)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 
Close()106 void WebSocketStreamHandleImpl::Context::Close() {
107   VLOG(1) << "Close";
108   if (bridge_.get())
109     bridge_->Close();
110 }
111 
Detach()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 
DidOpenStream(WebSocketStreamHandle * web_handle,int max_amount_send_allowed)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 
DidSendData(WebSocketStreamHandle * web_handle,int amount_sent)130 void WebSocketStreamHandleImpl::Context::DidSendData(
131     WebSocketStreamHandle* web_handle, int amount_sent) {
132   if (client_)
133     client_->didSendData(handle_, amount_sent);
134 }
135 
DidReceiveData(WebSocketStreamHandle * web_handle,const char * data,int size)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 
DidClose(WebSocketStreamHandle * web_handle)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 
DidFail(WebSocketStreamHandle * web_handle,int error_code,const base::string16 & error_msg)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 
WebSocketStreamHandleImpl()170 WebSocketStreamHandleImpl::WebSocketStreamHandleImpl()
171     : context_(new Context(this)) {
172 }
173 
~WebSocketStreamHandleImpl()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 
connect(const WebURL & url,WebSocketStreamHandleClient * client)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 
send(const WebData & data)190 bool WebSocketStreamHandleImpl::send(const WebData& data) {
191   return context_->Send(data);
192 }
193 
close()194 void WebSocketStreamHandleImpl::close() {
195   context_->Close();
196 }
197 
198 }  // namespace content
199