Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1692)

Unified Diff: mojo/public/dart/third_party/shelf/lib/shelf_io.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: mojo/public/dart/third_party/shelf/lib/shelf_io.dart
diff --git a/mojo/public/dart/third_party/shelf/lib/shelf_io.dart b/mojo/public/dart/third_party/shelf/lib/shelf_io.dart
new file mode 100644
index 0000000000000000000000000000000000000000..bc2835ea205762082eabe59b1f78b481af2f0f3e
--- /dev/null
+++ b/mojo/public/dart/third_party/shelf/lib/shelf_io.dart
@@ -0,0 +1,167 @@
+// 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].
+///
+/// This adapter supports request hijacking; see [Request.hijack]. It also
+/// supports the `"shelf.io.buffer_output"` `Response.context` property. If this
+/// property is `true` (the default), streamed responses will be buffered to
+/// improve performance; if it's `false`, all chunks will be pushed over the
+/// wire as they're received. See [`HttpResponse.bufferOutput`][bufferOutput]
+/// for more information.
+///
+/// [bufferOutput]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:io.HttpResponse#id_bufferOutput
+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 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;
+ });
+}
+
+/// 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) {
+ if (response.context.containsKey("shelf.io.buffer_output")) {
+ httpResponse.bufferOutput = response.context["shelf.io.buffer_output"];
+ }
+
+ 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();
+}
« no previous file with comments | « mojo/public/dart/third_party/shelf/lib/shelf.dart ('k') | mojo/public/dart/third_party/shelf/lib/src/body.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698