7e7426ae99
R=danrubel@google.com Review URL: https://codereview.chromium.org//214933002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@34529 260f80e4-7a28-3924-810f-c04153c831b5
184 lines
5.2 KiB
Dart
184 lines
5.2 KiB
Dart
// 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:analysis_server/src/analysis_server.dart';
|
|
import 'package:analysis_server/src/channel.dart';
|
|
import 'package:analysis_server/src/domain_context.dart';
|
|
import 'package:analysis_server/src/domain_server.dart';
|
|
import 'package:analysis_server/src/get_handler.dart';
|
|
import 'package:args/args.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 {
|
|
/**
|
|
* 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 analysisServer;
|
|
|
|
/**
|
|
* 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);
|
|
exitCode = 1;
|
|
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);
|
|
exitCode = 1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attach a listener to a newly created HTTP server.
|
|
*/
|
|
void _handleServer(HttpServer httServer) {
|
|
httServer.listen((HttpRequest request) {
|
|
List<String> updateValues = request.headers[HttpHeaders.UPGRADE];
|
|
if (updateValues != null && updateValues.indexOf('websocket') >= 0) {
|
|
if (analysisServer != 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 = analysisServer;
|
|
}
|
|
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) {
|
|
analysisServer = new AnalysisServer(new WebSocketServerChannel(socket));
|
|
_initializeHandlers(analysisServer);
|
|
if (getHandler != null) {
|
|
getHandler.server = analysisServer;
|
|
}
|
|
analysisServer.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();
|
|
}
|
|
}
|