Skip to content

Commit

Permalink
Added support for mounting paths using the typical REST style syntax …
Browse files Browse the repository at this point in the history
…with no trailing slash.
  • Loading branch information
oravecz authored and hns committed Aug 28, 2012
1 parent 4c6d2ce commit 888d637
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
10 changes: 8 additions & 2 deletions lib/middleware/mount.js
Expand Up @@ -9,6 +9,11 @@
* that will be matched against the URI path and `Host` header of incoming requests.
* _Note that virtual host based mounting has not been tested so far._
*
* The `mount` method accepts an optional third boolean `noRedirect` argument.
* If set to `true` it will disable redirecting GET requests to the mount base
* URL without a trailing slash to the same URL with trailing slash. By default,
* mount middleware will send a redirect to the mount URL with trailing slash.
*
* Mounting one application within another causes the `scriptName` and `pathInfo`
* properties in the request object to be adjusted so that the mounted application
* receives the same pathInfo as if it was the main application. This means
Expand Down Expand Up @@ -39,7 +44,7 @@ exports.middleware = function Mount(next, app) {
var mounts = [];

// define mount() method on application object
app.mount = function(spec, target) {
app.mount = function(spec, target, noRedirect) {
if (typeof spec === "string") {
spec = {path: spec};
} else if (!spec) {
Expand Down Expand Up @@ -75,6 +80,7 @@ exports.middleware = function Mount(next, app) {
},
path: spec.path,
canonicalPath: spec.canonicalPath,
redirect: !noRedirect,
app: resolved
});
mounts.sort(mostSpecificPathFirst);
Expand Down Expand Up @@ -104,7 +110,7 @@ exports.middleware = function Mount(next, app) {
if (mount.match(req)) {

// if trailing slash is missing redirect to canonical path
if (req.pathInfo === mount.path && req.method === "GET") {
if (mount.redirect && req.pathInfo === mount.path && req.method === "GET") {
var location = req.scriptName + mount.canonicalPath;
if (req.queryString) location += "?" + req.queryString;
return {
Expand Down
48 changes: 48 additions & 0 deletions test/stick_test.js
Expand Up @@ -67,6 +67,54 @@ exports.testMount = function() {
testMount(app);
};

/**
* The default behavior of mount.js middleware will issue a 303 redirect if the
* user enters a mount path which does not end with a slash on a GET request.
* The redirect returns the browser to the same path, but with a trailing slash.
* Not very nice for performance or style when using REST urls.
*/
exports.testMountRedirect = function() {
var response;

var app = new Application();
app.configure(mount);

app.mount("/", function() { return "root" });
app.mount("/foo", function() { return "foo" });
app.mount("/foo/bar", function() { return "foo/bar" });

// These URLs should return a 303 response using the default URL treatment
response = app({headers: {}, method: "GET", env: {}, scriptName: "", pathInfo: ""});
assert.strictEqual(response.status, 303);
assert.strictEqual(response.headers.Location, "/");
response = app({headers: {}, method: "GET", env: {}, scriptName: "", pathInfo: "/foo"});
assert.strictEqual(response.status, 303);
assert.strictEqual(response.headers.Location, "/foo/");
response = app({headers: {}, method: "GET", env: {}, scriptName: "", pathInfo: "/foo/bar"});
assert.strictEqual(response.status, 303);
assert.strictEqual(response.headers.Location, "/foo/bar/");
};

/**
* When using the mount command, the developer can choose to use REST-style URLs
* without a redirect and without a trailing slash on the end of the URL.
*/
exports.testMountNoRedirect = function() {
var response;

var app = new Application();
app.configure(mount);

app.mount("/", function() { return "root" }, true);
app.mount("/foo", function() { return "foo" }, true);
app.mount("/foo/bar", function() { return "foo/bar" }, true);

// Using REST urls, these requests should return the expected content
assert.equal(app({headers: {}, env: {}, method: "GET", pathInfo: ""}), "root");
assert.equal(app({headers: {}, env: {}, method: "GET", pathInfo: "/foo"}), "foo");
assert.equal(app({headers: {}, env: {}, method: "GET", pathInfo: "/foo/bar"}), "foo/bar");
};

exports.testMountSort = function() {
var app = new Application();
app.configure(mount);
Expand Down

0 comments on commit 888d637

Please sign in to comment.