Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: remoting/host/host_status_service.cc

Issue 11362267: Add status service for remoting host. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "remoting/host/host_status_service.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/stl_util.h"
10 #include "base/string_number_conversions.h"
11 #include "base/string_util.h"
12 #include "base/stringize_macros.h"
13 #include "base/values.h"
14 #include "net/base/ip_endpoint.h"
15 #include "net/base/net_util.h"
16 #include "remoting/host/websocket_connection.h"
17 #include "remoting/host/websocket_listener.h"
18
19 namespace remoting {
20
21 namespace {
22
23 // HostStatusService uses the first port available in the following range.
24 const int kPortRangeMin = 12810;
alexeypa (please no reviews) 2012/11/15 19:45:56 Does this range need a firewall rule on Windows?
Sergey Ulanov 2012/11/16 00:52:10 We are connecting from localhost to localhost. Are
25 const int kPortRangeMax = 12820;
26
27 const char kChromeExtensionProtocolPrefix[] = "chrome-extension://";
Wez 2012/11/15 23:34:59 You should really change this to kChromeExtensionU
Sergey Ulanov 2012/11/16 00:52:10 I considered this, but I don't think using GURL fo
28
29 #ifdef NDEBUG
Wez 2012/11/15 23:34:59 nit: #if !defined(NDEBUG)
Sergey Ulanov 2012/11/16 00:52:10 Changed to "#if defined(NDEBUG)",
30 const char* kAllowedWebApplicationIds[] = {
31 "gbchcmhmhahfdphkhkmpfmihenigjmpp", // Chrome Remote Desktop
32 "kgngmbheleoaphbjbaiobfdepmghbfah", // Pre-release Chrome Remote Desktop
33 "odkaodonbgfohohmklejpjiejmcipmib", // Dogfood Chrome Remote Desktop
34 "ojoimpklfciegopdfgeenehpalipignm", // Chromoting canary
35 };
36 #endif
37
38 } // namespace
39
40 class HostStatusService::Connection : public WebsocketConnection::Delegate {
41 public:
42 Connection(HostStatusService* service,
43 scoped_ptr<WebsocketConnection> websocket)
44 : service_(service),
alexeypa (please no reviews) 2012/11/15 19:45:56 nit: Add a comment explaining that |service| must
Sergey Ulanov 2012/11/16 00:52:10 Done, but I don't think its really necessary becau
45 websocket_(websocket.Pass()) {
46 websocket_->Accept(this);
alexeypa (please no reviews) 2012/11/15 19:45:56 I believe this constructor is too complex to defin
Sergey Ulanov 2012/11/16 00:52:10 Done.
47 }
48 virtual ~Connection() {
alexeypa (please no reviews) 2012/11/15 19:45:56 nit: it is not required by the style guide but it
Wez 2012/11/15 23:34:59 I'd prefer it be left in-line, and on a single lin
Sergey Ulanov 2012/11/16 00:52:10 Done.
Sergey Ulanov 2012/11/16 00:52:10 I've already moved it, so I'll leave it there.
49 }
50
51 // WebsocketConnection::Delegate interface.
52 virtual void OnWebsocketMessage(const std::string& message) OVERRIDE;
53 virtual void OnWebsocketClosed() OVERRIDE;
54
55 private:
56 void SendHostStatusMessage();
alexeypa (please no reviews) 2012/11/15 19:45:56 nit: Add comments explaining what these methods ar
Sergey Ulanov 2012/11/16 00:52:10 Done.
57 void SendMessage(const std::string& method,
58 scoped_ptr<base::DictionaryValue> data);
59
60 // Closes this connection. Destroys the object, so should be used with care.
Wez 2012/11/15 23:34:59 nit: Reword e.g "Closes the connection and destroy
Sergey Ulanov 2012/11/16 00:52:10 Done.
61 void CloseOnError();
Wez 2012/11/15 23:34:59 nit: CloseOnError sounds like it tells the thing t
Sergey Ulanov 2012/11/16 00:52:10 It means "close connection because there was a pro
62
63 HostStatusService* service_;
64 scoped_ptr<WebsocketConnection> websocket_;
65
66 DISALLOW_COPY_AND_ASSIGN(Connection);
67 };
68
69 void HostStatusService::Connection::OnWebsocketMessage(
70 const std::string& message) {
71 scoped_ptr<base::Value> json(
alexeypa (please no reviews) 2012/11/15 19:45:56 nit: Can anything bad happen if a malicious sender
Sergey Ulanov 2012/11/16 00:52:10 That's a good point. I think it's better to limit
72 base::JSONReader::Read(message, base::JSON_ALLOW_TRAILING_COMMAS));
73
74 base::DictionaryValue* message_dict = NULL;
Wez 2012/11/15 23:34:59 nit: Add a comment before this block explaining wh
Sergey Ulanov 2012/11/16 00:52:10 Done.
75 std::string method;
76 base::DictionaryValue* data = NULL;
Wez 2012/11/15 23:34:59 |data| doesn't seem to be used?
Sergey Ulanov 2012/11/16 00:52:10 We may need it in the future when we add some new
77 if (!json.get() ||
78 !json->GetAsDictionary(&message_dict) ||
79 !message_dict->GetString("method", &method) ||
80 !message_dict->GetDictionary("data", &data)) {
81 LOG(ERROR) << "Received invalid message: " << message;
82 CloseOnError();
83 return;
84 }
85
86 if (method == "getHostStatus") {
87 SendHostStatusMessage();
88 } else {
89 LOG(ERROR) << "Received message with unknown method: " << message;
alexeypa (please no reviews) 2012/11/15 19:45:56 Call CloseOnError() here?
Sergey Ulanov 2012/11/16 00:52:10 Actually I think it's better to keep it connected,
90 return;
91 }
92 }
93
94 void HostStatusService::Connection::OnWebsocketClosed() {
95 service_->OnConnectionClosed(this);
Wez 2012/11/15 23:34:59 You reset |websocket_| in CloseOnError() but not h
Sergey Ulanov 2012/11/16 00:52:10 Changed this to Close().
96 }
97
98 void HostStatusService::Connection::SendHostStatusMessage() {
99 SendMessage("hostStatus", service_->GetStatusMessage());
100 }
101
102 void HostStatusService::Connection::SendMessage(
103 const std::string& method,
104 scoped_ptr<base::DictionaryValue> data) {
105 scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue());
106 message->SetString("method", method);
107 message->Set("data", data.release());
108
109 std::string message_json;
110 base::JSONWriter::Write(message.get(), &message_json);
111 websocket_->SendText(message_json);
112 }
113
114 void HostStatusService::Connection::CloseOnError() {
115 websocket_.reset();
116 service_->OnConnectionClosed(this);
117 }
118
119 HostStatusService::HostStatusService()
120 : started_(false) {
121 char ip[] = {127, 0, 0, 1};
alexeypa (please no reviews) 2012/11/15 19:45:56 Will it still work in presence of IPv6?
Sergey Ulanov 2012/11/16 00:52:10 Yes. On Linux localhost normally resolves to IPv4
122 net::IPAddressNumber localhost(ip, ip + sizeof(ip));
123 for (int port = kPortRangeMin; port < kPortRangeMax; ++port) {
124 net::IPEndPoint endpoint(localhost, port);
125 if (websocket_listener_.Listen(
126 endpoint, base::Bind(&HostStatusService::OnNewConnection,
Wez 2012/11/15 23:34:59 nit: Moving endpoint to the previous line would ma
Sergey Ulanov 2012/11/16 00:52:10 No, it doesn't, because that would mean that the s
127 base::Unretained(this)))) {
alexeypa (please no reviews) 2012/11/15 19:45:56 How is it guaranteed that |this| will not be delet
Sergey Ulanov 2012/11/16 00:52:10 We own websocket_listener_ which is guaranteed to
128 host_name_ = "localhost:" + base::UintToString(port);
129 LOG(INFO) << "Listening for WebSocket connections on localhost:" << port;
130 break;
131 }
132 }
133 }
134
135 HostStatusService::~HostStatusService() {
136 STLDeleteElements(&connections_);
alexeypa (please no reviews) 2012/11/15 19:45:56 nit: Should |websocket_| be reset first?
Wez 2012/11/15 23:34:59 It's held in a scoped_ptr<> in Connection, so that
Sergey Ulanov 2012/11/16 00:52:10 It doesn't matter. websocket_listener_ is not conn
137 }
138
139 void HostStatusService::SetState(bool started, const std::string& host_id) {
140 started_ = started;
141 host_id_ = host_id;
142 }
143
144 bool HostStatusService::IsAllowedOrigin(const std::string& origin) {
Wez 2012/11/15 23:34:59 Use GURL to break down the URL first, and then deb
Sergey Ulanov 2012/11/16 00:52:10 As explained above I think it would be overkill to
145 #ifndef NDEBUG
alexeypa (please no reviews) 2012/11/15 19:45:56 Why is the difference? If it is just a sanity chec
Sergey Ulanov 2012/11/16 00:52:10 We want to limit which webapps can connect to the
146 // Allow all chrome extensions in Debug builds.
147 return StartsWithASCII(origin, kChromeExtensionProtocolPrefix, false);
148 #else
149 std::string prefix(kChromeExtensionProtocolPrefix);
150 for (int i = 0; i < arraysize(kAllowedWebApplicationIds)) {
151 if (origin == prefix + kAllowedWebApplicationIds[i]) {
152 return true;
153 }
154 }
155 return false;
156 #endif
157 }
158
159 void HostStatusService::OnNewConnection(
160 scoped_ptr<WebsocketConnection> connection) {
161 bool accept = true;
alexeypa (please no reviews) 2012/11/15 19:45:56 nit: It is better to set |accept| to false by defa
Wez 2012/11/15 23:34:59 I think this would be more readable as a series of
Sergey Ulanov 2012/11/16 00:52:10 Done.
Sergey Ulanov 2012/11/16 00:52:10 Done.
162
163 if (connection->request_host() != host_name_) {
164 LOG(ERROR) << "Received connection for invalid host: "
165 << connection->request_host()
166 << ". Expected " << host_name_;
167 accept = false;
168 } else if (connection->request_path() != "/remoting_host_status") {
169 LOG(ERROR) << "Received connection for unknown path: "
170 << connection->request_path();
171 accept = false;
172 } else if (!IsAllowedOrigin(connection->origin())) {
alexeypa (please no reviews) 2012/11/15 19:45:56 Can connection->origin() be trusted? Can the conne
Wez 2012/11/15 23:34:59 The origin protects from XSS; it's assumed the req
Sergey Ulanov 2012/11/16 00:52:10 A web site cannot spoof it, but any locally instal
173 LOG(ERROR) << "Rejecting connection from unknown origin: "
174 << connection->origin();
175 accept = false;
176 }
177
178 if (accept) {
179 connections_.insert(new Connection(this, connection.Pass()));
180 } else {
181 connection->Reject();
182 }
183 }
184
185 void HostStatusService::OnConnectionClosed(Connection* connection) {
186 connections_.erase(connection);
Wez 2012/11/15 23:34:59 This doesn't seem to delete Connection?
Sergey Ulanov 2012/11/16 00:52:10 Good catch. Fixed.
187 }
188
189 scoped_ptr<base::DictionaryValue> HostStatusService::GetStatusMessage() {
190 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
191 result->SetString("state", started_ ? "STARTED" : "STOPPED");
192 result->SetString("version", STRINGIZE(VERSION));
193 result->SetString("hostId", host_id_);
194 return result.Pass();
195 }
196
197 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698