@@ -849,7 +849,7 @@ the client should send the request body.

Flush the request headers.

For effiency reasons, node.js normally buffers the request headers until you
For efficiency reasons, node.js normally buffers the request headers until you
call `request.end()` or write the first chunk of request data. It then tries
hard to pack the request headers and data into a single TCP packet.

@@ -971,7 +971,7 @@ function SourceWrapper(options) {
self._source.readStop();
};
// When the source ends, we push the EOF-signalling `null` chunk
// When the source ends, we push the EOF-signaling `null` chunk
this._source.onend = function() {
self.push(null);
};
@@ -154,7 +154,7 @@ automatically set as a listener for the [secureConnection][] event. The
`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 posess the ability to break it.
It is speculated that state-level actors possess the ability to break it.

**NOTE**: Previous revisions of this section suggested `AES256-SHA` as an
acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore
@@ -573,8 +573,9 @@ Typical flow:
5. Client validates the response and either destroys socket or performs a
handshake.

NOTE: `issuer` could be null, if certficiate is self-signed or if issuer is not
in the root certificates list. (You could provide an issuer via `ca` option.)
NOTE: `issuer` could be null, if the certificate is self-signed or if the issuer
is not in the root certificates list. (You could provide an issuer via `ca`
option.)

NOTE: adding this event listener will have an effect only on connections
established after addition of event listener.
@@ -27,6 +27,7 @@ var crypto = require('crypto');
var net = require('net');
var tls = require('tls');
var util = require('util');
var listenerCount = require('events').listenerCount;
var common = require('_tls_common');

var Timer = process.binding('timer_wrap').Timer;
@@ -131,7 +132,7 @@ function requestOCSP(self, hello, ctx, cb) {
if (ctx.context)
ctx = ctx.context;

if (self.server.listeners('OCSPRequest').length === 0) {
if (listenerCount(self.server, 'OCSPRequest') === 0) {
return cb(null);
} else {
self.server.emit('OCSPRequest',
@@ -311,9 +312,9 @@ TLSSocket.prototype._init = function(socket) {
this.ssl.handshakes = 0;

if (this.server &&
(this.server.listeners('resumeSession').length > 0 ||
this.server.listeners('newSession').length > 0 ||
this.server.listeners('OCSPRequest').length > 0)) {
(listenerCount(this.server, 'resumeSession') > 0 ||
listenerCount(this.server, 'newSession') > 0 ||
listenerCount(this.server, 'OCSPRequest') > 0)) {
this.ssl.enableSessionCallbacks();
}
} else {
@@ -415,7 +415,7 @@ Socket.prototype.addMembership = function(multicastAddress,

var err = this._handle.addMembership(multicastAddress, interfaceAddress);
if (err) {
throw new errnoException(err, 'addMembership');
throw errnoException(err, 'addMembership');
}
};

@@ -430,7 +430,7 @@ Socket.prototype.dropMembership = function(multicastAddress,

var err = this._handle.dropMembership(multicastAddress, interfaceAddress);
if (err) {
throw new errnoException(err, 'dropMembership');
throw errnoException(err, 'dropMembership');
}
};

@@ -132,7 +132,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
if (simplePath[2]) {
this.search = simplePath[2];
if (parseQueryString) {
this.query = querystring.parse(this.search);
this.query = querystring.parse(this.search.substr(1));
} else {
this.query = this.search.substr(1);
}
@@ -37,8 +37,8 @@
// a nightmare so let's make the preprocessor generate them for us.
//
// Make sure that any macros defined here are undefined again at the bottom
// of context-inl.h. The sole exception is NODE_CONTEXT_EMBEDDER_DATA_INDEX,
// it may have been defined externally.
// of context-inl.h. The exceptions are NODE_CONTEXT_EMBEDDER_DATA_INDEX
// and NODE_ISOLATE_SLOT, they may have been defined externally.
namespace node {

// Pick an index that's hopefully out of the way when we're embedded inside
@@ -49,6 +49,14 @@ namespace node {
#define NODE_CONTEXT_EMBEDDER_DATA_INDEX 32
#endif

// The slot 0 and 1 had already been taken by "gin" and "blink" in Chrome,
// and the size of isolate's slots is 4 by default, so using 3 should
// hopefully make node work independently when embedded into other
// application.
#ifndef NODE_ISOLATE_SLOT
#define NODE_ISOLATE_SLOT 3
#endif

// Strings are per-isolate primitives but Environment proxies them
// for the sake of convenience.
#define PER_ISOLATE_STRING_PROPERTIES(V) \
@@ -430,7 +438,7 @@ class Environment {
#undef V

private:
static const int kIsolateSlot = 0;
static const int kIsolateSlot = NODE_ISOLATE_SLOT;

class GCInfo;
class IsolateData;
@@ -670,7 +670,7 @@
if (isSignal(type)) {
assert(signalWraps.hasOwnProperty(type));

if (this.listeners(type).length === 0) {
if (NativeModule.require('events').listenerCount(this, type) === 0) {
signalWraps[type].close();
delete signalWraps[type];
}
@@ -22,6 +22,7 @@
var path = require('path');
var fs = require('fs');
var assert = require('assert');
var os = require('os');

exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, 'fixtures');
@@ -46,6 +47,13 @@ if (process.platform === 'win32') {
"faketime");
}

var ifaces = os.networkInterfaces();
exports.hasIPv6 = Object.keys(ifaces).some(function(name) {
return /lo/.test(name) && ifaces[name].some(function(info) {
return info.family === 'IPv6';
});
});

var util = require('util');
for (var i in util) exports[i] = util[i];
//for (var i in exports) global[i] = exports[i];
@@ -226,3 +234,67 @@ exports.checkSpawnSyncRet = function(ret) {
assert.strictEqual(ret.status, 0);
assert.strictEqual(ret.error, undefined);
};

var etcServicesFileName = path.join('/etc', 'services');
if (process.platform === 'win32') {
etcServicesFileName = path.join(process.env.SystemRoot, 'System32', 'drivers',
'etc', 'services');
}

/*
* Returns a string that represents the service name associated
* to the service bound to port "port" and using protocol "protocol".
*
* If the service is not defined in the services file, it returns
* the port number as a string.
*
* Returns undefined if /etc/services (or its equivalent on non-UNIX
* platforms) can't be read.
*/
exports.getServiceName = function getServiceName(port, protocol) {
if (port == null) {
throw new Error("Missing port number");
}

if (typeof protocol !== 'string') {
throw new Error("Protocol must be a string");
}

/*
* By default, if a service can't be found in /etc/services,
* its name is considered to be its port number.
*/
var serviceName = port.toString();

try {
/*
* I'm not a big fan of readFileSync, but reading /etc/services asynchronously
* here would require implementing a simple line parser, which seems overkill
* for a simple utility function that is not running concurrently with any
* other one.
*/
var servicesContent = fs.readFileSync(etcServicesFileName,
{ encoding: 'utf8'});
var regexp = util.format('^(\\w+)\\s+\\s%d/%s\\s', port, protocol);
var re = new RegExp(regexp, 'm');

var matches = re.exec(servicesContent);
if (matches && matches.length > 1) {
serviceName = matches[1];
}
} catch(e) {
console.error('Cannot read file: ', etcServicesFileName);
return undefined;
}

return serviceName;
}

exports.isValidHostname = function(str) {
// See http://stackoverflow.com/a/3824105
var re = new RegExp(
'^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])' +
'(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]))*$');

return !!str.match(re) && str.length <= 255;
}
@@ -63,7 +63,6 @@ function checkWrap(req) {
assert.ok(typeof req === 'object');
}


TEST(function test_resolve4(done) {
var req = dns.resolve4('www.google.com', function(err, ips) {
if (err) throw err;
@@ -354,7 +353,7 @@ TEST(function test_lookup_ipv4_explicit_object(done) {

TEST(function test_lookup_ipv4_hint_addrconfig(done) {
var req = dns.lookup('www.google.com', {
hint: dns.ADDRCONFIG
hints: dns.ADDRCONFIG
}, function(err, ip, family) {
if (err) throw err;
assert.ok(net.isIPv4(ip));
@@ -411,8 +410,9 @@ TEST(function test_lookup_ipv6_explicit_object(done) {


TEST(function test_lookup_ipv6_hint(done) {
var req = dns.lookup('ipv6.google.com', {
hint: dns.V4MAPPED
var req = dns.lookup('www.google.com', {
family: 6,
hints: dns.V4MAPPED
}, function(err, ip, family) {
if (err) throw err;
assert.ok(net.isIPv6(ip));
@@ -494,8 +494,24 @@ TEST(function test_lookup_localhost_ipv4(done) {
TEST(function test_lookupservice_ip_ipv4(done) {
var req = dns.lookupService('127.0.0.1', 80, function(err, host, service) {
if (err) throw err;
assert.strictEqual(host, 'localhost');
assert.strictEqual(service, 'http');
assert.ok(common.isValidHostname(host));

/*
* Retrieve the actual HTTP service name as setup on the host currently
* running the test by reading it from /etc/services. This is not ideal,
* as the service name lookup could use another mechanism (e.g nscd), but
* it's already better than hardcoding it.
*/
var httpServiceName = common.getServiceName(80, 'tcp');
if (!httpServiceName) {
/*
* Couldn't find service name, reverting to the most sensible default
* for port 80.
*/
httpServiceName = 'http';
}

assert.strictEqual(service, httpServiceName);

done();
});
@@ -507,15 +523,24 @@ TEST(function test_lookupservice_ip_ipv4(done) {
TEST(function test_lookupservice_ip_ipv6(done) {
var req = dns.lookupService('::1', 80, function(err, host, service) {
if (err) throw err;
assert.ok(common.isValidHostname(host));

/*
* On some systems, ::1 can be set to "localhost", on others it
* can be set to "ip6-localhost". There does not seem to be
* a consensus on that. Ultimately, it could be set to anything
* else just by changing /etc/hosts for instance, but it seems
* that most sane platforms use either one of these two by default.
* Retrieve the actual HTTP service name as setup on the host currently
* running the test by reading it from /etc/services. This is not ideal,
* as the service name lookup could use another mechanism (e.g nscd), but
* it's already better than hardcoding it.
*/
assert(host === 'localhost' || host === 'ip6-localhost');
assert.strictEqual(service, 'http');
var httpServiceName = common.getServiceName(80, 'tcp');
if (!httpServiceName) {
/*
* Couldn't find service name, reverting to the most sensible default
* for port 80.
*/
httpServiceName = 'http';
}

assert.strictEqual(service, httpServiceName);

done();
});
@@ -29,6 +29,11 @@ dgram.createSocket('udp4').bind(common.PORT + 0, common.mustCall(function() {
this.close();
}));

if (!common.hasIPv6) {
console.error('Skipping udp6 part of test, no IPv6 support');
return;
}

dgram.createSocket('udp6').bind(common.PORT + 1, common.mustCall(function() {
assert.equal(this.address().port, common.PORT + 1);
var address = this.address().address;
@@ -69,8 +69,18 @@ assert.throws(function() {
return !(err instanceof TypeError);
}, 'Unexpected error');

/*
* Make sure that dns.lookup throws if hints does not represent a valid flag.
* (dns.V4MAPPED | dns.ADDRCONFIG) + 1 is invalid because:
* - it's different from dns.V4MAPPED and dns.ADDRCONFIG.
* - it's different from them bitwise ored.
* - it's different from 0.
* - it's an odd number different than 1, and thus is invalid, because
* flags are either === 1 or even.
*/
assert.throws(function() {
dns.lookup('www.google.com', { hints: 1 }, noop);
dns.lookup('www.google.com', { hints: (dns.V4MAPPED | dns.ADDRCONFIG) + 1 },
noop);
});

assert.throws(function() {
@@ -24,6 +24,11 @@ var assert = require('assert');
var net = require('net');
var dns = require('dns');

if (!common.hasIPv6) {
console.error('Skipping test, no IPv6 support');
return;
}

var serverGotEnd = false;
var clientGotEnd = false;

@@ -135,9 +135,13 @@ console.log(common.PIPE);
pingPongTest(common.PIPE);
pingPongTest(common.PORT);
pingPongTest(common.PORT + 1, 'localhost');
pingPongTest(common.PORT + 2, '::1');
if (common.hasIPv6)
pingPongTest(common.PORT + 2, '::1');

process.on('exit', function() {
assert.equal(4, tests_run);
if (common.hasIPv6)
assert.equal(4, tests_run);
else
assert.equal(3, tests_run);
console.log('done');
});