diff --git a/ChangeLog b/ChangeLog index 9b2d0ad2c0..92f8dd7357 100644 --- a/ChangeLog +++ b/ChangeLog @@ -370,7 +370,30 @@ * DTrace probes: support X-Forwarded-For (Dave Pacheco) -2011.08.17, Version 0.4.11 (stable) +2011.09.15, Version 0.4.12 (stable) + +* Improve docs + +* #1563 overflow in ChildProcess custom_fd. + +* #1569, parse error on multi-line HTTP headers. (Ben Noordhuis) + +* #1586 net: Socket write encoding case sensitivity (koichik) + +* #1610 Remove DigiNotar CA from trusted list (isaacs) + +* #1624 buffer: Avoid overrun with 'binary' encoding. (koichik) + +* #1633 buffer: write() should always set _charsWritten. (koichik) + +* #1707 hasOwnProperty usage security hole in querystring (isaacs) + +* #1719 Drain OpenSSL error queue + +* Fix error reporting in net.Server.listen + + +2011.08.17, Version 0.4.11 (stable), a745d19ce7d1c0e3778371af4f0346be70cf2c8e * #738 Fix crypto encryption/decryption with Base64. (SAWADA Tadashi) diff --git a/doc/api/child_processes.markdown b/doc/api/child_processes.markdown index 23279c0927..c2d8d6634a 100644 --- a/doc/api/child_processes.markdown +++ b/doc/api/child_processes.markdown @@ -141,6 +141,10 @@ Example of checking for failed exec: } }); +Note that if spawn receives an empty options object, it will result in +spawning the process with an empty environment rather than using +`process.env`. This due to backwards compatibility issues with a deprecated +API. See also: `child_process.exec()` diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 6ef889193f..f6e64dd0ef 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -485,7 +485,7 @@ be found in the [MDN JavaScript Reference][MDN-Date] page. ## fs.ReadStream -`ReadStream` is a `Readable Stream`. +`ReadStream` is a [Readable Stream](streams.html#readable_Stream). ### Event: 'open' @@ -517,7 +517,7 @@ An example to read the last 10 bytes of a file which is 100 bytes long: ## fs.WriteStream -`WriteStream` is a `Writable Stream`. +`WriteStream` is a [Writable Stream](streams.html#writable_Stream). ### Event: 'open' diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index 6dc8718857..c47f3812b8 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -126,6 +126,15 @@ h4 + h4 { margin: 0 0 0.5em; } + h3 a, + h4 a { + font-size: 0.8em; + float: right; + color: #000; + text-decoration: none; + opacity: 0.3; + } + h5 { font-size: 1.125em; line-height: 1.4em; @@ -232,4 +241,4 @@ a.octothorpe { h5:hover > a.octothorpe, h6:hover > a.octothorpe { opacity: 1; - } \ No newline at end of file + } diff --git a/lib/tls.js b/lib/tls.js index e84d501fc0..f2acd90fa8 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -77,6 +77,7 @@ function CryptoStream(pair) { this.readable = this.writable = true; this._paused = false; + this._needDrain = false; this._pending = []; this._pendingCallbacks = []; this._pendingBytes = 0; @@ -111,7 +112,7 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) { data = new Buffer(data, encoding); } - debug('clearIn data'); + debug((this === this.pair.cleartext ? 'clear' : 'encrypted') + 'In data'); this._pending.push(data); this._pendingCallbacks.push(cb); @@ -120,7 +121,26 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) { this.pair._writeCalled = true; this.pair.cycle(); - return this._pendingBytes < 128 * 1024; + // In the following cases, write() should return a false, + // then this stream should eventually emit 'drain' event. + // + // 1. There are pending data more than 128k bytes. + // 2. A forward stream shown below is paused. + // A) EncryptedStream for CleartextStream.write(). + // B) CleartextStream for EncryptedStream.write(). + // + if (!this._needDrain) { + if (this._pendingBytes >= 128 * 1024) { + this._needDrain = true; + } else { + if (this === this.pair.cleartext) { + this._needDrain = this.pair.encrypted._paused; + } else { + this._needDrain = this.pair.cleartext._paused; + } + } + } + return !this._needDrain; }; @@ -420,11 +440,25 @@ CryptoStream.prototype._pull = function() { assert(rv === tmp.length); } - // If we've cleared all of incoming encrypted data, emit drain. - if (havePending && this._pending.length === 0) { - debug('drain'); - this.emit('drain'); - if (this.__destroyOnDrain) this.end(); + // If pending data has cleared, 'drain' event should be emitted + // after write() returns a false. + // Except when a forward stream shown below is paused. + // A) EncryptedStream for CleartextStream._pull(). + // B) CleartextStream for EncryptedStream._pull(). + // + if (this._needDrain && this._pending.length === 0) { + var paused; + if (this === this.pair.cleartext) { + paused = this.pair.encrypted._paused; + } else { + paused = this.pair.cleartext._paused; + } + if (!paused) { + debug('drain'); + process.nextTick(this.emit.bind(this, 'drain')); + this._needDrain = false; + if (this.__destroyOnDrain) this.end(); + } } }; diff --git a/test/simple/test-tls-pause.js b/test/simple/test-tls-pause.js new file mode 100644 index 0000000000..3fc30018d2 --- /dev/null +++ b/test/simple/test-tls-pause.js @@ -0,0 +1,78 @@ +// 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. + +if (!process.versions.openssl) { + console.error('Skipping because node compiled without OpenSSL.'); + process.exit(0); +} + +var common = require('../common'); +var assert = require('assert'); +var tls = require('tls'); +var fs = require('fs'); +var path = require('path'); + +var options = { + key: fs.readFileSync(path.join(common.fixturesDir, 'test_key.pem')), + cert: fs.readFileSync(path.join(common.fixturesDir, 'test_cert.pem')) +}; + +var bufSize = 1024 * 1024; +var sent = 0; +var received = 0; + +var server = tls.Server(options, function(socket) { + socket.pipe(socket); +}); + +server.listen(common.PORT, function() { + var resumed = false; + var client = tls.connect(common.PORT, function() { + client.pause(); + common.debug('paused'); + send(); + function send() { + if (client.write(new Buffer(bufSize))) { + sent += bufSize; + assert.ok(sent < 100 * 1024 * 1024); // max 100MB + return process.nextTick(send); + } + sent += bufSize; + common.debug('sent: ' + sent); + resumed = true; + client.resume(); + common.debug('resumed'); + } + }); + client.on('data', function(data) { + assert.ok(resumed); + received += data.length; + if (received >= sent) { + common.debug('received: ' + received); + client.end(); + server.close(); + } + }); +}); + +process.on('exit', function() { + assert.equal(sent, received); +}); diff --git a/tools/doctool/doctool.js b/tools/doctool/doctool.js index 4b4f2f07b7..da31445fe1 100644 --- a/tools/doctool/doctool.js +++ b/tools/doctool/doctool.js @@ -88,6 +88,9 @@ function convertData(data) { .replace(/
<\/hr>/g, "
") .replace(/(\([^<]+)(\<\/h[1-6]\>)/gmi, function(o, ts, c, te) { return ts+' id="'+formatIdString(c)+'">'+c+te; + }) + .replace(/(\]+\>)([^<]+)(\<\/h[3-4]\>)/gmi, function(o, ts, c, te) { + return ts+c+' #'+te; }); return html;