- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / adb_web_socket.cc
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<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 }