Skip to content

Commit e5feb9f

Browse files
committed
Merge tag '4.20.0' into 5.0
2 parents 63992bb + 21df421 commit e5feb9f

9 files changed

+81
-15
lines changed

History.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,19 @@ This is the first Express 5.0 alpha release, based off 4.10.1.
176176
* add:
177177
- `app.router` is a reference to the base router
178178

179-
unreleased
179+
4.20.0 / 2024-09-10
180180
==========
181-
181+
182+
* Remove link renderization in html while redirecting
183+
184+
* Remove link renderization in html while redirecting
185+
186+
* add `depth` option to customize the depth level in the parser
187+
* IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
188+
* Remove link renderization in html while using `res.redirect`
189+
190+
- Adds support for named matching groups in the routes using a regex
191+
- Adds backtracking protection to parameters without regexes defined
182192
* deps: encodeurl@~2.0.0
183193
- Removes encoding of `\`, `|`, and `^` to align better with URL spec
184194
* Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`

Readme.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
202202
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
203203
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
204204
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
205+
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
205206
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
206207

207208
<details>
@@ -254,6 +255,6 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
254255
[npm-install-size-url]: https://packagephobia.com/result?p=express
255256
[npm-url]: https://npmjs.org/package/express
256257
[npm-version-image]: https://badgen.net/npm/v/express
257-
[ossf-scorecard-badge]: https://api.securityscorecards.dev/projects/github.com/expressjs/express/badge
258-
[ossf-scorecard-visualizer]: https://kooltheba.github.io/openssf-scorecard-api-visualizer/#/projects/github.com/expressjs/express
258+
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
259+
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
259260
[Code of Conduct]: https://github.com/expressjs/express/blob/master/Code-Of-Conduct.md

Triager-Guide.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,18 @@ classification:
99

1010
* `needs triage`: This can be kept if the triager is unsure which next steps to take
1111
* `awaiting more info`: If more info has been requested from the author, apply this label.
12-
* `question`: User questions that do not appear to be bugs or enhancements.
13-
* `discuss`: Topics for discussion. Might end in an `enhancement` or `question` label.
1412
* `bug`: Issues that present a reasonable conviction there is a reproducible bug.
1513
* `enhancement`: Issues that are found to be a reasonable candidate feature additions.
1614

15+
If the issue is a question or discussion, it should be moved to GitHub Discussions.
16+
17+
### Moving Discussions and Questions to GitHub Discussions
18+
19+
For issues labeled with `question` or `discuss`, it is recommended to move them to GitHub Discussions instead:
20+
21+
* **Questions**: User questions that do not appear to be bugs or enhancements should be moved to GitHub Discussions.
22+
* **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.
23+
1724
In all cases, issues may be closed by maintainers if they don't receive a timely response when
1825
further information is sought, or when additional questions are asked.
1926

lib/response.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ res.redirect = function redirect(url) {
837837

838838
html: function(){
839839
var u = escapeHtml(address);
840-
body = '<p>' + statuses.message[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>'
840+
body = '<p>' + statuses.message[status] + '. Redirecting to ' + u + '</p>'
841841
},
842842

843843
default: function(){

package.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
{
22
"name": "express",
33
"description": "Fast, unopinionated, minimalist web framework",
4+
<<<<<<< HEAD
45
"version": "5.0.0-beta.3",
6+
=======
7+
"version": "4.20.0",
8+
>>>>>>> master
59
"author": "TJ Holowaychuk <[email protected]>",
610
"contributors": [
711
"Aaron Heckmann <[email protected]>",
@@ -42,7 +46,7 @@
4246
"finalhandler": "1.2.0",
4347
"fresh": "0.5.2",
4448
"http-errors": "2.0.0",
45-
"merge-descriptors": "1.0.1",
49+
"merge-descriptors": "1.0.3",
4650
"methods": "~1.1.2",
4751
"mime-types": "~2.1.34",
4852
"on-finished": "2.4.1",

test/app.router.js

+26
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,23 @@ describe('app.router', function(){
194194
.expect('editing user 10', done);
195195
})
196196

197+
if (supportsRegexp('(?<foo>.*)')) {
198+
it('should populate req.params with named captures', function(done){
199+
var app = express();
200+
var re = new RegExp('^/user/(?<userId>[0-9]+)/(view|edit)?$');
201+
202+
app.get(re, function(req, res){
203+
var id = req.params.userId
204+
, op = req.params[0];
205+
res.end(op + 'ing user ' + id);
206+
});
207+
208+
request(app)
209+
.get('/user/10/edit')
210+
.expect('editing user 10', done);
211+
})
212+
}
213+
197214
it('should ensure regexp matches path prefix', function (done) {
198215
var app = express()
199216
var p = []
@@ -1140,3 +1157,12 @@ describe('app.router', function(){
11401157
assert.strictEqual(app.get('/', function () {}), app)
11411158
})
11421159
})
1160+
1161+
function supportsRegexp(source) {
1162+
try {
1163+
new RegExp(source)
1164+
return true
1165+
} catch (e) {
1166+
return false
1167+
}
1168+
}

test/express.static.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ describe('express.static()', function () {
486486
request(this.app)
487487
.get('/users')
488488
.expect('Location', '/users/')
489-
.expect(301, /<a href="\/users\/">/, done)
489+
.expect(301, /\/users\//, done)
490490
})
491491

492492
it('should redirect directories with query string', function (done) {
@@ -508,7 +508,7 @@ describe('express.static()', function () {
508508
.get('/snow')
509509
.expect('Location', '/snow%20%E2%98%83/')
510510
.expect('Content-Type', /html/)
511-
.expect(301, />Redirecting to <a href="\/snow%20%E2%98%83\/">\/snow%20%E2%98%83\/<\/a></, done)
511+
.expect(301, />Redirecting to \/snow%20%E2%98%83\/</, done)
512512
})
513513

514514
it('should respond with default Content-Security-Policy', function (done) {

test/express.urlencoded.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ describe('express.urlencoded()', function () {
186186
it('should parse deep object', function (done) {
187187
var str = 'foo'
188188

189-
for (var i = 0; i < 500; i++) {
189+
for (var i = 0; i < 32; i++) {
190190
str += '[p]'
191191
}
192192

@@ -204,7 +204,7 @@ describe('express.urlencoded()', function () {
204204
var depth = 0
205205
var ref = obj.foo
206206
while ((ref = ref.p)) { depth++ }
207-
assert.strictEqual(depth, 500)
207+
assert.strictEqual(depth, 32)
208208
})
209209
.expect(200, done)
210210
})

test/res.redirect.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ describe('res', function(){
9191
.set('Accept', 'text/html')
9292
.expect('Content-Type', /html/)
9393
.expect('Location', 'http://google.com')
94-
.expect(302, '<p>Found. Redirecting to <a href="http://google.com">http://google.com</a></p>', done)
94+
.expect(302, '<p>Found. Redirecting to http://google.com</p>', done)
9595
})
9696

9797
it('should escape the url', function(done){
@@ -107,9 +107,27 @@ describe('res', function(){
107107
.set('Accept', 'text/html')
108108
.expect('Content-Type', /html/)
109109
.expect('Location', '%3Cla\'me%3E')
110-
.expect(302, '<p>Found. Redirecting to <a href="%3Cla&#39;me%3E">%3Cla&#39;me%3E</a></p>', done)
110+
.expect(302, '<p>Found. Redirecting to %3Cla&#39;me%3E</p>', done)
111111
})
112112

113+
it('should not render evil javascript links in anchor href (prevent XSS)', function(done){
114+
var app = express();
115+
var xss = 'javascript:eval(document.body.innerHTML=`<p>XSS</p>`);';
116+
var encodedXss = 'javascript:eval(document.body.innerHTML=%60%3Cp%3EXSS%3C/p%3E%60);';
117+
118+
app.use(function(req, res){
119+
res.redirect(xss);
120+
});
121+
122+
request(app)
123+
.get('/')
124+
.set('Host', 'http://example.com')
125+
.set('Accept', 'text/html')
126+
.expect('Content-Type', /html/)
127+
.expect('Location', encodedXss)
128+
.expect(302, '<p>Found. Redirecting to ' + encodedXss +'</p>', done);
129+
});
130+
113131
it('should include the redirect type', function(done){
114132
var app = express();
115133

@@ -122,7 +140,7 @@ describe('res', function(){
122140
.set('Accept', 'text/html')
123141
.expect('Content-Type', /html/)
124142
.expect('Location', 'http://google.com')
125-
.expect(301, '<p>Moved Permanently. Redirecting to <a href="http://google.com">http://google.com</a></p>', done);
143+
.expect(301, '<p>Moved Permanently. Redirecting to http://google.com</p>', done);
126144
})
127145
})
128146

0 commit comments

Comments
 (0)