From 36b2a96a8d728e014698280d70ce8b0d52bc725d Mon Sep 17 00:00:00 2001 From: Harold Thetiot Date: Tue, 27 Jun 2017 13:56:39 -0700 Subject: [PATCH 1/2] jshint --- .jshintrc | 132 +++++++++++++++++++++++++++++++++++++++++++++ lib/http.js | 85 ++++++++++++++++------------- package.json | 2 + test/compressor.js | 40 ++++++++------ test/connection.js | 5 +- test/flow.js | 4 +- test/framer.js | 2 +- test/http.js | 20 +++---- test/stream.js | 4 +- test/util.js | 1 + 10 files changed, 230 insertions(+), 65 deletions(-) create mode 100644 .jshintrc diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..dccc1505 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,132 @@ +{ + // -------------------------------------------------------------------- + // JSHint Configuration, Strict Edition + // -------------------------------------------------------------------- + // + // This is a options template for [JSHint][1], using [JSHint example][2] + // and [Ory Band's example][3] as basis and setting config values to + // be most strict: + // + // * set all enforcing options to true + // * set all relaxing options to false + // * set all environment options to false, except the browser value + // * set all JSLint legacy options to false + // + // [1]: http://www.jshint.com/ + // [2]: https://github.com/jshint/node-jshint/blob/master/example/config.json + // [3]: https://github.com/oryband/dotfiles/blob/master/jshintrc + // + // @author http://michael.haschke.biz/ + // @license http://unlicense.org/ + + // == Enforcing Options =============================================== + // + // These options tell JSHint to be more strict towards your code. Use + // them if you want to allow only a safe subset of JavaScript, very + // useful when your codebase is shared with a big number of developers + // with different skill levels. + "unused" : false, + "bitwise" : false, // Prohibit bitwise operators (&, |, ^, etc.). + "curly" : true, // Require {} for every new block or scope. + "eqeqeq" : true, // Require triple equals i.e. `===`. + "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. + "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` + "latedef" : false, // Prohibit variable use before definition. + "newcap" : false, // Require capitalization of all constructor functions e.g. `new F()`. + "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. + "noempty" : true, // Prohibit use of empty blocks. + "nonew" : true, // Prohibit use of constructors for side-effects. + "plusplus" : false, // Prohibit use of `++` & `--`. + "regexp" : true, // Prohibit `.` and `[^...]` in regular expressions. + "undef" : true, // Require all non-global variables be declared before they are used. + "strict" : false, // Require `use strict` pragma in every file. + "trailing" : true, // Prohibit trailing whitespaces. + + // == Relaxing Options ================================================ + // + // These options allow you to suppress certain types of warnings. Use + // them only if you are absolutely positive that you know what you are + // doing. + + "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). + "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. + "debug" : false, // Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // Tolerate use of `== null`. + "es5" : false, // Allow EcmaScript 5 syntax. + "esnext" : false, // Allow ES.next specific features such as `const` and `let`. + "evil" : false, // Tolerate use of `eval`. + "expr" : false, // Tolerate `ExpressionStatement` as Programs. + "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. + "globalstrict" : true, // Allow global "use strict" (also enables 'strict'). + "iterator" : false, // Allow usage of __iterator__ property. + "lastsemic" : false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block. + "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. + "laxcomma" : false, // Suppress warnings about comma-first coding style. + "loopfunc" : false, // Allow functions to be defined within loops. + "multistr" : true, // Tolerate multi-line strings. + "onecase" : false, // Tolerate switches with just one case. + "proto" : true, // Tolerate __proto__ property. This property is deprecated. + "regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`. + "scripturl" : false, // Tolerate script-targeted URLs. + "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. + "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. + "sub" : true, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. + "supernew" : true, // Tolerate `new function () { ... };` and `new Object;`. + "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. + + // == Environments ==================================================== + // + // These options pre-define global variables that are exposed by + // popular JavaScript libraries and runtime environments—such as + // browser or node.js. + + "browser" : true, // Standard browser globals e.g. `window`, `document`. + "couch" : false, // Enable globals exposed by CouchDB. + "devel" : false, // Allow development statements e.g. `console.log();`. + "dojo" : false, // Enable globals exposed by Dojo Toolkit. + "jquery" : false, // Enable globals exposed by jQuery JavaScript library. + "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. + "node" : false, // Enable globals available when code is running inside of the NodeJS runtime environment. + "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. + "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. + "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. + "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. + + // == JSLint Legacy =================================================== + // + // These options are legacy from JSLint. Aside from bug fixes they will + // not be improved in any way and might be removed at any point. + + "nomen" : false, // Prohibit use of initial or trailing underbars in names. + "onevar" : false, // Allow only one `var` statement per function. + "passfail" : false, // Stop on first error. + "white" : false, // Check against strict whitespace and indentation rules. + + // == Undocumented Options ============================================ + // + // While I've found these options in [example1][2] and [example2][3] + // they are not described in the [JSHint Options documentation][4]. + // + // [4]: http://www.jshint.com/options/ + + "maxerr" : 100, // Maximum errors before stopping. + "predef" : [ // Extra globals. + //"exampleVar", + //"anotherCoolGlobal", + //"iLoveDouglas" + ], + "indent" : 4, // Specify indentation spacing + "mocha": true, + "globals": { + + "WebSocket": false, + "Buffer": false, + "require": false, + "exports": false, + "module": false, + + "WeakMap": true, + "Map": true, + "Set": true + } +} diff --git a/lib/http.js b/lib/http.js index 1cb5a464..9208ce23 100644 --- a/lib/http.js +++ b/lib/http.js @@ -338,6 +338,7 @@ IncomingMessage.prototype._checkSpecialHeader = function _checkSpecialHeader(key return value; }; +var headerNamePattern = /[A-Z]/; IncomingMessage.prototype._validateHeaders = function _validateHeaders(headers) { // * An HTTP/2.0 request or response MUST NOT include any of the following header fields: // Connection, Host, Keep-Alive, Proxy-Connection, Transfer-Encoding, and Upgrade. A server @@ -354,17 +355,19 @@ IncomingMessage.prototype._validateHeaders = function _validateHeaders(headers) } for (var headerName in headers) { - // * Empty header name field is malformed - if (headerName.length <= 1) { - this.stream.reset('PROTOCOL_ERROR'); - return; - } - // * A request or response containing uppercase header name field names MUST be - // treated as malformed (Section 8.1.3.5). Implementations that detect malformed - // requests or responses need to ensure that the stream ends. - if(/[A-Z]/.test(headerName)) { - this.stream.reset('PROTOCOL_ERROR'); - return; + if (headers.hasOwnProperty(headerName)) { + // * Empty header name field is malformed + if (headerName.length <= 1) { + this.stream.reset('PROTOCOL_ERROR'); + return; + } + // * A request or response containing uppercase header name field names MUST be + // treated as malformed (Section 8.1.3.5). Implementations that detect malformed + // requests or responses need to ensure that the stream ends. + if(headerNamePattern.test(headerName)) { + this.stream.reset('PROTOCOL_ERROR'); + return; + } } } }; @@ -498,7 +501,7 @@ function Server(options) { options.ALPNProtocols = supportedProtocols; options.NPNProtocols = supportedProtocols; options.ciphers = options.ciphers || cipherSuites; - options.honorCipherOrder = (options.honorCipherOrder != false); + options.honorCipherOrder = (options.honorCipherOrder !== false); this._server = https.createServer(options); this._originalSocketListeners = this._server.listeners('secureConnection'); this._server.removeAllListeners('secureConnection'); @@ -643,7 +646,7 @@ Server.prototype.addContext = function addContext(hostname, credentials) { }; Server.prototype.address = function address() { - return this._server.address() + return this._server.address(); }; function createServerRaw(options, requestListener) { @@ -775,8 +778,10 @@ OutgoingResponse.prototype.writeHead = function writeHead(statusCode, reasonPhra headers = reasonPhrase; } - for (var name in headers) { - this.setHeader(name, headers[name]); + for (var headerName in headers) { + if (headers.hasOwnProperty(headerName)) { + this.setHeader(headerName, headers[headerName]); + } } headers = this._headers; @@ -976,7 +981,9 @@ Agent.prototype.request = function request(options, callback) { this.emit('error', new Error('HTTP1.1 -> HTTP2 upgrade is not yet supported.')); } - var request = new OutgoingRequest(this._log); + var key, endpoint, + self = this, + request = new OutgoingRequest(self._log); if (callback) { request.on('response', callback); @@ -997,11 +1004,9 @@ Agent.prototype.request = function request(options, callback) { ]).join(':'); } - var self = this; - // * There's an existing HTTP/2 connection to this host if (key in this.endpoints && this.endpoints[key]) { - var endpoint = this.endpoints[key]; + endpoint = this.endpoints[key]; request._start(endpoint.createStream(), options); } @@ -1020,7 +1025,6 @@ Agent.prototype.request = function request(options, callback) { request.emit('error', error); }); - var self = this; endpoint.socket.on('close', function (error) { // DPW This is sort of a hack to protect against // the reuse of a endpoint that has the underlying @@ -1072,7 +1076,7 @@ Agent.prototype.request = function request(options, callback) { options.ciphers = options.ciphers || cipherSuites; if (createAgent) { options.agent = new https.Agent(options); - } else if (options.agent == null) { + } else if (!options.agent) { options.agent = this._httpsAgent; } var httpsRequest = https.request(options); @@ -1085,14 +1089,14 @@ Agent.prototype.request = function request(options, callback) { httpsRequest.on('socket', function(socket) { var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol; - if (negotiatedProtocol != null) { // null in >=0.11.0, undefined in <0.11.0 + if (negotiatedProtocol) { // null in >=0.11.0, undefined in <0.11.0 negotiated(); } else { socket.on('secureConnect', negotiated); } }); - function negotiated() { + var negotiated = function () { var endpoint; var negotiatedProtocol = httpsRequest.socket.alpnProtocol || httpsRequest.socket.npnProtocol; if (negotiatedProtocol === protocol.VERSION) { @@ -1119,7 +1123,7 @@ Agent.prototype.request = function request(options, callback) { self.emit(key, undefined); } } - } + }; this.once(key, function(endpoint) { started = true; @@ -1144,8 +1148,10 @@ Agent.prototype.destroy = function(error) { if (this._httpsAgent) { this._httpsAgent.destroy(); } - for (var key in this.endpoints) { - this.endpoints[key].close(error); + for (var endpointName in this.endpoints) { + if (this.endpoints.hasOwnProperty(endpointName)) { + this.endpoints[endpointName].close(error); + } } }; @@ -1160,15 +1166,20 @@ function unbundleSocket(socket) { delete socket.onend; } +function hasValue(obj) { + return obj === null && obj === undefined; +} + + function hasAgentOptions(options) { - return options.pfx != null || - options.key != null || - options.passphrase != null || - options.cert != null || - options.ca != null || - options.ciphers != null || - options.rejectUnauthorized != null || - options.secureProtocol != null; + return hasValue(options.pfx) || + hasValue(options.key) || + hasValue(options.passphrase) || + hasValue(options.cert) || + hasValue(options.ca) || + hasValue(options.ciphers) || + hasValue(options.rejectUnauthorized) || + hasValue(options.secureProtocol); } Object.defineProperty(Agent.prototype, 'maxSockets', { @@ -1200,8 +1211,10 @@ OutgoingRequest.prototype._start = function _start(stream, options) { this._log = stream._log.child({ component: 'http' }); - for (var key in options.headers) { - this.setHeader(key, options.headers[key]); + for (var headerName in options.headers) { + if (options.headers.hasOwnProperty(headerName)) { + this.setHeader(headerName, options.headers[headerName]); + } } var headers = this._headers; delete headers.host; diff --git a/package.json b/package.json index f5d98a5a..3d9187c9 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "events": "1.1.1" }, "devDependencies": { + "jshint": "*", "istanbul": "*", "chai": "*", "mocha": "*", @@ -25,6 +26,7 @@ "bunyan": "*" }, "scripts": { + "lint": "jshint lib/*.js test/*.js", "test": "istanbul test _mocha -- --reporter spec --slow 500 --timeout 15000", "doc": "docco lib/* --output doc --layout parallel --template root.jst --css doc/docco.css && docco lib/protocol/* --output doc/protocol --layout parallel --template protocol.jst --css doc/docco.css" }, diff --git a/test/compressor.js b/test/compressor.js index f86baf5d..35ae6755 100644 --- a/test/compressor.js +++ b/test/compressor.js @@ -35,7 +35,7 @@ var test_strings = [{ buffer: new Buffer('13c3a9c3a1c5b1c591c3bac3b6c3bcc3b3e282ac', 'hex') }]; -test_huffman_request = { +var test_huffman_request = { 'GET': 'c5837f', 'http': '9d29af', '/': '63', @@ -48,7 +48,7 @@ test_huffman_request = { 'custom-value': '25a849e95bb8e8b4bf' }; -test_huffman_response = { +var test_huffman_response = { '302': '6402', 'private': 'aec3771a4b', 'Mon, 21 OCt 2013 20:13:21 GMT': 'd07abe941054d5792a0801654102e059b820a98b46ff', @@ -395,29 +395,39 @@ describe('compressor.js', function() { describe('HuffmanTable', function() { describe('method encode(buffer)', function() { it('should return the Huffman encoded version of the input buffer', function() { - var table = HuffmanTable.huffmanTable; - for (var decoded in test_huffman_request) { - var encoded = test_huffman_request[decoded]; - expect(table.encode(new Buffer(decoded)).toString('hex')).to.equal(encoded); + var encoded, decoded, + table = HuffmanTable.huffmanTable; + for (decoded in test_huffman_request) { + if (test_huffman_request.hasOwnProperty(decoded)) { + encoded = test_huffman_request[decoded]; + expect(table.encode(new Buffer(decoded)).toString('hex')).to.equal(encoded); + } } table = HuffmanTable.huffmanTable; for (decoded in test_huffman_response) { - encoded = test_huffman_response[decoded]; - expect(table.encode(new Buffer(decoded)).toString('hex')).to.equal(encoded); + if (test_huffman_response.hasOwnProperty(decoded)) { + encoded = test_huffman_response[decoded]; + expect(table.encode(new Buffer(decoded)).toString('hex')).to.equal(encoded); + } } }); }); describe('method decode(buffer)', function() { it('should return the Huffman decoded version of the input buffer', function() { - var table = HuffmanTable.huffmanTable; - for (var decoded in test_huffman_request) { - var encoded = test_huffman_request[decoded]; - expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded); + var encoded, decoded, + table = HuffmanTable.huffmanTable; + for (decoded in test_huffman_request) { + if (test_huffman_request.hasOwnProperty(decoded)) { + encoded = test_huffman_request[decoded]; + expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded); + } } table = HuffmanTable.huffmanTable; for (decoded in test_huffman_response) { - encoded = test_huffman_response[decoded]; - expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded); + if (test_huffman_response.hasOwnProperty(decoded)) { + encoded = test_huffman_response[decoded]; + expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded); + } } }); }); @@ -562,7 +572,7 @@ describe('compressor.js', function() { for (var i = 0; i < 10; i++) { var buffer = []; while (Math.random() > 0.1) { - buffer.push(Math.floor(Math.random() * 256)) + buffer.push(Math.floor(Math.random() * 256)); } buffer = new Buffer(buffer); var table = HuffmanTable.huffmanTable; diff --git a/test/connection.js b/test/connection.js index 2c68857f..1ab3b265 100644 --- a/test/connection.js +++ b/test/connection.js @@ -49,7 +49,10 @@ describe('connection.js', function() { for (var i = 0; i < streamCount; i++) { oldPriority = randomPriority(); - while ((newPriority = randomPriority()) === oldPriority); + do { + newPriority = randomPriority(); + } while(newPriority === oldPriority); + stream = { _priority: oldPriority }; connection._insert(stream, oldPriority); connection._reprioritize(stream, newPriority); diff --git a/test/flow.js b/test/flow.js index a077c684..2c025c18 100644 --- a/test/flow.js +++ b/test/flow.js @@ -44,7 +44,9 @@ describe('flow.js', function() { flow._window = 0; flow._queue.push({ type: 'DATA', flags: {}, data: { length: 1 } }); var frame = flow.read(); - while (frame.type === notFlowControlledFrame.type) frame = flow.read(); + while (frame.type === notFlowControlledFrame.type) { + frame = flow.read(); + } expect(frame.type).to.equal('BLOCKED'); expect(flow.read()).to.equal(null); }); diff --git a/test/framer.js b/test/framer.js index 59cc711b..7e011b87 100644 --- a/test/framer.js +++ b/test/framer.js @@ -323,7 +323,7 @@ describe('framer.js', function() { var test = test_frames[i]; stream.write(test.frame); var chunk, buffer = new Buffer(0); - while (chunk = stream.read()) { + while ((chunk = stream.read())) { buffer = util.concat([buffer, chunk]); } expect(buffer).to.be.deep.equal(test.buffer); diff --git a/test/http.js b/test/http.js index 47c516ca..937e88d8 100644 --- a/test/http.js +++ b/test/http.js @@ -1,3 +1,4 @@ +/* global __dirname */ var expect = require('chai').expect; var util = require('./util'); var fs = require('fs'); @@ -34,7 +35,7 @@ describe('http.js', function() { describe('new Server(options)', function() { it('should throw if called without \'plain\' or TLS options', function() { expect(function() { - new http2.Server(); + return new http2.Server(); }).to.throw(Error); expect(function() { http2.createServer(util.noop); @@ -49,7 +50,7 @@ describe('http.js', function() { server.close(); done(); - }) + }); server.listen(0); }); @@ -61,8 +62,7 @@ describe('http.js', function() { var net = require('net').createServer(); server.on('error', function () { - net.close() - + net.close(); done(); }); @@ -203,7 +203,7 @@ describe('http.js', function() { var res; var server = http2.createServer(serverOptions, function(request, response) { res = response; - expect(res.finished).to.be.false; + expect(res.finished).to.equal(false); response.end('HiThere'); }); server.listen(1236, function() { @@ -212,7 +212,7 @@ describe('http.js', function() { var sink = data; // }); response.on('end',function(){ - expect(res.finished).to.be.true; + expect(res.finished).to.equal(true); server.close(); done(); }); @@ -380,8 +380,8 @@ describe('http.js', function() { request.on('response', function(response) { expect(response.headers[headerName]).to.equal(headerValue); expect(response.headers['nonexistent']).to.equal(undefined); - expect(response.headers['set-cookie']).to.an.instanceof(Array) - expect(response.headers['set-cookie']).to.deep.equal(['foo']) + expect(response.headers['set-cookie']).to.an.instanceof(Array); + expect(response.headers['set-cookie']).to.deep.equal(['foo']); expect(response.headers['date']).to.equal(undefined); response.on('data', function(data) { expect(data.toString()).to.equal(message); @@ -836,7 +836,7 @@ describe('http.js', function() { }); request.on('response', function (response) { - server._server._handle.destroy(); + //server._server._handle.destroy(); response.on('data', util.noop); @@ -859,7 +859,7 @@ describe('http.js', function() { }); request.on('response', function (response) { - server._server._handle.destroy(); + //server._server._handle.destroy(); response.on('data', util.noop); diff --git a/test/stream.js b/test/stream.js index e99f74c3..9f0ee937 100644 --- a/test/stream.js +++ b/test/stream.js @@ -80,7 +80,9 @@ function execute_sequence(stream, sequence, done) { if ('outgoing' in check) { var frame = outgoing_frames.shift(); for (var key in check.outgoing) { - expect(frame).to.have.property(key).that.deep.equals(check.outgoing[key]); + if (check.outgoing.hasOwnProperty(key)) { + expect(frame).to.have.property(key).that.deep.equals(check.outgoing[key]); + } } count_change(frame.count_change); } else if ('event' in check) { diff --git a/test/util.js b/test/util.js index b2c24940..4404da8c 100644 --- a/test/util.js +++ b/test/util.js @@ -1,3 +1,4 @@ +/* global process */ var path = require('path'); var fs = require('fs'); var spawn = require('child_process').spawn; From 14e2dadd70aa2b6a2dabb3d4aadcd46cfa78a75a Mon Sep 17 00:00:00 2001 From: Harold Thetiot Date: Tue, 27 Jun 2017 13:59:01 -0700 Subject: [PATCH 2/2] update .jshintrc --- .jshintrc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.jshintrc b/.jshintrc index dccc1505..a38fe497 100644 --- a/.jshintrc +++ b/.jshintrc @@ -118,15 +118,9 @@ "indent" : 4, // Specify indentation spacing "mocha": true, "globals": { - - "WebSocket": false, "Buffer": false, "require": false, "exports": false, - "module": false, - - "WeakMap": true, - "Map": true, - "Set": true + "module": false } }