| 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 { |
| 8 static const int PARSE_ERROR_CODE = 4000; |
| 9 static const int BINARY_MESSAGE_ERROR_CODE = 4001; |
| 10 static const int NOT_MAP_ERROR_CODE = 4002; |
| 11 final WebSocket socket; |
| 12 |
| 13 WebSocketClient(this.socket, service) : super(service) { |
| 14 socket.listen((message) => onWebSocketMessage(message)); |
| 15 socket.done.then((_) => close()); |
| 16 } |
| 17 |
| 18 void onWebSocketMessage(message) { |
| 19 if (message is String) { |
| 20 var map; |
| 21 try { |
| 22 map = JSON.decode(message); |
| 23 } catch (e) { |
| 24 socket.close(PARSE_ERROR_CODE, 'Message parse error: $e'); |
| 25 return; |
| 26 } |
| 27 if (map is! Map) { |
| 28 socket.close(NOT_MAP_ERROR_CODE, 'Message must be a JSON map.'); |
| 29 return; |
| 30 } |
| 31 var seq = map['seq']; |
| 32 onMessage(seq, new Message.fromMap(map)); |
| 33 } else { |
| 34 socket.close(BINARY_MESSAGE_ERROR_CODE, 'message must be a string.'); |
| 35 } |
| 36 } |
| 37 |
| 38 void post(var seq, String response) { |
| 39 try { |
| 40 Map map = { |
| 41 'seq': seq, |
| 42 'response': response |
| 43 }; |
| 44 socket.add(JSON.encode(map)); |
| 45 } catch (_) { |
| 46 // Error posting over WebSocket. |
| 47 } |
| 48 } |
| 49 |
| 50 Map toJson() { |
| 51 Map map = super.toJson(); |
| 52 map['type'] = 'WebSocketClient'; |
| 53 map['socket'] = '$socket'; |
| 54 return map; |
| 55 } |
| 56 } |
| 57 |
| 58 |
| 59 class HttpRequestClient extends Client { |
| 60 static ContentType jsonContentType = ContentType.parse('application/json'); |
| 61 final HttpRequest request; |
| 62 |
| 63 HttpRequestClient(this.request, service) : super(service); |
| 64 |
| 65 void post(var seq, String response) { |
| 66 request.response..headers.contentType = jsonContentType |
| 67 ..write(response) |
| 68 ..close(); |
| 69 close(); |
| 70 } |
| 71 |
| 72 Map toJson() { |
| 73 Map map = super.toJson(); |
| 74 map['type'] = 'HttpRequestClient'; |
| 75 map['request'] = '$request'; |
| 76 return map; |
| 77 } |
| 78 } |
| 79 |
| 7 class Server { | 80 class Server { |
| 81 static const WEBSOCKET_PATH = '/ws'; |
| 82 String defaultPath = '/index.html'; |
| 8 int port; | 83 int port; |
| 9 static ContentType jsonContentType = ContentType.parse('application/json'); | 84 |
| 10 final VmService service; | 85 final VMService service; |
| 11 HttpServer _server; | 86 HttpServer _server; |
| 12 | 87 |
| 13 Server(this.service, this.port); | 88 Server(this.service, this.port); |
| 14 | 89 |
| 15 void _sendResponse(HttpRequest request, String response) { | |
| 16 request.response..headers.contentType = jsonContentType | |
| 17 ..write(response) | |
| 18 ..close(); | |
| 19 } | |
| 20 | |
| 21 void _requestHandler(HttpRequest request) { | 90 void _requestHandler(HttpRequest request) { |
| 22 // Allow cross origin requests. | 91 // Allow cross origin requests. |
| 23 request.response.headers.add('Access-Control-Allow-Origin', '*'); | 92 request.response.headers.add('Access-Control-Allow-Origin', '*'); |
| 24 | 93 |
| 25 final String path = | 94 final String path = |
| 26 request.uri.path == '/' ? '/index.html' : request.uri.path; | 95 request.uri.path == '/' ? defaultPath : request.uri.path; |
| 27 | 96 |
| 28 var resource = Resource.resources[path]; | 97 var resource = Resource.resources[path]; |
| 29 if (resource != null) { | 98 if (resource != null) { |
| 30 // Serving up a static resource (e.g. .css, .html, .png). | 99 // Serving up a static resource (e.g. .css, .html, .png). |
| 31 request.response.headers.contentType = | 100 request.response.headers.contentType = |
| 32 ContentType.parse(resource.mimeType); | 101 ContentType.parse(resource.mimeType); |
| 33 request.response.add(resource.data); | 102 request.response.add(resource.data); |
| 34 request.response.close(); | 103 request.response.close(); |
| 35 return; | 104 return; |
| 36 } | 105 } |
| 37 | 106 |
| 38 var serviceRequest = new ServiceRequest(); | 107 if (path == WEBSOCKET_PATH) { |
| 39 var r = serviceRequest.parse(request.uri); | 108 WebSocketTransformer.upgrade(request).then((WebSocket webSocket) { |
| 40 if (r) { | 109 new WebSocketClient(webSocket, service); |
| 41 var f = service.runningIsolates.route(serviceRequest); | |
| 42 assert(f != null); | |
| 43 f.then((_) { | |
| 44 _sendResponse(request, serviceRequest.response); | |
| 45 }).catchError((e) { | |
| 46 // Error replying over HTTP. | |
| 47 }); | 110 }); |
| 48 return; | 111 return; |
| 49 } | 112 } |
| 50 _sendResponse(request, serviceRequest.response); | 113 |
| 114 var message = new Message.fromUri(request.uri); |
| 115 var client = new HttpRequestClient(request, service); |
| 116 client.onMessage('', message); |
| 51 } | 117 } |
| 52 | 118 |
| 53 Future startServer() { | 119 Future startServer() { |
| 54 return HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, port).then((s) { | 120 return HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, port).then((s) { |
| 55 // Only display message when port is automatically selected. | 121 // Only display message when port is not automatically selected. |
| 56 var display_message = (port == 0); | 122 var display_message = (port == 0); |
| 57 // Retrieve port. | 123 // Retrieve port. |
| 58 port = s.port; | 124 port = s.port; |
| 59 _server = s; | 125 _server = s; |
| 60 _server.listen(_requestHandler); | 126 _server.listen(_requestHandler); |
| 61 if (display_message) { | 127 if (display_message) { |
| 62 print('VmService listening on port $port'); | 128 print('VmService listening on port $port'); |
| 63 } | 129 } |
| 64 return s; | 130 return s; |
| 65 }); | 131 }); |
| 66 } | 132 } |
| 67 } | 133 } |
| OLD | NEW |