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