Home | History | Annotate | Download | only in devtools
      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