Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of vmservice_io; | 5 part of vmservice_io; |
| 6 | 6 |
| 7 class WebSocketClient extends Client { | 7 class WebSocketClient extends Client { |
| 8 static const int PARSE_ERROR_CODE = 4000; | 8 static const int PARSE_ERROR_CODE = 4000; |
| 9 static const int BINARY_MESSAGE_ERROR_CODE = 4001; | 9 static const int BINARY_MESSAGE_ERROR_CODE = 4001; |
| 10 static const int NOT_MAP_ERROR_CODE = 4002; | 10 static const int NOT_MAP_ERROR_CODE = 4002; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 class Server { | 119 class Server { |
| 120 static const WEBSOCKET_PATH = '/ws'; | 120 static const WEBSOCKET_PATH = '/ws'; |
| 121 static const ROOT_REDIRECT_PATH = '/index.html'; | 121 static const ROOT_REDIRECT_PATH = '/index.html'; |
| 122 | 122 |
| 123 final VMService _service; | 123 final VMService _service; |
| 124 final String _ip; | 124 final String _ip; |
| 125 final int _port; | 125 final int _port; |
| 126 final bool _originCheckDisabled; | 126 final bool _originCheckDisabled; |
| 127 HttpServer _server; | 127 HttpServer _server; |
| 128 bool get running => _server != null; | 128 bool get running => _server != null; |
| 129 bool _displayMessages = false; | |
| 130 | 129 |
| 131 Server(this._service, this._ip, this._port, this._originCheckDisabled) { | 130 /// Returns the server address including the auth token. |
| 132 _displayMessages = (_ip != '127.0.0.1' || _port != 8181); | 131 Uri get serverAddress { |
| 132 if (!running) { | |
| 133 return null; | |
| 134 } | |
| 135 var ip = _server.address.address; | |
| 136 var port = _server.port; | |
| 137 return Uri.parse('http://$ip:$port/$serviceAuthToken/'); | |
| 133 } | 138 } |
| 134 | 139 |
| 140 Server(this._service, this._ip, this._port, this._originCheckDisabled); | |
| 141 | |
| 135 bool _isAllowedOrigin(String origin) { | 142 bool _isAllowedOrigin(String origin) { |
| 136 Uri uri; | 143 Uri uri; |
| 137 try { | 144 try { |
| 138 uri = Uri.parse(origin); | 145 uri = Uri.parse(origin); |
| 139 } catch (_) { | 146 } catch (_) { |
| 140 return false; | 147 return false; |
| 141 } | 148 } |
| 142 | 149 |
| 143 // Explicitly add localhost and 127.0.0.1 on any port (necessary for | 150 // Explicitly add localhost and 127.0.0.1 on any port (necessary for |
| 144 // adb port forwarding). | 151 // adb port forwarding). |
| 145 if ((uri.host == 'localhost') || | 152 if ((uri.host == 'localhost') || |
| 146 (uri.host == '127.0.0.1')) { | 153 (uri.host == '127.0.0.1')) { |
| 147 return true; | 154 return true; |
| 148 } | 155 } |
| 149 | 156 |
| 150 if ((uri.port == _server.port) && | 157 if ((uri.port == _server.port) && |
| 151 ((uri.host == _server.address.address) || | 158 ((uri.host == _server.address.address) || |
| 152 (uri.host == _server.address.host))) { | 159 (uri.host == _server.address.host))) { |
| 153 return true; | 160 return true; |
| 154 } | 161 } |
| 155 | 162 |
| 156 return false; | 163 return false; |
| 157 } | 164 } |
| 158 | 165 |
| 159 bool _originCheck(HttpRequest request) { | 166 bool _originCheck(HttpRequest request) { |
|
rmacnak
2016/10/20 17:12:31
Not in this CL, but perhaps we can remove this bro
Cutch
2016/10/20 23:31:51
Acknowledged.
| |
| 160 if (_originCheckDisabled) { | 167 if (_originCheckDisabled) { |
| 161 // Always allow. | 168 // Always allow. |
| 162 return true; | 169 return true; |
| 163 } | 170 } |
| 164 // First check the web-socket specific origin. | 171 // First check the web-socket specific origin. |
| 165 List<String> origins = request.headers["Sec-WebSocket-Origin"]; | 172 List<String> origins = request.headers["Sec-WebSocket-Origin"]; |
| 166 if (origins == null) { | 173 if (origins == null) { |
| 167 // Fall back to the general Origin field. | 174 // Fall back to the general Origin field. |
| 168 origins = request.headers["Origin"]; | 175 origins = request.headers["Origin"]; |
| 169 } | 176 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 } | 231 } |
| 225 request.response.close(); | 232 request.response.close(); |
| 226 return; | 233 return; |
| 227 } | 234 } |
| 228 if (request.method != 'GET') { | 235 if (request.method != 'GET') { |
| 229 // Not a GET request. Do nothing. | 236 // Not a GET request. Do nothing. |
| 230 request.response.close(); | 237 request.response.close(); |
| 231 return; | 238 return; |
| 232 } | 239 } |
| 233 | 240 |
| 241 final List<String> requestPathSegments = request.uri.pathSegments; | |
| 242 if (requestPathSegments.length < 2) { | |
| 243 // Malformed. | |
| 244 request.response.close(); | |
| 245 return; | |
| 246 } | |
| 247 // Check that we were given the auth token. | |
| 248 final String authToken = requestPathSegments[0]; | |
| 249 if (authToken != serviceAuthToken) { | |
| 250 // Malformed. | |
| 251 request.response.close(); | |
| 252 return; | |
| 253 } | |
| 254 // Construct the actual request path by chopping off the auth token. | |
| 234 final String path = | 255 final String path = |
| 235 request.uri.path == '/' ? ROOT_REDIRECT_PATH : request.uri.path; | 256 (requestPathSegments[1] == '') ? |
| 257 ROOT_REDIRECT_PATH : '/${requestPathSegments.sublist(1).join('/')}'; | |
| 236 | 258 |
| 237 if (path == WEBSOCKET_PATH) { | 259 if (path == WEBSOCKET_PATH) { |
| 238 WebSocketTransformer.upgrade(request).then( | 260 WebSocketTransformer.upgrade(request).then( |
| 239 (WebSocket webSocket) { | 261 (WebSocket webSocket) { |
| 240 new WebSocketClient(webSocket, _service); | 262 new WebSocketClient(webSocket, _service); |
| 241 }); | 263 }); |
| 242 return; | 264 return; |
| 243 } | 265 } |
| 244 | 266 |
| 245 Asset asset = assets[path]; | 267 Asset asset = assets[path]; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 267 if (_server != null) { | 289 if (_server != null) { |
| 268 // Already running. | 290 // Already running. |
| 269 return new Future.value(this); | 291 return new Future.value(this); |
| 270 } | 292 } |
| 271 | 293 |
| 272 var address = new InternetAddress(_ip); | 294 var address = new InternetAddress(_ip); |
| 273 // Startup HTTP server. | 295 // Startup HTTP server. |
| 274 return HttpServer.bind(address, _port).then((s) { | 296 return HttpServer.bind(address, _port).then((s) { |
| 275 _server = s; | 297 _server = s; |
| 276 _server.listen(_requestHandler, cancelOnError: true); | 298 _server.listen(_requestHandler, cancelOnError: true); |
| 277 var ip = _server.address.address; | 299 print('Observatory listening on $serverAddress'); |
| 278 var port = _server.port; | |
| 279 if (_displayMessages) { | |
| 280 print('Observatory listening on http://$ip:$port'); | |
| 281 } | |
| 282 // Server is up and running. | 300 // Server is up and running. |
| 283 _notifyServerState(ip, _server.port); | 301 _notifyServerState(serverAddress.toString()); |
| 284 onServerAddressChange('http://$ip:$port'); | 302 onServerAddressChange('$serverAddress'); |
| 285 return this; | 303 return this; |
| 286 }).catchError((e, st) { | 304 }).catchError((e, st) { |
| 287 print('Could not start Observatory HTTP server:\n$e\n$st\n'); | 305 print('Could not start Observatory HTTP server:\n$e\n$st\n'); |
| 288 _notifyServerState("", 0); | 306 _notifyServerState(""); |
| 289 onServerAddressChange(null); | 307 onServerAddressChange(null); |
| 290 return this; | 308 return this; |
| 291 }); | 309 }); |
| 292 } | 310 } |
| 293 | 311 |
| 294 Future cleanup(bool force) { | 312 Future cleanup(bool force) { |
| 295 if (_server == null) { | 313 if (_server == null) { |
| 296 return new Future.value(null); | 314 return new Future.value(null); |
| 297 } | 315 } |
| 298 return _server.close(force: force); | 316 return _server.close(force: force); |
| 299 } | 317 } |
| 300 | 318 |
| 301 Future shutdown(bool forced) { | 319 Future shutdown(bool forced) { |
| 302 if (_server == null) { | 320 if (_server == null) { |
| 303 // Not started. | 321 // Not started. |
| 304 return new Future.value(this); | 322 return new Future.value(this); |
| 305 } | 323 } |
| 306 | 324 |
| 307 // Force displaying of status messages if we are forcibly shutdown. | |
| 308 _displayMessages = _displayMessages || forced; | |
| 309 | |
| 310 // Shutdown HTTP server and subscription. | 325 // Shutdown HTTP server and subscription. |
| 311 var ip = _server.address.address.toString(); | 326 String oldServerAddress = serverAddress; |
| 312 var port = _server.port.toString(); | |
| 313 return cleanup(forced).then((_) { | 327 return cleanup(forced).then((_) { |
| 314 if (_displayMessages) { | 328 print('Observatory no longer listening on $oldServerAddress'); |
| 315 print('Observatory no longer listening on http://$ip:$port'); | |
| 316 } | |
| 317 _server = null; | 329 _server = null; |
| 318 _notifyServerState("", 0); | 330 _notifyServerState(""); |
| 319 onServerAddressChange(null); | 331 onServerAddressChange(null); |
| 320 return this; | 332 return this; |
| 321 }).catchError((e, st) { | 333 }).catchError((e, st) { |
| 322 _server = null; | 334 _server = null; |
| 323 print('Could not shutdown Observatory HTTP server:\n$e\n$st\n'); | 335 print('Could not shutdown Observatory HTTP server:\n$e\n$st\n'); |
| 324 _notifyServerState("", 0); | 336 _notifyServerState(""); |
| 325 onServerAddressChange(null); | 337 onServerAddressChange(null); |
| 326 return this; | 338 return this; |
| 327 }); | 339 }); |
| 328 } | 340 } |
| 329 | 341 |
| 330 } | 342 } |
| 331 | 343 |
| 332 void _notifyServerState(String ip, int port) | 344 void _notifyServerState(String uri) |
| 333 native "VMServiceIO_NotifyServerState"; | 345 native "VMServiceIO_NotifyServerState"; |
| OLD | NEW |