expressjs / compression

Node.js compression middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Compress crashes if given a not valid HTTP method name

crystalfp opened this issue · comments

My simple REST server based on express uses the compress middleware. Everything works perfectly except if I ask for an arbitrary, not valid, HTTP method name. Accessing with curl this way (note the typo):

curl -k -X GOT https://localhost:8899/api/kb

Make the server crash with the following stack trace:

TypeError: Cannot read property 'toLowerCase' of null
    at Route._handles_method (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\route.js:63:21)
    at next (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:244:30)
    at Function.handle (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:174:3)
    at router (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:47:12)
    at Layer.handle [as handle_request] (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:317:13)
    at D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:335:12)
    at next (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:275:10)
    at compression (D:\Projects\IdeaMixerNodeJS\node_modules\compression\index.js:220:5)

If I comment the call to app.use(compression()); the server returns status 500, but does not crash.

What should I do to harden my web server?

More details: the server does not crash using simple http. It crashes using http/2. The following simple server reproduces the error when accessed by:
C:/apps/curl/bin/curl.exe -k -X GOT https://localhost:9999/api/kb

"use strict";

/* Load required modules */
const express = require("express");
const compression = require("compression");
const spdy = require("spdy");
const fs = require("fs");

/* Initialize application */
const app = express();

// Compress the traffic (application-wide)
app.use(compression());

// Get an instance of router
const router = express.Router();

/* Endpoint "kb" */
router.get("/kb", function(req, res) {

	res.send("All OK\n");
});

/* Apply the routes to handle the API */
app.use("/api", router);

// This does not crash
// app.listen(9999, () => console.log(`\nServer started\n`));

// This crashes
const certDir = __dirname + "/cert";
const options = {
	key: fs.readFileSync(certDir + "/server.key"),
	cert: fs.readFileSync(certDir + "/server.crt")
};
spdy
	.createServer(options, app)
	.listen(9999, (error) => {
		if(error) {
			console.error(error);
			throw error;
		}
		else {
			console.log(`\nServer started (HTTP/2)\n`);
		}
	});

Sorry for the noise. In the example above there are too many moving parts. Even compression() seems a red herring. Here is the simplified code:

"use strict";

/* > Load required modules */
const express = require("express");
const spdy = require("spdy");
const fs = require("fs");

/* > Initialize application */
const app = express();

/* > Endpoint "kb" */
app.get("/api/kb", function(req, res) {res.send("All OK\n");});

if(false) {
	// This does not crash (curl returns "empty reply from server")
	app.listen(9999, () => console.log(`\nServer started\n`));
}
else {
	// This crashes
	const certDir = __dirname + "/js/cert";
	const options = {
		key: fs.readFileSync(certDir + "/server.key"),
		cert: fs.readFileSync(certDir + "/server.crt")
	};

	spdy
		.createServer(options, app)
		.listen(9999, (error) => {
			if(error) {
				console.error(error);
				throw error;
			}
			else {
				console.log(`\nServer started (HTTP/2)\n`);
			}
		});
}

The crash this time is:


TypeError: Cannot read property 'toLowerCase' of null
    at Route._handles_method (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\route.js:63:21)
    at next (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:244:30)
    at expressInit (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\middleware\init.js:40:5)
    at Layer.handle [as handle_request] (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:317:13)
    at D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:335:12)
    at next (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\index.js:275:10)
    at query (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\middleware\query.js:45:5)
    at Layer.handle [as handle_request] (D:\Projects\IdeaMixerNodeJS\node_modules\express\lib\router\layer.js:95:5)

there is no reference to spdy so I think it is an express problem. Should I move this problem to the general express queue? Thanks!

AFAIK the spdy module doesn't work with custom HTTP method names. Your stack traces seem to indicate that the property req.method is undefined instead of the expected "GOT"

Ah ah! So express is not to blame because it receive back the method string from spdy and this module do nothing to manage an invalid method name, but returns null or something undefined.

OK, I will open an issue with spdy. Thanks!

No problem!