Express: Express middleware not honoured if there is a duplicate slash (//)

Created on 25 Sep 2018  路  13Comments  路  Source: expressjs/express

Hello,

I'm running express v 4.16.2 and I have a middleware routing that looks as follows:

app.use('/path/to/my/resource/*', middlewares.myMiddleware);

If there's an extra / in certain spots, the middleware is bypassed.

Middleware is bypassed in the following cases:

/path/to/my//resource/resourceId
/path/to//my/resource/resourceId

Middleware is not bypassed in the following cases and works as expected:

//path/to/my/resource/resourceId
/path//to/my/resource/resourceId
/path/to/my/resource//resourceId

All 13 comments

I think this is a path-to-regexp issue, as it generates the regular expressions to match the paths against.

@dougwilson Thanks for the quick response. Do you suggest I open an issue against that package? Or is there someone on express team that can confirm it is an issue with path-to-regexp?

I was just trying to provide a quick response that may help point to the root cause. I have not invested anything yet. Someone (you could if you're inclined / able) needs to track down the technical cause of this issue and figure out either (a) is this expected behavior (b) what the specific fix is or (c) something else.

I hope this helps.

Here's a simple app that I used to reproduce the issue:

var express = require('express');
var app = express();
var router = express.Router();

app.use('/path/to/my/resource/*', function(req, res, next) {
  console.log('in middleware');
  return next();
});

app.use('/path/to', router.use('/my', router.get('/resource/:resourceId', function(req, res) {
  res.send();
})));

app.listen(3009);

If I do localhost:3009/path/to//my//resource/resourceId, I get 200, but I don't get the print statement (i.e, it didn't go through the middleware).

Hey I would like to take this issue up. Any pointers where to start?

Thanks @mintunitish for offering to help. I ran the above example in debug mode and express creates a separate layer for every route used. So what happens is as follows:

1st layer app.use('/path/to/my/resource/*')
path: /path/to/my//resource/resourceId
regex: /^\/path\/to\/my\/resource\/(.*)\/?(?=\/|$)/i
match: false

2nd layer app.use('/path/to')
path: /path/to
regex: /^\/path\/to\/?(?=\/|$)/i
match: true

3rd layer router.use('/my')
path: /my/ please note the trailing slash
regex: /^\/my\/?(?=\/|$)/i
match: true

4th layer router.get('/resource/:resourceId')
path: /resource/resourceId
regex: /^\/resource\/(?:([^\/]+?))\/?$/i
match: true

I expected the 4th layer path to be //resource/resourceId. Because express doesn't attempt to match the path as a whole, but matches them in chunks, it depends on the code structure whether express matches the pattern or not. For example if I had router.get('/path/to/my/resource/:resourceId', function(req, res){}) and I attempt localhost:3009/path/to//my//resource/resourceId I'd get 404 as expected. However listing routers as full routes like router.get('/path/to/my/resource/:resourceId', function(req, res){}) does not allow for better encapsulation.

I would move this conversation over to the path-to-regexp repo. I am sure @blakeembrey will have input and opinions, and no matter the change you land on, pulling that into the express release will be a separate issue.

I believe this works as expected in path-to-regexp >= 1, it was one of the first things I resolved when I refactored. I didn't alter this behaviour in the version that Express.js uses because it would have broken some layer of compatibility that someone _may_ have been using.

However, based on the comments, I can't really tell what you expect here. To change the behaviour to purposefully match duplicate slashes is a different change than making it act consistently, which is the behaviour I mentioned in my previous comments. If you _want_ it to match multiple slashes as if they were one, that would require a change (but could, for now, be resolved with a middleware that rewrites URLs).

@micophilip Were you able to resolve this issue?
I created a Repl with the version of Express that you noted so that I could test the cases you said were failing but in both cases I ended up seeing the "in middleware" log printed.
https://repl.it/@ejmuentes/expressissues3752
https://imgur.com/UlLMSGS

If you were able to sort the issue out and you have a moment to clarify what your solution was, it may help others landing on this issue from a search engine.

Either way, if this issue no longer needs attention from the Express maintainers, please close this issue.

@Emuentes Thanks for checking in. The issue is still reproducible actually with the latest express 4.17.1. However I restructured my middlewares in a way where it's not reproducible as illustrated in my earlier comments. Closing the issue.

@micophilip glad to hear you were able to refactor the problem away.

If you find a solution using the approach you were trying to implement, add a codesandbox example for any folks who may have a similar issue :-D

If you have example code (that you can share) illustrating what you did as an alternative, it may be helpful to others who find stumble upon this issue.

Share a running code example if you have a chance :-)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ZeddYu picture ZeddYu  路  3Comments

Sunriselegacy picture Sunriselegacy  路  3Comments

zackarychapple picture zackarychapple  路  3Comments

Domiii picture Domiii  路  3Comments

AndrewEQ picture AndrewEQ  路  4Comments