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

Side by Side Diff: sdk/lib/_internal/pub/lib/src/barback/server.dart

Issue 23625002: Support loading transformer plugins from pub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 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 | 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:path/path.dart' as path;
12
13 import '../entrypoint.dart';
14 import '../utils.dart';
15
16 /// A server that serves assets transformed by barback.
17 class BarbackServer {
18 /// The underlying HTTP server.
19 final HttpServer _server;
20
21 /// The name of the root package, from whose `web` directory root assets will
22 /// be served.
23 final String _rootPackage;
24
25 /// The barback instance from which this serves assets.
26 final Barback barback;
27
28 /// The server's port.
29 final int port;
30
31 /// The results of requests handled by the server.
32 ///
33 /// These can be used to provide visual feedback for the server's processing.
34 /// This stream is also used to emit any programmatic errors that occur in the
35 /// server.
36 Stream<BarbackServerResult> get results => _resultsController.stream;
37 final _resultsController =
38 new StreamController<BarbackServerResult>.broadcast();
39
40 /// Creates a new server and binds it to [port] of [host].
41 ///
42 /// This server will serve assets from [barback], and use [entrypoint] as the
Bob Nystrom 2013/08/27 22:12:30 "entrypoint" -> "rootPackage".
nweiz 2013/08/28 20:45:23 Done.
43 /// root package.
44 static Future<BarbackServer> bind(String host, int port, Barback barback,
45 String rootPackage) {
46 return HttpServer.bind(host, port)
47 .then((server) => new BarbackServer._(server, barback, rootPackage));
48 }
49
50 BarbackServer._(HttpServer server, this.barback, this._rootPackage)
51 : _server = server,
52 port = server.port {
53 _server.listen(_handleRequest, onError: (error) {
54 _resultsController.addError(error);
55 close();
56 });
57 }
58
59 /// Closes this server.
60 Future close() {
61 _server.close();
62 _resultsController.close();
63 }
64
65 /// Handles an HTTP request.
66 void _handleRequest(HttpRequest request) {
67 if (request.method != "GET" && request.method != "HEAD") {
68 _methodNotAllowed(request);
Bob Nystrom 2013/08/27 22:12:30 Should add a test for this.
nweiz 2013/08/28 20:45:23 Done.
69 return;
70 }
71
72 var id = _getIdFromUri(request.uri);
73 if (id == null) {
74 _notFound(request, "Path ${request.uri.path} is not valid.");
75 return;
76 }
77
78 barback.getAssetById(id).then((asset) {
79 return validateStream(asset.read()).then((stream) {
80 _resultsController.add(
81 new BarbackServerResult._success(request.uri, id));
82 // TODO(rnystrom): Set content-type based on asset type.
83 return request.response.addStream(stream).then((_) {
84 request.response.close();
85 });
86 }).catchError((error) {
87 _resultsController.add(
88 new BarbackServerResult._failure(request.uri, id, error));
89
90 // If we couldn't read the asset, handle the error gracefully.
91 if (error is FileException) {
92 // Assume this means the asset was a file-backed source asset
93 // and we couldn't read it, so treat it like a missing asset.
94 _notFound(request, error);
95 return;
96 }
97
98 // Otherwise, it's some internal error.
99 request.response.statusCode = 500;
100 request.response.reasonPhrase = "Internal Error";
101 request.response.write(error);
102 request.response.close();
103 });
104 }).catchError((error) {
105 if (error is! AssetNotFoundException) {
106 _resultsController.addError(error);
107 close();
108 return;
109 }
110
111 _resultsController.add(
112 new BarbackServerResult._failure(request.uri, id, error));
113 _notFound(request, error);
114 });
115 }
116
117 /// Responds to [request] with a 405 response and closes it.
118 void _methodNotAllowed(HttpRequest request) {
119 request.response.statusCode = 405;
120 request.response.reasonPhrase = "Method Not Allowed";
121 request.response.headers['Allow'] = 'GET, HEAD';
122 request.response.write(
123 "The ${request.method} method is not allowed for ${request.uri}.");
124 request.response.close();
125 }
126
127 /// Responds to [request] with a 404 response and closes it.
128 void _notFound(HttpRequest request, message) {
129 request.response.statusCode = 404;
130 request.response.reasonPhrase = "Not Found";
131 request.response.write(message);
132 request.response.close();
133 }
134
135 /// Converts a request [uri] into an [AssetId] that can be requested from
136 /// barback.
137 AssetId _getIdFromUri(Uri uri) {
138 var parts = path.url.split(uri.path);
139
140 // Strip the leading "/" from the URL.
141 parts.removeAt(0);
142
143 var isSpecial = false;
144
145 // Checks to see if [uri]'s path contains a special directory [name] that
146 // identifies an asset within some package. If so, maps the package name
147 // and path following that to be within [dir] inside that package.
148 AssetId _trySpecialUrl(String name, String dir) {
149 // Find the package name and the relative path in the package.
150 var index = parts.indexOf(name);
151 if (index == -1) return null;
152
153 // If we got here, the path *did* contain the special directory, which
154 // means we should not interpret it as a regular path, even if it's
155 // missing the package name after it, which makes it invalid here.
156 isSpecial = true;
157 if (index + 1 >= parts.length) return null;
158
159 var package = parts[index + 1];
160 var assetPath = path.url.join(dir,
161 path.url.joinAll(parts.skip(index + 2)));
162 return new AssetId(package, assetPath);
163 }
164
165 // See if it's "packages" URL.
166 var id = _trySpecialUrl("packages", "lib");
167 if (id != null) return id;
168
169 // See if it's an "assets" URL.
170 id = _trySpecialUrl("assets", "asset");
171 if (id != null) return id;
172
173 // If we got here, we had a path like "/packages" which is a special
174 // directory, but not a valid path since it lacks a following package name.
175 if (isSpecial) return null;
176
177 // Otherwise, it's a path in current package's web directory.
178 return new AssetId(_rootPackage,
179 path.url.join("web", path.url.joinAll(parts)));
180 }
181 }
182
183 /// The result of the server handling a URL.
184 ///
185 /// Only requests for which an asset was requested from barback will emit a
186 /// result. Malformed requests will be handled internally.
187 class BarbackServerResult {
188 /// The requested url.
189 final Url url;
190
191 /// The id that [url] identifies.
192 final AssetId id;
193
194 /// The error thrown by barback.
195 ///
196 /// If the request was served successfully, this will be null.
197 final error;
198
199 /// Whether the request was served successfully.
200 bool get isSuccess => error == null;
201
202 /// Whether the request was served unsuccessfully.
203 bool get isFailure => !isSuccess;
204
205 BarbackServerResult._success(this.url, this.id)
206 : error = null;
207
208 BarbackServerResult._failure(this.url, this.id, this.error);
209 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698