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.
4
5 #include "chrome/browser/devtools/adb_web_socket.h"
6
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"
13
14 using content::BrowserThread;
15 using net::WebSocket;
16
17 const int kBufferSize = 16 * 1024;
18
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"
24 "\r\n";
25
AdbWebSocket(scoped_refptr<AndroidDevice> device,const std::string & socket_name,const std::string & url,base::MessageLoop * adb_message_loop,Delegate * delegate)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,
31 Delegate* delegate)
32 : device_(device),
33 socket_name_(socket_name),
34 url_(url),
35 adb_message_loop_(adb_message_loop),
36 delegate_(delegate) {
37 adb_message_loop_->PostTask(
38 FROM_HERE, base::Bind(&AdbWebSocket::ConnectOnHandlerThread, this));
39 }
40
Disconnect()41 void AdbWebSocket::Disconnect() {
42 adb_message_loop_->PostTask(
43 FROM_HERE,
44 base::Bind(&AdbWebSocket::DisconnectOnHandlerThread, this, false));
45 adb_message_loop_ = NULL;
46 }
47
SendFrame(const std::string & message)48 void AdbWebSocket::SendFrame(const std::string& message) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
50 adb_message_loop_->PostTask(
51 FROM_HERE,
52 base::Bind(&AdbWebSocket::SendFrameOnHandlerThread, this, message));
53 }
54
SendFrameOnHandlerThread(const std::string & 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);
61 }
62
~AdbWebSocket()63 AdbWebSocket::~AdbWebSocket() {}
64
ConnectOnHandlerThread()65 void AdbWebSocket::ConnectOnHandlerThread() {
66 device_->HttpUpgrade(
67 socket_name_,
68 base::StringPrintf(kWebSocketUpgradeRequest, url_.c_str()),
69 base::Bind(&AdbWebSocket::ConnectedOnHandlerThread, this));
70 }
71
ConnectedOnHandlerThread(int result,net::StreamSocket * socket)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));
77 return;
78 }
79 socket_.reset(socket);
80 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
81 base::Bind(&AdbWebSocket::OnSocketOpened, this));
82 StartListeningOnHandlerThread();
83 }
84
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(),
90 kBufferSize,
91 base::Bind(&AdbWebSocket::OnBytesRead, this, response_buffer));
92 if (result != net::ERR_IO_PENDING)
93 OnBytesRead(response_buffer, result);
94 }
95
OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer,int result)96 void AdbWebSocket::OnBytesRead(
97 scoped_refptr<net::IOBuffer> response_buffer, int result) {
98 if (!socket_)
99 return;
100
101 if (result <= 0) {
102 DisconnectOnHandlerThread(true);
103 return;
104 }
105
106 std::string data = std::string(response_buffer->data(), result);
107 response_buffer_ += data;
108
109 int bytes_consumed;
110 std::string output;
111 WebSocket::ParseResult parse_result = WebSocket::DecodeFrameHybi17(
112 response_buffer_, false, &bytes_consumed, &output);
113
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));
119 }
120 parse_result = WebSocket::DecodeFrameHybi17(
121 response_buffer_, false, &bytes_consumed, &output);
122 }
123
124 if (parse_result == WebSocket::FRAME_ERROR ||
125 parse_result == WebSocket::FRAME_CLOSE) {
126 DisconnectOnHandlerThread(true);
127 return;
128 }
129
130 result = socket_->Read(
131 response_buffer.get(),
132 kBufferSize,
133 base::Bind(&AdbWebSocket::OnBytesRead, this, response_buffer));
134 if (result != net::ERR_IO_PENDING)
135 OnBytesRead(response_buffer, result);
136 }
137
SendPendingRequests(int result)138 void AdbWebSocket::SendPendingRequests(int result) {
139 if (!socket_)
140 return;
141 if (result < 0) {
142 DisconnectOnHandlerThread(true);
143 return;
144 }
145 request_buffer_ = request_buffer_.substr(result);
146 if (request_buffer_.empty())
147 return;
148
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,
153 this));
154 if (result != net::ERR_IO_PENDING)
155 SendPendingRequests(result);
156 }
157
DisconnectOnHandlerThread(bool closed_by_device)158 void AdbWebSocket::DisconnectOnHandlerThread(bool closed_by_device) {
159 if (!socket_)
160 return;
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));
166 }
167
OnSocketOpened()168 void AdbWebSocket::OnSocketOpened() {
169 delegate_->OnSocketOpened();
170 }
171
OnFrameRead(const std::string & message)172 void AdbWebSocket::OnFrameRead(const std::string& message) {
173 delegate_->OnFrameRead(message);
174 }
175
OnSocketClosed(bool closed_by_device)176 void AdbWebSocket::OnSocketClosed(bool closed_by_device) {
177 delegate_->OnSocketClosed(closed_by_device);
178 }
179