« index
Coverage for /Users/kris/q-io/http-apps/route.js : 87%
123 lines |
108 run |
15 missing |
0 partial |
27 blocks |
15 blocks run |
12 blocks missing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | var Q = require("q"); var StatusApps = require("./status"); /** * Makes a Q-JSGI app that only responds when there is nothing left * on the path to route. If the there is unprocessed data on the * path, the returned app either forwards to the `notFound` app or * returns a `404 Not Found` response. * * @param {App} app a Q-JSGI application to * respond to this end of the routing chain. * @param {App} notFound (optional) defaults * to the `notFound` app. * @returns {App} */ exports.Cap = function (app, notFound) { notFound = notFound || StatusApps.notFound; return function (request, response) { // TODO Distinguish these cases if (request.pathInfo === "" || request.pathInfo === "/") { return app(request, response); } else { return notFound(request, response); } }; }; /** * Wraps an app with a function that will observe incoming requests * before giving the app an opportunity to respond. If the "tap" * function returns a response, it will be used in lieu of forwarding * the request to the wrapped app. */ exports.Tap = function (app, tap) { return function (request, response) { var self = this, args = arguments; return Q.when(tap.apply(this, arguments), function (response) { if (response) { return response; } else { return app.apply(self, args); } }); }; }; /** * Wraps an app with a "trap" function that intercepts and may * alter or replace the response of the wrapped application. */ exports.Trap = function (app, trap) { return function (request, response) { return Q.when(app.apply(this, arguments), function (response) { if (response) { response.headers = response.headers || {}; return trap(response, request) || response; } }); }; }; /** * Makes a Q-JSGI app that branches requests based on the next * unprocessed path component. * @param {Object * App} paths a mapping from path components (single * file or directory names) to Q-JSGI applications for subsequent * routing. The mapping may be a plain JavaScript `Object` record, * which must own the mapping properties, or an object that has * `has(key)` and `get(key)` methods in its prototype chain. * @param {App} notFound a Q-JSGI application * that handles requests for which the next file name does not exist * in paths. * @returns {App} */ exports.Branch = function (paths, notFound) { if (!paths) paths = {}; if (!notFound) notFound = StatusApps.notFound; return function (request, response) { if (!/^\//.test(request.pathInfo)) { return notFound(request, response); } var path = request.pathInfo.slice(1); var parts = path.split("/"); var part = decodeURIComponent(parts.shift()); if (Object.has(paths, part)) { request.scriptName = request.scriptName + part + "/"; request.pathInfo = path.slice(part.length); return Object.get(paths, part)(request, response); } return notFound(request, response); }; }; /** * Returns the response of the first application that returns a * non-404 response status. * * @param {Array * App} apps a cascade of applications to try * successively until one of them returns a non-404 status. * @returns {App} */ exports.FirstFound = function (cascade) { return function (request, response) { var i = 0, ii = cascade.length; function next() { var response = cascade[i++](request, response); if (i < ii) { return Q.when(response, function (response) { if (response.status === 404) { return next(); } else { return response; } }); } else { return response; } } return next(); }; }; |