Index: pkg/shelf/lib/shelf_io.dart |
diff --git a/pkg/shelf/lib/shelf_io.dart b/pkg/shelf/lib/shelf_io.dart |
deleted file mode 100644 |
index 878935f0a188a40d2a8df8675253414534ca2dda..0000000000000000000000000000000000000000 |
--- a/pkg/shelf/lib/shelf_io.dart |
+++ /dev/null |
@@ -1,153 +0,0 @@ |
-// 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. |
- |
-/// A Shelf adapter for handling [HttpRequest] objects from `dart:io`. |
-/// |
-/// One can provide an instance of [HttpServer] as the `requests` parameter in |
-/// [serveRequests]. |
-/// |
-/// The `dart:io` adapter supports request hijacking; see [Request.hijack]. |
-library shelf.io; |
- |
-import 'dart:async'; |
-import 'dart:io'; |
- |
-import 'package:stack_trace/stack_trace.dart'; |
- |
-import 'shelf.dart'; |
-import 'src/util.dart'; |
- |
-/// Starts an [HttpServer] that listens on the specified [address] and |
-/// [port] and sends requests to [handler]. |
-/// |
-/// See the documentation for [HttpServer.bind] for more details on [address], |
-/// [port], and [backlog]. |
-Future<HttpServer> serve(Handler handler, address, int port, |
- {int backlog}) { |
- if (backlog == null) backlog = 0; |
- return HttpServer.bind(address, port, backlog: backlog).then((server) { |
- serveRequests(server, handler); |
- return server; |
- }); |
-} |
- |
-/// Serve a [Stream] of [HttpRequest]s. |
-/// |
-/// [HttpServer] implements [Stream<HttpRequest>] so it can be passed directly |
-/// to [serveRequests]. |
-/// |
-/// Errors thrown by [handler] while serving a request will be printed to the |
-/// console and cause a 500 response with no body. Errors thrown asynchronously |
-/// by [handler] will be printed to the console or, if there's an active error |
-/// zone, passed to that zone. |
-void serveRequests(Stream<HttpRequest> requests, Handler handler) { |
- catchTopLevelErrors(() { |
- requests.listen((request) => handleRequest(request, handler)); |
- }, (error, stackTrace) { |
- _logError('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) { |
- var shelfRequest; |
- try { |
- shelfRequest = _fromHttpRequest(request); |
- } catch (error, stackTrace) { |
- var response = _logError('Error parsing request.\n$error', stackTrace); |
- return _writeResponse(response, request.response); |
- } |
- |
- // TODO(nweiz): abstract out hijack handling to make it easier to implement an |
- // adapter. |
- return syncFuture(() => 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) { |
- response = _logError('null response from handler.'); |
- } else if (!shelfRequest.canHijack) { |
- 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()); |
- } |
- |
- return _writeResponse(response, request.response); |
- }).catchError((error, stackTrace) { |
- // Ignore HijackExceptions. |
- if (error is! HijackException) throw error; |
- }); |
-} |
- |
-/// Creates a new [Request] from the provided [HttpRequest]. |
-Request _fromHttpRequest(HttpRequest request) { |
- var headers = {}; |
- request.headers.forEach((k, v) { |
- // Multiple header values are joined with commas. |
- // See http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21#page-22 |
- headers[k] = v.join(','); |
- }); |
- |
- onHijack(callback) { |
- return request.response.detachSocket(writeHeaders: false) |
- .then((socket) => callback(socket, socket)); |
- } |
- |
- return new Request(request.method, request.requestedUri, |
- protocolVersion: request.protocolVersion, headers: headers, |
- body: request, onHijack: onHijack); |
-} |
- |
-Future _writeResponse(Response response, HttpResponse httpResponse) { |
- httpResponse.statusCode = response.statusCode; |
- |
- response.headers.forEach((header, value) { |
- if (value == null) return; |
- httpResponse.headers.set(header, value); |
- }); |
- |
- if (!response.headers.containsKey(HttpHeaders.SERVER)) { |
- httpResponse.headers.set(HttpHeaders.SERVER, 'dart:io with Shelf'); |
- } |
- |
- if (!response.headers.containsKey(HttpHeaders.DATE)) { |
- httpResponse.headers.date = new DateTime.now().toUtc(); |
- } |
- |
- return httpResponse.addStream(response.read()) |
- .then((_) => httpResponse.close()); |
-} |
- |
-// 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]) { |
- var chain = new Chain.current(); |
- if (stackTrace != null) { |
- chain = new Chain.forTrace(stackTrace); |
- } |
- chain = chain |
- .foldFrames((frame) => frame.isCore || frame.package == 'shelf') |
- .terse; |
- |
- stderr.writeln('ERROR - ${new DateTime.now()}'); |
- stderr.writeln(message); |
- stderr.writeln(chain); |
- return new Response.internalServerError(); |
-} |