Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 4.18 #4287

Merged
merged 31 commits into from
Apr 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
eb4c930
build: support Node.js 15.x
kkalavantavanich Dec 5, 2021
8bf0720
build: support Node.js 16.x
kkalavantavanich Dec 5, 2021
87279c0
Support proper 205 responses using res.send
tkesgar May 20, 2021
c17fe05
Ignore Object.prototype values in settings through app.set/app.get
EvanHahn Feb 3, 2022
4847d0e
Deprecate string and non-integer arguments to res.status
jonchurch Mar 21, 2020
0def9bb
Add "root" option to res.download
mmito Mar 11, 2022
dd69eed
deps: [email protected]
dougwilson Mar 25, 2022
c924206
deps: [email protected]
dougwilson Mar 25, 2022
f739b16
deps: [email protected]
dougwilson Mar 25, 2022
03dc367
Allow options without filename in res.download
dougwilson Mar 25, 2022
10b9b50
examples: use updated res.download in example
dougwilson Mar 25, 2022
9482b82
Invoke default with same arguments as types in res.format
shesek Mar 13, 2018
1cc8169
deps: [email protected]
UlisesGascon Feb 5, 2020
5855339
Fix behavior of null/undefined as "maxAge" in res.cookie
cjbarth Apr 18, 2019
a107702
Use http-errors for res.format error
dougwilson Mar 28, 2022
32c558d
deps: [email protected]
dougwilson Apr 3, 2022
1df7576
deps: [email protected]
dougwilson Apr 3, 2022
980d881
deps: [email protected]
3imed-jaberi Jul 3, 2020
2e2d78c
deps: [email protected]
dougwilson Apr 3, 2022
04da4aa
build: use [email protected] for Node.js 6.x
dougwilson Apr 7, 2022
1b2e097
tests: fix typo in description
Hashen110 Apr 7, 2022
99175c3
docs: fix typo in casing of HTTP
ghousemohamed Mar 26, 2022
ecaf67c
docs: remove Node Security Project from security policy
netcode Apr 11, 2022
b91c7ff
examples: use http-errors to create errors
dougwilson Apr 11, 2022
8880dda
examples: add missing html label associations
Hashen110 Apr 7, 2022
92c5ce5
deps: [email protected]
dougwilson Apr 12, 2022
708ac4c
Fix handling very large stacks of sync middleware
dougwilson Apr 14, 2022
fd8e45c
tests: mark stack overflow as long running
grisu48 Apr 8, 2022
11a209e
build: support Node.js 17.x
dougwilson Apr 21, 2022
29ea1b2
build: use 64-bit Node.js in AppVeyor
dougwilson Apr 21, 2022
158a170
build: support Node.js 18.x
dougwilson Apr 21, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ jobs:
- Node.js 12.x
- Node.js 13.x
- Node.js 14.x
- Node.js 15.x
- Node.js 16.x
- Node.js 17.x
- Node.js 18.x

include:
- name: Node.js 0.10
Expand Down Expand Up @@ -59,7 +63,7 @@ jobs:

- name: Node.js 6.x
node-version: "6.17"
npm-i: [email protected] [email protected] supertest@6.1.6
npm-i: [email protected] [email protected] supertest@3.4.2

- name: Node.js 7.x
node-version: "7.10"
Expand Down Expand Up @@ -90,6 +94,18 @@ jobs:
- name: Node.js 14.x
node-version: "14.19"

- name: Node.js 15.x
node-version: "15.14"

- name: Node.js 16.x
node-version: "16.14"

- name: Node.js 17.x
node-version: "17.9"

- name: Node.js 18.x
node-version: "18.0"

steps:
- uses: actions/checkout@v2

Expand Down
4 changes: 2 additions & 2 deletions Charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ also easily visible to outsiders.

## Section 1: Scope

Express is a http web server framework with a simple and expressive API
Express is a HTTP web server framework with a simple and expressive API
which is highly aligned with Node.js core. We aim to be the best in
class for writing performant, spec compliant, and powerful web servers
in Node.js. As one of the oldest and most popular web frameworks in
Expand All @@ -24,7 +24,7 @@ Express is made of many modules spread between three GitHub Orgs:
libraries
- [pillarjs](http://github.com/pillarjs/): Components which make up
Express but can also be used for other web frameworks
- [jshttp](http://github.com/jshttp/): Low level http libraries
- [jshttp](http://github.com/jshttp/): Low level HTTP libraries

### 1.2: Out-of-Scope

Expand Down
49 changes: 49 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
unreleased
==========

* 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
===================

Expand Down
3 changes: 1 addition & 2 deletions Security.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ endeavor to keep you informed of the progress towards a fix and full
announcement, and may ask for additional information or guidance.

Report security bugs in third-party modules to the person or team maintaining
the module. You can also report a vulnerability through the
[Node Security Project](https://nodesecurity.io/report).
the module.

## Disclosure Policy

Expand Down
10 changes: 7 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ environment:
- nodejs_version: "12.22"
- nodejs_version: "13.14"
- nodejs_version: "14.19"
- nodejs_version: "15.14"
- nodejs_version: "16.14"
- nodejs_version: "17.9"
- nodejs_version: "18.0"
cache:
- node_modules
install:
# Install Node.js
- ps: >-
try { Install-Product node $env:nodejs_version -ErrorAction Stop }
catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) }
catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) x64 }
# Configure npm
- ps: |
npm config set loglevel error
Expand Down Expand Up @@ -69,11 +73,11 @@ install:
- ps: |
# supertest for http calls
# - use 2.0.0 for Node.js < 4
# - use 3.4.2 for Node.js < 6
# - use 3.4.2 for Node.js < 7
# - use 6.1.6 for Node.js < 8
if ([int]$env:nodejs_version.split(".")[0] -lt 4) {
npm install --silent --save-dev [email protected]
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) {
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 7) {
npm install --silent --save-dev [email protected]
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) {
npm install --silent --save-dev [email protected]
Expand Down
8 changes: 4 additions & 4 deletions examples/auth/views/login.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
<form method="post" action="/login">
<p>
<label>Username:</label>
<input type="text" name="username">
<label for="username">Username:</label>
<input type="text" name="username" id="username">
</p>
<p>
<label>Password:</label>
<input type="text" name="password">
<label for="password">Password:</label>
<input type="text" name="password" id="password">
</p>
<p>
<input type="submit" value="Login">
Expand Down
5 changes: 1 addition & 4 deletions examples/downloads/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

var express = require('../../');
var path = require('path');
var resolvePath = require('resolve-path')

var app = module.exports = express();

Expand All @@ -25,9 +24,7 @@ app.get('/', function(req, res){
// /files/* is accessed via req.params[0]
// but here we name it :file
app.get('/files/:file(*)', function(req, res, next){
var filePath = resolvePath(FILES_DIR, req.params.file)

res.download(filePath, function (err) {
res.download(req.params.file, { root: FILES_DIR }, function (err) {
if (!err) return; // file sent
if (err.status !== 404) return next(err); // non-404 error
// file for download not found
Expand Down
9 changes: 1 addition & 8 deletions examples/params/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Module dependencies.
*/

var createError = require('http-errors')
var express = require('../../');
var app = module.exports = express();

Expand All @@ -17,14 +18,6 @@ var users = [
, { name: 'bandit' }
];

// Create HTTP error

function createError(status, message) {
var err = new Error(message);
err.status = status;
return err;
}

// Convert :to and :from to integers

app.param(['to', 'from'], function(req, res, next, num, name){
Expand Down
19 changes: 18 additions & 1 deletion lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ 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;

/**
Expand Down Expand Up @@ -352,7 +359,17 @@ app.param = function param(name, fn) {
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);
Expand Down
56 changes: 39 additions & 17 deletions lib/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

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');
Expand Down Expand Up @@ -64,6 +65,9 @@ var charsetRegExp = /;\s*charset\s*=/;
*/

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;
};
Expand Down Expand Up @@ -135,7 +139,7 @@ res.send = function send(body) {

deprecate('res.send(status): Use res.sendStatus(status) instead');
this.statusCode = chunk;
chunk = statuses[chunk]
chunk = statuses.message[chunk]
}

switch (typeof chunk) {
Expand Down Expand Up @@ -213,6 +217,13 @@ res.send = function send(body) {
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();
Expand Down Expand Up @@ -356,7 +367,7 @@ res.jsonp = function jsonp(obj) {
*/

res.sendStatus = function sendStatus(statusCode) {
var body = statuses[statusCode] || String(statusCode)
var body = statuses.message[statusCode] || String(statusCode)

this.statusCode = statusCode;
this.type('txt');
Expand Down Expand Up @@ -551,6 +562,13 @@ res.download = function download (path, filename, options, callback) {
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)
Expand All @@ -572,7 +590,9 @@ res.download = function download (path, filename, options, callback) {
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)
Expand Down Expand Up @@ -665,9 +685,8 @@ 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)
Expand All @@ -678,13 +697,12 @@ res.format = function(obj){
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;
Expand Down Expand Up @@ -850,9 +868,13 @@ res.cookie = function (name, value, options) {
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) {
Expand Down Expand Up @@ -933,12 +955,12 @@ res.redirect = function redirect(url) {
// 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(){
Expand Down
Loading