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

Unified Diff: third_party/pkg/route_hierarchical/lib/server.dart

Issue 124053002: Adding Angular and dependent packages for testing (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 12 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: third_party/pkg/route_hierarchical/lib/server.dart
diff --git a/third_party/pkg/route_hierarchical/lib/server.dart b/third_party/pkg/route_hierarchical/lib/server.dart
new file mode 100644
index 0000000000000000000000000000000000000000..67c66ababc89819cd75fd271898f1e7f30a20502
--- /dev/null
+++ b/third_party/pkg/route_hierarchical/lib/server.dart
@@ -0,0 +1,134 @@
+// Copyright (c) 2013, 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.
+
+/**
+ * This library provides a simple API for routing HttpRequests based on thier
+ * URL.
+ */
+library route.server;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:io';
+import 'package:route_hierarchical/src/async_utils.dart';
+export 'url_pattern.dart';
+import 'pattern.dart';
+
+typedef Future<bool> Filter(HttpRequest request);
+
+/**
+ * A request router that makes it easier to handle [HttpRequest]s from an
+ * [HttpServer].
+ *
+ * [serve] creates a new [Stream] of requests whose paths match against the
+ * given pattern. Matching requests are not sent to any other streams created by
+ * a server() call.
+ *
+ * [filter] registers a [Filter] function to run against matching requests. On
+ * each request the filters that match are run in order, waiting for each to
+ * complete since filters return a Future. If any filter completes false, the
+ * subsequent filters and request handlers are not run. This way a filter can
+ * prevent further processing, like needed for authentication.
+ *
+ * Requests not matched by a call to [serve] are sent to the [defaultStream].
+ * If there's no subscriber to the defaultStream then a 404 is sent to the
+ * response.
+ *
+ * Example:
+ * import 'package:route/server.dart';
+ * import 'package:route/pattern.dart';
+ *
+ * HttpServer.bind().then((server) {
+ * var router = new Router(server);
+ * router.filter(matchesAny(['/foo', '/bar']), authFilter);
+ * router.serve('/foo').listen(fooHandler);
+ * router.serve('/bar').listen(barHandler);
+ * router.defaultStream.listen(send404);
+ * });
+ */
+class Router {
+ final Stream<HttpRequest> _incoming;
+
+ final List<_Route> _routes = <_Route>[];
+
+ final Map<Pattern, Filter> _filters = new LinkedHashMap<Pattern, Filter>();
+
+ final StreamController<HttpRequest> _defaultController =
+ new StreamController<HttpRequest>();
+
+ /**
+ * Create a new Router that listens to the [incoming] stream, usually an
+ * instance of [HttpServer].
+ */
+ Router(Stream<HttpRequest> incoming) : _incoming = incoming {
+ _incoming.listen(_handleRequest);
+ }
+
+ /**
+ * Request whose URI matches [url] and [method] (if provided) are sent to the
+ * stream created by this method, and not sent to any other router streams.
+ */
+ Stream<HttpRequest> serve(Pattern url, {String method}) {
+ var controller = new StreamController<HttpRequest>();
+ _routes.add(new _Route(controller, url, method:method));
+ return controller.stream;
+ }
+
+ /**
+ * A [Filter] returns a [Future<bool>] that tells the router whether to apply
+ * the remaining filters and send requests to the streams created by [serve].
+ *
+ * If the filter returns true, the request is passed to the next filter, and
+ * then to the first matching server stream. If the filter returns false, it's
+ * assumed that the filter is handling the request and it's not forwarded.
+ */
+ void filter(Pattern url, Filter filter) {
+ _filters[url] = filter;
+ }
+
+ Stream<HttpRequest> get defaultStream => _defaultController.stream;
+
+ void _handleRequest(HttpRequest req) {
+ bool cont = true;
+ doWhile(_filters.keys, (Pattern pattern) {
+ if (matchesFull(pattern, req.uri.path)) {
+ return _filters[pattern](req).then((c) {
+ cont = c;
+ return c;
+ });
+ }
+ return new Future.value(true);
+ }).then((_) {
+ if (cont) {
+ bool handled = false;
+ var matches = _routes.where((r) => r.matches(req));
+ if (!matches.isEmpty) {
+ matches.first.controller.add(req);
+ } else {
+ if (_defaultController.hasListener) {
+ _defaultController.add(req);
+ } else {
+ send404(req);
+ }
+ }
+ }
+ });
+ }
+}
+
+void send404(HttpRequest req) {
+ req.response.statusCode = HttpStatus.NOT_FOUND;
+ req.response.write("Not Found");
+ req.response.close();
+}
+
+class _Route {
+ final Pattern url;
+ final String method;
+ final StreamController controller;
+ _Route(this.controller, this.url, {this.method});
+
+ bool matches(HttpRequest request) => matchesFull(url, request.uri.path) &&
+ (method == null || request.method.toUpperCase() == method);
+}

Powered by Google App Engine
This is Rietveld 408576698