1 // Copyright (c) 2013 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.
5 #include "chrome/browser/devtools/adb_web_socket.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/rand_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "net/base/net_errors.h"
12 #include "net/server/web_socket.h"
14 using content::BrowserThread
;
17 const int kBufferSize
= 16 * 1024;
19 static const char kWebSocketUpgradeRequest
[] = "GET %s HTTP/1.1\r\n"
20 "Upgrade: WebSocket\r\n"
21 "Connection: Upgrade\r\n"
22 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
23 "Sec-WebSocket-Version: 13\r\n"
26 AdbWebSocket::AdbWebSocket(
27 scoped_refptr
<AndroidDevice
> device
,
28 const std::string
& socket_name
,
29 const std::string
& url
,
30 base::MessageLoop
* adb_message_loop
,
33 socket_name_(socket_name
),
35 adb_message_loop_(adb_message_loop
),
37 adb_message_loop_
->PostTask(
38 FROM_HERE
, base::Bind(&AdbWebSocket::ConnectOnHandlerThread
, this));
41 void AdbWebSocket::Disconnect() {
42 adb_message_loop_
->PostTask(
44 base::Bind(&AdbWebSocket::DisconnectOnHandlerThread
, this, false));
45 adb_message_loop_
= NULL
;
48 void AdbWebSocket::SendFrame(const std::string
& message
) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
50 adb_message_loop_
->PostTask(
52 base::Bind(&AdbWebSocket::SendFrameOnHandlerThread
, this, message
));
55 void AdbWebSocket::SendFrameOnHandlerThread(const std::string
& message
) {
56 int mask
= base::RandInt(0, 0x7FFFFFFF);
57 std::string encoded_frame
= WebSocket::EncodeFrameHybi17(message
, mask
);
58 request_buffer_
+= encoded_frame
;
59 if (request_buffer_
.length() == encoded_frame
.length())
60 SendPendingRequests(0);
63 AdbWebSocket::~AdbWebSocket() {}
65 void AdbWebSocket::ConnectOnHandlerThread() {
68 base::StringPrintf(kWebSocketUpgradeRequest
, url_
.c_str()),
69 base::Bind(&AdbWebSocket::ConnectedOnHandlerThread
, this));
72 void AdbWebSocket::ConnectedOnHandlerThread(
73 int result
, net::StreamSocket
* socket
) {
74 if (result
!= net::OK
|| socket
== NULL
) {
75 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
76 base::Bind(&AdbWebSocket::OnSocketClosed
, this, true));
79 socket_
.reset(socket
);
80 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
81 base::Bind(&AdbWebSocket::OnSocketOpened
, this));
82 StartListeningOnHandlerThread();
85 void AdbWebSocket::StartListeningOnHandlerThread() {
86 scoped_refptr
<net::IOBuffer
> response_buffer
=
87 new net::IOBuffer(kBufferSize
);
88 int result
= socket_
->Read(
89 response_buffer
.get(),
91 base::Bind(&AdbWebSocket::OnBytesRead
, this, response_buffer
));
92 if (result
!= net::ERR_IO_PENDING
)
93 OnBytesRead(response_buffer
, result
);
96 void AdbWebSocket::OnBytesRead(
97 scoped_refptr
<net::IOBuffer
> response_buffer
, int result
) {
102 DisconnectOnHandlerThread(true);
106 std::string data
= std::string(response_buffer
->data(), result
);
107 response_buffer_
+= data
;
111 WebSocket::ParseResult parse_result
= WebSocket::DecodeFrameHybi17(
112 response_buffer_
, false, &bytes_consumed
, &output
);
114 while (parse_result
== WebSocket::FRAME_OK
) {
115 response_buffer_
= response_buffer_
.substr(bytes_consumed
);
116 if (!delegate_
|| !delegate_
->ProcessIncomingMessage(output
)) {
117 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
118 base::Bind(&AdbWebSocket::OnFrameRead
, this, output
));
120 parse_result
= WebSocket::DecodeFrameHybi17(
121 response_buffer_
, false, &bytes_consumed
, &output
);
124 if (parse_result
== WebSocket::FRAME_ERROR
||
125 parse_result
== WebSocket::FRAME_CLOSE
) {
126 DisconnectOnHandlerThread(true);
130 result
= socket_
->Read(
131 response_buffer
.get(),
133 base::Bind(&AdbWebSocket::OnBytesRead
, this, response_buffer
));
134 if (result
!= net::ERR_IO_PENDING
)
135 OnBytesRead(response_buffer
, result
);
138 void AdbWebSocket::SendPendingRequests(int result
) {
142 DisconnectOnHandlerThread(true);
145 request_buffer_
= request_buffer_
.substr(result
);
146 if (request_buffer_
.empty())
149 scoped_refptr
<net::StringIOBuffer
> buffer
=
150 new net::StringIOBuffer(request_buffer_
);
151 result
= socket_
->Write(buffer
.get(), buffer
->size(),
152 base::Bind(&AdbWebSocket::SendPendingRequests
,
154 if (result
!= net::ERR_IO_PENDING
)
155 SendPendingRequests(result
);
158 void AdbWebSocket::DisconnectOnHandlerThread(bool closed_by_device
) {
161 // Wipe out socket_ first since Disconnect can re-enter this method.
162 scoped_ptr
<net::StreamSocket
> socket(socket_
.release());
163 socket
->Disconnect();
164 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
165 base::Bind(&AdbWebSocket::OnSocketClosed
, this, closed_by_device
));
168 void AdbWebSocket::OnSocketOpened() {
169 delegate_
->OnSocketOpened();
172 void AdbWebSocket::OnFrameRead(const std::string
& message
) {
173 delegate_
->OnFrameRead(message
);
176 void AdbWebSocket::OnSocketClosed(bool closed_by_device
) {
177 delegate_
->OnSocketClosed(closed_by_device
);