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 26 AdbWebSocket::AdbWebSocket( 27 scoped_refptr<DevToolsAdbBridge::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 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 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 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 63 AdbWebSocket::~AdbWebSocket() {} 64 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 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 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 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 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 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 168 void AdbWebSocket::OnSocketOpened() { 169 delegate_->OnSocketOpened(); 170 } 171 172 void AdbWebSocket::OnFrameRead(const std::string& message) { 173 delegate_->OnFrameRead(message); 174 } 175 176 void AdbWebSocket::OnSocketClosed(bool closed_by_device) { 177 delegate_->OnSocketClosed(closed_by_device); 178 } 179