express
4.17.14.18.2
~
Modified (10 files)
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,8 +1,8 @@
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
- "version": "4.17.1",
+ "version": "4.18.2",
"author": "TJ Holowaychuk <[email protected]>",
"contributors": [
"Aaron Heckmann <[email protected]>",
"Ciaran Jessup <[email protected]>",
@@ -19,64 +19,65 @@
"express",
"framework",
"sinatra",
"web",
+ "http",
"rest",
"restful",
"router",
"app",
"api"
],
"dependencies": {
- "accepts": "~1.3.7",
+ "accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.19.0",
- "content-disposition": "0.5.3",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.4.0",
+ "cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
- "depd": "~1.1.2",
+ "depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "~1.1.2",
+ "finalhandler": "1.2.0",
"fresh": "0.5.2",
+ "http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.5",
- "qs": "6.7.0",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
"range-parser": "~1.2.1",
- "safe-buffer": "5.1.2",
- "send": "0.17.1",
- "serve-static": "1.14.1",
- "setprototypeof": "1.1.1",
- "statuses": "~1.5.0",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"devDependencies": {
"after": "0.8.2",
- "connect-redis": "3.4.1",
- "cookie-parser": "~1.4.4",
- "cookie-session": "1.3.3",
- "ejs": "2.6.1",
- "eslint": "2.13.1",
- "express-session": "1.16.1",
- "hbs": "4.0.4",
- "istanbul": "0.4.5",
- "marked": "0.6.2",
+ "connect-redis": "3.4.2",
+ "cookie-parser": "1.4.6",
+ "cookie-session": "2.0.0",
+ "ejs": "3.1.8",
+ "eslint": "8.24.0",
+ "express-session": "1.17.2",
+ "hbs": "4.2.0",
+ "marked": "0.7.0",
"method-override": "3.0.0",
- "mocha": "5.2.0",
- "morgan": "1.9.1",
- "multiparty": "4.2.1",
+ "mocha": "10.0.0",
+ "morgan": "1.10.0",
+ "multiparty": "4.2.3",
+ "nyc": "15.1.0",
"pbkdf2-password": "1.2.1",
- "should": "13.2.3",
- "supertest": "3.3.0",
+ "supertest": "6.3.0",
"vhost": "~3.0.2"
},
"engines": {
"node": ">= 0.10.0"
@@ -90,9 +91,9 @@
],
"scripts": {
"lint": "eslint .",
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
- "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
- "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
+ "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
+ "test-cov": "nyc --reporter=html --reporter=text npm test",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
}
} Index: package/History.md
===================================================================
--- package/History.md
+++ package/History.md
@@ -1,4 +1,115 @@
+4.18.2 / 2022-10-08
+===================
+
+ * Fix regression routing a large stack in a single route
+ * deps: [email protected]
+ - deps: [email protected]
+ - perf: remove unnecessary object clone
+ * deps: [email protected]
+
+4.18.1 / 2022-04-29
+===================
+
+ * Fix hanging on large stack of sync routes
+
+4.18.0 / 2022-04-25
+===================
+
+ * Add "root" option to `res.download`
+ * Allow `options` without `filename` in `res.download`
+ * Deprecate string and non-integer arguments to `res.status`
+ * Fix behavior of `null`/`undefined` as `maxAge` in `res.cookie`
+ * Fix handling very large stacks of sync middleware
+ * Ignore `Object.prototype` values in settings through `app.set`/`app.get`
+ * Invoke `default` with same arguments as types in `res.format`
+ * Support proper 205 responses using `res.send`
+ * Use `http-errors` for `res.format` error
+ * deps: [email protected]
+ - Fix error message for json parse whitespace in `strict`
+ - Fix internal error when inflated body exceeds limit
+ - Prevent loss of async hooks context
+ - Prevent hanging when request already read
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ - Add `priority` option
+ - Fix `expires` option to reject invalid dates
+ * deps: [email protected]
+ - Replace internal `eval` usage with `Function` constructor
+ - Use instance methods on `process` to check for listeners
+ * deps: [email protected]
+ - Remove set content headers that break response
+ - deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ - Prevent loss of async hooks context
+ * deps: [email protected]
+ * deps: [email protected]
+ - Fix emitted 416 error missing headers property
+ - Limit the headers removed for 304 response
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ - Remove code 306
+ - Rename `425 Unordered Collection` to standard `425 Too Early`
+
+4.17.3 / 2022-02-16
+===================
+
+ * deps: accepts@~1.3.8
+ - deps: mime-types@~2.1.34
+ - deps: [email protected]
+ * deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ * deps: [email protected]
+ * Fix handling of `__proto__` keys
+ * pref: remove unnecessary regexp for trust proxy
+
+4.17.2 / 2021-12-16
+===================
+
+ * Fix handling of `undefined` in `res.jsonp`
+ * Fix handling of `undefined` when `"json escape"` is enabled
+ * Fix incorrect middleware execution with unanchored `RegExp`s
+ * Fix `res.jsonp(obj, status)` deprecation message
+ * Fix typo in `res.is` JSDoc
+ * deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - deps: type-is@~1.6.18
+ * deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ - Fix `maxAge` option to reject invalid values
+ * deps: proxy-addr@~2.0.7
+ - Use `req.socket` over deprecated `req.connection`
+ - deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+ * deps: [email protected]
+ * deps: [email protected]
+ - deps: [email protected]
+ - deps: [email protected]
+ - pref: ignore empty http tokens
+ * deps: [email protected]
+ - deps: [email protected]
+ * deps: [email protected]
+
4.17.1 / 2019-05-25
===================
* Revert "Improve error message for `null`/`undefined` to `res.status`" Index: package/Readme.md
===================================================================
--- package/Readme.md
+++ package/Readme.md
@@ -1,13 +1,11 @@
[](http://expressjs.com/)
- Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
+ Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org).
- [![NPM Version][npm-image]][npm-url]
- [![NPM Downloads][downloads-image]][downloads-url]
- [![Linux Build][travis-image]][travis-url]
- [![Windows Build][appveyor-image]][appveyor-url]
- [![Test Coverage][coveralls-image]][coveralls-url]
+ [![NPM Version][npm-version-image]][npm-url]
+ [![NPM Install Size][npm-install-size-image]][npm-install-size-url]
+ [![NPM Downloads][npm-downloads-image]][npm-downloads-url]
```js
const express = require('express')
const app = express()
@@ -26,12 +24,15 @@
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
Node.js 0.10 or higher is required.
+If this is a brand new project, make sure to create a `package.json` first with
+the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
+
Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
-```bash
+```console
$ npm install express
```
Follow [our installing guide](http://expressjs.com/en/starter/installing.html)
@@ -49,54 +50,50 @@
## Docs & Community
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
- * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
+ * [#express](https://web.libera.chat/#express) on [Libera Chat](https://libera.chat) IRC
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
* Visit the [Wiki](https://github.com/expressjs/express/wiki)
* [Google Group](https://groups.google.com/group/express-js) for discussion
* [Gitter](https://gitter.im/expressjs/express) for support and discussion
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).
-### Security Issues
-
-If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).
-
## Quick Start
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
-```bash
+```console
$ npm install -g express-generator@4
```
Create the app:
-```bash
+```console
$ express /tmp/foo && cd /tmp/foo
```
Install dependencies:
-```bash
+```console
$ npm install
```
Start the server:
-```bash
+```console
$ npm start
```
View the website at: http://localhost:3000
## Philosophy
The Express philosophy is to provide small, robust tooling for HTTP servers, making
- it a great solution for single page applications, web sites, hybrids, or public
+ it a great solution for single page applications, websites, hybrids, or public
HTTP APIs.
Express does not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
@@ -105,33 +102,45 @@
## Examples
To view the examples, clone the Express repo and install the dependencies:
-```bash
+```console
$ git clone git://github.com/expressjs/express.git --depth 1
$ cd express
$ npm install
```
Then run whichever example you want:
-```bash
+```console
$ node examples/content-negotiation
```
-## Tests
+## Contributing
- To run the test suite, first install the dependencies, then run `npm test`:
+ [![Linux Build][github-actions-ci-image]][github-actions-ci-url]
+ [![Windows Build][appveyor-image]][appveyor-url]
+ [![Test Coverage][coveralls-image]][coveralls-url]
-```bash
+The Express.js project welcomes all constructive contributions. Contributions take many forms,
+from code for bug fixes and enhancements, to additions and fixes to documentation, additional
+tests, triaging incoming pull requests and issues, and more!
+
+See the [Contributing Guide](Contributing.md) for more technical details on contributing.
+
+### Security Issues
+
+If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).
+
+### Running Tests
+
+To run the test suite, first install the dependencies, then run `npm test`:
+
+```console
$ npm install
$ npm test
```
-## Contributing
-
-[Contributing Guide](Contributing.md)
-
## People
The original author of Express is [TJ Holowaychuk](https://github.com/tj)
@@ -142,14 +151,16 @@
## License
[MIT](LICENSE)
-[npm-image]: https://img.shields.io/npm/v/express.svg
-[npm-url]: https://npmjs.org/package/express
-[downloads-image]: https://img.shields.io/npm/dm/express.svg
-[downloads-url]: https://npmjs.org/package/express
-[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux
-[travis-url]: https://travis-ci.org/expressjs/express
-[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows
+[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/express/master?label=windows
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
-[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg
+[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/express/master
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
+[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=linux
+[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml
+[npm-downloads-image]: https://badgen.net/npm/dm/express
+[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true
+[npm-install-size-image]: https://badgen.net/packagephobia/install/express
+[npm-install-size-url]: https://packagephobia.com/result?p=express
+[npm-url]: https://npmjs.org/package/express
+[npm-version-image]: https://badgen.net/npm/v/express Index: package/lib/application.js
===================================================================
--- package/lib/application.js
+++ package/lib/application.js
@@ -28,8 +28,15 @@
var flatten = require('array-flatten');
var merge = require('utils-merge');
var resolve = require('path').resolve;
var setPrototypeOf = require('setprototypeof')
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var hasOwnProperty = Object.prototype.hasOwnProperty
var slice = Array.prototype.slice;
/**
* Application prototype.
@@ -275,9 +282,9 @@
*
* In this case EJS provides a `.renderFile()` method with
* the same signature that Express expects: `(path, options, callback)`,
* though note that it aliases this method as `ejs.__express` internally
- * so if you're using ".ejs" extensions you dont need to do anything.
+ * so if you're using ".ejs" extensions you don't need to do anything.
*
* Some template engines do not follow this convention, the
* [Consolidate.js](https://github.com/tj/consolidate.js)
* library was created to map all of node's popular template
@@ -351,9 +358,19 @@
app.set = function set(setting, val) {
if (arguments.length === 1) {
// app.get(setting)
- return this.settings[setting];
+ var settings = this.settings
+
+ while (settings && settings !== Object.prototype) {
+ if (hasOwnProperty.call(settings, setting)) {
+ return settings[setting]
+ }
+
+ settings = Object.getPrototypeOf(settings)
+ }
+
+ return undefined
}
debug('set "%s" to %o', setting, val); Index: package/lib/request.js
===================================================================
--- package/lib/request.js
+++ package/lib/request.js
@@ -250,9 +250,9 @@
};
/**
* Check if the incoming request contains the "Content-Type"
- * header field, and it contains the give mime `type`.
+ * header field, and it contains the given mime `type`.
*
* Examples:
*
* // With Content-Type: text/html; charset=utf-8 Index: package/lib/response.js
===================================================================
--- package/lib/response.js
+++ package/lib/response.js
@@ -13,8 +13,9 @@
*/
var Buffer = require('safe-buffer').Buffer
var contentDisposition = require('content-disposition');
+var createError = require('http-errors')
var deprecate = require('depd')('express');
var encodeUrl = require('encodeurl');
var escapeHtml = require('escape-html');
var http = require('http');
@@ -63,8 +64,11 @@
* @public
*/
res.status = function status(code) {
+ if ((typeof code === 'string' || Math.floor(code) !== code) && code > 99 && code < 1000) {
+ deprecate('res.status(' + JSON.stringify(code) + '): use res.status(' + Math.floor(code) + ') instead')
+ }
this.statusCode = code;
return this;
};
@@ -134,9 +138,9 @@
}
deprecate('res.send(status): Use res.sendStatus(status) instead');
this.statusCode = chunk;
- chunk = statuses[chunk]
+ chunk = statuses.message[chunk]
}
switch (typeof chunk) {
// string defaulting to html
@@ -212,8 +216,15 @@
this.removeHeader('Transfer-Encoding');
chunk = '';
}
+ // alter headers for 205
+ if (this.statusCode === 205) {
+ this.set('Content-Length', '0')
+ this.removeHeader('Transfer-Encoding')
+ chunk = ''
+ }
+
if (req.method === 'HEAD') {
// skip body for HEAD
this.end();
} else {
@@ -283,11 +294,11 @@
var val = obj;
// allow status / body
if (arguments.length === 2) {
- // res.json(body, status) backwards compat
+ // res.jsonp(body, status) backwards compat
if (typeof arguments[1] === 'number') {
- deprecate('res.jsonp(obj, status): Use res.status(status).json(obj) instead');
+ deprecate('res.jsonp(obj, status): Use res.status(status).jsonp(obj) instead');
this.statusCode = arguments[1];
} else {
deprecate('res.jsonp(status, obj): Use res.status(status).jsonp(obj) instead');
this.statusCode = arguments[0];
@@ -321,12 +332,17 @@
// restrict callback charset
callback = callback.replace(/[^\[\]\w$.]/g, '');
- // replace chars not allowed in JavaScript that are in JSON
- body = body
- .replace(/\u2028/g, '\\u2028')
- .replace(/\u2029/g, '\\u2029');
+ if (body === undefined) {
+ // empty argument
+ body = ''
+ } else if (typeof body === 'string') {
+ // replace chars not allowed in JavaScript that are in JSON
+ body = body
+ .replace(/\u2028/g, '\\u2028')
+ .replace(/\u2029/g, '\\u2029')
+ }
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
// the typeof check is just to reduce client error noise
body = '/**/ typeof ' + callback + ' === \'function\' && ' + callback + '(' + body + ');';
@@ -350,9 +366,9 @@
* @public
*/
res.sendStatus = function sendStatus(statusCode) {
- var body = statuses[statusCode] || String(statusCode)
+ var body = statuses.message[statusCode] || String(statusCode)
this.statusCode = statusCode;
this.type('txt');
@@ -363,9 +379,9 @@
* Transfer the file at the given `path`.
*
* Automatically sets the _Content-Type_ response header field.
* The callback `callback(err)` is invoked when the transfer is complete
- * or when an error occurs. Be sure to check `res.sentHeader`
+ * or when an error occurs. Be sure to check `res.headersSent`
* if you wish to attempt responding, as the header and some data
* may have already been transferred.
*
* Options:
@@ -445,9 +461,9 @@
* Transfer the file at the given `path`.
*
* Automatically sets the _Content-Type_ response header field.
* The callback `callback(err)` is invoked when the transfer is complete
- * or when an error occurs. Be sure to check `res.sentHeader`
+ * or when an error occurs. Be sure to check `res.headersSent`
* if you wish to attempt responding, as the header and some data
* may have already been transferred.
*
* Options:
@@ -518,9 +534,9 @@
*
* Optionally providing an alternate attachment `filename`,
* and optional callback `callback(err)`. The callback is invoked
* when the data transfer is complete, or when an error has
- * ocurred. Be sure to check `res.headersSent` if you plan to respond.
+ * occurred. Be sure to check `res.headersSent` if you plan to respond.
*
* Optionally providing an `options` object to use with `res.sendFile()`.
* This function will set the `Content-Disposition` header, overriding
* any `Content-Disposition` header passed as header options in order
@@ -545,8 +561,15 @@
done = options
opts = null
}
+ // support optional filename, where options may be in it's place
+ if (typeof filename === 'object' &&
+ (typeof options === 'function' || options === undefined)) {
+ name = null
+ opts = filename
+ }
+
// set Content-Disposition when file is sent
var headers = {
'Content-Disposition': contentDisposition(name || path)
};
@@ -566,9 +589,11 @@
opts = Object.create(opts)
opts.headers = headers
// Resolve the full path for sendFile
- var fullPath = resolve(path);
+ var fullPath = !opts.root
+ ? resolve(path)
+ : path
// send file
return this.sendFile(fullPath, opts, done)
};
@@ -622,9 +647,9 @@
* 'text/html': function(){
* res.send('<p>hey</p>');
* },
*
- * 'appliation/json': function(){
+ * 'application/json': function () {
* res.send({ message: 'hey' });
* }
* });
*
@@ -659,11 +684,10 @@
res.format = function(obj){
var req = this.req;
var next = req.next;
- var fn = obj.default;
- if (fn) delete obj.default;
- var keys = Object.keys(obj);
+ var keys = Object.keys(obj)
+ .filter(function (v) { return v !== 'default' })
var key = keys.length > 0
? req.accepts(keys)
: false;
@@ -672,15 +696,14 @@
if (key) {
this.set('Content-Type', normalizeType(key).value);
obj[key](req, this, next);
- } else if (fn) {
- fn();
+ } else if (obj.default) {
+ obj.default(req, this, next)
} else {
- var err = new Error('Not Acceptable');
- err.status = err.statusCode = 406;
- err.types = normalizeTypes(keys).map(function(o){ return o.value });
- next(err);
+ next(createError(406, {
+ types: normalizeTypes(keys).map(function (o) { return o.value })
+ }))
}
return this;
};
@@ -725,9 +748,9 @@
if (prev) {
// concat the new and prev vals
value = Array.isArray(prev) ? prev.concat(val)
: Array.isArray(val) ? [prev].concat(val)
- : [prev, val];
+ : [prev, val]
}
return this.set(field, value);
};
@@ -844,11 +867,15 @@
if (signed) {
val = 's:' + sign(val, secret);
}
- if ('maxAge' in opts) {
- opts.expires = new Date(Date.now() + opts.maxAge);
- opts.maxAge /= 1000;
+ if (opts.maxAge != null) {
+ var maxAge = opts.maxAge - 0
+
+ if (!isNaN(maxAge)) {
+ opts.expires = new Date(Date.now() + maxAge)
+ opts.maxAge = Math.floor(maxAge / 1000)
+ }
}
if (opts.path == null) {
opts.path = '/';
@@ -927,14 +954,14 @@
// Support text/{plain,html} by default
this.format({
text: function(){
- body = statuses[status] + '. Redirecting to ' + address
+ body = statuses.message[status] + '. Redirecting to ' + address
},
html: function(){
var u = escapeHtml(address);
- body = '<p>' + statuses[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>'
+ body = '<p>' + statuses.message[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>'
},
default: function(){
body = '';
@@ -1107,9 +1134,9 @@
* Stringify JSON, like JSON.stringify, but v8 optimized, with the
* ability to escape characters that can trigger HTML sniffing.
*
* @param {*} value
- * @param {function} replaces
+ * @param {function} replacer
* @param {number} spaces
* @param {boolean} escape
* @returns {string}
* @private
@@ -1121,9 +1148,9 @@
var json = replacer || spaces
? JSON.stringify(value, replacer, spaces)
: JSON.stringify(value);
- if (escape) {
+ if (escape && typeof json === 'string') {
json = json.replace(/[<>&]/g, function (c) {
switch (c.charCodeAt(0)) {
case 0x3c:
return '\\u003c' Index: package/lib/router/index.js
===================================================================
--- package/lib/router/index.js
+++ package/lib/router/index.js
@@ -107,10 +107,10 @@
var len = params.length;
var ret;
if (name[0] === ':') {
- deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead');
- name = name.substr(1);
+ deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.slice(1)) + ', fn) instead')
+ name = name.slice(1)
}
for (var i = 0; i < len; ++i) {
if (ret = params[i](name, fn)) {
@@ -141,8 +141,9 @@
var idx = 0;
var protohost = getProtohost(req.url) || ''
var removed = '';
var slashAdded = false;
+ var sync = 0
var paramcalled = {};
// store options for OPTIONS request
// only used if OPTIONS request
@@ -179,16 +180,16 @@
: err;
// remove added slash
if (slashAdded) {
- req.url = req.url.substr(1);
+ req.url = req.url.slice(1)
slashAdded = false;
}
// restore altered req.url
if (removed.length !== 0) {
req.baseUrl = parentUrl;
- req.url = protohost + removed + req.url.substr(protohost.length);
+ req.url = protohost + removed + req.url.slice(protohost.length)
removed = '';
}
// signal to exit router
@@ -202,8 +203,13 @@
setImmediate(done, layerError);
return;
}
+ // max sync stack
+ if (++sync > 100) {
+ return setImmediate(next, err)
+ }
+
// get pathname of request
var path = getPathname(req);
if (path == null) {
@@ -250,9 +256,8 @@
// don't even bother matching route
if (!has_method && method !== 'HEAD') {
match = false;
- continue;
}
}
// no match
@@ -273,30 +278,36 @@
// this should be done for the layer
self.process_params(layer, paramcalled, req, res, function (err) {
if (err) {
- return next(layerError || err);
+ next(layerError || err)
+ } else if (route) {
+ layer.handle_request(req, res, next)
+ } else {
+ trim_prefix(layer, layerError, layerPath, path)
}
- if (route) {
- return layer.handle_request(req, res, next);
- }
-
- trim_prefix(layer, layerError, layerPath, path);
+ sync = 0
});
}
function trim_prefix(layer, layerError, layerPath, path) {
if (layerPath.length !== 0) {
+ // Validate path is a prefix match
+ if (layerPath !== path.slice(0, layerPath.length)) {
+ next(layerError)
+ return
+ }
+
// Validate path breaks on a path separator
var c = path[layerPath.length]
if (c && c !== '/' && c !== '.') return next(layerError)
// Trim off the part of the url that matches the route
// middleware (.use stuff) needs to have the path stripped
debug('trim prefix (%s) from url %s', layerPath, req.url);
removed = layerPath;
- req.url = protohost + req.url.substr(protohost.length + removed.length);
+ req.url = protohost + req.url.slice(protohost.length + removed.length)
// Ensure leading slash
if (!protohost && req.url[0] !== '/') {
req.url = '/' + req.url;
@@ -540,12 +551,12 @@
var searchIndex = url.indexOf('?')
var pathLength = searchIndex !== -1
? searchIndex
: url.length
- var fqdnIndex = url.substr(0, pathLength).indexOf('://')
+ var fqdnIndex = url.slice(0, pathLength).indexOf('://')
return fqdnIndex !== -1
- ? url.substr(0, url.indexOf('/', 3 + fqdnIndex))
+ ? url.substring(0, url.indexOf('/', 3 + fqdnIndex))
: undefined
}
// get type for error message Index: package/lib/router/route.js
===================================================================
--- package/lib/router/route.js
+++ package/lib/router/route.js
@@ -97,8 +97,10 @@
Route.prototype.dispatch = function dispatch(req, res, done) {
var idx = 0;
var stack = this.stack;
+ var sync = 0
+
if (stack.length === 0) {
return done();
}
@@ -121,22 +123,29 @@
if (err && err === 'router') {
return done(err)
}
- var layer = stack[idx++];
- if (!layer) {
- return done(err);
+ // max sync stack
+ if (++sync > 100) {
+ return setImmediate(next, err)
}
- if (layer.method && layer.method !== method) {
- return next(err);
+ var layer = stack[idx++]
+
+ // end of layers
+ if (!layer) {
+ return done(err)
}
- if (err) {
+ if (layer.method && layer.method !== method) {
+ next(err)
+ } else if (err) {
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
+
+ sync = 0
}
};
/** Index: package/lib/utils.js
===================================================================
--- package/lib/utils.js
+++ package/lib/utils.js
@@ -119,8 +119,9 @@
* object with `.value`, `.quality` and `.params`.
* also includes `.originalIndex` for stable sorting
*
* @param {String} str
+ * @param {Number} index
* @return {Object}
* @api private
*/
@@ -156,18 +157,16 @@
}
switch (val) {
case true:
+ case 'weak':
fn = exports.wetag;
break;
case false:
break;
case 'strong':
fn = exports.etag;
break;
- case 'weak':
- fn = exports.wetag;
- break;
default:
throw new TypeError('unknown value for etag function: ' + val);
}
@@ -190,19 +189,17 @@
}
switch (val) {
case true:
+ case 'simple':
fn = querystring.parse;
break;
case false:
fn = newObject;
break;
case 'extended':
fn = parseExtendedQueryString;
break;
- case 'simple':
- fn = querystring.parse;
- break;
default:
throw new TypeError('unknown value for query parser function: ' + val);
}
@@ -231,9 +228,10 @@
}
if (typeof val === 'string') {
// Support comma-separated values
- val = val.split(/ *, */);
+ val = val.split(',')
+ .map(function (v) { return v.trim() })
}
return proxyaddr.compile(val || []);
} Index: package/lib/view.js
===================================================================
--- package/lib/view.js
+++ package/lib/view.js
@@ -73,9 +73,9 @@
}
if (!opts.engines[this.ext]) {
// load engine
- var mod = this.ext.substr(1)
+ var mod = this.ext.slice(1)
debug('require "%s"', mod)
// default engine export
var fn = require(mod).__express