serve-static
Advanced tools
Comparing version 1.9.3 to 1.10.0
@@ -0,1 +1,26 @@ | ||
1.10.0 / 2015-06-17 | ||
=================== | ||
* Add `fallthrough` option | ||
- Allows declaring this middleware is the final destination | ||
- Provides better integration with Express patterns | ||
* Fix reading options from options prototype | ||
* Improve the default redirect response headers | ||
* deps: escape-html@1.0.2 | ||
* deps: send@0.13.0 | ||
- Allow Node.js HTTP server to set `Date` response header | ||
- Fix incorrectly removing `Content-Location` on 304 response | ||
- Improve the default redirect response headers | ||
- Send appropriate headers on default error response | ||
- Use `http-errors` for standard emitted errors | ||
- Use `statuses` instead of `http` module for status messages | ||
- deps: escape-html@1.0.2 | ||
- deps: etag@~1.7.0 | ||
- deps: fresh@0.3.0 | ||
- deps: on-finished@~2.3.0 | ||
- perf: enable strict mode | ||
- perf: remove unnecessary array allocations | ||
* perf: enable strict mode | ||
* perf: remove argument reassignment | ||
1.9.3 / 2015-05-14 | ||
@@ -2,0 +27,0 @@ ================== |
173
index.js
@@ -5,25 +5,35 @@ /*! | ||
* Copyright(c) 2011 TJ Holowaychuk | ||
* Copyright(c) 2014 Douglas Christopher Wilson | ||
* Copyright(c) 2014-2015 Douglas Christopher Wilson | ||
* MIT Licensed | ||
*/ | ||
'use strict' | ||
/** | ||
* Module dependencies. | ||
* @private | ||
*/ | ||
var escapeHtml = require('escape-html'); | ||
var merge = require('utils-merge'); | ||
var parseurl = require('parseurl'); | ||
var resolve = require('path').resolve; | ||
var send = require('send'); | ||
var url = require('url'); | ||
var escapeHtml = require('escape-html') | ||
var parseUrl = require('parseurl') | ||
var resolve = require('path').resolve | ||
var send = require('send') | ||
var url = require('url') | ||
/** | ||
* @param {String} root | ||
* @param {Object} options | ||
* @return {Function} | ||
* @api public | ||
* Module exports. | ||
* @public | ||
*/ | ||
exports = module.exports = function serveStatic(root, options) { | ||
module.exports = serveStatic | ||
module.exports.mime = send.mime | ||
/** | ||
* @param {string} root | ||
* @param {object} [options] | ||
* @return {function} | ||
* @public | ||
*/ | ||
function serveStatic(root, options) { | ||
if (!root) { | ||
@@ -38,13 +48,12 @@ throw new TypeError('root path required') | ||
// copy options object | ||
options = merge({}, options) | ||
var opts = Object.create(options || null) | ||
// resolve root to absolute | ||
root = resolve(root) | ||
// fall-though | ||
var fallthrough = opts.fallthrough !== false | ||
// default redirect | ||
var redirect = options.redirect !== false | ||
var redirect = opts.redirect !== false | ||
// headers listener | ||
var setHeaders = options.setHeaders | ||
delete options.setHeaders | ||
var setHeaders = opts.setHeaders | ||
@@ -56,17 +65,30 @@ if (setHeaders && typeof setHeaders !== 'function') { | ||
// setup options for send | ||
options.maxage = options.maxage || options.maxAge || 0 | ||
options.root = root | ||
opts.maxage = opts.maxage || opts.maxAge || 0 | ||
opts.root = resolve(root) | ||
// construct directory listener | ||
var onDirectory = redirect | ||
? createRedirectDirectoryListener() | ||
: createNotFoundDirectoryListener() | ||
return function serveStatic(req, res, next) { | ||
if (req.method !== 'GET' && req.method !== 'HEAD') { | ||
return next() | ||
if (fallthrough) { | ||
return next() | ||
} | ||
// method not allowed | ||
res.statusCode = 405 | ||
res.setHeader('Allow', 'GET, HEAD') | ||
res.setHeader('Content-Length', '0') | ||
res.end() | ||
return | ||
} | ||
var opts = merge({}, options) | ||
var originalUrl = parseurl.original(req) | ||
var path = parseurl(req).pathname | ||
var hasTrailingSlash = originalUrl.pathname[originalUrl.pathname.length - 1] === '/' | ||
var forwardError = !fallthrough | ||
var originalUrl = parseUrl.original(req) | ||
var path = parseUrl(req).pathname | ||
if (path === '/' && !hasTrailingSlash) { | ||
// make sure redirect occurs at mount | ||
// make sure redirect occurs at mount | ||
if (path === '/' && originalUrl.pathname.substr(-1) !== '/') { | ||
path = '' | ||
@@ -78,27 +100,5 @@ } | ||
if (redirect) { | ||
// redirect relative to originalUrl | ||
stream.on('directory', function redirect() { | ||
if (hasTrailingSlash) { | ||
return next() | ||
} | ||
// add directory handler | ||
stream.on('directory', onDirectory) | ||
// append trailing slash | ||
originalUrl.path = null | ||
originalUrl.pathname = collapseLeadingSlashes(originalUrl.pathname + '/') | ||
// reformat the URL | ||
var target = url.format(originalUrl) | ||
// send redirect response | ||
res.statusCode = 303 | ||
res.setHeader('Content-Type', 'text/html; charset=utf-8') | ||
res.setHeader('Location', target) | ||
res.end('Redirecting to <a href="' + escapeHtml(target) + '">' + escapeHtml(target) + '</a>\n') | ||
}) | ||
} else { | ||
// forward to next middleware on directory | ||
stream.on('directory', next) | ||
} | ||
// add headers listener | ||
@@ -109,5 +109,18 @@ if (setHeaders) { | ||
// forward non-404 errors | ||
// add file listener for fallthrough | ||
if (fallthrough) { | ||
stream.on('file', function onFile() { | ||
// once file is determined, always forward error | ||
forwardError = true | ||
}) | ||
} | ||
// forward errors | ||
stream.on('error', function error(err) { | ||
next(err.status === 404 ? null : err) | ||
if (forwardError || !(err.statusCode < 500)) { | ||
next(err) | ||
return | ||
} | ||
next() | ||
}) | ||
@@ -121,11 +134,2 @@ | ||
/** | ||
* Expose mime module. | ||
* | ||
* If you wish to extend the mime table use this | ||
* reference to the "mime" module in the npm registry. | ||
*/ | ||
exports.mime = send.mime | ||
/** | ||
* Collapse all leading slashes into a single slash | ||
@@ -145,1 +149,46 @@ * @private | ||
} | ||
/** | ||
* Create a directory listener that just 404s. | ||
* @private | ||
*/ | ||
function createNotFoundDirectoryListener() { | ||
return function notFound() { | ||
this.error(404) | ||
} | ||
} | ||
/** | ||
* Create a directory listener that performs a redirect. | ||
* @private | ||
*/ | ||
function createRedirectDirectoryListener() { | ||
return function redirect() { | ||
if (this.hasTrailingSlash()) { | ||
this.error(404) | ||
return | ||
} | ||
// get original URL | ||
var originalUrl = parseUrl.original(this.req) | ||
// append trailing slash | ||
originalUrl.path = null | ||
originalUrl.pathname = collapseLeadingSlashes(originalUrl.pathname + '/') | ||
// reformat the URL | ||
var loc = url.format(originalUrl) | ||
var msg = 'Redirecting to <a href="' + escapeHtml(loc) + '">' + escapeHtml(loc) + '</a>\n' | ||
var res = this.res | ||
// send redirect response | ||
res.statusCode = 303 | ||
res.setHeader('Content-Type', 'text/html; charset=UTF-8') | ||
res.setHeader('Content-Length', Buffer.byteLength(msg)) | ||
res.setHeader('X-Content-Type-Options', 'nosniff') | ||
res.setHeader('Location', loc) | ||
res.end(msg) | ||
} | ||
} |
{ | ||
"name": "serve-static", | ||
"description": "Serve static files", | ||
"version": "1.9.3", | ||
"version": "1.10.0", | ||
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>", | ||
@@ -9,6 +9,5 @@ "license": "MIT", | ||
"dependencies": { | ||
"escape-html": "1.0.1", | ||
"escape-html": "1.0.2", | ||
"parseurl": "~1.3.0", | ||
"send": "0.12.3", | ||
"utils-merge": "1.0.0" | ||
"send": "0.13.0" | ||
}, | ||
@@ -15,0 +14,0 @@ "devDependencies": { |
@@ -44,4 +44,4 @@ # serve-static | ||
- `'allow'` No special treatment for dotfiles. | ||
- `'deny'` Send a 403 for any request for a dotfile. | ||
- `'ignore'` Pretend like the dotfile does not exist and call `next()`. | ||
- `'deny'` Deny a request for a dotfile and 403/`next()`. | ||
- `'ignore'` Pretend like the dotfile does not exist and 404/`next()`. | ||
@@ -60,2 +60,21 @@ ##### etag | ||
##### fallthrough | ||
Set the middleware to have client errors fall-through as just unhandled | ||
requests, otherwise forward a client error. The difference is that client | ||
errors like a bad request or a request to a non-existent file will cause | ||
this middleware to simply `next()` to your next middleware when this value | ||
is `true`. When this value is `false`, these errors (even 404s), will invoke | ||
`next(err)`. | ||
Typically `true` is desired such that multiple physical directories can be | ||
mapped to the same web address or for routes to fill in non-existent files. | ||
The value `false` can be used if this middleware is mounted at a path that | ||
is designed to be strictly a single file system directory, which allows for | ||
short-circuiting 404s for less overhead. This middleware will also reply to | ||
all methods. | ||
The default value is `true`. | ||
##### index | ||
@@ -62,0 +81,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18665
3
151
236
+ Addedee-first@1.1.1(transitive)
+ Addedescape-html@1.0.2(transitive)
+ Addedetag@1.7.0(transitive)
+ Addedfresh@0.3.0(transitive)
+ Addedhttp-errors@1.3.1(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedon-finished@2.3.0(transitive)
+ Addedsend@0.13.0(transitive)
+ Addedstatuses@1.2.1(transitive)
- Removedutils-merge@1.0.0
- Removedcrc@3.2.1(transitive)
- Removedee-first@1.1.0(transitive)
- Removedescape-html@1.0.1(transitive)
- Removedetag@1.6.0(transitive)
- Removedfresh@0.2.4(transitive)
- Removedon-finished@2.2.1(transitive)
- Removedsend@0.12.3(transitive)
- Removedutils-merge@1.0.0(transitive)
Updatedescape-html@1.0.2
Updatedsend@0.13.0