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
25using blink::WebData;
26using blink::WebSocketStreamError;
27using blink::WebSocketStreamHandle;
28using blink::WebSocketStreamHandleClient;
29using blink::WebURL;
30
31namespace content {
32
33// WebSocketStreamHandleImpl::Context -----------------------------------------
34
35class 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
82WebSocketStreamHandleImpl::Context::Context(WebSocketStreamHandleImpl* handle)
83    : handle_(handle),
84      client_(NULL) {
85}
86
87void 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
99bool 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
106void WebSocketStreamHandleImpl::Context::Close() {
107  VLOG(1) << "Close";
108  if (bridge_.get())
109    bridge_->Close();
110}
111
112void 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
123void 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
130void WebSocketStreamHandleImpl::Context::DidSendData(
131    WebSocketStreamHandle* web_handle, int amount_sent) {
132  if (client_)
133    client_->didSendData(handle_, amount_sent);
134}
135
136void WebSocketStreamHandleImpl::Context::DidReceiveData(
137    WebSocketStreamHandle* web_handle, const char* data, int size) {
138  if (client_)
139    client_->didReceiveData(handle_, WebData(data, size));
140}
141
142void 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
156void 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
170WebSocketStreamHandleImpl::WebSocketStreamHandleImpl()
171    : context_(new Context(this)) {
172}
173
174WebSocketStreamHandleImpl::~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
181void 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
190bool WebSocketStreamHandleImpl::send(const WebData& data) {
191  return context_->Send(data);
192}
193
194void WebSocketStreamHandleImpl::close() {
195  context_->Close();
196}
197
198}  // namespace content
199