Merge tag '4.20.0' into 5.0

This commit is contained in:
Wes Todd 2024-09-09 21:06:41 -05:00
commit e5feb9fcc9
9 changed files with 81 additions and 15 deletions

View File

@ -176,9 +176,19 @@ This is the first Express 5.0 alpha release, based off 4.10.1.
* add: * add:
- `app.router` is a reference to the base router - `app.router` is a reference to the base router
unreleased 4.20.0 / 2024-09-10
========== ==========
* deps: serve-static@0.16.0
* Remove link renderization in html while redirecting
* deps: send@0.19.0
* Remove link renderization in html while redirecting
* deps: body-parser@0.6.0
* add `depth` option to customize the depth level in the parser
* IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
* Remove link renderization in html while using `res.redirect`
* deps: path-to-regexp@0.1.10
- Adds support for named matching groups in the routes using a regex
- Adds backtracking protection to parameters without regexes defined
* deps: encodeurl@~2.0.0 * deps: encodeurl@~2.0.0
- Removes encoding of `\`, `|`, and `^` to align better with URL spec - Removes encoding of `\`, `|`, and `^` to align better with URL spec
* Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie` * Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`

View File

@ -202,6 +202,7 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi** * [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him) * [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego** * [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger** * [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
<details> <details>
@ -254,6 +255,6 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
[npm-install-size-url]: https://packagephobia.com/result?p=express [npm-install-size-url]: https://packagephobia.com/result?p=express
[npm-url]: https://npmjs.org/package/express [npm-url]: https://npmjs.org/package/express
[npm-version-image]: https://badgen.net/npm/v/express [npm-version-image]: https://badgen.net/npm/v/express
[ossf-scorecard-badge]: https://api.securityscorecards.dev/projects/github.com/expressjs/express/badge [ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
[ossf-scorecard-visualizer]: https://kooltheba.github.io/openssf-scorecard-api-visualizer/#/projects/github.com/expressjs/express [ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
[Code of Conduct]: https://github.com/expressjs/express/blob/master/Code-Of-Conduct.md [Code of Conduct]: https://github.com/expressjs/express/blob/master/Code-Of-Conduct.md

View File

@ -9,11 +9,18 @@ classification:
* `needs triage`: This can be kept if the triager is unsure which next steps to take * `needs triage`: This can be kept if the triager is unsure which next steps to take
* `awaiting more info`: If more info has been requested from the author, apply this label. * `awaiting more info`: If more info has been requested from the author, apply this label.
* `question`: User questions that do not appear to be bugs or enhancements.
* `discuss`: Topics for discussion. Might end in an `enhancement` or `question` label.
* `bug`: Issues that present a reasonable conviction there is a reproducible bug. * `bug`: Issues that present a reasonable conviction there is a reproducible bug.
* `enhancement`: Issues that are found to be a reasonable candidate feature additions. * `enhancement`: Issues that are found to be a reasonable candidate feature additions.
If the issue is a question or discussion, it should be moved to GitHub Discussions.
### Moving Discussions and Questions to GitHub Discussions
For issues labeled with `question` or `discuss`, it is recommended to move them to GitHub Discussions instead:
* **Questions**: User questions that do not appear to be bugs or enhancements should be moved to GitHub Discussions.
* **Discussions**: Topics for discussion should be moved to GitHub Discussions. If the discussion leads to a new feature or bug identification, it can be moved back to Issues.
In all cases, issues may be closed by maintainers if they don't receive a timely response when In all cases, issues may be closed by maintainers if they don't receive a timely response when
further information is sought, or when additional questions are asked. further information is sought, or when additional questions are asked.

View File

@ -837,7 +837,7 @@ res.redirect = function redirect(url) {
html: function(){ html: function(){
var u = escapeHtml(address); var u = escapeHtml(address);
body = '<p>' + statuses.message[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>' body = '<p>' + statuses.message[status] + '. Redirecting to ' + u + '</p>'
}, },
default: function(){ default: function(){

View File

@ -1,7 +1,11 @@
{ {
"name": "express", "name": "express",
"description": "Fast, unopinionated, minimalist web framework", "description": "Fast, unopinionated, minimalist web framework",
<<<<<<< HEAD
"version": "5.0.0-beta.3", "version": "5.0.0-beta.3",
=======
"version": "4.20.0",
>>>>>>> master
"author": "TJ Holowaychuk <tj@vision-media.ca>", "author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [ "contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>", "Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@ -42,7 +46,7 @@
"finalhandler": "1.2.0", "finalhandler": "1.2.0",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"merge-descriptors": "1.0.1", "merge-descriptors": "1.0.3",
"methods": "~1.1.2", "methods": "~1.1.2",
"mime-types": "~2.1.34", "mime-types": "~2.1.34",
"on-finished": "2.4.1", "on-finished": "2.4.1",

View File

@ -194,6 +194,23 @@ describe('app.router', function(){
.expect('editing user 10', done); .expect('editing user 10', done);
}) })
if (supportsRegexp('(?<foo>.*)')) {
it('should populate req.params with named captures', function(done){
var app = express();
var re = new RegExp('^/user/(?<userId>[0-9]+)/(view|edit)?$');
app.get(re, function(req, res){
var id = req.params.userId
, op = req.params[0];
res.end(op + 'ing user ' + id);
});
request(app)
.get('/user/10/edit')
.expect('editing user 10', done);
})
}
it('should ensure regexp matches path prefix', function (done) { it('should ensure regexp matches path prefix', function (done) {
var app = express() var app = express()
var p = [] var p = []
@ -1140,3 +1157,12 @@ describe('app.router', function(){
assert.strictEqual(app.get('/', function () {}), app) assert.strictEqual(app.get('/', function () {}), app)
}) })
}) })
function supportsRegexp(source) {
try {
new RegExp(source)
return true
} catch (e) {
return false
}
}

View File

@ -486,7 +486,7 @@ describe('express.static()', function () {
request(this.app) request(this.app)
.get('/users') .get('/users')
.expect('Location', '/users/') .expect('Location', '/users/')
.expect(301, /<a href="\/users\/">/, done) .expect(301, /\/users\//, done)
}) })
it('should redirect directories with query string', function (done) { it('should redirect directories with query string', function (done) {
@ -508,7 +508,7 @@ describe('express.static()', function () {
.get('/snow') .get('/snow')
.expect('Location', '/snow%20%E2%98%83/') .expect('Location', '/snow%20%E2%98%83/')
.expect('Content-Type', /html/) .expect('Content-Type', /html/)
.expect(301, />Redirecting to <a href="\/snow%20%E2%98%83\/">\/snow%20%E2%98%83\/<\/a></, done) .expect(301, />Redirecting to \/snow%20%E2%98%83\/</, done)
}) })
it('should respond with default Content-Security-Policy', function (done) { it('should respond with default Content-Security-Policy', function (done) {

View File

@ -186,7 +186,7 @@ describe('express.urlencoded()', function () {
it('should parse deep object', function (done) { it('should parse deep object', function (done) {
var str = 'foo' var str = 'foo'
for (var i = 0; i < 500; i++) { for (var i = 0; i < 32; i++) {
str += '[p]' str += '[p]'
} }
@ -204,7 +204,7 @@ describe('express.urlencoded()', function () {
var depth = 0 var depth = 0
var ref = obj.foo var ref = obj.foo
while ((ref = ref.p)) { depth++ } while ((ref = ref.p)) { depth++ }
assert.strictEqual(depth, 500) assert.strictEqual(depth, 32)
}) })
.expect(200, done) .expect(200, done)
}) })

View File

@ -91,7 +91,7 @@ describe('res', function(){
.set('Accept', 'text/html') .set('Accept', 'text/html')
.expect('Content-Type', /html/) .expect('Content-Type', /html/)
.expect('Location', 'http://google.com') .expect('Location', 'http://google.com')
.expect(302, '<p>Found. Redirecting to <a href="http://google.com">http://google.com</a></p>', done) .expect(302, '<p>Found. Redirecting to http://google.com</p>', done)
}) })
it('should escape the url', function(done){ it('should escape the url', function(done){
@ -107,9 +107,27 @@ describe('res', function(){
.set('Accept', 'text/html') .set('Accept', 'text/html')
.expect('Content-Type', /html/) .expect('Content-Type', /html/)
.expect('Location', '%3Cla\'me%3E') .expect('Location', '%3Cla\'me%3E')
.expect(302, '<p>Found. Redirecting to <a href="%3Cla&#39;me%3E">%3Cla&#39;me%3E</a></p>', done) .expect(302, '<p>Found. Redirecting to %3Cla&#39;me%3E</p>', done)
}) })
it('should not render evil javascript links in anchor href (prevent XSS)', function(done){
var app = express();
var xss = 'javascript:eval(document.body.innerHTML=`<p>XSS</p>`);';
var encodedXss = 'javascript:eval(document.body.innerHTML=%60%3Cp%3EXSS%3C/p%3E%60);';
app.use(function(req, res){
res.redirect(xss);
});
request(app)
.get('/')
.set('Host', 'http://example.com')
.set('Accept', 'text/html')
.expect('Content-Type', /html/)
.expect('Location', encodedXss)
.expect(302, '<p>Found. Redirecting to ' + encodedXss +'</p>', done);
});
it('should include the redirect type', function(done){ it('should include the redirect type', function(done){
var app = express(); var app = express();
@ -122,7 +140,7 @@ describe('res', function(){
.set('Accept', 'text/html') .set('Accept', 'text/html')
.expect('Content-Type', /html/) .expect('Content-Type', /html/)
.expect('Location', 'http://google.com') .expect('Location', 'http://google.com')
.expect(301, '<p>Moved Permanently. Redirecting to <a href="http://google.com">http://google.com</a></p>', done); .expect(301, '<p>Moved Permanently. Redirecting to http://google.com</p>', done);
}) })
}) })