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

Side by Side Diff: lib/server.dart

Issue 12578002: Add Router.defaultStream Base URL: https://github.com/dart-lang/route.git@master
Patch Set: Created 7 years, 9 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
« no previous file with comments | « no previous file | test/server_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * This library provides a simple API for routing HttpRequests based on thier 6 * This library provides a simple API for routing HttpRequests based on thier
7 * URL. 7 * URL.
8 */ 8 */
9 library route.server; 9 library route.server;
10 10
(...skipping 14 matching lines...) Expand all
25 * [serve] creates a new [Stream] of requests whose paths match against the 25 * [serve] creates a new [Stream] of requests whose paths match against the
26 * given pattern. Matching requests are not sent to any other streams created by 26 * given pattern. Matching requests are not sent to any other streams created by
27 * a server() call. 27 * a server() call.
28 * 28 *
29 * [filter] registers a [Filter] function to run against matching requests. On 29 * [filter] registers a [Filter] function to run against matching requests. On
30 * each request the filters that match are run in order, waiting for each to 30 * each request the filters that match are run in order, waiting for each to
31 * complete since filters return a Future. If any filter completes false, the 31 * complete since filters return a Future. If any filter completes false, the
32 * subsequent filters and request handlers are not run. This way a filter can 32 * subsequent filters and request handlers are not run. This way a filter can
33 * prevent further processing, like needed for authentication. 33 * prevent further processing, like needed for authentication.
34 * 34 *
35 * Requests not matched by a call to [serve] are sent to the [defaultStream].
36 * If there's no subscriber to the defaultStream then a 404 is sent to the
37 * response.
38 *
35 * Example: 39 * Example:
36 * import 'package:route/server.dart'; 40 * import 'package:route/server.dart';
37 * import 'package:route/pattern.dart'; 41 * import 'package:route/pattern.dart';
38 * 42 *
39 * HttpServer.bind().then((server) { 43 * HttpServer.bind().then((server) {
40 * var router = new Router(server); 44 * var router = new Router(server);
41 * router.filter(matchesAny(['/foo', '/bar']), authFilter); 45 * router.filter(matchesAny(['/foo', '/bar']), authFilter);
42 * router.serve('/foo').listen(fooHandler); 46 * router.serve('/foo').listen(fooHandler);
43 * router.serve('/bar').listen(barHandler); 47 * router.serve('/bar').listen(barHandler);
48 * router.defaultStream.listen(send404);
44 * }); 49 * });
45 */ 50 */
46 class Router { 51 class Router {
47 final Stream<HttpRequest> incoming; 52 final Stream<HttpRequest> _incoming;
48 final Map<Pattern, StreamController> _controllers = new LinkedHashMap(); 53
49 final Map<Pattern, Filter> _filters = new LinkedHashMap(); 54 final Map<Pattern, StreamController> _controllers =
50 55 new LinkedHashMap<Pattern, StreamController>();
51 Router(this.incoming) { 56
52 incoming.listen(_handleRequest); 57 final Map<Pattern, Filter> _filters = new LinkedHashMap<Pattern, Filter>();
58
59 final StreamController<HttpRequest> _defaultController =
60 new StreamController<HttpRequest>();
61
62 /**
63 * Create a new Router that listens to the [incoming] stream, usually an
64 * instance of [HttpServer].
65 */
66 Router(Stream<HttpRequest> incoming) : _incoming = incoming {
67 _incoming.listen(_handleRequest);
53 } 68 }
54 69
55 /** 70 /**
56 * Request whose URI matches [url] are sent the the stream created by this\ 71 * Request whose URI matches [url] are sent the the stream created by this
butlermatt 2013/03/07 13:21:52 double 'the'
57 * method, and not sent to any other serve streams. 72 * method, and not sent to any other serve streams.
58 */ 73 */
59 Stream<HttpRequest> serve(Pattern url) { 74 Stream<HttpRequest> serve(Pattern url) {
60 var controller = new StreamController<HttpRequest>(); 75 var controller = new StreamController<HttpRequest>();
61 _controllers[url] = controller; 76 _controllers[url] = controller;
62 return controller.stream; 77 return controller.stream;
63 } 78 }
64 79
65 /** 80 /**
66 * A [Filter] returns a [Future<bool>] that tells the router whether to apply 81 * A [Filter] returns a [Future<bool>] that tells the router whether to apply
67 * the remaining filters and send requests to the streams created by [serve]. 82 * the remaining filters and send requests to the streams created by [serve].
68 * 83 *
69 * If the filter returns true, the request is passed to the next filter, and 84 * If the filter returns true, the request is passed to the next filter, and
70 * then to the first matching server stream. If the filter returns false, it's 85 * then to the first matching server stream. If the filter returns false, it's
71 * assumed that the filter is handling the request and it's not forwarded. 86 * assumed that the filter is handling the request and it's not forwarded.
72 */ 87 */
73 void filter(Pattern url, Filter filter) { 88 void filter(Pattern url, Filter filter) {
74 _filters[url] = filter; 89 _filters[url] = filter;
75 } 90 }
76 91
92 Stream<HttpRequest> get defaultStream => _defaultController.stream;
93
77 void _handleRequest(HttpRequest req) { 94 void _handleRequest(HttpRequest req) {
78 bool cont = true; 95 bool cont = true;
79 doWhile(_filters.keys, (Pattern pattern) { 96 doWhile(_filters.keys, (Pattern pattern) {
80 if (matchesFull(pattern, req.uri.path)) { 97 if (matchesFull(pattern, req.uri.path)) {
81 return _filters[pattern](req).then((c) { 98 return _filters[pattern](req).then((c) {
82 cont = c; 99 cont = c;
83 return c; 100 return c;
84 }); 101 });
85 } 102 }
86 return new Future.immediate(true); 103 return new Future.immediate(true);
87 }).then((_) { 104 }).then((_) {
88 if (cont) { 105 if (cont) {
89 bool handled = false; 106 bool handled = false;
90 for (Pattern pattern in _controllers.keys) { 107 for (Pattern pattern in _controllers.keys) {
91 if (matchesFull(pattern, req.uri.path)) { 108 if (matchesFull(pattern, req.uri.path)) {
92 _controllers[pattern].add(req); 109 _controllers[pattern].add(req);
93 handled = true; 110 handled = true;
94 break; 111 break;
95 } 112 }
96 } 113 }
97 if (!handled) { 114 if (!handled) {
98 send404(req); 115 if (_defaultController.hasSubscribers) {
116 _defaultController.add(req);
117 } else {
118 send404(req);
119 }
99 } 120 }
100 } 121 }
101 }); 122 });
102 } 123 }
103 } 124 }
104 125
105 void send404(HttpRequest req) { 126 void send404(HttpRequest req) {
106 req.response.statusCode = HttpStatus.NOT_FOUND; 127 req.response.statusCode = HttpStatus.NOT_FOUND;
107 req.response.addString("Not Found"); 128 req.response.addString("Not Found");
108 req.response.close(); 129 req.response.close();
109 } 130 }
OLDNEW
« no previous file with comments | « no previous file | test/server_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698