OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, 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 shelf.cascade; |
| 6 |
| 7 import 'dart:async'; |
| 8 |
| 9 import 'handler.dart'; |
| 10 import 'response.dart'; |
| 11 |
| 12 /// A typedef for [Cascade._shouldCascade]. |
| 13 typedef bool _ShouldCascade(Response response); |
| 14 |
| 15 /// A helper that calls several handlers in sequence and returns the first |
| 16 /// acceptable response. |
| 17 /// |
| 18 /// By default, a response is considered acceptable if it has a status other |
| 19 /// than 404 or 405; other statuses indicate that the handler understood the |
| 20 /// request. |
| 21 /// |
| 22 /// If all handlers return unacceptable responses, the final response will be |
| 23 /// returned. |
| 24 /// |
| 25 /// var handler = new Cascade() |
| 26 /// .add(webSocketHandler) |
| 27 /// .add(staticFileHandler) |
| 28 /// .add(application) |
| 29 /// .handler; |
| 30 class Cascade { |
| 31 /// The function used to determine whether the cascade should continue on to |
| 32 /// the next handler. |
| 33 final _ShouldCascade _shouldCascade; |
| 34 |
| 35 final Cascade _parent; |
| 36 final Handler _handler; |
| 37 |
| 38 /// Creates a new, empty cascade. |
| 39 /// |
| 40 /// If [statusCodes] is passed, responses with those status codes are |
| 41 /// considered unacceptable. If [shouldCascade] is passed, responses for which |
| 42 /// it returns `true` are considered unacceptable. [statusCode] and |
| 43 /// [shouldCascade] may not both be passed. |
| 44 Cascade({Iterable<int> statusCodes, bool shouldCascade(Response response)}) |
| 45 : _shouldCascade = _computeShouldCascade(statusCodes, shouldCascade), |
| 46 _parent = null, |
| 47 _handler = null { |
| 48 if (statusCodes != null && shouldCascade != null) { |
| 49 throw new ArgumentError("statusCodes and shouldCascade may not both be " |
| 50 "passed."); |
| 51 } |
| 52 } |
| 53 |
| 54 Cascade._(this._parent, this._handler, this._shouldCascade); |
| 55 |
| 56 /// Returns a new cascade with [handler] added to the end. |
| 57 /// |
| 58 /// [handler] will only be called if all previous handlers in the cascade |
| 59 /// return unacceptable responses. |
| 60 Cascade add(Handler handler) => new Cascade._(this, handler, _shouldCascade); |
| 61 |
| 62 /// Exposes this cascade as a single handler. |
| 63 /// |
| 64 /// This handler will call each inner handler in the cascade until one returns |
| 65 /// an acceptable response, and return that. If no inner handlers return an |
| 66 /// acceptable response, this will return the final response. |
| 67 Handler get handler { |
| 68 if (_handler == null) { |
| 69 throw new StateError("Can't get a handler for a cascade with no inner " |
| 70 "handlers."); |
| 71 } |
| 72 |
| 73 return (request) { |
| 74 if (_parent._handler == null) return _handler(request); |
| 75 return new Future.sync(() => _parent.handler(request)).then((response) { |
| 76 if (_shouldCascade(response)) return _handler(request); |
| 77 return response; |
| 78 }); |
| 79 }; |
| 80 } |
| 81 } |
| 82 |
| 83 /// Computes the [Cascade._shouldCascade] function based on the user's |
| 84 /// parameters. |
| 85 Function _computeShouldCascade( |
| 86 Iterable<int> statusCodes, Function shouldCascade) { |
| 87 if (shouldCascade != null) return shouldCascade; |
| 88 if (statusCodes == null) statusCodes = [404, 405]; |
| 89 statusCodes = statusCodes.toSet(); |
| 90 return (response) => statusCodes.contains(response.statusCode); |
| 91 } |
OLD | NEW |