diff --git a/README.md b/README.md index 056e650d4..cb389d92f 100755 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ infrastructure. The framework supports a powerful plugin architecture for pain-f For the latest updates and release information follow [@hapijs](https://twitter.com/hapijs) on twitter. -Current version: **1.7.x** +Current version: **1.8.x** Node version: **0.10** required diff --git a/docs/Reference.md b/docs/Reference.md index aaa370749..399d6d49a 100755 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -1,4 +1,4 @@ -# 1.7.x API Reference +# 1.8.x API Reference - [`Hapi.Server`](#hapiserver) - [`new Server([host], [port], [options])`](#new-serverhost-port-options) @@ -357,6 +357,8 @@ The following options are available when adding a route: - `listing` - optional boolean, determines if directory listing is generated when a directory is requested without an index document. Defaults to `false`. - `showHidden` - optional boolean, determines if hidden files will be shown and served. Defaults to `false`. + - `redirectToSlash` - optional boolean, determines if requests for a directory without a trailing slash are redirected to the same path with + the missing slash. Useful for ensuring relative links inside the response are resolved correctly.

- `proxy` - generates a reverse proxy handler with the following options: - `host` - the upstream service host to proxy requests to. The same path on the client request will be used as the path on the host. diff --git a/examples/directory/server.js b/examples/directory/server.js index b0599297d..36dbaa015 100755 --- a/examples/directory/server.js +++ b/examples/directory/server.js @@ -16,15 +16,15 @@ internals.serveImages = function (request) { internals.main = function () { - var http = new Hapi.Server(8080); + var server = new Hapi.Server(8000, { files: { relativeTo: 'routes' } }); - http.route([ + server.route([ { method: 'GET', path: '/img/{path}', handler: { directory: { path: internals.serveImages } } }, - { method: 'GET', path: '/files/{path*}', handler: { directory: { path: '../../', listing: true } } }, + { method: 'GET', path: '/files/{path*}', handler: { directory: { path: '../../', listing: true, redirectToSlash: true } } }, { method: 'GET', path: '/{path?}', handler: { directory: { path: './' } } } ]); - http.start(); + server.start(); }; diff --git a/lib/files.js b/lib/files.js index 639ccb473..fee75fc07 100755 --- a/lib/files.js +++ b/lib/files.js @@ -118,7 +118,8 @@ exports.directoryHandler = function (route, options) { selection: selection, index: settings.index, listing: settings.listing, - showHidden: settings.showHidden + showHidden: settings.showHidden, + redirectToSlash: settings.redirectToSlash }); return request.reply(response); diff --git a/lib/response/directory.js b/lib/response/directory.js index 3761b7423..c81c60d1b 100755 --- a/lib/response/directory.js +++ b/lib/response/directory.js @@ -4,6 +4,7 @@ var Fs = require('fs'); var Path = require('path'); var Async = require('async'); var Cacheable = require('./cacheable'); +var Redirection = require('./redirection'); var Boom = require('boom'); var File = require('./file'); var Utils = require('../utils'); @@ -31,6 +32,9 @@ exports = module.exports = internals.Directory = function (paths, options) { this._index = options.index === false ? false : true; // Defaults to true this._listing = !!options.listing; // Defaults to false this._showHidden = !!options.showHidden; // Defaults to false + this._redirectToSlash = !!options.redirectToSlash; // Defaults to false + + this._hasTrailingSlash = this._resource && (this._resource[this._resource.length - 1] === '/'); }; Utils.inherits(internals.Directory, Cacheable); @@ -99,6 +103,12 @@ internals.Directory.prototype._preparePath = function (path, request, callback) return callback(Boom.forbidden()); } + if (self._redirectToSlash && + !self._hasTrailingSlash) { + + return callback(new Redirection(self._resource + '/')); + } + if (!self._index) { return self._generateListing(path, request, callback); } @@ -141,19 +151,17 @@ internals.Directory.prototype._generateListing = function (path, request, callba return callback(Boom.internal('Error accessing directory')); } - var separator = ''; var display = Utils.escapeHtml(self._resource); var html = '' + display + '

Directory: ' + display + '