See [net.Server.close()](net.html#server.close).
+### server.maxHeadersCount
+
+Limits maximum incoming headers count, equal to 1000 by default. If set to 0 -
+no limit will be applied.
+
+
## http.ServerRequest
This object is created internally by a HTTP server -- not by
// returns
'foo:bar;baz:qux'
-### querystring.parse(str, [sep], [eq])
+### querystring.parse(str, [sep], [eq], [options])
Deserialize a query string to an object.
Optionally override the default separator (`'&'`) and assignment (`'='`)
characters.
+Options object may contain `maxKeys` property (equal to 1000 by default), it'll
+be used to limit processed keys. Set it to 0 to remove key count limitation.
+
Example:
querystring.parse('foo=bar&baz=qux&baz=quux&corge')
parser._headers = [];
parser._url = '';
+ // Limit incoming headers count as it may cause
+ // hash collision DoS
+ parser.maxHeadersCount = 1000;
+
// Only called in the slow case where slow means
// that the request headers were either fragmented
// across multiple TCP packets or too large to be
parser.incoming.httpVersion = info.versionMajor + '.' + info.versionMinor;
parser.incoming.url = url;
- for (var i = 0, n = headers.length; i < n; i += 2) {
+ var n = headers.length;
+
+ // If parser.maxHeadersCount <= 0 - assume that there're no limit
+ if (parser.maxHeadersCount > 0) {
+ n = Math.min(n, parser.maxHeadersCount << 1);
+ }
+
+ for (var i = 0; i < n; i += 2) {
var k = headers[i];
var v = headers[i + 1];
parser.incoming._addHeaderLine(k.toLowerCase(), v);
parser.incoming = null;
req.parser = parser;
+ // Propagate headers limit from request object to parser
+ if (req.maxHeadersCount) {
+ parser.maxHeadersCount = req.maxHeadersCount;
+ }
+
socket._httpMessage = req;
// Setup "drain" propogation.
httpSocketSetup(socket);
parser.socket = socket;
parser.incoming = null;
+ // Propagate headers limit from server instance to parser
+ if (this.maxHeadersCount) {
+ parser.maxHeadersCount = this.maxHeadersCount;
+ }
+
socket.addListener('error', function(e) {
self.emit('clientError', e);
});
};
// Parse a key=val string.
-QueryString.parse = QueryString.decode = function(qs, sep, eq) {
+QueryString.parse = QueryString.decode = function(qs, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
- var obj = {};
+ var obj = {},
+ maxKeys = options && options.maxKeys || 1000;
if (typeof qs !== 'string' || qs.length === 0) {
return obj;
}
- qs.split(sep).forEach(function(kvp) {
+ qs = qs.split(sep);
+
+ // maxKeys <= 0 means that we should not limit keys count
+ if (maxKeys > 0) {
+ qs = qs.slice(0, maxKeys);
+ }
+
+ qs.forEach(function(kvp) {
var x = kvp.split(eq);
var k = QueryString.unescape(x[0], true);
var v = QueryString.unescape(x.slice(1).join(eq), true);
assert.deepEqual({}, qs.parse());
+// Test limiting
+assert.equal(
+ Object.keys(qs.parse('a=1&b=1&c=1', null, null, { maxKeys: 1 })).length,
+ 1
+);
+
var b = qs.unescapeBuffer('%d3%f2Ug%1f6v%24%5e%98%cb' +
'%0d%ac%a2%2f%9d%eb%d8%a2%e6');
assert.equal(0xd8, b[17]);
assert.equal(0xa2, b[18]);
assert.equal(0xe6, b[19]);
-