Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / device / android_web_socket.cc
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 #include "base/message_loop/message_loop.h"
6 #include "base/rand_util.h"
7 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/server/web_socket.h"
12 #include "net/socket/stream_socket.h"
13
14 using content::BrowserThread;
15 using net::WebSocket;
16
17 namespace {
18
19 const int kBufferSize = 16 * 1024;
20
21 class WebSocketImpl : public DevToolsAndroidBridge::AndroidWebSocket {
22  public:
23   WebSocketImpl(scoped_refptr<DevToolsAndroidBridge> android_bridge,
24                    AndroidDeviceManager* device_manager,
25                    base::MessageLoop* device_message_loop,
26                    const std::string& serial,
27                    const std::string& socket_name,
28                    const std::string& url,
29                    Delegate* delegate);
30
31   virtual void Connect() OVERRIDE;
32   virtual void Disconnect() OVERRIDE;
33
34   virtual void SendFrame(const std::string& message) OVERRIDE;
35
36  private:
37   friend class base::RefCountedThreadSafe<AndroidWebSocket>;
38
39   virtual ~WebSocketImpl();
40
41   void ConnectOnHandlerThread();
42   void ConnectedOnHandlerThread(int result, net::StreamSocket* socket);
43   void StartListeningOnHandlerThread();
44   void OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer, int result);
45   void SendFrameOnHandlerThread(const std::string& message);
46   void SendPendingRequests(int result);
47   void DisconnectOnHandlerThread(bool closed_by_device);
48
49   void OnSocketOpened();
50   void OnFrameRead(const std::string& message);
51   void OnSocketClosed(bool closed_by_device);
52
53   scoped_refptr<DevToolsAndroidBridge> android_bridge_;
54   AndroidDeviceManager* device_manager_;
55   base::MessageLoop* device_message_loop_;
56   std::string serial_;
57   std::string socket_name_;
58   std::string url_;
59   scoped_ptr<net::StreamSocket> socket_;
60   Delegate* delegate_;
61   std::string response_buffer_;
62   std::string request_buffer_;
63 };
64
65 WebSocketImpl::WebSocketImpl(
66     scoped_refptr<DevToolsAndroidBridge> android_bridge,
67     AndroidDeviceManager* device_manager,
68     base::MessageLoop* device_message_loop,
69     const std::string& serial,
70     const std::string& socket_name,
71     const std::string& url,
72     Delegate* delegate)
73     : android_bridge_(android_bridge),
74       device_manager_(device_manager),
75       device_message_loop_(device_message_loop),
76       serial_(serial),
77       socket_name_(socket_name),
78       url_(url),
79       delegate_(delegate) {
80 }
81
82 void WebSocketImpl::Connect() {
83   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84   device_message_loop_->PostTask(
85       FROM_HERE, base::Bind(&WebSocketImpl::ConnectOnHandlerThread, this));
86 }
87
88 void WebSocketImpl::Disconnect() {
89   device_message_loop_->PostTask(
90       FROM_HERE,
91       base::Bind(&WebSocketImpl::DisconnectOnHandlerThread, this, false));
92 }
93
94 void WebSocketImpl::SendFrame(const std::string& message) {
95   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
96   device_message_loop_->PostTask(
97       FROM_HERE,
98       base::Bind(&WebSocketImpl::SendFrameOnHandlerThread, this, message));
99 }
100
101 void WebSocketImpl::SendFrameOnHandlerThread(const std::string& message) {
102   int mask = base::RandInt(0, 0x7FFFFFFF);
103   std::string encoded_frame = WebSocket::EncodeFrameHybi17(message, mask);
104   request_buffer_ += encoded_frame;
105   if (request_buffer_.length() == encoded_frame.length())
106     SendPendingRequests(0);
107 }
108
109 WebSocketImpl::~WebSocketImpl() {}
110
111 void WebSocketImpl::ConnectOnHandlerThread() {
112   device_manager_->HttpUpgrade(
113       serial_,
114       socket_name_,
115       url_,
116       base::Bind(&WebSocketImpl::ConnectedOnHandlerThread, this));
117 }
118
119 void WebSocketImpl::ConnectedOnHandlerThread(
120   int result, net::StreamSocket* socket) {
121   if (result != net::OK || socket == NULL) {
122     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
123         base::Bind(&WebSocketImpl::OnSocketClosed, this, true));
124     return;
125   }
126   socket_.reset(socket);
127   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
128       base::Bind(&WebSocketImpl::OnSocketOpened, this));
129   StartListeningOnHandlerThread();
130 }
131
132 void WebSocketImpl::StartListeningOnHandlerThread() {
133   scoped_refptr<net::IOBuffer> response_buffer =
134       new net::IOBuffer(kBufferSize);
135   int result = socket_->Read(
136       response_buffer.get(),
137       kBufferSize,
138       base::Bind(&WebSocketImpl::OnBytesRead, this, response_buffer));
139   if (result != net::ERR_IO_PENDING)
140     OnBytesRead(response_buffer, result);
141 }
142
143 void WebSocketImpl::OnBytesRead(
144     scoped_refptr<net::IOBuffer> response_buffer, int result) {
145   if (!socket_)
146     return;
147
148   if (result <= 0) {
149     DisconnectOnHandlerThread(true);
150     return;
151   }
152
153   std::string data = std::string(response_buffer->data(), result);
154   response_buffer_ += data;
155
156   int bytes_consumed;
157   std::string output;
158   WebSocket::ParseResult parse_result = WebSocket::DecodeFrameHybi17(
159       response_buffer_, false, &bytes_consumed, &output);
160
161   while (parse_result == WebSocket::FRAME_OK) {
162     response_buffer_ = response_buffer_.substr(bytes_consumed);
163     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
164         base::Bind(&WebSocketImpl::OnFrameRead, this, output));
165     parse_result = WebSocket::DecodeFrameHybi17(
166         response_buffer_, false, &bytes_consumed, &output);
167   }
168
169   if (parse_result == WebSocket::FRAME_ERROR ||
170       parse_result == WebSocket::FRAME_CLOSE) {
171     DisconnectOnHandlerThread(true);
172     return;
173   }
174
175   result = socket_->Read(
176       response_buffer.get(),
177       kBufferSize,
178       base::Bind(&WebSocketImpl::OnBytesRead, this, response_buffer));
179   if (result != net::ERR_IO_PENDING)
180     OnBytesRead(response_buffer, result);
181 }
182
183 void WebSocketImpl::SendPendingRequests(int result) {
184   if (!socket_)
185     return;
186   if (result < 0) {
187     DisconnectOnHandlerThread(true);
188     return;
189   }
190   request_buffer_ = request_buffer_.substr(result);
191   if (request_buffer_.empty())
192     return;
193
194   scoped_refptr<net::StringIOBuffer> buffer =
195       new net::StringIOBuffer(request_buffer_);
196   result = socket_->Write(buffer.get(), buffer->size(),
197                           base::Bind(&WebSocketImpl::SendPendingRequests,
198                                      this));
199   if (result != net::ERR_IO_PENDING)
200     SendPendingRequests(result);
201 }
202
203 void WebSocketImpl::DisconnectOnHandlerThread(bool closed_by_device) {
204   if (!socket_)
205     return;
206   // Wipe out socket_ first since Disconnect can re-enter this method.
207   scoped_ptr<net::StreamSocket> socket(socket_.release());
208   socket->Disconnect();
209   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
210       base::Bind(&WebSocketImpl::OnSocketClosed, this, closed_by_device));
211 }
212
213 void WebSocketImpl::OnSocketOpened() {
214   delegate_->OnSocketOpened();
215 }
216
217 void WebSocketImpl::OnFrameRead(const std::string& message) {
218   delegate_->OnFrameRead(message);
219 }
220
221 void WebSocketImpl::OnSocketClosed(bool closed_by_device) {
222   delegate_->OnSocketClosed(closed_by_device);
223 }
224
225 }  // namespace
226
227 scoped_refptr<DevToolsAndroidBridge::AndroidWebSocket>
228 DevToolsAndroidBridge::RemoteBrowser::CreateWebSocket(
229     const std::string& url,
230     DevToolsAndroidBridge::AndroidWebSocket::Delegate* delegate) {
231   return new WebSocketImpl(
232       android_bridge_,
233       android_bridge_->device_manager(),
234       android_bridge_->device_message_loop(),
235       serial_, socket_, url, delegate);
236 }