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

Side by Side Diff: sdk/lib/_internal/pub_generated/lib/src/barback/barback_server.dart

Issue 937243002: Revert "Revert "Use native async/await support in pub."" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 library pub.barback.server;
6
7 import 'dart:async';
8 import 'dart:io';
9
10 import 'package:barback/barback.dart';
11 import 'package:mime/mime.dart';
12 import 'package:path/path.dart' as path;
13 import 'package:shelf/shelf.dart' as shelf;
14 import 'package:stack_trace/stack_trace.dart';
15
16 import '../barback.dart';
17 import '../io.dart';
18 import '../log.dart' as log;
19 import '../utils.dart';
20 import 'base_server.dart';
21 import 'asset_environment.dart';
22
23 /// Callback for determining if an asset with [id] should be served or not.
24 typedef bool AllowAsset(AssetId id);
25
26 /// A server that serves assets transformed by barback.
27 class BarbackServer extends BaseServer<BarbackServerResult> {
28 /// The package whose assets are being served.
29 final String package;
30
31 /// The directory in the root which will serve as the root of this server as
32 /// a native platform path.
33 ///
34 /// This may be `null` in which case no files in the root package can be
35 /// served and only assets in "lib" directories are available.
36 final String rootDirectory;
37
38 /// Optional callback to determine if an asset should be served.
39 ///
40 /// This can be set to allow outside code to filter out assets. Pub serve
41 /// uses this after plug-ins are loaded to avoid serving ".dart" files in
42 /// release mode.
43 ///
44 /// If this is `null`, all assets may be served.
45 AllowAsset allowAsset;
46
47 /// Creates a new server and binds it to [port] of [host].
48 ///
49 /// This server serves assets from [barback], and uses [rootDirectory]
50 /// (which is relative to the root directory of [package]) as the root
51 /// directory. If [rootDirectory] is omitted, the bound server can only be
52 /// used to serve assets from packages' lib directories (i.e. "packages/..."
53 /// URLs). If [package] is omitted, it defaults to the entrypoint package.
54 static Future<BarbackServer> bind(AssetEnvironment environment, String host,
55 int port, {String package, String rootDirectory}) {
56 if (package == null) package = environment.rootPackage.name;
57 return bindServer(host, port).then((server) {
58 if (rootDirectory == null) {
59 log.fine('Serving packages on $host:$port.');
60 } else {
61 log.fine('Bound "$rootDirectory" to $host:$port.');
62 }
63 return new BarbackServer._(environment, server, package, rootDirectory);
64 });
65 }
66
67 BarbackServer._(AssetEnvironment environment, HttpServer server, this.package,
68 this.rootDirectory)
69 : super(environment, server);
70
71 /// Converts a [url] served by this server into an [AssetId] that can be
72 /// requested from barback.
73 AssetId urlToId(Uri url) {
74 // See if it's a URL to a public directory in a dependency.
75 var id = packagesUrlToId(url);
76 if (id != null) return id;
77
78 if (rootDirectory == null) {
79 throw new FormatException(
80 "This server cannot serve out of the root directory. Got $url.");
81 }
82
83 // Otherwise, it's a path in current package's [rootDirectory].
84 var parts = path.url.split(url.path);
85
86 // Strip the leading "/" from the URL.
87 if (parts.isNotEmpty && parts.first == "/") parts = parts.skip(1);
88
89 var relativePath = path.url.join(rootDirectory, path.url.joinAll(parts));
90 return new AssetId(package, relativePath);
91 }
92
93 /// Handles an HTTP request.
94 handleRequest(shelf.Request request) {
95 if (request.method != "GET" && request.method != "HEAD") {
96 return methodNotAllowed(request);
97 }
98
99 var id;
100 try {
101 id = urlToId(request.url);
102 } on FormatException catch (ex) {
103 // If we got here, we had a path like "/packages" which is a special
104 // directory, but not a valid path since it lacks a following package
105 // name.
106 return notFound(request, error: ex.message);
107 }
108
109 // See if the asset should be blocked.
110 if (allowAsset != null && !allowAsset(id)) {
111 return notFound(
112 request,
113 error: "Asset $id is not available in this configuration.",
114 asset: id);
115 }
116
117 return environment.barback.getAssetById(id).then((result) {
118 return result;
119 }).then((asset) => _serveAsset(request, asset)).catchError((error, trace) {
120 if (error is! AssetNotFoundException) throw error;
121 return environment.barback.getAssetById(
122 id.addExtension("/index.html")).then((asset) {
123 if (request.url.path.endsWith('/')) return _serveAsset(request, asset);
124
125 // We only want to serve index.html if the URL explicitly ends in a
126 // slash. For other URLs, we redirect to one with the slash added to
127 // implicitly support that too. This follows Apache's behavior.
128 logRequest(request, "302 Redirect to ${request.url}/");
129 return new shelf.Response.found('${request.url}/');
130 }).catchError((newError, newTrace) {
131 // If we find neither the original file or the index, we should report
132 // the error about the original to the user.
133 throw newError is AssetNotFoundException ? error : newError;
134 });
135 }).catchError((error, trace) {
136 if (error is! AssetNotFoundException) {
137 trace = new Chain.forTrace(trace);
138 logRequest(request, "$error\n$trace");
139
140 addError(error, trace);
141 close();
142 return new shelf.Response.internalServerError();
143 }
144
145 addResult(new BarbackServerResult._failure(request.url, id, error));
146 return notFound(request, asset: id);
147 }).then((response) {
148 // Allow requests of any origin to access "pub serve". This is useful for
149 // running "pub serve" in parallel with another development server. Since
150 // "pub serve" is only used as a development server and doesn't require
151 // any sort of credentials anyway, this is secure.
152 return response.change(headers: const {
153 "Access-Control-Allow-Origin": "*"
154 });
155 });
156 }
157
158 /// Returns the body of [asset] as a response to [request].
159 Future<shelf.Response> _serveAsset(shelf.Request request, Asset asset) {
160 return validateStream(asset.read()).then((stream) {
161 addResult(new BarbackServerResult._success(request.url, asset.id));
162 var headers = {};
163 var mimeType = lookupMimeType(asset.id.path);
164 if (mimeType != null) headers['Content-Type'] = mimeType;
165 return new shelf.Response.ok(stream, headers: headers);
166 }).catchError((error, trace) {
167 addResult(new BarbackServerResult._failure(request.url, asset.id, error));
168
169 // If we couldn't read the asset, handle the error gracefully.
170 if (error is FileSystemException) {
171 // Assume this means the asset was a file-backed source asset
172 // and we couldn't read it, so treat it like a missing asset.
173 return notFound(request, error: error.toString(), asset: asset.id);
174 }
175
176 trace = new Chain.forTrace(trace);
177 logRequest(request, "$error\n$trace");
178
179 // Otherwise, it's some internal error.
180 return new shelf.Response.internalServerError(body: error.toString());
181 });
182 }
183 }
184
185 /// The result of the server handling a URL.
186 ///
187 /// Only requests for which an asset was requested from barback will emit a
188 /// result. Malformed requests will be handled internally.
189 class BarbackServerResult {
190 /// The requested url.
191 final Uri url;
192
193 /// The id that [url] identifies.
194 final AssetId id;
195
196 /// The error thrown by barback.
197 ///
198 /// If the request was served successfully, this will be null.
199 final error;
200
201 /// Whether the request was served successfully.
202 bool get isSuccess => error == null;
203
204 /// Whether the request was served unsuccessfully.
205 bool get isFailure => !isSuccess;
206
207 BarbackServerResult._success(this.url, this.id)
208 : error = null;
209
210 BarbackServerResult._failure(this.url, this.id, this.error);
211 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698