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

Side by Side 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, 11 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 /**
6 * This library provides a simple API for routing HttpRequests based on thier
7 * URL.
8 */
9 library route.server;
10
11 import 'dart:async';
12 import 'dart:collection';
13 import 'dart:io';
14 import 'package:route_hierarchical/src/async_utils.dart';
15 export 'url_pattern.dart';
16 import 'pattern.dart';
17
18 typedef Future<bool> Filter(HttpRequest request);
19
20 /**
21 * A request router that makes it easier to handle [HttpRequest]s from an
22 * [HttpServer].
23 *
24 * [serve] creates a new [Stream] of requests whose paths match against the
25 * given pattern. Matching requests are not sent to any other streams created by
26 * a server() call.
27 *
28 * [filter] registers a [Filter] function to run against matching requests. On
29 * each request the filters that match are run in order, waiting for each to
30 * complete since filters return a Future. If any filter completes false, the
31 * subsequent filters and request handlers are not run. This way a filter can
32 * prevent further processing, like needed for authentication.
33 *
34 * Requests not matched by a call to [serve] are sent to the [defaultStream].
35 * If there's no subscriber to the defaultStream then a 404 is sent to the
36 * response.
37 *
38 * Example:
39 * import 'package:route/server.dart';
40 * import 'package:route/pattern.dart';
41 *
42 * HttpServer.bind().then((server) {
43 * var router = new Router(server);
44 * router.filter(matchesAny(['/foo', '/bar']), authFilter);
45 * router.serve('/foo').listen(fooHandler);
46 * router.serve('/bar').listen(barHandler);
47 * router.defaultStream.listen(send404);
48 * });
49 */
50 class Router {
51 final Stream<HttpRequest> _incoming;
52
53 final List<_Route> _routes = <_Route>[];
54
55 final Map<Pattern, Filter> _filters = new LinkedHashMap<Pattern, Filter>();
56
57 final StreamController<HttpRequest> _defaultController =
58 new StreamController<HttpRequest>();
59
60 /**
61 * Create a new Router that listens to the [incoming] stream, usually an
62 * instance of [HttpServer].
63 */
64 Router(Stream<HttpRequest> incoming) : _incoming = incoming {
65 _incoming.listen(_handleRequest);
66 }
67
68 /**
69 * Request whose URI matches [url] and [method] (if provided) are sent to the
70 * stream created by this method, and not sent to any other router streams.
71 */
72 Stream<HttpRequest> serve(Pattern url, {String method}) {
73 var controller = new StreamController<HttpRequest>();
74 _routes.add(new _Route(controller, url, method:method));
75 return controller.stream;
76 }
77
78 /**
79 * A [Filter] returns a [Future<bool>] that tells the router whether to apply
80 * the remaining filters and send requests to the streams created by [serve].
81 *
82 * If the filter returns true, the request is passed to the next filter, and
83 * then to the first matching server stream. If the filter returns false, it's
84 * assumed that the filter is handling the request and it's not forwarded.
85 */
86 void filter(Pattern url, Filter filter) {
87 _filters[url] = filter;
88 }
89
90 Stream<HttpRequest> get defaultStream => _defaultController.stream;
91
92 void _handleRequest(HttpRequest req) {
93 bool cont = true;
94 doWhile(_filters.keys, (Pattern pattern) {
95 if (matchesFull(pattern, req.uri.path)) {
96 return _filters[pattern](req).then((c) {
97 cont = c;
98 return c;
99 });
100 }
101 return new Future.value(true);
102 }).then((_) {
103 if (cont) {
104 bool handled = false;
105 var matches = _routes.where((r) => r.matches(req));
106 if (!matches.isEmpty) {
107 matches.first.controller.add(req);
108 } else {
109 if (_defaultController.hasListener) {
110 _defaultController.add(req);
111 } else {
112 send404(req);
113 }
114 }
115 }
116 });
117 }
118 }
119
120 void send404(HttpRequest req) {
121 req.response.statusCode = HttpStatus.NOT_FOUND;
122 req.response.write("Not Found");
123 req.response.close();
124 }
125
126 class _Route {
127 final Pattern url;
128 final String method;
129 final StreamController controller;
130 _Route(this.controller, this.url, {this.method});
131
132 bool matches(HttpRequest request) => matchesFull(url, request.uri.path) &&
133 (method == null || request.method.toUpperCase() == method);
134 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698