Index: pkg/appengine/lib/src/server/server.dart |
diff --git a/pkg/appengine/lib/src/server/server.dart b/pkg/appengine/lib/src/server/server.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6ea12e724e821fd15f8977a6f95704fc5f641377 |
--- /dev/null |
+++ b/pkg/appengine/lib/src/server/server.dart |
@@ -0,0 +1,133 @@ |
+// 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 application; |
+ |
+import 'dart:async'; |
+import 'dart:convert' show UTF8; |
+import 'dart:io'; |
+ |
+import 'context_registry.dart'; |
+import 'http_wrapper.dart'; |
+ |
+void _info(String message) { |
+ var formattedMessage = "${new DateTime.now()}: " + message; |
+ print(formattedMessage); |
+} |
+ |
+String _getHostname() => |
+ (Process.runSync('/bin/hostname', []).stdout as String).trim(); |
+ |
+class AppEngineHttpServer { |
+ final ContextRegistry _contextRegistry; |
+ |
+ final String _hostname; |
+ final int _port; |
+ |
+ final String _localHostname; |
+ final Completer _shutdownCompleter = new Completer(); |
+ int _pendingRequests = 0; |
+ |
+ HttpServer _httpServer; |
+ |
+ AppEngineHttpServer(this._contextRegistry, |
+ {String hostname: '0.0.0.0', int port: 8080}) |
+ : _localHostname = _getHostname(), _hostname = hostname, _port = port; |
+ |
+ Future get done => _shutdownCompleter.future; |
+ |
+ void run(applicationHandler(request, context)) { |
+ var serviceHandlers = { |
+ '/_ah/start' : _start, |
+ '/_ah/health' : _health, |
+ '/_ah/stop' : _stop |
+ }; |
+ |
+ HttpServer.bind(_hostname, _port).then((HttpServer server) { |
+ _httpServer = server; |
+ |
+ server.listen((HttpRequest request) { |
+ var hooksBeforeSendingResponse = []; |
+ var appengineRequest = new AppengineHttpRequest(request); |
+ |
+ _info("Got request: ${appengineRequest.uri}"); |
+ |
+ // Default handling is sending the request to the aplication. |
+ var handler = applicationHandler; |
+ |
+ // Check if the request path is one of the service handlers. |
+ String path = appengineRequest.uri.path; |
+ for (var pattern in serviceHandlers.keys) { |
+ if (path.startsWith(pattern)) { |
+ handler = serviceHandlers[pattern]; |
+ break; |
+ } |
+ } |
+ |
+ _pendingRequests++; |
+ var context = _contextRegistry.add(appengineRequest); |
+ /* |
+ * This sets the 'Server' header in the http response to the hostname |
+ * of the machine the application is running on. |
+ * It seems like the AppEngine VmRuntime stub (on the other end) will |
+ * not accept the response if we use the default value. |
+ */ |
+ appengineRequest.response.headers.set('Server', _localHostname); |
+ appengineRequest.response.registerHook( |
+ () => _contextRegistry.remove(appengineRequest)); |
+ |
+ appengineRequest.response.done.catchError((error) { |
+ _info("Error while handling response: $error"); |
+ _pendingRequests--; |
+ _checkShutdown(); |
+ }); |
+ |
+ handler(appengineRequest, context); |
+ }); |
+ }); |
+ } |
+ |
+ void _start(HttpRequest request, _) { |
+ request.drain().then((_) { |
+ _sendResponse(request.response, HttpStatus.OK, "ok"); |
+ }); |
+ } |
+ |
+ void _health(HttpRequest request, _) { |
+ request.drain().then((_) { |
+ _sendResponse(request.response, HttpStatus.OK, "ok"); |
+ }); |
+ } |
+ |
+ void _stop(HttpRequest request, _) { |
+ request.drain().then((_) { |
+ if (_httpServer != null) { |
+ _httpServer.close().then((_) { |
+ _httpServer = null; |
+ _sendResponse(request.response, HttpStatus.OK, "ok"); |
+ }); |
+ } else { |
+ _sendResponse(request.response, HttpStatus.CONFLICT, "fail"); |
+ } |
+ }); |
+ } |
+ |
+ _checkShutdown() { |
+ if (_pendingRequests == 0 && _httpServer == null) { |
+ _shutdownCompleter.complete(); |
+ } |
+ } |
+ |
+ void _sendResponse(HttpResponse response, int statusCode, String message) { |
+ var data = UTF8.encode(message); |
+ response.headers.contentType = |
+ new ContentType('text', 'plain', charset: 'utf-8'); |
+ response.headers.set("Cache-Control", "no-cache"); |
+ response.headers.set("Server", _hostname); |
+ response.contentLength = data.length; |
+ response.statusCode = statusCode; |
+ response.add(data); |
+ response.close(); |
+ } |
+} |