10
var express = require('express');
var app = express();

app.get('*', function (req, res) {
    var host = req.get('Host');
    return res.redirect(['https://', host, req.url].join(''));
});

var server = app.listen(8080, function () {
  console.log('starting');
});

I have a simple script that redirects http to https. This is working fine except when there is a malformed url for example: website.com/%c0%ae%c0%ae. It displays something like:

URIError: Failed to decode param '/%c0%ae%c0%ae'
   at decodeURIComponent (native)
   at decode_param (/...<PROJECT DIRECTORY>.../node_modules/express/lib/router/layer.js:167:12)
   at Layer.match (/.../node_modules/express/lib/router/layer.js:143:15)
   at matchLayer (/.../node_modules/express/lib/router/index.js:557:18)
   at next (/.../node_modules/express/lib/router/index.js:216:15)
   at expressInit (/.../node_modules/express/lib/middleware/init.js:33:5)
   at Layer.handle [as handle_request] (/.../node_modules/express/lib/router/layer.js:95:5)
   at trim_prefix (/.../node_modules/express/lib/router/index.js:312:13)
   at /.../node_modules/express/lib/router/index.js:280:7
   at Function.process_params (/.../node_modules/express/lib/router/index.js:330:12)

It's not nice when a user can randomly see where my project files are in the server. Any way to handle this error?

pewpewlasers
  • 3,025
  • 4
  • 31
  • 58

3 Answers3

14

Thanks @Oleg for the tip. But somehow your solution wasn't logging error for me. Here's what I have come up with:

var express = require('express');
var app = express();

app.use(function(req, res, next) {
    var err = null;
    try {
        decodeURIComponent(req.path)
    }
    catch(e) {
        err = e;
    }
    if (err){
        console.log(err, req.url);
        return res.redirect(['https://', req.get('Host'), '/404'].join(''));    
    }
    next();
});

app.get('*', function (req, res) {
    return res.redirect(['https://', req.get('Host'), req.url].join(''));
});

var server = app.listen(8080, function () {
    console.log('Starting');
});
pewpewlasers
  • 3,025
  • 4
  • 31
  • 58
  • A tip that is obvious in hindsight, but might save someone else some time: if your express backend server is proxied behind a webpack-dev-server (as used when developing a react app), don't forget to send the malformed URL request directly to the server. If you make the request using your normal front-end port, the webpack-dev-server will handle (barf on) the malformed URL instead, and it won't be proxied through to your actual back end application, so your custom handler won't have a chance to be invoked. – Robert Rendell Feb 17 '22 at 07:26
7

Possible workaround:

var express = require('express');
var app = express();

app.get('*', function (req, res) {
    // redirect regular paths
    var host = req.get('Host');
    return res.redirect(['https://', host, req.url].join(''));
});

// your express error handler
app.use(function(err, req, res, next) {
    // in case of specific URIError
    if (err instanceof URIError) {
        err.message = 'Failed to decode param: ' + req.url;
        err.status = err.statusCode = 400;

        // .. your redirect here if still needed
        return res.redirect(['https://', req.get('Host'), req.url].join(''));
    } else {
        // ..
    }
    // ..
});

var server = app.listen(8080, function () {
    console.log('starting');
});
oleh.meleshko
  • 4,675
  • 2
  • 27
  • 40
6
var express = require('express');
var app = express();

// handles 400 error
app.use((err, req, res, next) => {
  if (!err) return next();
  return res.status(400).json({
    status: 400,
    error: 'OOps! Bad request',
  });
});

Edited: The code snippet should be placed as the last route, it checks if there is an error that was skipped by other routes, which obviously there is, and sends a default response. This error happens when you add % as last character of an API endpoint..

Shonubi Korede
  • 541
  • 6
  • 4