mirror of
https://github.com/zebrajr/express.git
synced 2025-12-06 12:19:51 +01:00
Merge tag '4.20.0' into 5.0
This commit is contained in:
commit
e5feb9fcc9
14
History.md
14
History.md
|
|
@ -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`
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(){
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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'me%3E">%3Cla'me%3E</a></p>', done)
|
.expect(302, '<p>Found. Redirecting to %3Cla'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);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user