Index: pkg/analysis_server/lib/src/http_server.dart |
diff --git a/pkg/analysis_server/lib/src/http_server.dart b/pkg/analysis_server/lib/src/http_server.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..674f5e550038355dde3783d8cdc227fb7e6e28bf |
--- /dev/null |
+++ b/pkg/analysis_server/lib/src/http_server.dart |
@@ -0,0 +1,182 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library http.server; |
+ |
+import 'dart:io'; |
+ |
+import 'package:args/args.dart'; |
+ |
+import 'analysis_server.dart'; |
+import 'channel.dart'; |
+import 'domain_context.dart'; |
+import 'domain_server.dart'; |
+import 'get_handler.dart'; |
+ |
+/** |
+ * Instances of the class [HttpServer] implement a simple HTTP server. The |
+ * primary responsibility of this server is to listen for an UPGRADE request and |
+ * to start an analysis server |
+ */ |
+class HttpAnalysisServer { |
danrubel
2014/01/21 22:36:27
Consider moving this to /lib if others can instant
Brian Wilkerson
2014/01/22 01:05:49
Done
|
+ /** |
+ * The name of the application that is used to start a server. |
+ */ |
+ static const BINARY_NAME = 'server'; |
+ |
+ /** |
+ * The name of the option used to print usage information. |
+ */ |
+ static const String HELP_OPTION = "help"; |
+ |
+ /** |
+ * The name of the option used to specify the port to which the server will |
+ * connect. |
+ */ |
+ static const String PORT_OPTION = "port"; |
+ |
+ /** |
+ * The analysis server that was created when an UPGRADE request was received, |
+ * or `null` if no such request has yet been received. |
+ */ |
+ AnalysisServer server; |
+ |
+ /** |
+ * An object that can handle GET requests. |
+ */ |
+ GetHandler getHandler; |
+ |
+ /** |
+ * Initialize a newly created HTTP server. |
+ */ |
+ HttpAnalysisServer(); |
+ |
+ /** |
+ * Use the given command-line arguments to start this server. |
+ */ |
+ void start(List<String> args) { |
+ ArgParser parser = new ArgParser(); |
+ parser.addFlag( |
+ HELP_OPTION, |
+ help: "print this help message without starting a server", |
+ defaultsTo: false, |
+ negatable: false); |
+ parser.addOption( |
+ PORT_OPTION, |
+ help: "[port] the port on which the server will listen"); |
+ |
+ ArgResults results = parser.parse(args); |
+ if (results[HELP_OPTION]) { |
+ _printUsage(parser); |
+ return; |
+ } |
+ if (results[PORT_OPTION] == null) { |
+ print('Missing required port number'); |
+ print(''); |
+ _printUsage(parser); |
+ return; |
+ } |
+ |
+ try { |
+ int port = int.parse(results[PORT_OPTION]); |
+ HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, port).then(_handleServer); |
+ print('Listening on port $port'); |
+ } on FormatException { |
+ print('Invalid port number: ${results[PORT_OPTION]}'); |
+ print(''); |
+ _printUsage(parser); |
+ return; |
+ } |
+ } |
+ |
+ /** |
+ * Attach a listener to a newly created HTTP server. |
+ */ |
+ void _handleServer(HttpServer server) { |
+ server.listen((HttpRequest request) { |
+ List<String> updateValues = request.headers[HttpHeaders.UPGRADE]; |
+ if (updateValues != null && updateValues.indexOf('websocket') >= 0) { |
+ if (server != null) { |
+ _returnServerAlreadyStarted(request); |
+ return; |
+ } |
+ WebSocketTransformer.upgrade(request).then((WebSocket websocket) { |
+ _handleWebSocket(websocket); |
+ }); |
+ } else if (request.method == 'GET') { |
+ _handleGetRequest(request); |
+ } else { |
+ _returnUnknownRequest(request); |
+ } |
+ }); |
+ } |
+ |
+ /** |
+ * Handle a GET request received by the HTTP server. |
+ */ |
+ void _handleGetRequest(HttpRequest request) { |
+ if (getHandler == null) { |
+ getHandler = new GetHandler(); |
+ getHandler.server = server; |
+ } |
+ getHandler.handleGetRequest(request); |
+ } |
+ |
+ /** |
+ * Handle an UPGRADE request received by the HTTP server by creating and |
+ * running an analysis server on a [WebSocket]-based communication channel. |
+ */ |
+ void _handleWebSocket(WebSocket socket) { |
+ server = new AnalysisServer(new WebSocketChannel(socket)); |
+ _initializeHandlers(server); |
+ if (getHandler != null) { |
+ getHandler.server = server; |
+ } |
+ server.run(); |
+ } |
+ |
+ /** |
+ * Initialize the handlers to be used by the given [server]. |
+ */ |
+ void _initializeHandlers(AnalysisServer server) { |
+ server.handlers = [ |
+ new ServerDomainHandler(server), |
+ new ContextDomainHandler(server), |
+ ]; |
+ } |
+ |
+ /** |
+ * Print information about how to use the server. |
+ */ |
+ void _printUsage(ArgParser parser) { |
+ print('Usage: $BINARY_NAME [flags]'); |
+ print(''); |
+ print('Supported flags are:'); |
+ print(parser.getUsage()); |
+ } |
+ |
+ /** |
+ * Return an error in response to an UPGRADE request received after the server |
+ * has already been started by a previous UPGRADE request. |
+ */ |
+ void _returnServerAlreadyStarted(HttpRequest request) { |
+ HttpResponse response = request.response; |
+ response.statusCode = HttpStatus.SERVICE_UNAVAILABLE; |
+ response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain"); |
+ response.write('The server has already been started'); |
+ response.close(); |
+ } |
+ |
+ /** |
+ * Return an error in response to an unrecognized request received by the HTTP |
+ * server. |
+ */ |
+ void _returnUnknownRequest(HttpRequest request) { |
+ HttpResponse response = request.response; |
+ response.statusCode = HttpStatus.NOT_FOUND; |
+ response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain"); |
+ response.write('Not found'); |
+ response.close(); |
+ } |
+} |