Revert of Referrer Policy: Update SanitizeForRequest with new default behavior. ...
[chromium-blink-merge.git] / content / browser / devtools / tethering_handler.cc
blob5f039117ff4206c1913d195d1442604fc36cfa2d
1 // Copyright (c) 2012 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 "content/browser/devtools/tethering_handler.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/stl_util.h"
10 #include "base/values.h"
11 #include "content/browser/devtools/devtools_http_handler_impl.h"
12 #include "content/browser/devtools/devtools_protocol_constants.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/devtools_http_handler_delegate.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/ip_endpoint.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/net_log.h"
19 #include "net/socket/server_socket.h"
20 #include "net/socket/stream_socket.h"
21 #include "net/socket/tcp_server_socket.h"
23 namespace content {
25 namespace {
27 const char kLocalhost[] = "127.0.0.1";
29 const int kListenBacklog = 5;
30 const int kBufferSize = 16 * 1024;
32 const int kMinTetheringPort = 1024;
33 const int kMaxTetheringPort = 32767;
35 class SocketPump {
36 public:
37 SocketPump(DevToolsHttpHandlerDelegate* delegate,
38 net::StreamSocket* client_socket)
39 : client_socket_(client_socket),
40 delegate_(delegate),
41 pending_writes_(0),
42 pending_destruction_(false) {
45 std::string Init() {
46 std::string channel_name;
47 server_socket_ = delegate_->CreateSocketForTethering(&channel_name);
48 if (!server_socket_.get() || channel_name.empty())
49 SelfDestruct();
51 int result = server_socket_->Accept(
52 &accepted_socket_,
53 base::Bind(&SocketPump::OnAccepted, base::Unretained(this)));
54 if (result != net::ERR_IO_PENDING)
55 OnAccepted(result);
56 return channel_name;
59 private:
60 void OnAccepted(int result) {
61 if (result < 0) {
62 SelfDestruct();
63 return;
66 ++pending_writes_; // avoid SelfDestruct in first Pump
67 Pump(client_socket_.get(), accepted_socket_.get());
68 --pending_writes_;
69 if (pending_destruction_) {
70 SelfDestruct();
71 } else {
72 Pump(accepted_socket_.get(), client_socket_.get());
76 void Pump(net::StreamSocket* from, net::StreamSocket* to) {
77 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
78 int result = from->Read(
79 buffer.get(),
80 kBufferSize,
81 base::Bind(
82 &SocketPump::OnRead, base::Unretained(this), from, to, buffer));
83 if (result != net::ERR_IO_PENDING)
84 OnRead(from, to, buffer, result);
87 void OnRead(net::StreamSocket* from,
88 net::StreamSocket* to,
89 scoped_refptr<net::IOBuffer> buffer,
90 int result) {
91 if (result <= 0) {
92 SelfDestruct();
93 return;
96 int total = result;
97 scoped_refptr<net::DrainableIOBuffer> drainable =
98 new net::DrainableIOBuffer(buffer.get(), total);
100 ++pending_writes_;
101 result = to->Write(drainable.get(),
102 total,
103 base::Bind(&SocketPump::OnWritten,
104 base::Unretained(this),
105 drainable,
106 from,
107 to));
108 if (result != net::ERR_IO_PENDING)
109 OnWritten(drainable, from, to, result);
112 void OnWritten(scoped_refptr<net::DrainableIOBuffer> drainable,
113 net::StreamSocket* from,
114 net::StreamSocket* to,
115 int result) {
116 --pending_writes_;
117 if (result < 0) {
118 SelfDestruct();
119 return;
122 drainable->DidConsume(result);
123 if (drainable->BytesRemaining() > 0) {
124 ++pending_writes_;
125 result = to->Write(drainable.get(),
126 drainable->BytesRemaining(),
127 base::Bind(&SocketPump::OnWritten,
128 base::Unretained(this),
129 drainable,
130 from,
131 to));
132 if (result != net::ERR_IO_PENDING)
133 OnWritten(drainable, from, to, result);
134 return;
137 if (pending_destruction_) {
138 SelfDestruct();
139 return;
141 Pump(from, to);
144 void SelfDestruct() {
145 if (pending_writes_ > 0) {
146 pending_destruction_ = true;
147 return;
149 delete this;
153 private:
154 scoped_ptr<net::StreamSocket> client_socket_;
155 scoped_ptr<net::ServerSocket> server_socket_;
156 scoped_ptr<net::StreamSocket> accepted_socket_;
157 DevToolsHttpHandlerDelegate* delegate_;
158 int pending_writes_;
159 bool pending_destruction_;
162 static int GetPort(scoped_refptr<DevToolsProtocol::Command> command,
163 const std::string& paramName) {
164 base::DictionaryValue* params = command->params();
165 int port = 0;
166 if (!params ||
167 !params->GetInteger(paramName, &port) ||
168 port < kMinTetheringPort || port > kMaxTetheringPort)
169 return 0;
170 return port;
173 class BoundSocket {
174 public:
175 typedef base::Callback<void(int, const std::string&)> AcceptedCallback;
177 BoundSocket(AcceptedCallback accepted_callback,
178 DevToolsHttpHandlerDelegate* delegate)
179 : accepted_callback_(accepted_callback),
180 delegate_(delegate),
181 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
182 port_(0) {
185 virtual ~BoundSocket() {
188 bool Listen(int port) {
189 port_ = port;
190 net::IPAddressNumber ip_number;
191 if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
192 return false;
194 net::IPEndPoint end_point(ip_number, port);
195 int result = socket_->Listen(end_point, kListenBacklog);
196 if (result < 0)
197 return false;
199 net::IPEndPoint local_address;
200 result = socket_->GetLocalAddress(&local_address);
201 if (result < 0)
202 return false;
204 DoAccept();
205 return true;
208 private:
209 typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
211 void DoAccept() {
212 while (true) {
213 int result = socket_->Accept(
214 &accept_socket_,
215 base::Bind(&BoundSocket::OnAccepted, base::Unretained(this)));
216 if (result == net::ERR_IO_PENDING)
217 break;
218 else
219 HandleAcceptResult(result);
223 void OnAccepted(int result) {
224 HandleAcceptResult(result);
225 if (result == net::OK)
226 DoAccept();
229 void HandleAcceptResult(int result) {
230 if (result != net::OK)
231 return;
233 SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
234 std::string name = pump->Init();
235 if (!name.empty())
236 accepted_callback_.Run(port_, name);
239 AcceptedCallback accepted_callback_;
240 DevToolsHttpHandlerDelegate* delegate_;
241 scoped_ptr<net::ServerSocket> socket_;
242 scoped_ptr<net::StreamSocket> accept_socket_;
243 int port_;
246 } // namespace
248 // TetheringHandler::TetheringImpl -------------------------------------------
250 class TetheringHandler::TetheringImpl {
251 public:
252 TetheringImpl(
253 base::WeakPtr<TetheringHandler> handler,
254 DevToolsHttpHandlerDelegate* delegate);
255 ~TetheringImpl();
257 void Bind(scoped_refptr<DevToolsProtocol::Command> command, int port);
258 void Unbind(scoped_refptr<DevToolsProtocol::Command> command, int port);
259 void Accepted(int port, const std::string& name);
261 private:
262 void SendInternalError(scoped_refptr<DevToolsProtocol::Command> command,
263 const std::string& message);
265 base::WeakPtr<TetheringHandler> handler_;
266 DevToolsHttpHandlerDelegate* delegate_;
268 typedef std::map<int, BoundSocket*> BoundSockets;
269 BoundSockets bound_sockets_;
272 TetheringHandler::TetheringImpl::TetheringImpl(
273 base::WeakPtr<TetheringHandler> handler,
274 DevToolsHttpHandlerDelegate* delegate)
275 : handler_(handler),
276 delegate_(delegate) {
279 TetheringHandler::TetheringImpl::~TetheringImpl() {
280 STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
281 bound_sockets_.end());
284 void TetheringHandler::TetheringImpl::Bind(
285 scoped_refptr<DevToolsProtocol::Command> command, int port) {
286 if (bound_sockets_.find(port) != bound_sockets_.end()) {
287 SendInternalError(command, "Port already bound");
288 return;
291 BoundSocket::AcceptedCallback callback = base::Bind(
292 &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this));
293 scoped_ptr<BoundSocket> bound_socket(new BoundSocket(callback, delegate_));
294 if (!bound_socket->Listen(port)) {
295 SendInternalError(command, "Could not bind port");
296 return;
299 bound_sockets_[port] = bound_socket.release();
300 BrowserThread::PostTask(
301 BrowserThread::UI,
302 FROM_HERE,
303 base::Bind(&TetheringHandler::SendBindSuccess, handler_, command));
306 void TetheringHandler::TetheringImpl::Unbind(
307 scoped_refptr<DevToolsProtocol::Command> command, int port) {
309 BoundSockets::iterator it = bound_sockets_.find(port);
310 if (it == bound_sockets_.end()) {
311 SendInternalError(command, "Port is not bound");
312 return;
315 delete it->second;
316 bound_sockets_.erase(it);
317 BrowserThread::PostTask(
318 BrowserThread::UI,
319 FROM_HERE,
320 base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command));
323 void TetheringHandler::TetheringImpl::Accepted(
324 int port, const std::string& name) {
325 BrowserThread::PostTask(
326 BrowserThread::UI,
327 FROM_HERE,
328 base::Bind(&TetheringHandler::Accepted, handler_, port, name));
331 void TetheringHandler::TetheringImpl::SendInternalError(
332 scoped_refptr<DevToolsProtocol::Command> command,
333 const std::string& message) {
334 BrowserThread::PostTask(
335 BrowserThread::UI,
336 FROM_HERE,
337 base::Bind(&TetheringHandler::SendInternalError, handler_,
338 command, message));
342 // TetheringHandler ----------------------------------------------------------
344 // static
345 TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr;
347 TetheringHandler::TetheringHandler(
348 DevToolsHttpHandlerDelegate* delegate,
349 scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
350 : delegate_(delegate),
351 message_loop_proxy_(message_loop_proxy),
352 is_active_(false),
353 weak_factory_(this) {
354 RegisterCommandHandler(devtools::Tethering::bind::kName,
355 base::Bind(&TetheringHandler::OnBind,
356 base::Unretained(this)));
357 RegisterCommandHandler(devtools::Tethering::unbind::kName,
358 base::Bind(&TetheringHandler::OnUnbind,
359 base::Unretained(this)));
362 TetheringHandler::~TetheringHandler() {
363 if (is_active_) {
364 message_loop_proxy_->DeleteSoon(FROM_HERE, impl_);
365 impl_ = nullptr;
369 void TetheringHandler::Accepted(int port, const std::string& name) {
370 base::DictionaryValue* params = new base::DictionaryValue();
371 params->SetInteger(devtools::Tethering::accepted::kParamPort, port);
372 params->SetString(devtools::Tethering::accepted::kParamConnectionId, name);
373 SendNotification(devtools::Tethering::accepted::kName, params);
376 bool TetheringHandler::Activate() {
377 if (is_active_)
378 return true;
379 if (impl_)
380 return false;
381 is_active_ = true;
382 impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), delegate_);
383 return true;
386 scoped_refptr<DevToolsProtocol::Response>
387 TetheringHandler::OnBind(scoped_refptr<DevToolsProtocol::Command> command) {
388 const std::string& portParamName = devtools::Tethering::bind::kParamPort;
389 int port = GetPort(command, portParamName);
390 if (port == 0)
391 return command->InvalidParamResponse(portParamName);
393 if (!Activate()) {
394 return command->ServerErrorResponse(
395 "Tethering is used by another connection");
397 DCHECK(impl_);
398 message_loop_proxy_->PostTask(
399 FROM_HERE,
400 base::Bind(&TetheringImpl::Bind, base::Unretained(impl_),
401 command, port));
402 return command->AsyncResponsePromise();
405 scoped_refptr<DevToolsProtocol::Response>
406 TetheringHandler::OnUnbind(scoped_refptr<DevToolsProtocol::Command> command) {
407 const std::string& portParamName = devtools::Tethering::unbind::kParamPort;
408 int port = GetPort(command, portParamName);
409 if (port == 0)
410 return command->InvalidParamResponse(portParamName);
412 if (!Activate()) {
413 return command->ServerErrorResponse(
414 "Tethering is used by another connection");
416 DCHECK(impl_);
417 message_loop_proxy_->PostTask(
418 FROM_HERE,
419 base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_),
420 command, port));
421 return command->AsyncResponsePromise();
424 void TetheringHandler::SendBindSuccess(
425 scoped_refptr<DevToolsProtocol::Command> command) {
426 SendAsyncResponse(command->SuccessResponse(nullptr));
429 void TetheringHandler::SendUnbindSuccess(
430 scoped_refptr<DevToolsProtocol::Command> command) {
431 SendAsyncResponse(command->SuccessResponse(nullptr));
434 void TetheringHandler::SendInternalError(
435 scoped_refptr<DevToolsProtocol::Command> command,
436 const std::string& message) {
437 SendAsyncResponse(command->InternalErrorResponse(message));
440 } // namespace content