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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// A Shelf adapter for handling [HttpRequest] objects from `dart:io`.
6 ///
7 /// One can provide an instance of [HttpServer] as the `requests` parameter in
8 /// [serveRequests].
9 ///
10 /// This adapter supports request hijacking; see [Request.hijack]. It also
11 /// supports the `"shelf.io.buffer_output"` `Response.context` property. If this
12 /// property is `true` (the default), streamed responses will be buffered to
13 /// improve performance; if it's `false`, all chunks will be pushed over the
14 /// wire as they're received. See [`HttpResponse.bufferOutput`][bufferOutput]
15 /// for more information.
16 ///
17 /// [bufferOutput]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-vie wer/dart:io.HttpResponse#id_bufferOutput
18 library shelf.io;
19
20 import 'dart:async';
21 import 'dart:io';
22
23 import 'package:stack_trace/stack_trace.dart';
24
25 import 'shelf.dart';
26 import 'src/util.dart';
27
28 /// Starts an [HttpServer] that listens on the specified [address] and
29 /// [port] and sends requests to [handler].
30 ///
31 /// See the documentation for [HttpServer.bind] for more details on [address],
32 /// [port], and [backlog].
33 Future<HttpServer> serve(Handler handler, address, int port, {int backlog}) {
34 if (backlog == null) backlog = 0;
35 return HttpServer.bind(address, port, backlog: backlog).then((server) {
36 serveRequests(server, handler);
37 return server;
38 });
39 }
40
41 /// Serve a [Stream] of [HttpRequest]s.
42 ///
43 /// [HttpServer] implements [Stream<HttpRequest>] so it can be passed directly
44 /// to [serveRequests].
45 ///
46 /// Errors thrown by [handler] while serving a request will be printed to the
47 /// console and cause a 500 response with no body. Errors thrown asynchronously
48 /// by [handler] will be printed to the console or, if there's an active error
49 /// zone, passed to that zone.
50 void serveRequests(Stream<HttpRequest> requests, Handler handler) {
51 catchTopLevelErrors(() {
52 requests.listen((request) => handleRequest(request, handler));
53 }, (error, stackTrace) {
54 _logError('Asynchronous error\n$error', stackTrace);
55 });
56 }
57
58 /// Uses [handler] to handle [request].
59 ///
60 /// Returns a [Future] which completes when the request has been handled.
61 Future handleRequest(HttpRequest request, Handler handler) {
62 var shelfRequest;
63 try {
64 shelfRequest = _fromHttpRequest(request);
65 } catch (error, stackTrace) {
66 var response = _logError('Error parsing request.\n$error', stackTrace);
67 return _writeResponse(response, request.response);
68 }
69
70 // TODO(nweiz): abstract out hijack handling to make it easier to implement an
71 // adapter.
72 return new Future.sync(() => handler(shelfRequest))
73 .catchError((error, stackTrace) {
74 if (error is HijackException) {
75 // A HijackException should bypass the response-writing logic entirely.
76 if (!shelfRequest.canHijack) throw error;
77
78 // If the request wasn't hijacked, we shouldn't be seeing this exception.
79 return _logError(
80 "Caught HijackException, but the request wasn't hijacked.",
81 stackTrace);
82 }
83
84 return _logError('Error thrown by handler.\n$error', stackTrace);
85 }).then((response) {
86 if (response == null) {
87 return _writeResponse(
88 _logError('null response from handler.'), request.response);
89 } else if (shelfRequest.canHijack) {
90 return _writeResponse(response, request.response);
91 }
92
93 var message = new StringBuffer()
94 ..writeln("Got a response for hijacked request "
95 "${shelfRequest.method} ${shelfRequest.requestedUri}:")
96 ..writeln(response.statusCode);
97 response.headers
98 .forEach((key, value) => message.writeln("${key}: ${value}"));
99 throw new Exception(message.toString().trim());
100 }).catchError((error, stackTrace) {
101 // Ignore HijackExceptions.
102 if (error is! HijackException) throw error;
103 });
104 }
105
106 /// Creates a new [Request] from the provided [HttpRequest].
107 Request _fromHttpRequest(HttpRequest request) {
108 var headers = {};
109 request.headers.forEach((k, v) {
110 // Multiple header values are joined with commas.
111 // See http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21#page-22
112 headers[k] = v.join(',');
113 });
114
115 onHijack(callback) {
116 return request.response
117 .detachSocket(writeHeaders: false)
118 .then((socket) => callback(socket, socket));
119 }
120
121 return new Request(request.method, request.requestedUri,
122 protocolVersion: request.protocolVersion,
123 headers: headers,
124 body: request,
125 onHijack: onHijack);
126 }
127
128 Future _writeResponse(Response response, HttpResponse httpResponse) {
129 if (response.context.containsKey("shelf.io.buffer_output")) {
130 httpResponse.bufferOutput = response.context["shelf.io.buffer_output"];
131 }
132
133 httpResponse.statusCode = response.statusCode;
134
135 response.headers.forEach((header, value) {
136 if (value == null) return;
137 httpResponse.headers.set(header, value);
138 });
139
140 if (!response.headers.containsKey(HttpHeaders.SERVER)) {
141 httpResponse.headers.set(HttpHeaders.SERVER, 'dart:io with Shelf');
142 }
143
144 if (!response.headers.containsKey(HttpHeaders.DATE)) {
145 httpResponse.headers.date = new DateTime.now().toUtc();
146 }
147
148 return httpResponse
149 .addStream(response.read())
150 .then((_) => httpResponse.close());
151 }
152
153 // TODO(kevmoo) A developer mode is needed to include error info in response
154 // TODO(kevmoo) Make error output plugable. stderr, logging, etc
155 Response _logError(String message, [StackTrace stackTrace]) {
156 var chain = new Chain.current();
157 if (stackTrace != null) {
158 chain = new Chain.forTrace(stackTrace);
159 }
160 chain = chain
161 .foldFrames((frame) => frame.isCore || frame.package == 'shelf').terse;
162
163 stderr.writeln('ERROR - ${new DateTime.now()}');
164 stderr.writeln(message);
165 stderr.writeln(chain);
166 return new Response.internalServerError();
167 }
OLDNEW
« 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