PSo3G
PSo3G

Reputation: 195

Intercept HTTP responses on an HTTPS server in Node.JS and Express

I'm just starting with node.js and express and I'm doing a simple HTTPS server. I've been working with nginx for some time and when I make an HTTP request to an HTTPS endpoint I get a "400 Bad Request" error. However, when using node.js the request never finishes.

How can I intercept an HTTP request in Express to be able to generate the "400 Bad Request" response?

This is my code:

var express = require('express'); 
var https = require('https');
var fs = require('fs');

var port = process.env.PORT || 8080;

var tls_options = {
  key: fs.readFileSync('certs/server.key'),
  cert: fs.readFileSync('certs/server.crt'),
  ca: fs.readFileSync('certs/ca.crt'),
  requestCert: true,
};

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

router.get('/', function(req, res) {
    res.json({ message: 'Checkpoint!!' });  
});

app.use('/', router);

var secureServer = https.createServer(tls_options, app);
secureServer.listen(port);
console.log('Listening on port ' + port);

Until now the only thing I've been able to use is getting a 'connection' event every time a request arrives to the server:

secureServer.on('connection', function (stream) {
   console.log('someone connected!');
});

Upvotes: 1

Views: 2536

Answers (2)

PSo3G
PSo3G

Reputation: 195

Done. In fact, an HTTP request to an HTTPS socket ends after the default 120secs TLS handsahke timeout. This way I can end the request without waiting. I include the solution I used just for future references if anything needs the same functionality.

var secureServer = https.createServer(options, app);
secureServer.on('connection', function(socket) {
    socket.on('data', function(data) {
    var first_line = data.toString().split('\r\n')[0];
    var pattern = /\bhttp\/1\.[01]$\b/i;
    if (pattern.test(first_line)) {
        var headers = {};
        headers['Date'] = new Date().toUTCString();
        headers['Connection'] = 'close';
        var headers_string = '';
        for (var name in headers) {
            headers_string = headers_string + '\r\n' + name + ': ' + headers[name];
        }
        socket.end('HTTP/1.1 400 Bad Request' + headers_string);
    }
});

Upvotes: 2

dylants
dylants

Reputation: 23340

There isn't a way of starting both HTTP and HTTPS servers on the same port. What most people do is either:

Start two servers (one HTTP and one HTTPS) on different ports, and redirect the HTTP traffic to HTTPS. Using Express it would mean the additional code:

// create two ports, one for HTTP and one for HTTPS
var port = process.env.PORT || 8080;
var httpsPort = 8081;

// redirect all HTTP requests to HTTPS
app.use(function(req, res, next) {
    var hostname;

    if (!req.secure) {
        hostname = req.get("host").split(":")[0];
        return res.redirect(["https://", hostname, ":", httpsPort, req.url].join(""));
    }
    next();
});

app.listen(port);  // listen on HTTP
https.createServer(tls_options, app).listen(httpsPort);  // listen on HTTPS

Or they use nginx or apache to handle outside connections (both HTTP and HTTPS) and redirect traffic to the Node server (which can then just run on HTTP).

Upvotes: -1

Related Questions