| Index: lib/shelf_io.dart
|
| diff --git a/lib/shelf_io.dart b/lib/shelf_io.dart
|
| index 7d0c053d427cf8b690d1a2598c8b108ac2c1aa78..c2813c7c49df7934ee3801803397b0dde1ddef01 100644
|
| --- a/lib/shelf_io.dart
|
| +++ b/lib/shelf_io.dart
|
| @@ -53,56 +53,60 @@ void serveRequests(Stream<HttpRequest> requests, Handler handler) {
|
| catchTopLevelErrors(() {
|
| requests.listen((request) => handleRequest(request, handler));
|
| }, (error, stackTrace) {
|
| - _logError('Asynchronous error\n$error', stackTrace);
|
| + _logTopLevelError('Asynchronous error\n$error', stackTrace);
|
| });
|
| }
|
|
|
| /// Uses [handler] to handle [request].
|
| ///
|
| /// Returns a [Future] which completes when the request has been handled.
|
| -Future handleRequest(HttpRequest request, Handler handler) {
|
| +Future handleRequest(HttpRequest request, Handler handler) async {
|
| var shelfRequest;
|
| try {
|
| shelfRequest = _fromHttpRequest(request);
|
| } catch (error, stackTrace) {
|
| - var response = _logError('Error parsing request.\n$error', stackTrace);
|
| - return _writeResponse(response, request.response);
|
| + var response = _logTopLevelError(
|
| + 'Error parsing request.\n$error', stackTrace);
|
| + await _writeResponse(response, request.response);
|
| + return;
|
| }
|
|
|
| // TODO(nweiz): abstract out hijack handling to make it easier to implement an
|
| // adapter.
|
| - return new Future.sync(() => handler(shelfRequest))
|
| - .catchError((error, stackTrace) {
|
| - if (error is HijackException) {
|
| - // A HijackException should bypass the response-writing logic entirely.
|
| - if (!shelfRequest.canHijack) throw error;
|
| -
|
| - // If the request wasn't hijacked, we shouldn't be seeing this exception.
|
| - return _logError(
|
| - "Caught HijackException, but the request wasn't hijacked.",
|
| - stackTrace);
|
| - }
|
| -
|
| - return _logError('Error thrown by handler.\n$error', stackTrace);
|
| - }).then((response) {
|
| - if (response == null) {
|
| - return _writeResponse(
|
| - _logError('null response from handler.'), request.response);
|
| - } else if (shelfRequest.canHijack) {
|
| - return _writeResponse(response, request.response);
|
| - }
|
| -
|
| - var message = new StringBuffer()
|
| - ..writeln("Got a response for hijacked request "
|
| - "${shelfRequest.method} ${shelfRequest.requestedUri}:")
|
| - ..writeln(response.statusCode);
|
| - response.headers
|
| - .forEach((key, value) => message.writeln("${key}: ${value}"));
|
| - throw new Exception(message.toString().trim());
|
| - }).catchError((error, stackTrace) {
|
| - // Ignore HijackExceptions.
|
| - if (error is! HijackException) throw error;
|
| - });
|
| + var response;
|
| + try {
|
| + response = await handler(shelfRequest);
|
| + } on HijackException catch (error, stackTrace) {
|
| + // A HijackException should bypass the response-writing logic entirely.
|
| + if (!shelfRequest.canHijack) return;
|
| +
|
| + // If the request wasn't hijacked, we shouldn't be seeing this exception.
|
| + response = _logError(
|
| + shelfRequest,
|
| + "Caught HijackException, but the request wasn't hijacked.",
|
| + stackTrace);
|
| + } catch (error, stackTrace) {
|
| + response = _logError(
|
| + shelfRequest, 'Error thrown by handler.\n$error', stackTrace);
|
| + }
|
| +
|
| + if (response == null) {
|
| + await _writeResponse(
|
| + _logError(shelfRequest, 'null response from handler.'),
|
| + request.response);
|
| + return;
|
| + } else if (shelfRequest.canHijack) {
|
| + await _writeResponse(response, request.response);
|
| + return;
|
| + }
|
| +
|
| + var message = new StringBuffer()
|
| + ..writeln("Got a response for hijacked request "
|
| + "${shelfRequest.method} ${shelfRequest.requestedUri}:")
|
| + ..writeln(response.statusCode);
|
| + response.headers
|
| + .forEach((key, value) => message.writeln("${key}: ${value}"));
|
| + throw new Exception(message.toString().trim());
|
| }
|
|
|
| /// Creates a new [Request] from the provided [HttpRequest].
|
| @@ -154,7 +158,20 @@ Future _writeResponse(Response response, HttpResponse httpResponse) {
|
|
|
| // TODO(kevmoo) A developer mode is needed to include error info in response
|
| // TODO(kevmoo) Make error output plugable. stderr, logging, etc
|
| -Response _logError(String message, [StackTrace stackTrace]) {
|
| +Response _logError(Request request, String message, [StackTrace stackTrace]) {
|
| + // Add information about the request itself.
|
| + var buffer = new StringBuffer();
|
| + buffer.write("${request.method} ${request.requestedUri.path}");
|
| + if (request.requestedUri.query.isNotEmpty) {
|
| + buffer.write("?${request.requestedUri.query}");
|
| + }
|
| + buffer.writeln();
|
| + buffer.write(message);
|
| +
|
| + return _logTopLevelError(buffer.toString(), stackTrace);
|
| +}
|
| +
|
| +Response _logTopLevelError(String message, [StackTrace stackTrace]) {
|
| var chain = new Chain.current();
|
| if (stackTrace != null) {
|
| chain = new Chain.forTrace(stackTrace);
|
|
|