Skip to content
Browse files

refactor route validation, always use arrays for route.method

  • Loading branch information...
1 parent 3e40db8 commit 4963776d2313d406282bbc6c0c3331d3d9d5c89b @cloudhead committed Feb 1, 2011
Showing with 87 additions and 95 deletions.
  1. +87 −95 lib/journey.js
View
182 lib/journey.js
@@ -71,24 +71,24 @@ journey.map = function (context) {
var args = Array.prototype.slice.call(arguments),
map = (typeof(args[args.length - 1]) === 'function') && args.pop(),
filter = args.pop() || context.options.filter;
-
+
this.required.push(filter);
map.call(this, this);
this.required.pop();
},
-
+
get: function (pattern, opts) { return this.route('GET', pattern, opts) },
put: function (pattern, opts) { return this.route('PUT', pattern, opts) },
post: function (pattern, opts) { return this.route('POST', pattern, opts) },
del: function (pattern, opts) { return this.route('DELETE', pattern, opts) },
route: function (/* variable arguments */) {
- var that = this, route,
+ var that = this, route,
args = Array.prototype.slice.call(arguments).filter(function (a) { return a }),
// Defaults
pattern = this.paths.length ? '' : /.*/,
ignoreCase = false,
- method = journey.Router.methods,
+ method = journey.Router.methods.slice(0),
constraints = [],
extension = context.options.extension ? '(?:' + context.options.extension + ')?' : '';
@@ -121,10 +121,10 @@ journey.map = function (context) {
extension;
pattern += context.options.strictUrls ? '$' : '\\/?$'; // Add optional trailing slash if requested
pattern = new(RegExp)(pattern, ignoreCase ? 'i' : '');
-
+
context.routes.push(route = {
pattern: pattern,
- method: method,
+ method: Array.isArray(method) ? method : [method],
constraints: constraints
});
@@ -188,7 +188,7 @@ journey.Router.prototype = {
if (callback) { callback(outcome) }
else { promise.emit("success", outcome) }
- promise.emit("log", {
+ promise.emit("log", {
date: new(Date)(),
method: request.method,
href: request.url.href,
@@ -200,93 +200,85 @@ journey.Router.prototype = {
},
constraints: [],
-
- resolve: function (request, body, dispatcher) {
- var that = this, allowedMethods = [];
- var validateRoute = function (route, cb) {
- // Match the pattern with the url
- var match = (function (pattern) {
- var path = request.url.pathname;
+ validateRoute: function (route, request, body, allowedMethods, cb) {
+ // Match the pattern with the url
+ var match = (function (pattern) {
+ var path = request.url.pathname;
if (! path) { return new(BadRequest) }
return (path.length > 1 ? path.slice(1) : path).match(pattern);
})(route.pattern);
- //
- // Return here if no match to avoid potentially expensive
- // async constraint operations.
- //
- if (!Array.isArray(match)) {
- return match === null ? cb(null, false) : cb(match);
- }
-
- //
- // Run through the specified constraints,
- // asynchronously making sure everything passes.
- //
- (function checkConstraints(constraints) {
- var constraint = constraints.shift();
-
- if (constraint) {
- // If the constraint is a function then expect it to have a method signature:
- // asyncConstraint(request, body, callback);
- constraint(request, body, function (err) {
- if (err) return cb(err);
- checkConstraints(constraints);
+ //
+ // Return here if no match to avoid potentially expensive
+ // async constraint operations.
+ //
+ if (!Array.isArray(match)) {
+ return match === null ? cb(null, false) : cb(match);
+ }
+
+ //
+ // Run through the specified constraints,
+ // asynchronously making sure everything passes.
+ //
+ (function checkConstraints(constraints) {
+ var constraint = constraints.shift();
+
+ if (constraint) {
+ // If the constraint is a function then expect it to have a method signature:
+ // asyncConstraint(request, body, callback);
+ constraint(request, body, function (err) {
+ if (err) return cb(err);
+ checkConstraints(constraints);
+ });
+ } else {
+ // If there is no handler for this route, return a new NotImplemented exception
+ if (! ('handler' in route)) { return cb(new(journey.NotImplemented)("unbound route")) }
+
+ // Otherwise, validate the route method, and return accordingly
+ if ((route.method.indexOf(request.method) !== -1) || !route.method) {
+ return cb(null, function (res, params) {
+ var args = [];
+ args.push(res);
+ args.push.apply(args, match.slice(1).map(function (m) {
+ return /^\d+$/.test(m) ? parseInt(m) : m;
+ }));
+ args.push(params);
+ return route.handler.apply(this, args);
});
} else {
- // If there is no handler for this route, return a new NotImplemented exception
- if (! ('handler' in route)) { return cb(new(NotImplemented)("unbound route")) }
-
- // Otherwise, validate the route method, and return accordingly
- if ((Array.isArray(route.method) && route.method.indexOf(request.method) !== -1) ||
- (route.method === request.method) || !route.method) {
- return cb(null, function (res, params) {
- var args = [];
- args.push(res);
- args.push.apply(args, match.slice(1).map(function (m) {
- return /^\d+$/.test(m) ? parseInt(m) : m;
- }));
- args.push(params);
- return route.handler.apply(this, args);
- });
- } else {
- if (allowedMethods.indexOf(route.method) === -1) {
- allowedMethods.push(route.method);
+ for (var i = 0; i < route.method.length; i++) {
+ if (allowedMethods.indexOf(route.method[i]) === -1) {
+ allowedMethods.push(route.method[i]);
}
- return cb(null, false);
}
+ return cb(null, false);
}
- })(route.constraints.slice(0));
- };
+ }
+ })(route.constraints.slice(0));
+ },
+ resolve: function (request, body, dispatcher) {
+ var that = this, allowedMethods = [];
//
// Return the first matching route
//
(function find(routes, callback) {
var route = routes.shift();
- if (route) {
- validateRoute(route, function (err, found) {
- if (err) { callback(err) }
- else if (found) { callback(null, found) }
+ if (route) { // While there are still routes to process
+ that.validateRoute(route, request, body, allowedMethods, function (err, found, method) {
+ if (err) { dispatcher(err) }
+ else if (found) { dispatcher(null, found) }
else { find(routes, callback) }
});
- } else { // End
- callback(null, false);
- }
- })(this.routes.slice(0), function (err, found) {
- if (err) {
- dispatcher(err);
- } else if (found) {
- dispatcher(null, found);
} else if (allowedMethods.length) {
dispatcher(new(journey.MethodNotAllowed)(allowedMethods.join(',')));
} else {
dispatcher(null, false);
}
- });
+ })(this.routes.slice(0));
},
verifyHeaders: function (request, respond) {
@@ -322,34 +314,34 @@ journey.Router.prototype = {
status: err.status,
body: JSON.stringify(err.body)
});
+ } else {
+ throw err;
+ }
+ }
+
+ route = that.draw(request, respond);
+
+ if (resolved) {
+ if (body) {
+ parser = /^application\/json/.test(
+ request.headers["content-type"]
+ ) ? JSON.parse : querystring.parse;
+
+ try {
+ body = parser(body);
+ } catch (e) {
+ return respond(new(journey.BadRequest)("malformed data"));
+ }
+
+ // If the body is an Array, we want to return params as an array,
+ // else, an object. The `mixin` function will preserve the type
+ // of its first parameter.
+ params = Array.isArray(body) ? mixin(body, params) : mixin(params, body);
+ }
+ return route.go(resolved, params);
} else {
- throw err;
+ return respond(new(journey.NotFound)("request not found"));
}
- }
-
- route = that.draw(request, respond);
-
- if (resolved) {
- if (body) {
- parser = /^application\/json/.test(
- request.headers["content-type"]
- ) ? JSON.parse : querystring.parse;
-
- try {
- body = parser(body);
- } catch (e) {
- return respond(new(BadRequest)("malformed data"));
- }
-
- // If the body is an Array, we want to return params as an array,
- // else, an object. The `mixin` function will preserve the type
- // of its first parameter.
- params = Array.isArray(body) ? mixin(body, params) : mixin(params, body);
- }
- return route.go(resolved, params);
- } else {
- return respond(new(NotFound)("request not found"));
- }
});
},

0 comments on commit 4963776

Please sign in to comment.
Something went wrong with that request. Please try again.