diff --git a/AUTHORS b/AUTHORS index 21b9736c1f1..59783d9912b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -203,6 +203,7 @@ Feross Aboukhadijeh Florin-Cristian Gavrila Forrest L Norvell Francois Marier +Frank Cash Fred K. Schott Frederico Silva Friedemann Altrock diff --git a/Makefile b/Makefile index 1629d14f74d..3597f43af74 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ out/doc/%: doc/% cp -r $< $@ out/doc/api/%.json: doc/api/%.markdown node - NODE_DOC_VERSION=$(NODE_DOC_VERSION) out/Release/node tools/doc/generate.js --format=json $< > $@ + NODE_DOC_VERSION=$(NODE_DOC_VERSION) out/Release/node tools/doc/generate.js --format=json $< --output=$@ out/doc/api/%.html: doc/api/%.markdown node NODE_DOC_VERSION=$(NODE_DOC_VERSION) out/Release/node tools/doc/generate.js --format=html --template=doc/template.html $< > $@ diff --git a/README.md b/README.md index acaf24b372c..61f3e519220 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ Resources for Newcomers - [searching the npm registry](http://npmjs.org/) - [list of companies and projects using node](https://github.com/joyent/node/wiki/Projects,-Applications,-and-Companies-Using-Node) - [node.js mailing list](http://groups.google.com/group/nodejs) - - irc chatroom, [#node.js on freenode.net](http://webchat.freenode.net?channels=node.js&uio=d4) + - [irc chatroom, #node.js on freenode.net](http://webchat.freenode.net?channels=node.js&uio=d4) - [community](https://github.com/joyent/node/wiki/Community) - [contributing](https://github.com/joyent/node/wiki/Contributing) - [big list of all the helpful wiki pages](https://github.com/joyent/node/wiki/_pages) diff --git a/deps/debugger-agent/lib/_debugger_agent.js b/deps/debugger-agent/lib/_debugger_agent.js index 680c5e95c49..d0e6dff257a 100644 --- a/deps/debugger-agent/lib/_debugger_agent.js +++ b/deps/debugger-agent/lib/_debugger_agent.js @@ -1,3 +1,5 @@ +'use strict'; + var assert = require('assert'); var net = require('net'); var util = require('util'); diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index 25c2f752164..f0a867360cf 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -101,7 +101,7 @@ Example: this program that takes the sha1 sum of a file var shasum = crypto.createHash('sha1'); - var s = fs.ReadStream(filename); + var s = fs.createReadStream(filename); s.on('data', function(d) { shasum.update(d); }); diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 3ba57a19567..98da286460c 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -511,8 +511,13 @@ Example: console.log('STATUS: ' + res.statusCode); console.log('HEADERS: ' + JSON.stringify(res.headers)); res.setEncoding('utf8'); + var data = ''; res.on('data', function (chunk) { - console.log('BODY: ' + chunk); + console.log('PARTIAL BODY: ' + chunk); + data += chunk; + }); + res.on('end', function() { + console.log('COMPLETE BODY: ' + data); }); }); @@ -524,6 +529,12 @@ Example: req.write(postData); req.end(); +The `res` object handed off to the callback function passed into to +`http.request` is an instance of [http.IncomingMessage], which is an +instance of a Readable Stream. The content of a successful response will be +delivered using zero or more `data` events followed by a closing `end` +event. + Note that in the example `req.end()` was called. With `http.request()` one must always call `req.end()` to signify that you're done with the request - even if there is no data being written to the request body. @@ -557,6 +568,8 @@ Example: http.get("http://www.google.com/index.html", function(res) { console.log("Got response: " + res.statusCode); + // consume response body + res.resume(); }).on('error', function(e) { console.log("Got error: " + e.message); }); diff --git a/doc/api/path.markdown b/doc/api/path.markdown index 3489f1811f5..d4daeab46f4 100644 --- a/doc/api/path.markdown +++ b/doc/api/path.markdown @@ -200,7 +200,7 @@ An example on Windows: process.env.PATH.split(path.delimiter) // returns - ['C:\Windows\system32', 'C:\Windows', 'C:\Program Files\nodejs\'] + ['C:\\Windows\\system32', 'C:\\Windows', 'C:\\Program Files\\nodejs\\'] ## path.parse(pathString) @@ -223,8 +223,8 @@ An example on Windows: path.parse('C:\\path\\dir\\index.html') // returns { - root : "C:\", - dir : "C:\path\dir", + root : "C:\\", + dir : "C:\\path\\dir", base : "index.html", ext : ".html", name : "index" diff --git a/doc/api/stream.markdown b/doc/api/stream.markdown index 1029c43c943..26978e8e545 100644 --- a/doc/api/stream.markdown +++ b/doc/api/stream.markdown @@ -1175,9 +1175,9 @@ as a result of this chunk. Call the callback function only when the current chunk is completely consumed. Note that there may or may not be output as a result of any -particular input chunk. If you supply as the second argument to the -it will be passed to push method, in other words the following are -equivalent: +particular input chunk. If you supply a data chunk as the second argument +to the callback function it will be passed to push method, in other words +the following are equivalent: ```javascript transform.prototype._transform = function (data, encoding, callback) { diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index dc3a0431bee..7e1d45c6de0 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -25,8 +25,10 @@ To create a self-signed certificate with the CSR, do this: Alternatively you can send the CSR to a Certificate Authority for signing. -(TODO: docs on creating a CA, for now interested users should just look at -`test/fixtures/keys/Makefile` in the Node source code) +For Perfect Forward Secrecy, it is required to generate Diffie-Hellman +parameters: + + openssl dhparam -outform PEM -out dhparam.pem 2048 To create .pfx or .p12, do this: @@ -134,6 +136,81 @@ the character "E" appended to the traditional abbreviations): Ephemeral methods may have some performance drawbacks, because key generation is expensive. +## Modifying the Default Cipher Suite + +Node.js is built with a default suite of enabled and disabled ciphers. +Currently, the default cipher suite is: + + ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256: + DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256: + HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA + +This default can be overridden entirely using the `--cipher-list` command line +switch or `NODE_CIPHER_LIST` environment variable. For instance: + + node --cipher-list=ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384 + +Setting the environment variable would have the same effect: + + NODE_CIPHER_LIST=ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384 + +CAUTION: The default cipher suite has been carefully selected to reflect current +security best practices and risk mitigation. Changing the default cipher suite +can have a significant impact on the security of an application. The +`--cipher-list` and `NODE_CIPHER_LIST` options should only be used if +absolutely necessary. + +### Using Legacy Default Cipher Suite ### + +It is possible for the built-in default cipher suite to change from one release +of Node.js to another. For instance, v0.10.38 uses a different default than +v0.12.2. Such changes can cause issues with applications written to assume +certain specific defaults. To help buffer applications against such changes, +the `--enable-legacy-cipher-list` command line switch or `NODE_LEGACY_CIPHER_LIST` +environment variable can be set to specify a specific preset default: + + # Use the v0.10.38 defaults + node --enable-legacy-cipher-list=v0.10.38 + // or + NODE_LEGACY_CIPHER_LIST=v0.10.38 + + # Use the v0.12.2 defaults + node --enable-legacy-cipher-list=v0.12.2 + // or + NODE_LEGACY_CIPHER_LIST=v0.12.2 + +Currently, the values supported for the `enable-legacy-cipher-list` switch and +`NODE_LEGACY_CIPHER_LIST` environment variable include: + + v0.10.38 - To enable the default cipher suite used in v0.10.38 + + ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH + + v0.10.39 - To enable the default cipher suite used in v0.10.39 + + ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH + + v0.12.2 - To enable the default cipher suite used in v0.12.2 + + ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4: + HIGH:!MD5:!aNULL + + v.0.12.3 - To enable the default cipher suite used in v0.12.3 + + ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH: + !RC4:!MD5:!aNULL + +These legacy cipher suites are also made available for use via the +`getLegacyCiphers()` method: + + var tls = require('tls'); + console.log(tls.getLegacyCiphers('v0.10.38')); + +CAUTION: Changes to the default cipher suite are typically made in order to +strengthen the default security for applications running within Node.js. +Reverting back to the defaults used by older releases can weaken the security +of your applications. The legacy cipher suites should only be used if absolutely +necessary. ## tls.getCiphers() @@ -144,6 +221,12 @@ Example: var ciphers = tls.getCiphers(); console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...] +## tls.getLegacyCiphers(version) + +Returns the legacy default cipher suite for the specified Node.js release. + +Example: + var cipher_suite = tls.getLegacyCiphers('v0.10.38'); ## tls.createServer(options[, secureConnectionListener]) @@ -170,31 +253,20 @@ automatically set as a listener for the [secureConnection][] event. The - `crl` : Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List) - - `ciphers`: A string describing the ciphers to use or exclude. - - To mitigate [BEAST attacks] it is recommended that you use this option in - conjunction with the `honorCipherOrder` option described below to - prioritize the non-CBC cipher. - - Defaults to - `ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL`. - Consult the [OpenSSL cipher list format documentation] for details - on the format. - - `ECDHE-RSA-AES128-SHA256`, `DHE-RSA-AES128-SHA256` and - `AES128-GCM-SHA256` are TLS v1.2 ciphers and used when Node.js is - linked against OpenSSL 1.0.1 or newer, such as the bundled version - of OpenSSL. Note that it is still possible for a TLS v1.2 client - to negotiate a weaker cipher unless `honorCipherOrder` is enabled. + - `ciphers`: A string describing the ciphers to use or exclude, separated by + `:`. The default cipher suite is: - `RC4` is used as a fallback for clients that speak on older version of - the TLS protocol. `RC4` has in recent years come under suspicion and - should be considered compromised for anything that is truly sensitive. - It is speculated that state-level actors possess the ability to break it. + ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256: + DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256: + HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA - **NOTE**: Previous revisions of this section suggested `AES256-SHA` as an - acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore - susceptible to [BEAST attacks]. Do *not* use it. + The default cipher suite prefers ECDHE and DHE ciphers for Perfect Forward + secrecy, while offering *some* backward compatibility. Old clients which + rely on insecure and deprecated RC4 or DES-based ciphers (like Internet + Explorer 6) aren't able to complete the handshake with the default + configuration. If you absolutely must support these clients, the + [TLS recommendations] may offer a compatible cipher suite. For more details + on the format, see the [OpenSSL cipher list format documentation]. - `ecdhCurve`: A string describing a named curve to use for ECDH key agreement or false to disable ECDH. @@ -212,7 +284,7 @@ automatically set as a listener for the [secureConnection][] event. The times out. - `honorCipherOrder` : When choosing a cipher, use the server's preferences - instead of the client preferences. + instead of the client preferences. Default: `true`. Although, this option is disabled by default, it is *recommended* that you use this option in conjunction with the `ciphers` option to mitigate @@ -512,7 +584,7 @@ encrypted data, and one reads/writes cleartext data. Generally the encrypted one is piped to/from an incoming encrypted data stream, and the cleartext one is used as a replacement for the initial encrypted stream. - - `credentials`: A secure context object from tls.createSecureContext( ... ) + - `context`: A secure context object from tls.createSecureContext( ... ) - `isServer`: A boolean indicating whether this tls connection should be opened as a server or a client. @@ -868,5 +940,6 @@ The numeric representation of the local port. [ECDHE]: https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman [asn1.js]: http://npmjs.org/package/asn1.js [OCSP request]: http://en.wikipedia.org/wiki/OCSP_stapling +[TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS [SSL_CTX_set_options]: https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html [CVE-2014-3566]: https://access.redhat.com/articles/1232123 diff --git a/lib/_debugger.js b/lib/_debugger.js index 6f7a80b77a8..8c831d74971 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'), path = require('path'), net = require('net'), diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 6fbff37d85d..96797b2e822 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var net = require('net'); var util = require('util'); var EventEmitter = require('events').EventEmitter; diff --git a/lib/_http_client.js b/lib/_http_client.js index 538586e5482..429d7e8c83b 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); var net = require('net'); var url = require('url'); diff --git a/lib/_http_common.js b/lib/_http_common.js index 7994cdd98d9..8edc6713940 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var FreeList = require('freelist').FreeList; var HTTPParser = process.binding('http_parser').HTTPParser; diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js index 69d3d86ec6a..a252c114bf8 100644 --- a/lib/_http_incoming.js +++ b/lib/_http_incoming.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); var Stream = require('stream'); diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index d02bdf7f23e..7f61aac35ed 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var assert = require('assert').ok; var Stream = require('stream'); var timers = require('timers'); diff --git a/lib/_http_server.js b/lib/_http_server.js index 787fc27bbf1..876e2f9081b 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); var net = require('net'); var EventEmitter = require('events').EventEmitter; @@ -448,7 +450,7 @@ function connectionListener(socket) { } // When we're finished writing the response, check if this is the last - // respose, if so destroy the socket. + // response, if so destroy the socket. res.on('prefinish', resOnFinish); function resOnFinish() { // Usually the first incoming element should be our request. it may diff --git a/lib/_linklist.js b/lib/_linklist.js index b73bbed22b8..048e933ee3a 100644 --- a/lib/_linklist.js +++ b/lib/_linklist.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + function init(list) { list._idleNext = list; list._idlePrev = list; diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js index 75cf30d7987..474a31303d9 100644 --- a/lib/_stream_duplex.js +++ b/lib/_stream_duplex.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // a duplex stream is just a stream that is both readable and writable. // Since JS doesn't have multiple prototypal inheritance, this class // prototypally inherits from Readable, and then parasitically from diff --git a/lib/_stream_passthrough.js b/lib/_stream_passthrough.js index a5e986430d7..7a9102aedc7 100644 --- a/lib/_stream_passthrough.js +++ b/lib/_stream_passthrough.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // a passthrough stream. // basically just the most minimal sort of Transform stream. // Every written chunk gets output as-is. diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 5f280b77360..5afb8c6998a 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + module.exports = Readable; Readable.ReadableState = ReadableState; @@ -142,8 +144,7 @@ function readableAddChunk(stream, state, chunk, encoding, addToFront) { stream.emit('error', er); } else if (chunk === null) { state.reading = false; - if (!state.ended) - onEofChunk(stream, state); + onEofChunk(stream, state); } else if (state.objectMode || chunk && chunk.length > 0) { if (state.ended && !addToFront) { var e = new Error('stream.push() after EOF'); @@ -388,7 +389,8 @@ function chunkInvalid(state, chunk) { function onEofChunk(stream, state) { - if (state.decoder && !state.ended) { + if (state.ended) return; + if (state.decoder) { var chunk = state.decoder.end(); if (chunk && chunk.length) { state.buffer.push(chunk); diff --git a/lib/_stream_transform.js b/lib/_stream_transform.js index 1843f51b751..3c6bb9db968 100644 --- a/lib/_stream_transform.js +++ b/lib/_stream_transform.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // a transform stream is a readable/writable stream where you do // something with the data. Sometimes it's called a "filter", diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index f39393b0617..70da498da3e 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // A bit simpler than readable streams. // Implement an async ._write(chunk, cb), and it'll handle all // the drain event emission and buffering. diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 72648be9843..113abbcc1f6 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); var constants = require('constants'); var tls = require('tls'); diff --git a/lib/_tls_legacy.js b/lib/_tls_legacy.js index 6dc5c3493cf..5745be3efa3 100644 --- a/lib/_tls_legacy.js +++ b/lib/_tls_legacy.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var assert = require('assert'); var events = require('events'); var stream = require('stream'); diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 6e2a430840a..378f6053278 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -22,6 +22,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var assert = require('assert'); var crypto = require('crypto'); var net = require('net'); @@ -733,10 +735,10 @@ Server.prototype.setOptions = function(options) { secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE; } - if (options.honorCipherOrder) - this.honorCipherOrder = true; + if (options.honorCipherOrder !== undefined) + this.honorCipherOrder = !!options.honorCipherOrder; else - this.honorCipherOrder = false; + this.honorCipherOrder = true; this.secureOptions = secureOptions; diff --git a/lib/assert.js b/lib/assert.js index 357dd1bb0c6..58f320d6836 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -22,6 +22,8 @@ // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // UTILITY var util = require('util'); var b = require('buffer'); diff --git a/lib/buffer.js b/lib/buffer.js index 1a9f7caeb5a..13f701ba2d2 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var buffer = process.binding('buffer'); var smalloc = process.binding('smalloc'); var util = require('util'); diff --git a/lib/child_process.js b/lib/child_process.js index 8b29132cb4e..7e64ae683e1 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var StringDecoder = require('string_decoder').StringDecoder; var EventEmitter = require('events').EventEmitter; var net = require('net'); diff --git a/lib/cluster.js b/lib/cluster.js index 71ebf41c454..e05de4568bc 100644 --- a/lib/cluster.js +++ b/lib/cluster.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var EventEmitter = require('events').EventEmitter; var assert = require('assert'); var dgram = require('dgram'); diff --git a/lib/console.js b/lib/console.js index 1aaedfea286..5d4077ab7e1 100644 --- a/lib/console.js +++ b/lib/console.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); function Console(stdout, stderr) { diff --git a/lib/constants.js b/lib/constants.js index 1b87b2b2d0c..816dc853e1b 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -19,4 +19,6 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + module.exports = process.binding('constants'); diff --git a/lib/crypto.js b/lib/crypto.js index 97cceb67f5c..8f80fff1594 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // Note: In 0.8 and before, crypto functions all defaulted to using // binary-encoded strings rather than buffers. diff --git a/lib/dgram.js b/lib/dgram.js index 764892a90bc..582b6203660 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var assert = require('assert'); var util = require('util'); var events = require('events'); @@ -293,7 +295,7 @@ Socket.prototype.send = function(buffer, self._healthCheck(); if (self._bindState == BIND_STATE_UNBOUND) - self.bind(0, null); + self.bind({port: 0, exclusive: true}, null); // If the socket hasn't been bound yet, push the outbound packet onto the // send queue and send after binding is complete. diff --git a/lib/dns.js b/lib/dns.js index 18023fab162..45349718521 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var net = require('net'); var util = require('util'); diff --git a/lib/domain.js b/lib/domain.js index 5924b44ebdf..4121ede82cc 100644 --- a/lib/domain.js +++ b/lib/domain.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); var EventEmitter = require('events'); var inherits = util.inherits; diff --git a/lib/events.js b/lib/events.js index 0cd841b8445..f8c651feac6 100644 --- a/lib/events.js +++ b/lib/events.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var domain; var util = require('util'); diff --git a/lib/freelist.js b/lib/freelist.js index 588facd25b3..561ca53458c 100644 --- a/lib/freelist.js +++ b/lib/freelist.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // This is a free list to avoid creating so many of the same object. exports.FreeList = function(name, max, constructor) { this.name = name; diff --git a/lib/fs.js b/lib/fs.js index bd9fde680df..daeb20e747e 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // Maintainers, keep in mind that octal literals are not allowed // in strict mode. Use the decimal value and add a comment with // the octal value. Example: @@ -87,10 +89,14 @@ function maybeCallback(cb) { // for callbacks that are passed to the binding layer, callbacks that are // invoked from JS already run in the proper scope. function makeCallback(cb) { - if (!util.isFunction(cb)) { + if (util.isNullOrUndefined(cb)) { return rethrow(); } + if (!util.isFunction(cb)) { + throw new TypeError('callback must be a function'); + } + return function() { return cb.apply(null, arguments); }; diff --git a/lib/http.js b/lib/http.js index d12f12d60ce..c0b2b0af112 100644 --- a/lib/http.js +++ b/lib/http.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var util = require('util'); var EventEmitter = require('events').EventEmitter; diff --git a/lib/https.js b/lib/https.js index f9011648fb6..4c2731ab581 100644 --- a/lib/https.js +++ b/lib/https.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var tls = require('tls'); var url = require('url'); var http = require('http'); diff --git a/lib/module.js b/lib/module.js index 4ac8cfa30a0..0f1f38c7bb0 100644 --- a/lib/module.js +++ b/lib/module.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var NativeModule = require('native_module'); var util = require('util'); var runInThisContext = require('vm').runInThisContext; diff --git a/lib/net.js b/lib/net.js index e6e48f4d9fd..67109895bbb 100644 --- a/lib/net.js +++ b/lib/net.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var events = require('events'); var stream = require('stream'); var timers = require('timers'); @@ -68,8 +70,8 @@ function isPipeName(s) { } -exports.createServer = function() { - return new Server(arguments[0], arguments[1]); +exports.createServer = function(options, connectionListener) { + return new Server(options, connectionListener); }; @@ -577,10 +579,10 @@ function onread(nread, buffer) { Socket.prototype._getpeername = function() { - if (!this._handle || !this._handle.getpeername) { - return {}; - } if (!this._peername) { + if (!this._handle || !this._handle.getpeername) { + return {}; + } var out = {}; var err = this._handle.getpeername(out); if (err) return {}; // FIXME(bnoordhuis) Throw? @@ -866,6 +868,7 @@ Socket.prototype.connect = function(options, cb) { this._writableState.errorEmitted = false; this.destroyed = false; this._handle = null; + this._peername = null; } var self = this; @@ -1012,23 +1015,23 @@ function afterConnect(status, handle, req, readable, writable) { } -function Server(/* [ options, ] listener */) { - if (!(this instanceof Server)) return new Server(arguments[0], arguments[1]); +function Server(options, connectionListener) { + if (!(this instanceof Server)) + return new Server(options, connectionListener); + events.EventEmitter.call(this); var self = this; - var options; - - if (util.isFunction(arguments[0])) { + if (util.isFunction(options)) { + connectionListener = options; options = {}; - self.on('connection', arguments[0]); + self.on('connection', connectionListener); } else { - options = arguments[0] || {}; + options = options || {}; - if (util.isFunction(arguments[1])) { - self.on('connection', arguments[1]); - } + if (util.isFunction(connectionListener)) + self.on('connection', connectionListener); } this._connections = 0; diff --git a/lib/os.js b/lib/os.js index 814c054ef31..79cef00a4ae 100644 --- a/lib/os.js +++ b/lib/os.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var binding = process.binding('os'); var util = require('util'); var isWindows = process.platform === 'win32'; diff --git a/lib/path.js b/lib/path.js index d91feff305d..937bc792cd6 100644 --- a/lib/path.js +++ b/lib/path.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var isWindows = process.platform === 'win32'; var util = require('util'); diff --git a/lib/querystring.js b/lib/querystring.js index 04c083d8abc..0f317fc30b8 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // Query String Utilities var QueryString = exports; diff --git a/lib/readline.js b/lib/readline.js index fe2def0350a..4676bccb3fb 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // Inspiration for this code comes from Salvatore Sanfilippo's linenoise. // https://github.com/antirez/linenoise // Reference: diff --git a/lib/repl.js b/lib/repl.js index ef720a2f57c..3bb145bb44f 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + /* A repl library that you can include in your own code to get a runtime * interface to your program. * diff --git a/lib/smalloc.js b/lib/smalloc.js index 2b4175e0cb1..994b3f281ba 100644 --- a/lib/smalloc.js +++ b/lib/smalloc.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var smalloc = process.binding('smalloc'); var kMaxLength = smalloc.kMaxLength; var util = require('util'); diff --git a/lib/stream.js b/lib/stream.js index 073c6ed338f..83815e84049 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + module.exports = Stream; var EE = require('events').EventEmitter; diff --git a/lib/string_decoder.js b/lib/string_decoder.js index fd11e51c8da..84ac9a9d445 100644 --- a/lib/string_decoder.js +++ b/lib/string_decoder.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + function assertEncoding(encoding) { if (encoding && !Buffer.isEncoding(encoding)) { throw new Error('Unknown encoding: ' + encoding); diff --git a/lib/sys.js b/lib/sys.js index cf98a073e6c..6dc415c31f8 100644 --- a/lib/sys.js +++ b/lib/sys.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + // the sys module was renamed to 'util'. // this shim remains to keep old programs working. module.exports = require('util'); diff --git a/lib/timers.js b/lib/timers.js index 5ef5f37ed76..68f87d7c9f3 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var Timer = process.binding('timer_wrap').Timer; var L = require('_linklist'); var assert = require('assert').ok; diff --git a/lib/tls.js b/lib/tls.js index a00fbb9d722..aebafc1bd93 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -19,6 +19,10 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + +var _crypto = process.binding('crypto'); + var net = require('net'); var url = require('url'); var util = require('util'); @@ -33,16 +37,14 @@ exports.CLIENT_RENEG_WINDOW = 600; exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024; -exports.DEFAULT_CIPHERS = - // TLS 1.2 - 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' + - // TLS 1.0 - 'RC4:HIGH:!MD5:!aNULL'; +exports.DEFAULT_CIPHERS = _crypto.DEFAULT_CIPHER_LIST; exports.DEFAULT_ECDH_CURVE = 'prime256v1'; +exports.getLegacyCiphers = _crypto.getLegacyCiphers; + exports.getCiphers = function() { - var names = process.binding('crypto').getSSLCiphers(); + var names = _crypto.getSSLCiphers(); // Drop all-caps names in favor of their lowercase aliases, var ctx = {}; names.forEach(function(name) { diff --git a/lib/tty.js b/lib/tty.js index 74300fc1e4b..3d5c2a66493 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var inherits = require('util').inherits; var net = require('net'); var TTY = process.binding('tty_wrap').TTY; diff --git a/lib/url.js b/lib/url.js index ac712318bcd..c5a3793b9a9 100644 --- a/lib/url.js +++ b/lib/url.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var punycode = require('punycode'); var util = require('util'); @@ -639,8 +641,8 @@ Url.prototype.resolveObject = function(relative) { // then it must NOT get a trailing slash. var last = srcPath.slice(-1)[0]; var hasTrailingSlash = ( - (result.host || relative.host) && (last === '.' || last === '..') || - last === ''); + (result.host || relative.host || srcPath.length > 1) && + (last === '.' || last === '..') || last === ''); // strip single dots, resolve double dots to parent dir // if the path tries to go above the root, `up` ends up > 0 diff --git a/lib/util.js b/lib/util.js index e97820c9af3..4fed8311a09 100644 --- a/lib/util.js +++ b/lib/util.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var formatRegExp = /%[sdj%]/g; exports.format = function(f) { if (!isString(f)) { diff --git a/lib/vm.js b/lib/vm.js index 7c6c59c0af4..653c27c0d85 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var binding = process.binding('contextify'); var Script = binding.ContextifyScript; var util = require('util'); diff --git a/lib/zlib.js b/lib/zlib.js index f80c9833a44..a85e8efb518 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -19,6 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +'use strict'; + var Transform = require('_stream_transform'); var binding = process.binding('zlib'); diff --git a/src/node.cc b/src/node.cc index e669706f128..a431e9e83e2 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2936,6 +2936,9 @@ static void PrintHelp() { #endif " --enable-ssl2 enable ssl2\n" " --enable-ssl3 enable ssl3\n" + " --cipher-list=val specify the default TLS cipher list\n" + " --enable-legacy-cipher-list=val \n" + " val = v0.10.38, v0.10.39, v0.12.2 or v0.12.3\n" "\n" "Environment variables:\n" #ifdef _WIN32 @@ -2953,6 +2956,9 @@ static void PrintHelp() { " (will extend linked-in data)\n" #endif #endif + "NODE_CIPHER_LIST Override the default TLS cipher list\n" + "NODE_LEGACY_CIPHER_LIST=val\n" + " val = v0.10.38, v0.10.39, v0.12.2 or v0.12.3\n" "\n" "Documentation can be found at http://nodejs.org/\n"); } @@ -2992,6 +2998,7 @@ static void ParseArgs(int* argc, unsigned int new_argc = 1; new_v8_argv[0] = argv[0]; new_argv[0] = argv[0]; + bool using_legacy_cipher_list = false; unsigned int index = 1; while (index < nargs && argv[index][0] == '-') { @@ -3047,6 +3054,20 @@ static void ParseArgs(int* argc, } else if (strcmp(arg, "--v8-options") == 0) { new_v8_argv[new_v8_argc] = "--help"; new_v8_argc += 1; + } else if (strncmp(arg, "--cipher-list=", 14) == 0) { + if (!using_legacy_cipher_list) { + DEFAULT_CIPHER_LIST = arg + 14; + } + } else if (strncmp(arg, "--enable-legacy-cipher-list=", 28) == 0) { + // use the original v0.10.x/v0.12.x cipher lists + const char * legacy_list = legacy_cipher_list(arg+28); + if (legacy_list != NULL) { + using_legacy_cipher_list = true; + DEFAULT_CIPHER_LIST = legacy_list; + } else { + fprintf(stderr, "Error: An unknown legacy cipher list was specified\n"); + exit(9); + } #if defined(NODE_HAVE_I18N_SUPPORT) } else if (strncmp(arg, "--icu-data-dir=", 15) == 0) { icu_data_dir = arg + 15; @@ -3414,6 +3435,26 @@ void Init(int* argc, } } + const char * cipher_list = getenv("NODE_CIPHER_LIST"); + if (cipher_list != NULL) { + DEFAULT_CIPHER_LIST = cipher_list; + } + // Allow the NODE_LEGACY_CIPHER_LIST envar to override the other + // cipher list options. NODE_LEGACY_CIPHER_LIST=v0.10.38 will use + // the cipher list from v0.10.38, NODE_LEGACY_CIPHER_LIST=v0.12.2 will + // use the cipher list from v0.12.2 + const char * leg_cipher_id = getenv("NODE_LEGACY_CIPHER_LIST"); + if (leg_cipher_id != NULL) { + const char * leg_cipher_list = + legacy_cipher_list(leg_cipher_id); + if (leg_cipher_list != NULL) { + DEFAULT_CIPHER_LIST = leg_cipher_list; + } else { + fprintf(stderr, "Error: An unknown legacy cipher list was specified\n"); + exit(9); + } + } + #if defined(NODE_HAVE_I18N_SUPPORT) if (icu_data_dir == NULL) { // if the parameter isn't given, use the env variable. diff --git a/src/node.h b/src/node.h index 38356ac44fe..e42713b5ba6 100644 --- a/src/node.h +++ b/src/node.h @@ -223,6 +223,17 @@ NODE_EXTERN void RunAtExit(Environment* env); } \ while (0) +#define NODE_DEFINE_STRING_CONSTANT(isolate, target, constant) \ + do { \ + v8::Local constant_name = \ + v8::String::NewFromUtf8(isolate, #constant); \ + v8::Local constant_value = \ + v8::String::NewFromUtf8(isolate, constant); \ + v8::PropertyAttribute constant_attributes = \ + static_cast(v8::ReadOnly | v8::DontDelete); \ + (target)->ForceSet(constant_name, constant_value, constant_attributes); \ + } while (0) + // Used to be a macro, hence the uppercase name. template inline void NODE_SET_METHOD(const TypeName& recv, diff --git a/src/node.js b/src/node.js index 50460383ff7..02aee1708c4 100644 --- a/src/node.js +++ b/src/node.js @@ -24,6 +24,9 @@ // This file is invoked by node::Load in src/node.cc, and responsible for // bootstrapping the node.js core. Special caution is given to the performance // of the startup process, so many dependencies are invoked lazily. + +'use strict'; + (function(process) { this.global = this; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 03650a98c61..143e09f1d29 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -77,6 +77,7 @@ namespace node { bool SSL2_ENABLE = false; bool SSL3_ENABLE = false; +const char * DEFAULT_CIPHER_LIST = DEFAULT_CIPHER_LIST_HEAD; namespace crypto { @@ -4851,6 +4852,26 @@ static void array_push_back(const TypeName* md, ctx->arr->Set(ctx->arr->Length(), OneByteString(ctx->env()->isolate(), from)); } +// borrowed from v8 +// (see http://v8.googlecode.com/svn/trunk/samples/shell.cc) +const char* ToCString(const String::Utf8Value& value) { + return *value ? *value : ""; +} + +void DefaultCiphers(const v8::FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args.GetIsolate()); + HandleScope scope(env->isolate()); + v8::String::Utf8Value key(args[0]); + const char * list = legacy_cipher_list(ToCString(key)); + if (list != NULL) { + args.GetReturnValue().Set( + v8::String::NewFromUtf8(args.GetIsolate(), list)); + } else { + args.GetReturnValue().Set( + v8::String::NewFromUtf8(args.GetIsolate(), + DEFAULT_CIPHER_LIST_HEAD)); + } +} void GetCiphers(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); @@ -5171,6 +5192,9 @@ void InitCrypto(Handle target, NODE_DEFINE_CONSTANT(target, SSL3_ENABLE); NODE_DEFINE_CONSTANT(target, SSL2_ENABLE); + + NODE_DEFINE_STRING_CONSTANT(env->isolate(), target, DEFAULT_CIPHER_LIST); + NODE_SET_METHOD(target, "getLegacyCiphers", DefaultCiphers); } } // namespace crypto diff --git a/src/node_crypto.h b/src/node_crypto.h index 0a4c34a1f33..b9f266f75fd 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -38,6 +38,7 @@ #include "v8.h" +#include #include #include #include @@ -59,10 +60,51 @@ # define NODE__HAVE_TLSEXT_STATUS_CB #endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) +#define DEFAULT_CIPHER_LIST_V10_38 "ECDHE-RSA-AES128-SHA256:" \ + "AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH" + +#define DEFAULT_CIPHER_LIST_V10_39 "ECDHE-RSA-AES128-SHA256:" \ + "AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH" + +#define DEFAULT_CIPHER_LIST_V12_2 "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:" \ + "HIGH:!MD5:!aNULL" + +#define DEFAULT_CIPHER_LIST_V12_3 "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:"\ + "!RC4:!MD5:!aNULL" + +#define DEFAULT_CIPHER_LIST_HEAD "ECDHE-RSA-AES256-SHA384:" \ + "DHE-RSA-AES256-SHA384:" \ + "ECDHE-RSA-AES256-SHA256:" \ + "DHE-RSA-AES256-SHA256:" \ + "ECDHE-RSA-AES128-SHA256:" \ + "DHE-RSA-AES128-SHA256:" \ + "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:" \ + "!PSK:!SRP:!CAMELLIA" + +static inline const char * legacy_cipher_list(const char * ver) { + if (ver == NULL) { + return NULL; + } + if (strncmp(ver, "v0.10.38", 8) == 0) { + return DEFAULT_CIPHER_LIST_V10_38; + } else if (strncmp(ver, "v0.10.39", 8) == 0) { + return DEFAULT_CIPHER_LIST_V10_39; + } else if (strncmp(ver, "v0.12.2", 7) == 0) { + return DEFAULT_CIPHER_LIST_V12_2; + } else if (strncmp(ver, "v0.12.3", 7) == 0) { + return DEFAULT_CIPHER_LIST_V12_3; + } else { + return NULL; + } +} + namespace node { extern bool SSL2_ENABLE; extern bool SSL3_ENABLE; +extern const char * DEFAULT_CIPHER_LIST; namespace crypto { diff --git a/src/node_os.cc b/src/node_os.cc index a7041aed7a0..57465386000 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -37,7 +37,7 @@ # include // gethostname, sysconf # include // MAXHOSTNAMELEN on Linux and the BSDs. # include -#endif // __MINGW32__ +#endif // __POSIX__ // Add Windows fallback. #ifndef MAXHOSTNAMELEN diff --git a/src/node_version.h b/src/node_version.h index 52200050110..9497e111d2b 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,8 +23,8 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 0 -#define NODE_MINOR_VERSION 12 -#define NODE_PATCH_VERSION 5 +#define NODE_MINOR_VERSION 13 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_RELEASE 0 diff --git a/test/simple/test-cluster-dgram-2.js b/test/simple/test-cluster-dgram-2.js index cb5eaf0675f..4ba41b8219f 100644 --- a/test/simple/test-cluster-dgram-2.js +++ b/test/simple/test-cluster-dgram-2.js @@ -74,6 +74,11 @@ function worker() { var socket = dgram.createSocket('udp4'); var buf = new Buffer('hello world'); + // This test is intended to exercise the cluster binding of udp sockets, but + // since sockets aren't clustered when implicitly bound by at first call of + // send(), explicitly bind them to an ephemeral port. + socket.bind(0); + for (var i = 0; i < PACKETS_PER_WORKER; i++) socket.send(buf, 0, buf.length, common.PORT, '127.0.0.1'); diff --git a/test/simple/test-dgram-exclusive-implicit-bind.js b/test/simple/test-dgram-exclusive-implicit-bind.js new file mode 100644 index 00000000000..057b891eb6d --- /dev/null +++ b/test/simple/test-dgram-exclusive-implicit-bind.js @@ -0,0 +1,100 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var cluster = require('cluster'); +var dgram = require('dgram'); + +// Without an explicit bind, send() causes an implicit bind, which always +// generate a unique per-socket ephemeral port. An explicit bind to a port +// number causes all sockets bound to that number to share a port. +// +// The 2 workers that call bind() will share a port, the two workers that do +// not will not share a port, so master will see 3 unique source ports. + +// Note that on Windows, clustered dgram is not supported. Since explicit +// binding causes the dgram to be clustered, don't fork the workers that bind. +// This is a useful test, still, because it demonstrates that by avoiding +// clustering, client (ephemeral, implicitly bound) dgram sockets become +// supported while using cluster, though servers still cause the master to error +// with ENOTSUP. + +var windows = process.platform === 'win32'; + +if (cluster.isMaster) { + var pass; + var messages = 0; + var ports = {}; + + process.on('exit', function() { + assert.equal(pass, true); + }); + + var target = dgram.createSocket('udp4'); + + target.on('message', function(buf, rinfo) { + messages++; + ports[rinfo.port] = true; + + if (windows && messages === 2) { + assert.equal(Object.keys(ports).length, 2); + done(); + } + + if (!windows && messages === 4) { + assert.equal(Object.keys(ports).length, 3); + done(); + } + + function done() { + pass = true; + cluster.disconnect(); + target.close(); + } + }); + + target.on('listening', function() { + cluster.fork(); + cluster.fork(); + if (!windows) { + cluster.fork({BOUND: 'y'}); + cluster.fork({BOUND: 'y'}); + } + }); + + target.bind({port: common.PORT, exclusive: true}); + + return; +} + +var source = dgram.createSocket('udp4'); + +if (process.env.BOUND === 'y') { + source.bind(0); +} else { + // cluster doesn't know about exclusive sockets, so it won't close them. This + // is expected, its the same situation for timers, outgoing tcp connections, + // etc, which also keep workers alive after disconnect was requested. + source.unref(); +} + +source.send(Buffer('abc'), 0, 3, common.PORT, '127.0.0.1'); diff --git a/test/simple/test-net-remote-address-port.js b/test/simple/test-net-remote-address-port.js index 0cfe47afe6c..9fc53ffe389 100644 --- a/test/simple/test-net-remote-address-port.js +++ b/test/simple/test-net-remote-address-port.js @@ -41,6 +41,10 @@ var server = net.createServer(function(socket) { socket.on('end', function() { if (++conns_closed == 2) server.close(); }); + socket.on('close', function() { + assert.notEqual(-1, remoteAddrCandidates.indexOf(socket.remoteAddress)); + assert.notEqual(-1, remoteFamilyCandidates.indexOf(socket.remoteFamily)); + }); socket.resume(); }); @@ -53,12 +57,20 @@ server.listen(common.PORT, 'localhost', function() { assert.equal(common.PORT, client.remotePort); client.end(); }); + client.on('close', function() { + assert.notEqual(-1, remoteAddrCandidates.indexOf(client.remoteAddress)); + assert.notEqual(-1, remoteFamilyCandidates.indexOf(client.remoteFamily)); + }); client2.on('connect', function() { assert.notEqual(-1, remoteAddrCandidates.indexOf(client2.remoteAddress)); assert.notEqual(-1, remoteFamilyCandidates.indexOf(client2.remoteFamily)); assert.equal(common.PORT, client2.remotePort); client2.end(); }); + client2.on('close', function() { + assert.notEqual(-1, remoteAddrCandidates.indexOf(client2.remoteAddress)); + assert.notEqual(-1, remoteFamilyCandidates.indexOf(client2.remoteFamily)); + }); }); process.on('exit', function() { diff --git a/test/simple/test-tls-cipher-list.js b/test/simple/test-tls-cipher-list.js new file mode 100644 index 00000000000..8e54d8d36a4 --- /dev/null +++ b/test/simple/test-tls-cipher-list.js @@ -0,0 +1,66 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var spawn = require('child_process').spawn; +var assert = require('assert'); +var tls = require('tls'); + +function doTest(checklist, env, useswitch) { + var options; + var args = ['-e', 'console.log(require(\'tls\').DEFAULT_CIPHERS)']; + + switch(useswitch) { + case 1: + // Test --cipher-list + args.unshift('--cipher-list=' + env); + break; + case 2: + // Test --enable-legacy-cipher-list + args.unshift('--enable-legacy-cipher-list=' + env); + break; + case 3: + // Test NODE_LEGACY_CIPHER_LIST + if (env) options = {env:{"NODE_LEGACY_CIPHER_LIST": env}}; + break; + default: + // Test NODE_CIPHER_LIST + if (env) options = {env:env}; + } + + var out = ''; + spawn(process.execPath, args, options). + stdout. + on('data', function(data) { + out += data; + }). + on('end', function() { + assert.equal(out.trim(), checklist); + }); +} + +doTest(tls.DEFAULT_CIPHERS); // test the default +doTest('ABC', {'NODE_CIPHER_LIST':'ABC'}); // test the envar +doTest('ABC', 'ABC', 1); // test the --cipher-list switch + +['v0.10.38', 'v0.10.39', 'v0.12.2', 'v0.12.3'].forEach(function(ver) { + doTest(tls.getLegacyCiphers(ver), ver, 2); + doTest(tls.getLegacyCiphers(ver), ver, 3); +}); diff --git a/test/simple/test-tls-dhe.js b/test/simple/test-tls-dhe.js index 3975c5ed40a..8844f852799 100644 --- a/test/simple/test-tls-dhe.js +++ b/test/simple/test-tls-dhe.js @@ -47,6 +47,7 @@ function test(keylen, expectedCipher, cb) { var options = { key: key, cert: cert, + ciphers: ciphers, dhparam: loadDHParam(keylen) }; diff --git a/test/simple/test-tls-getcipher.js b/test/simple/test-tls-getcipher.js index 22a280e5874..8fb9d528731 100644 --- a/test/simple/test-tls-getcipher.js +++ b/test/simple/test-tls-getcipher.js @@ -49,7 +49,7 @@ server.listen(common.PORT, '127.0.0.1', function() { rejectUnauthorized: false }, function() { var cipher = client.getCipher(); - assert.equal(cipher.name, cipher_list[0]); + assert.equal(cipher.name, cipher_list[1]); assert(cipher_version_pattern.test(cipher.version)); client.end(); server.close(); diff --git a/test/simple/test-url.js b/test/simple/test-url.js index e81908a883f..d0ddaf20318 100644 --- a/test/simple/test-url.js +++ b/test/simple/test-url.js @@ -1178,6 +1178,14 @@ var relativeTests = [ ['/foo/bar/baz/', 'quux/baz', '/foo/bar/baz/quux/baz'], ['/foo/bar/baz', '../../../../../../../../quux/baz', '/quux/baz'], ['/foo/bar/baz', '../../../../../../../quux/baz', '/quux/baz'], + ['/foo', '.', '/'], + ['/foo', '..', '/'], + ['/foo/', '.', '/foo/'], + ['/foo/', '..', '/'], + ['/foo/bar', '.', '/foo/'], + ['/foo/bar', '..', '/'], + ['/foo/bar/', '.', '/foo/bar/'], + ['/foo/bar/', '..', '/foo/'], ['foo/bar', '../../../baz', '../../baz'], ['foo/bar/', '../../../baz', '../baz'], ['http://example.com/b//c//d;p?q#blarg', 'https:#hash2', 'https:///#hash2'], diff --git a/tools/doc/generate.js b/tools/doc/generate.js index 2bab2f3ef3e..4a11c654d2d 100755 --- a/tools/doc/generate.js +++ b/tools/doc/generate.js @@ -31,6 +31,7 @@ var args = process.argv.slice(2); var format = 'json'; var template = null; var inputFile = null; +var outputFile = null; args.forEach(function (arg) { if (!arg.match(/^\-\-/)) { @@ -39,6 +40,8 @@ args.forEach(function (arg) { format = arg.replace(/^\-\-format=/, ''); } else if (arg.match(/^\-\-template=/)) { template = arg.replace(/^\-\-template=/, ''); + } else if (arg.match(/^\-\-output=/)) { + outputFile = arg.replace(/^\-\-output=/, ''); } }) @@ -100,7 +103,7 @@ function next(er, input) { if (er) throw er; switch (format) { case 'json': - require('./json.js')(input, inputFile, function(er, obj) { + require('./json.js')(input, inputFile, outputFile, function(er, obj) { console.log(JSON.stringify(obj, null, 2)); if (er) throw er; }); diff --git a/tools/doc/json.js b/tools/doc/json.js index 9fdc3bc1b4a..9c83ca751cf 100644 --- a/tools/doc/json.js +++ b/tools/doc/json.js @@ -23,16 +23,25 @@ module.exports = doJSON; // Take the lexed input, and return a JSON-encoded object // A module looks like this: https://gist.github.com/1777387 - +var fs = require('fs'); +var path = require('path'); var marked = require('marked'); -function doJSON(input, filename, cb) { +function doJSON(input, filename, outfile, cb) { var root = {source: filename}; + // Default index file + var indexfile = "index.json"; var stack = [root]; var depth = 0; var current = root; var state = null; var lexed = marked.lexer(input); + + // If outfile is same as index file do nothing + if (outfile && outfile.slice(-indexfile.length) === indexfile) { + return; + } + lexed.forEach(function (tok) { var type = tok.type; var text = tok.text; @@ -55,6 +64,10 @@ function doJSON(input, filename, cb) { return cb(new Error('Inappropriate heading level\n'+ JSON.stringify(tok))); } + // set first heading to title + if (current && !current.title) { + current.title = tok.text; + } // Sometimes we have two headings with a single // blob of description. Treat as a clone. @@ -146,9 +159,64 @@ function doJSON(input, filename, cb) { finishSection(current, stack[stack.length - 1]); } - return cb(null, root) + if (outfile) { + writeOutputToFile(root, filename, outfile, indexfile, function(err, root, sourcefile, outfile) { + if (err) { + cb(err, root); + } + else { + writeToIndexFile(root, sourcefile, outfile, cb); + } + }); + } + else { + return cb(null, root) + } +} + +// write output object to outfile +function writeOutputToFile(obj, sourcefile, outfile, indexfile, cb) { + fs.writeFile(outfile, JSON.stringify(obj, null, 2), function(err) { + cb(err, obj, sourcefile, path.join(path.dirname(outfile), indexfile)); + }); } +// make an entry into index file +function writeToIndexFile(root, sourcefile, outfile, cb) { + // default type of an index + var obj = {"type":"index"}; + var entry = {"source":sourcefile}; + + // check if indexfile already exists + if (fs.existsSync(outfile)) { + var data = fs.readFileSync(outfile); + try { + obj = JSON.parse(data.toString()); + } + catch(e) { + // invalid json use default obj + } + } + // check if index file is valid + if (obj.type !== "index") { + cb(new Error('invalid index file - '+ outfile)); + } + // construct an entry object + entry.title = root.title; + entry.html = path.basename(sourcefile).replace(/\.(markdown|md)/i, ".html"); + entry.json = entry.html.replace(/\.html/i, ".json"); + + // append mode + if (obj.chapters && typeof obj.chapters === "object") { + obj.chapters.push(entry); + } + else { + obj.chapters = [entry]; + } + fs.writeFile(outfile, JSON.stringify(obj, null, 2), function(err) { + cb(err); + }); +} // go from something like this: // [ { type: 'list_item_start' },