express

4.18.04.19.0
~

Modified (7 files)

Index: package/lib/router/index.js
===================================================================
--- package/lib/router/index.js
+++ package/lib/router/index.js
@@ -35,9 +35,9 @@
 /**
  * Initialize a new `Router` with the given `options`.
  *
  * @param {Object} [options]
- * @return {Router} which is an callable function
+ * @return {Router} which is a callable function
  * @public
  */
 
 var proto = module.exports = function(options) {
@@ -278,16 +278,16 @@
 
     // 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) {
@@ -326,10 +326,8 @@
       layer.handle_error(layerError, req, res, next);
     } else {
       layer.handle_request(req, res, next);
     }
-
-    sync = 0
   }
 };
 
 /**
Index: package/lib/response.js
===================================================================
--- package/lib/response.js
+++ package/lib/response.js
@@ -33,8 +33,9 @@
 var extname = path.extname;
 var mime = send.mime;
 var resolve = path.resolve;
 var vary = require('vary');
+var urlParse = require('url').parse;
 
 /**
  * Response prototype.
  * @public
@@ -910,10 +911,27 @@
   if (url === 'back') {
     loc = this.req.get('Referrer') || '/';
   }
 
+  var lowerLoc = loc.toLowerCase();
+  var encodedUrl = encodeUrl(loc);
+  if (lowerLoc.indexOf('https://') === 0 || lowerLoc.indexOf('http://') === 0) {
+    try {
+      var parsedUrl = urlParse(loc);
+      var parsedEncodedUrl = urlParse(encodedUrl);
+      // Because this can encode the host, check that we did not change the host
+      if (parsedUrl.host !== parsedEncodedUrl.host) {
+        // If the host changes after encodeUrl, return the original url
+        return this.set('Location', loc);
+      }
+    } catch (e) {
+      // If parse fails, return the original url
+      return this.set('Location', loc);
+    }
+  }
+
   // set location
-  return this.set('Location', encodeUrl(loc));
+  return this.set('Location', encodedUrl);
 };
 
 /**
  * Redirect to the given `url` with optional response `status`
Index: package/lib/router/route.js
===================================================================
--- package/lib/router/route.js
+++ package/lib/router/route.js
@@ -59,9 +59,12 @@
   if (this.methods._all) {
     return true;
   }
 
-  var name = method.toLowerCase();
+  // normalize name
+  var name = typeof method === 'string'
+    ? method.toLowerCase()
+    : method
 
   if (name === 'head' && !this.methods['head']) {
     name = 'get';
   }
@@ -102,10 +105,12 @@
 
   if (stack.length === 0) {
     return done();
   }
+  var method = typeof req.method === 'string'
+    ? req.method.toLowerCase()
+    : req.method
 
-  var method = req.method.toLowerCase();
   if (method === 'head' && !this.methods['head']) {
     method = 'get';
   }
 
@@ -123,23 +128,23 @@
     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);
     }
Index: package/lib/utils.js
===================================================================
--- package/lib/utils.js
+++ package/lib/utils.js
@@ -116,19 +116,17 @@
 
 /**
  * Parse accept params `str` returning an
  * object with `.value`, `.quality` and `.params`.
- * also includes `.originalIndex` for stable sorting
  *
  * @param {String} str
- * @param {Number} index
  * @return {Object}
  * @api private
  */
 
-function acceptParams(str, index) {
+function acceptParams (str) {
   var parts = str.split(/ *; */);
-  var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index };
+  var ret = { value: parts[0], quality: 1, params: {} }
 
   for (var i = 1; i < parts.length; ++i) {
     var pms = parts[i].split(/ *= */);
     if ('q' === pms[0]) {
@@ -281,8 +279,9 @@
 
 /**
  * Parse an extended query string with qs.
  *
+ * @param {String} str
  * @return {Object}
  * @private
  */
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,8 +1,8 @@
 {
   "name": "express",
   "description": "Fast, unopinionated, minimalist web framework",
-  "version": "4.18.0",
+  "version": "4.19.0",
   "author": "TJ Holowaychuk <tj@vision-media.ca>",
   "contributors": [
     "Aaron Heckmann <aaron.heckmann+github@gmail.com>",
     "Ciaran Jessup <ciaranj@gmail.com>",
@@ -29,12 +29,12 @@
   ],
   "dependencies": {
     "accepts": "~1.3.8",
     "array-flatten": "1.1.1",
-    "body-parser": "1.20.0",
+    "body-parser": "1.20.2",
     "content-disposition": "0.5.4",
     "content-type": "~1.0.4",
-    "cookie": "0.5.0",
+    "cookie": "0.6.0",
     "cookie-signature": "1.0.6",
     "debug": "2.6.9",
     "depd": "2.0.0",
     "encodeurl": "~1.0.2",
@@ -48,9 +48,9 @@
     "on-finished": "2.4.1",
     "parseurl": "~1.3.3",
     "path-to-regexp": "0.1.7",
     "proxy-addr": "~2.0.7",
-    "qs": "6.10.3",
+    "qs": "6.11.0",
     "range-parser": "~1.2.1",
     "safe-buffer": "5.2.1",
     "send": "0.18.0",
     "serve-static": "1.15.0",
@@ -64,20 +64,19 @@
     "after": "0.8.2",
     "connect-redis": "3.4.2",
     "cookie-parser": "1.4.6",
     "cookie-session": "2.0.0",
-    "ejs": "3.1.6",
-    "eslint": "7.32.0",
+    "ejs": "3.1.9",
+    "eslint": "8.47.0",
     "express-session": "1.17.2",
     "hbs": "4.2.0",
     "marked": "0.7.0",
     "method-override": "3.0.0",
-    "mocha": "9.2.1",
+    "mocha": "10.2.0",
     "morgan": "1.10.0",
-    "multiparty": "4.2.3",
     "nyc": "15.1.0",
     "pbkdf2-password": "1.2.1",
-    "supertest": "6.2.2",
+    "supertest": "6.3.0",
     "vhost": "~3.0.2"
   },
   "engines": {
     "node": ">= 0.10.0"
Index: package/History.md
===================================================================
--- package/History.md
+++ package/History.md
@@ -1,4 +1,35 @@
+4.18.3 / 2024-03-20
+==========
+
+  * Prevent open redirect allow list bypass due to encodeurl
+  * deps: cookie@0.6.0
+
+4.18.3 / 2024-02-29
+==========
+
+  * Fix routing requests without method
+  * deps: body-parser@1.20.2
+    - Fix strict json error message on Node.js 19+
+    - deps: content-type@~1.0.5
+    - deps: raw-body@2.5.2
+  * deps: cookie@0.6.0
+    - Add `partitioned` option
+
+4.18.2 / 2022-10-08
+===================
+
+  * Fix regression routing a large stack in a single route
+  * deps: body-parser@1.20.1
+    - deps: qs@6.11.0
+    - perf: remove unnecessary object clone
+  * deps: qs@6.11.0
+
+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`
@@ -2096,9 +2127,9 @@
  * use `media-typer` to alter content-type charset
  * deps: connect@2.21.0
    - deprecate `connect(middleware)` -- use `app.use(middleware)` instead
    - deprecate `connect.createServer()` -- use `connect()` instead
-   - fix `res.setHeader()` patch to work with with get -> append -> set pattern
+   - fix `res.setHeader()` patch to work with get -> append -> set pattern
    - deps: compression@~1.0.8
    - deps: errorhandler@~1.1.1
    - deps: express-session@~1.5.0
    - deps: serve-index@~1.1.3
@@ -3307,10 +3338,10 @@
 
   * Added node v0.1.97 compatibility
   * Added support for deleting cookies via Request#cookie('key', null)
   * Updated haml submodule
-  * Fixed not-found page, now using using charset utf-8
-  * Fixed show-exceptions page, now using using charset utf-8
+  * Fixed not-found page, now using charset utf-8
+  * Fixed show-exceptions page, now using charset utf-8
   * Fixed view support due to fs.readFile Buffers
   * Changed; mime.type() no longer accepts ".type" due to node extname() changes
 
 0.12.0 / 2010-05-22
@@ -3343,9 +3374,9 @@
 0.10.0 / 2010-04-30
 ==================
 
   * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
-    encoding is set to 'utf8' or 'utf-8'.
+    encoding is set to 'utf8' or 'utf-8').
   * Added "encoding" option to Request#render(). Closes #299
   * Added "dump exceptions" setting, which is enabled by default.
   * Added simple ejs template engine support
   * Added error response support for text/plain, application/json. Closes #297
@@ -3382,9 +3413,9 @@
   * Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254
   * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
   * Added callback function support to Request#halt() as 3rd/4th arg
   * Added preprocessing of route param wildcards using param(). Closes #251
-  * Added view partial support (with collections etc)
+  * Added view partial support (with collections etc.)
   * Fixed bug preventing falsey params (such as ?page=0). Closes #286
   * Fixed setting of multiple cookies. Closes #199
   * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
   * Changed; session cookie is now httpOnly
Index: package/Readme.md
===================================================================
--- package/Readme.md
+++ package/Readme.md
@@ -1,7 +1,7 @@
 [![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](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-version-image]][npm-url]
   [![NPM Install Size][npm-install-size-image]][npm-install-size-url]
   [![NPM Downloads][npm-downloads-image]][npm-downloads-url]
@@ -50,9 +50,9 @@
 
 ## 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
@@ -103,9 +103,9 @@
 
   To view the examples, clone the Express repo and install the dependencies:
 
 ```console
-$ git clone git://github.com/expressjs/express.git --depth 1
+$ git clone https://github.com/expressjs/express.git --depth 1
 $ cd express
 $ npm install
 ```