Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{
// --------------------------------------------------------------------
// 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": {
"Buffer": false,
"require": false,
"exports": false,
"module": false
}
}
85 changes: 49 additions & 36 deletions lib/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
}
}
};
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -1119,7 +1123,7 @@ Agent.prototype.request = function request(options, callback) {
self.emit(key, undefined);
}
}
}
};

this.once(key, function(endpoint) {
started = true;
Expand All @@ -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);
}
}
};

Expand All @@ -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', {
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"events": "1.1.1"
},
"devDependencies": {
"jshint": "*",
"istanbul": "*",
"chai": "*",
"mocha": "*",
Expand All @@ -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"
},
Expand Down
Loading