If a client connection emits an 'error' event - it will forwarded here.
- ### http.createServer(requestListener)
+ ### http.createServer([requestListener])
Returns a new web server object.
- `host`: A domain name or IP address of the server to issue the request to.
- `port`: Port of remote server.
+- `socketPath`: Unix Domain Socket (use one of host:port or socketPath)
- `method`: A string specifying the HTTP request method. Possible values:
`'GET'` (default), `'POST'`, `'PUT'`, and `'DELETE'`.
- `path`: Request path. Should include query string and fragments if any.
});
});
+ req.on('error', function(e) {
+ console.log('problem with request: ' + e.message);
+ });
+
// write data to request body
req.write('data\n');
req.write('data\n');
## http.Agent
-## http.getAgent(host, port)
+## http.getAgent(options)
`http.request()` uses a special `Agent` for managing multiple connections to
an HTTP server. Normally `Agent` instances should not be exposed to user
code, however in certain situations it's useful to check the status of the
agent. The `http.getAgent()` function allows you to access the agents.
+Options:
+
+- `host`: A domain name or IP address of the server to issue the request to.
+- `port`: Port of remote server.
+- `socketPath`: Unix Domain Socket (use one of host:port or socketPath)
+
### Event: 'upgrade'
`function (request, socket, head)`
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var SlowBuffer = process.binding('buffer').SlowBuffer;
+var assert = require('assert');
function toHex(n) {
};
+SlowBuffer.prototype.hexSlice = function(start, end) {
+ var len = this.length;
+
+ if (!start || start < 0) start = 0;
+ if (!end || end < 0 || end > len) end = len;
+
+ var out = '';
+ for (var i = start; i < end; i++) {
+ out += toHex(this[i]);
+ }
+ return out;
+};
+
+
+
SlowBuffer.prototype.toString = function(encoding, start, end) {
encoding = String(encoding || 'utf8').toLowerCase();
start = +start || 0;
}
switch (encoding) {
+ case 'hex':
+ return this.hexSlice(start, end);
+
case 'utf8':
case 'utf-8':
return this.utf8Slice(start, end);
};
+SlowBuffer.prototype.hexWrite = function(string, offset) {
+ var len = string.length;
+ offset = +offset || 0;
+
+ // must be an even number of digits
+ if (len % 2) {
+ throw new Error('Invalid hex string');
+ }
+ for (var i = 0; i < len / 2; i++) {
+ var byte = parseInt(string.substr(i * 2, 2), 16);
+ if (isNaN(byte)) throw new Error('Invalid hex string');
+ this[offset + i] = byte;
+ }
+ return i;
+};
+
+
SlowBuffer.prototype.write = function(string, offset, encoding) {
// Support both (string, offset, encoding)
// and the legacy (string, encoding, offset)
encoding = String(encoding || 'utf8').toLowerCase();
switch (encoding) {
+ case 'hex':
+ return this.hexWrite(string, offset);
+
case 'utf8':
case 'utf-8':
return this.utf8Write(string, offset);
case 'ucs2':
case 'ucs-2':
- return this.ucs2Write(start, end);
+ return this.ucs2Write(string, offset);
default:
throw new Error('Unknown encoding');
var ret;
switch (encoding) {
+ case 'hex':
+ ret = this.parent.hexWrite(string, this.offset + offset, maxLength);
+ break;
+
case 'utf8':
case 'utf-8':
ret = this.parent.utf8Write(string, this.offset + offset, maxLength);
end = end + this.offset;
switch (encoding) {
+ case 'hex':
+ return this.parent.hexSlice(start, end);
+
case 'utf8':
case 'utf-8':
return this.parent.utf8Slice(start, end);
Buffer.byteLength = SlowBuffer.byteLength;
+// fill(value, start=0, end=buffer.length)
+Buffer.prototype.fill = function fill (value, start, end) {
+ value || (value = 0);
+ start || (start = 0);
+ end || (end = this.length);
+
+ if (typeof value === "string") {
+ value = value.charCodeAt(0);
+ }
+ if (!(typeof value === "number") || isNaN(value)) {
+ throw new Error("value is not a number");
+ }
+
+ if (end < start) throw new Error("end < start");
+
+ // Fill 0 bytes; we're done
+ if (end === start) return 0;
+ if (this.length == 0) return 0;
+
+ if (start < 0 || start >= this.length) {
+ throw new Error("start out of bounds");
+ }
+
+ if (end < 0 || end > this.length) {
+ throw new Error("end out of bounds");
+ }
+
+ return this.parent.fill(value,
+ start + this.offset,
+ end + this.offset);
+};
+
+
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy = function(target, target_start, start, end) {
var source = this;
return this.write(string, offset, 'ascii');
};
+Buffer.prototype.readUInt8 = function(offset, endian) {
+ var buffer = this;
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ return buffer[offset];
+};
+
+
+Buffer.prototype.readUInt16 = function(offset, endian) {
+ var val = 0;
+ var buffer = this;
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 1 < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ if (endian == 'big') {
+ val = buffer[offset] << 8;
+ val |= buffer[offset + 1];
+ } else {
+ val = buffer[offset];
+ val |= buffer[offset + 1] << 8;
+ }
+
+ return val;
+};
+
+
+Buffer.prototype.readUInt32 = function(offset, endian) {
+ var val = 0;
+ var buffer = this;
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 3 < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ if (endian == 'big') {
+ val = buffer[offset + 1] << 16;
+ val |= buffer[offset + 2] << 8;
+ val |= buffer[offset + 3];
+ val = val + (buffer[offset] << 24 >>> 0);
+ } else {
+ val = buffer[offset + 2] << 16;
+ val |= buffer[offset + 1] << 8;
+ val |= buffer[offset];
+ val = val + (buffer[offset + 3] << 24 >>> 0);
+ }
+
+ return val;
+};
+
+
+/*
+ * Signed integer types, yay team! A reminder on how two's complement actually
+ * works. The first bit is the signed bit, i.e. tells us whether or not the
+ * number should be positive or negative. If the two's complement value is
+ * positive, then we're done, as it's equivalent to the unsigned representation.
+ *
+ * Now if the number is positive, you're pretty much done, you can just leverage
+ * the unsigned translations and return those. Unfortunately, negative numbers
+ * aren't quite that straightforward.
+ *
+ * At first glance, one might be inclined to use the traditional formula to
+ * translate binary numbers between the positive and negative values in two's
+ * complement. (Though it doesn't quite work for the most negative value)
+ * Mainly:
+ * - invert all the bits
+ * - add one to the result
+ *
+ * Of course, this doesn't quite work in Javascript. Take for example the value
+ * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
+ * course, Javascript will do the following:
+ *
+ * > ~0xff80
+ * -65409
+ *
+ * Whoh there, Javascript, that's not quite right. But wait, according to
+ * Javascript that's perfectly correct. When Javascript ends up seeing the
+ * constant 0xff80, it has no notion that it is actually a signed number. It
+ * assumes that we've input the unsigned value 0xff80. Thus, when it does the
+ * binary negation, it casts it into a signed value, (positive 0xff80). Then
+ * when you perform binary negation on that, it turns it into a negative number.
+ *
+ * Instead, we're going to have to use the following general formula, that works
+ * in a rather Javascript friendly way. I'm glad we don't support this kind of
+ * weird numbering scheme in the kernel.
+ *
+ * (BIT-MAX - (unsigned)val + 1) * -1
+ *
+ * The astute observer, may think that this doesn't make sense for 8-bit numbers
+ * (really it isn't necessary for them). However, when you get 16-bit numbers,
+ * you do. Let's go back to our prior example and see how this will look:
+ *
+ * (0xffff - 0xff80 + 1) * -1
+ * (0x007f + 1) * -1
+ * (0x0080) * -1
+ */
+Buffer.prototype.readInt8 = function(offset, endian) {
+ var buffer = this;
+ var neg;
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ neg = buffer[offset] & 0x80;
+ if (!neg) {
+ return (buffer[offset]);
+ }
+
+ return ((0xff - buffer[offset] + 1) * -1);
+};
+
+
+Buffer.prototype.readInt16 = function(offset, endian) {
+ var buffer = this;
+ var neg;
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 1 < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ val = buffer.readUInt16(offset, endian);
+ neg = val & 0x8000;
+ if (!neg) {
+ return val;
+ }
+
+ return (0xffff - val + 1) * -1;
+};
+
+
+Buffer.prototype.readInt32 = function(offset, endian) {
+ var buffer = this;
+ var neg;
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 3 < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ val = buffer.readUInt32(offset, endian);
+ neg = val & 0x80000000;
+ if (!neg) {
+ return (val);
+ }
+
+ return (0xffffffff - val + 1) * -1;
+};
+
+
+/*
+ * We have to make sure that the value is a valid integer. This means that it is
+ * non-negative. It has no fractional component and that it does not exceed the
+ * maximum allowed value.
+ *
+ * value The number to check for validity
+ *
+ * max The maximum value
+ */
+function verifuint(value, max) {
+ assert.ok(typeof (value) == 'number',
+ 'cannot write a non-number as a number');
+
+ assert.ok(value >= 0,
+ 'specified a negative value for writing an unsigned value');
+
+ assert.ok(value <= max, 'value is larger than maximum value for type');
+
+ assert.ok(Math.floor(value) === value, 'value has a fractional component');
+}
+
+
+Buffer.prototype.writeUInt8 = function(value, offset, endian) {
+ var buffer = this;
+
+ assert.ok(value !== undefined && value !== null,
+ 'missing value');
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset < buffer.length,
+ 'trying to read beyond buffer length');
+
+ verifuint(value, 0xff);
+ buffer[offset] = value;
+};
+
+
+Buffer.prototype.writeUInt16 = function(value, offset, endian) {
+ var buffer = this;
+
+ assert.ok(value !== undefined && value !== null,
+ 'missing value');
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 1 < buffer.length,
+ 'trying to read beyond buffer length');
+
+ verifuint(value, 0xffff);
+
+ if (endian == 'big') {
+ buffer[offset] = (value & 0xff00) >>> 8;
+ buffer[offset + 1] = value & 0x00ff;
+ } else {
+ buffer[offset + 1] = (value & 0xff00) >>> 8;
+ buffer[offset] = value & 0x00ff;
+ }
+};
+
+
+Buffer.prototype.writeUInt32 = function(value, offset, endian) {
+ var buffer = this;
+
+ assert.ok(value !== undefined && value !== null,
+ 'missing value');
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 3 < buffer.length,
+ 'trying to read beyond buffer length');
+
+ verifuint(value, 0xffffffff);
+ if (endian == 'big') {
+ buffer[offset] = (value >>> 24) & 0xff;
+ buffer[offset + 1] = (value >>> 16) & 0xff;
+ buffer[offset + 2] = (value >>> 8) & 0xff;
+ buffer[offset + 3] = value & 0xff;
+ } else {
+ buffer[offset + 3] = (value >>> 24) & 0xff;
+ buffer[offset + 2] = (value >>> 16) & 0xff;
+ buffer[offset + 1] = (value >>> 8) & 0xff;
+ buffer[offset] = value & 0xff;
+ }
+};
+
+
+/*
+ * We now move onto our friends in the signed number category. Unlike unsigned
+ * numbers, we're going to have to worry a bit more about how we put values into
+ * arrays. Since we are only worrying about signed 32-bit values, we're in
+ * slightly better shape. Unfortunately, we really can't do our favorite binary
+ * & in this system. It really seems to do the wrong thing. For example:
+ *
+ * > -32 & 0xff
+ * 224
+ *
+ * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
+ * this aren't treated as a signed number. Ultimately a bad thing.
+ *
+ * What we're going to want to do is basically create the unsigned equivalent of
+ * our representation and pass that off to the wuint* functions. To do that
+ * we're going to do the following:
+ *
+ * - if the value is positive
+ * we can pass it directly off to the equivalent wuint
+ * - if the value is negative
+ * we do the following computation:
+ * mb + val + 1, where
+ * mb is the maximum unsigned value in that byte size
+ * val is the Javascript negative integer
+ *
+ *
+ * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
+ * you do out the computations:
+ *
+ * 0xffff - 128 + 1
+ * 0xffff - 127
+ * 0xff80
+ *
+ * You can then encode this value as the signed version. This is really rather
+ * hacky, but it should work and get the job done which is our goal here.
+ */
+
+/*
+ * A series of checks to make sure we actually have a signed 32-bit number
+ */
+function verifsint(value, max, min) {
+ assert.ok(typeof (value) == 'number',
+ 'cannot write a non-number as a number');
+
+ assert.ok(value <= max, 'value larger than maximum allowed value');
+
+ assert.ok(value >= min, 'value smaller than minimum allowed value');
+
+ assert.ok(Math.floor(value) === value, 'value has a fractional component');
+}
+
+Buffer.prototype.writeInt8 = function(value, offset, endian) {
+ var buffer = this;
+
+ assert.ok(value !== undefined && value !== null,
+ 'missing value');
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ verifsint(value, 0x7f, -0xf0);
+
+ if (value >= 0) {
+ buffer.writeUInt8(value, offset, endian);
+ } else {
+ buffer.writeUInt8(0xff + value + 1, offset, endian);
+ }
+};
+
+
+Buffer.prototype.writeInt16 = function(value, offset, endian) {
+ var buffer = this;
+
+ assert.ok(value !== undefined && value !== null,
+ 'missing value');
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 1 < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ verifsint(value, 0x7fff, -0xf000);
+
+ if (value >= 0) {
+ buffer.writeUInt16(value, offset, endian);
+ } else {
+ buffer.writeUInt16(0xffff + value + 1, offset, endian);
+ }
+};
+
+
+Buffer.prototype.writeInt32 = function(value, offset, endian) {
+ var buffer = this;
+
+ assert.ok(value !== undefined && value !== null,
+ 'missing value');
+
+ assert.ok(endian !== undefined && endian !== null,
+ 'missing endian');
+
+ assert.ok(endian == 'big' || endian == 'little',
+ 'bad endian value');
+
+ assert.ok(offset !== undefined && offset !== null,
+ 'missing offset');
+
+ assert.ok(offset + 3 < buffer.length,
+ 'Trying to read beyond buffer length');
+
+ verifsint(value, 0x7fffffff, -0xf0000000);
+ if (value >= 0) {
+ buffer.writeUInt32(value, offset, endian);
+ } else {
+ buffer.writeUInt32(0xffffffff + value + 1, offset, endian);
+ }
+};
this.options = options;
this.host = options.host;
this.port = options.port || this.defaultPort;
+ this.socketPath = options.socketPath;
this.queue = [];
this.sockets = [];
this.maxSockets = Agent.defaultMaxSockets;
+
}
util.inherits(Agent, EventEmitter);
exports.Agent = Agent;
// Grab a new "socket". Depending on the implementation of _getConnection
// this could either be a raw TCP socket or a TLS stream.
- var socket = this._getConnection(this.host, this.port, function() {
+ var socket = this._getConnection(self, function() {
socket._httpConnecting = false;
self.emit('connect'); // mostly for the shim.
debug('Agent _getConnection callback');
req = self.queue.shift();
assert(req._queue === self.queue);
req._queue = null;
- } else {
- // No requests on queue? Where is the request
- assert(0);
}
- req.emit('error', err);
- req._hadError = true; // hacky
+ if (req) {
+ req.emit('error', err);
+ req._hadError = true; // hacky
+ }
// clean up so that agent can handle new requests
parser.finish();
// Sub-classes can overwrite this method with e.g. something that supplies
// TLS streams.
-Agent.prototype._getConnection = function(host, port, cb) {
+Agent.prototype._getConnection = function(options, cb) {
debug('Agent connected!');
- var c = net.createConnection(port, host);
+
+ var c;
+
+ if (options.host) {
+ c = net.createConnection(options.port, options.host);
+ } else if (options.socketPath) {
+ c = net.createConnection(options.socketPath);
+ } else {
+ c = net.createConnection(options.port);
+ }
c.on('connect', cb);
return c;
};
// to remove it?
var agents = {};
+// Backwards compatible with legacy getAgent(host, port);
+function getAgent(options) {
+ var agent;
+ var host;
+ var id;
+ var port;
+
+ var _opts = {};
+
+ if (options instanceof String) {
+ port = arguments[1] || 80;
+ id = options + ':' + port;
+ _opts.host = options;
+ _opts.port = port;
+ } else if (options instanceof Object) {
+ if (options.port || options.host) {
+ host = options.host || 'localhost';
+ port = options.port || 80;
+ id = host + port;
+ _opts.host = host;
+ _opts.port = port;
+ } else if (options.socketPath) {
+ id = options.socketPath;
+ _opts.socketPath = options.socketPath;
+ } else {
+ throw new TypeError('Invalid options specification to getAgent');
+ }
+ } else {
+ throw new TypeError('Invalid argument to getAgent');
+ }
-function getAgent(host, port) {
- port = port || 80;
- var id = host + ':' + port;
- var agent = agents[id];
+ agent = agents[id];
if (!agent) {
- agent = agents[id] = new Agent({ host: host, port: port });
+ agent = agents[id] = new Agent(_opts);
}
return agent;
exports.request = function(options, cb) {
if (options.agent === undefined) {
- options.agent = getAgent(options.host, options.port);
+ options.agent = getAgent(options);
} else if (options.agent === false) {
options.agent = new Agent(options);
}
headers = {},
callback = null;
+ console.error("http.cat will be removed in the near future. use http.get");
+
// parse the arguments for the various options... very ugly
if (typeof(arguments[1]) == 'string') {
encoding = arguments[1];
// hack for repl require to work properly with node_modules folders
module.paths = require('module')._nodeModulePaths(module.filename);
-
-function resetContext() {
- context = vm.createContext();
- for (var i in global) context[i] = global[i];
- context.module = module;
- context.require = require;
- context.global = context;
- context.global.global = context;
- for (var i in require.cache) delete require.cache[i];
-}
-
-
// Can overridden with custom print functions, such as `probe` or `eyes.js`
exports.writer = util.inspect;
function REPLServer(prompt, stream) {
var self = this;
- if (!context) resetContext();
- if (!exports.repl) exports.repl = this;
- self.context = context;
+
+ self.resetContext();
self.bufferedCommand = '';
if (stream) {
process.stdin.resume();
}
- self.prompt = prompt || '> ';
+ self.prompt = (prompt != undefined ? prompt : '> ');
function complete(text) {
return self.complete(text);
this.commands = {};
defineDefaultCommands(this);
- if (rli.enabled && !disableColors) {
+ if (rli.enabled && !disableColors && exports.writer === util.inspect) {
// Turn on ANSI coloring.
exports.writer = function(obj, showHidden, depth) {
return util.inspect(obj, showHidden, depth, true);
rli.setPrompt(self.prompt);
+ var sawSIGINT = false;
rli.on('SIGINT', function() {
- if (self.bufferedCommand && self.bufferedCommand.length > 0) {
- rli.write('\n');
- self.bufferedCommand = '';
- self.displayPrompt();
- } else {
- rli.close();
+ if (sawSIGINT) {
+ rli.close();
+ process.exit();
}
+ var bareInt = false;
+ if (!(self.bufferedCommand && self.bufferedCommand.length > 0) &&
+ rli.line.length === 0) {
+ rli.write('\n(^C again to quit)');
+ bareInt = true;
+ }
+ rli.line = '';
+ rli.write('\n');
+ self.bufferedCommand = '';
+ self.displayPrompt();
+ sawSIGINT = bareInt;
});
rli.addListener('line', function(cmd) {
+ sawSIGINT = false;
var skipCatchall = false;
cmd = trimWhitespace(cmd);
// First we attempt to eval as expression with parens.
// This catches '{a : 1}' properly.
ret = vm.runInContext('(' + self.bufferedCommand + ')',
- context,
+ self.context,
'repl');
if (typeof ret !== 'function') success = true;
} catch (e) {
if (!success) {
// Now as statement without parens.
- ret = vm.runInContext(self.bufferedCommand, context, 'repl');
+ ret = vm.runInContext(self.bufferedCommand, self.context, 'repl');
}
if (ret !== undefined) {
- context._ = ret;
+ self.context._ = ret;
self.outputStream.write(exports.writer(ret) + '\n');
}
// It could also be an error from JSON.parse
} else if (e &&
e.stack &&
- e.stack.match('Unexpected token ILLEGAL') &&
- e.stack.match(/Object.parse \(native\)/)) {
+ e.stack.match(/^SyntaxError: Unexpected token .*\n/) &&
+ e.stack.match(/\n at Object.parse \(native\)\n/)) {
throw e;
}
}
// prompt is a string to print on each line for the prompt,
// source is a stream to use for I/O, defaulting to stdin/stdout.
exports.start = function(prompt, source) {
- return new REPLServer(prompt, source);
+ var repl = new REPLServer(prompt, source);
+ if (!exports.repl) exports.repl = repl;
+ return repl;
};
+REPLServer.prototype.createContext = function() {
+ var context = vm.createContext();
+
+ for (var i in global) context[i] = global[i];
+ context.module = module;
+ context.require = require;
+ context.global = context;
+ context.global.global = context;
+
+ return context;
+};
+
+REPLServer.prototype.resetContext = function(force) {
+ if (!context || force) {
+ context = this.createContext();
+ for (var i in require.cache) delete require.cache[i];
+ }
+
+ this.context = context;
+};
+
REPLServer.prototype.displayPrompt = function() {
this.rli.setPrompt(this.bufferedCommand.length ? '... ' : this.prompt);
this.rli.prompt();
action: function() {
this.outputStream.write('Clearing context...\n');
this.bufferedCommand = '';
- resetContext();
+ this.resetContext(true);
this.displayPrompt();
}
});
var END_OF_FILE = 42;
var assert = require('assert').ok;
+var NPN_ENABLED = process.binding('constants').NPN_ENABLED;
+
var debug;
if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
debug = function(a) { console.error('TLS:', a); };
var Connection = null;
try {
Connection = process.binding('crypto').Connection;
+ exports.NPN_ENABLED = NPN_ENABLED;
} catch (e) {
throw new Error('node.js not compiled with openssl crypto support.');
}
+// Convert protocols array into valid OpenSSL protocols list
+// ("\x06spdy/2\x08http/1.1\x08http/1.0")
+function convertNPNProtocols(NPNProtocols, out) {
+ // If NPNProtocols is Array - translate it into buffer
+ if (Array.isArray(NPNProtocols)) {
+ var buff = new Buffer(NPNProtocols.reduce(function(p, c) {
+ return p + 1 + Buffer.byteLength(c);
+ }, 0));
+
+ NPNProtocols.reduce(function(offset, c) {
+ var clen = Buffer.byteLength(c);
+ buff[offset] = clen;
+ buff.write(c, offset + 1);
+
+ return offset + 1 + clen;
+ }, 0);
+
+ NPNProtocols = buff;
+ }
+
+ // If it's already a Buffer - store it
+ if (Buffer.isBuffer(NPNProtocols)) {
+ out.NPNProtocols = NPNProtocols;
+ }
+};
// Base class of both CleartextStream and EncryptedStream
function CryptoStream(pair) {
this.readable = this.writable = true;
- this._writeState = true;
+ this._paused = false;
this._pending = [];
this._pendingCallbacks = [];
this._pendingBytes = 0;
this._pending.push(data);
this._pendingCallbacks.push(cb);
-
this._pendingBytes += data.length;
this.pair._writeCalled = true;
- this.pair._cycle();
+ this.pair.cycle();
return this._pendingBytes < 128 * 1024;
};
CryptoStream.prototype.pause = function() {
debug('paused ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
- this._writeState = false;
+ this._paused = true;
};
CryptoStream.prototype.resume = function() {
debug('resume ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
- this._writeState = true;
- this.pair._cycle();
+ this._paused = false;
+ this.pair.cycle();
};
CryptoStream.prototype.getPeerCertificate = function() {
- if (this.pair._ssl) {
- var c = this.pair._ssl.getPeerCertificate();
+ if (this.pair.ssl) {
+ var c = this.pair.ssl.getPeerCertificate();
if (c) {
if (c.issuer) c.issuer = parseCertString(c.issuer);
CryptoStream.prototype.getCipher = function(err) {
- if (this.pair._ssl) {
- return this.pair._ssl.getCurrentCipher();
+ if (this.pair.ssl) {
+ return this.pair.ssl.getCurrentCipher();
} else {
return null;
}
CryptoStream.prototype.end = function(d) {
- if (this.writable) {
- if (this.pair._done) return;
+ if (this.pair._doneFlag) return;
+ if (!this.writable) return;
- if (d) {
- this.write(d);
- }
+ if (d) {
+ this.write(d);
+ }
- this._pending.push(END_OF_FILE);
- this._pendingCallbacks.push(null);
+ this._pending.push(END_OF_FILE);
+ this._pendingCallbacks.push(null);
- // If this is an encrypted stream then we need to disable further 'data'
- // events.
+ // If this is an encrypted stream then we need to disable further 'data'
+ // events.
- this.writable = false;
+ this.writable = false;
- this.pair._cycle();
- }
+ this.pair.cycle();
};
CryptoStream.prototype.destroy = function(err) {
- if (this.pair._done) return;
- this.pair._destroy();
+ if (this.pair._doneFlag) return;
+ this.pair.destroy();
};
if (this.pair.cleartext._doneFlag &&
this.pair.encrypted._doneFlag &&
- !this.pair._done) {
+ !this.pair._doneFlag) {
// If both streams are done:
- this.pair._destroy();
+ this.pair.destroy();
}
};
return;
}
- while (this._writeState == true) {
+ while (!this._paused) {
var bytesRead = 0;
var chunkBytes = 0;
var pool = new Buffer(16 * 4096); // alloc every time?
do {
chunkBytes = this._pusher(pool, bytesRead, pool.length - bytesRead);
- if (this.pair._ssl && this.pair._ssl.error) {
- this.pair._error();
+ if (this.pair.ssl && this.pair.ssl.error) {
+ this.pair.error();
return;
}
- this.pair._maybeInitFinished();
+ this.pair.maybeInitFinished();
if (chunkBytes >= 0) {
bytesRead += chunkBytes;
}
- } while ((chunkBytes > 0) && (bytesRead < pool.length));
+ } while (chunkBytes > 0 && bytesRead < pool.length);
assert(bytesRead >= 0);
assert(havePending || this._pendingBytes == 0);
while (this._pending.length > 0) {
- if (!this.pair._ssl) break;
+ if (!this.pair.ssl) break;
var tmp = this._pending.shift();
var cb = this._pendingCallbacks.shift();
assert(this === this.pair.cleartext);
debug('end cleartext');
- this.pair._ssl.shutdown();
+ this.pair.ssl.shutdown();
// TODO check if we get EAGAIN From shutdown, would have to do it
// again. should unshift END_OF_FILE back onto pending and wait for
this.pair.encrypted._destroyAfterPush = true;
}
- this.pair._cycle();
+ this.pair.cycle();
this._done()
return;
}
var rv = this._puller(tmp);
- if (this.pair._ssl && this.pair._ssl.error) {
- this.pair._error();
+ if (this.pair.ssl && this.pair.ssl.error) {
+ this.pair.error();
return;
}
- this.pair._maybeInitFinished();
+ this.pair.maybeInitFinished();
if (rv === 0 || rv < 0) {
this._pending.unshift(tmp);
CleartextStream.prototype._internallyPendingBytes = function() {
- if (this.pair._ssl) {
- return this.pair._ssl.clearPending();
+ if (this.pair.ssl) {
+ return this.pair.ssl.clearPending();
} else {
return 0;
}
CleartextStream.prototype._puller = function(b) {
debug('clearIn ' + b.length + ' bytes');
- return this.pair._ssl.clearIn(b, 0, b.length);
+ return this.pair.ssl.clearIn(b, 0, b.length);
};
CleartextStream.prototype._pusher = function(pool, offset, length) {
debug('reading from clearOut');
- if (!this.pair._ssl) return -1;
- return this.pair._ssl.clearOut(pool, offset, length);
+ if (!this.pair.ssl) return -1;
+ return this.pair.ssl.clearOut(pool, offset, length);
};
EncryptedStream.prototype._internallyPendingBytes = function() {
- if (this.pair._ssl) {
- return this.pair._ssl.encPending();
+ if (this.pair.ssl) {
+ return this.pair.ssl.encPending();
} else {
return 0;
}
EncryptedStream.prototype._puller = function(b) {
debug('writing from encIn');
- return this.pair._ssl.encIn(b, 0, b.length);
+ return this.pair.ssl.encIn(b, 0, b.length);
};
EncryptedStream.prototype._pusher = function(pool, offset, length) {
debug('reading from encOut');
- if (!this.pair._ssl) return -1;
- return this.pair._ssl.encOut(pool, offset, length);
+ if (!this.pair.ssl) return -1;
+ return this.pair.ssl.encOut(pool, offset, length);
};
* Provides a pair of streams to do encrypted communication.
*/
-function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
+function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
+ NPNProtocols) {
if (!(this instanceof SecurePair)) {
return new SecurePair(credentials,
isServer,
requestCert,
- rejectUnauthorized);
+ rejectUnauthorized,
+ NPNProtocols);
}
var self = this;
this._isServer = isServer ? true : false;
this._encWriteState = true;
this._clearWriteState = true;
- this._done = false;
-
- var crypto = require('crypto');
+ this._doneFlag = false;
if (!credentials) {
this.credentials = crypto.createCredentials();
this._rejectUnauthorized = rejectUnauthorized ? true : false;
this._requestCert = requestCert ? true : false;
- this._ssl = new Connection(this.credentials.context,
+ this.ssl = new Connection(this.credentials.context,
this._isServer ? true : false,
this._requestCert,
this._rejectUnauthorized);
- this._ssl.setNPNProtocols(NPNProtocols);
+ if (NPN_ENABLED && NPNProtocols) {
++ this.ssl.setNPNProtocols(NPNProtocols);
+ this.npnProtocol = null;
+ }
/* Acts as a r/w stream to the cleartext side of the stream. */
this.cleartext = new CleartextStream(this);
this.encrypted = new EncryptedStream(this);
process.nextTick(function() {
- self._ssl.start();
- self._cycle();
+ self.ssl.start();
+ self.cycle();
});
}
* Because it is also called everywhere, we also check if the connection has
* completed negotiation and emit 'secure' from here if it has.
*/
- SecurePair.prototype._cycle = function(depth) {
+ SecurePair.prototype.cycle = function(depth) {
+ if (this._doneFlag) return;
+
depth = depth ? depth : 0;
- if (this._done) {
- return;
- }
- if(depth == 0) this._writeCalled = false;
+ if (depth == 0) this._writeCalled = false;
var established = this._secureEstablished;
- if (!this._cycleEncryptedPullLock) {
- this._cycleEncryptedPullLock = true;
+ if (!this.cycleEncryptedPullLock) {
+ this.cycleEncryptedPullLock = true;
debug("encrypted._pull");
this.encrypted._pull();
- this._cycleEncryptedPullLock = false;
+ this.cycleEncryptedPullLock = false;
}
- if (!this._cycleCleartextPullLock) {
- this._cycleCleartextPullLock = true;
+ if (!this.cycleCleartextPullLock) {
+ this.cycleCleartextPullLock = true;
debug("cleartext._pull");
this.cleartext._pull();
- this._cycleCleartextPullLock = false;
+ this.cycleCleartextPullLock = false;
}
- if (!this._cycleCleartextPushLock) {
- this._cycleCleartextPushLock = true;
+ if (!this.cycleCleartextPushLock) {
+ this.cycleCleartextPushLock = true;
debug("cleartext._push");
this.cleartext._push();
- this._cycleCleartextPushLock = false;
+ this.cycleCleartextPushLock = false;
}
- if (!this._cycleEncryptedPushLock) {
- this._cycleEncryptedPushLock = true;
+ if (!this.cycleEncryptedPushLock) {
+ this.cycleEncryptedPushLock = true;
debug("encrypted._push");
this.encrypted._push();
- this._cycleEncryptedPushLock = false;
- }
-
- if (this._done) {
- return;
+ this.cycleEncryptedPushLock = false;
}
if ((!established && this._secureEstablished) ||
(depth == 0 && this._writeCalled)) {
// If we were not established but now we are, let's cycle again.
// Or if there is some data to write...
- this._cycle(depth + 1);
+ this.cycle(depth + 1);
}
};
- SecurePair.prototype._maybeInitFinished = function() {
- if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) {
+ SecurePair.prototype.maybeInitFinished = function() {
+ if (this.ssl && !this._secureEstablished && this.ssl.isInitFinished()) {
+ if (NPN_ENABLED) {
- this.npnProtocol = this._ssl.getNegotiatedProtocol();
++ this.npnProtocol = this.ssl.getNegotiatedProtocol();
+ }
-
this._secureEstablished = true;
debug('secure established');
this.emit('secure');
};
- SecurePair.prototype._destroy = function() {
+ SecurePair.prototype.destroy = function() {
var self = this;
- if (!this._done) {
- this._done = true;
- this._ssl.error = null;
- this._ssl.close();
- this._ssl = null;
+ if (!this._doneFlag) {
+ this._doneFlag = true;
+ this.ssl.error = null;
+ this.ssl.close();
+ this.ssl = null;
self.encrypted.writable = self.encrypted.readable = false;
self.cleartext.writable = self.cleartext.readable = false;
process.nextTick(function() {
- self.encrypted.emit('end');
- if (self.encrypted.onend) self.encrypted.onend();
self.encrypted.emit('close');
-
- self.cleartext.emit('end');
- if (self.cleartext.onend) self.cleartext.onend();
self.cleartext.emit('close');
});
}
-
- this._cycle();
};
- SecurePair.prototype._error = function() {
+ SecurePair.prototype.error = function() {
if (!this._secureEstablished) {
- this._destroy();
+ this.destroy();
} else {
- var err = this._ssl.error;
- this._ssl.error = null;
+ var err = this.ssl.error;
+ this.ssl.error = null;
if (this._isServer &&
this._rejectUnauthorized &&
/peer did not return a certificate/.test(err.message)) {
// Not really an error.
- this._destroy();
+ this.destroy();
} else {
this.cleartext.emit('error', err);
}
key: self.key,
cert: self.cert,
ca: self.ca,
+ ciphers: self.ciphers,
secureProtocol: self.secureProtocol,
+ secureOptions: self.secureOptions,
crl: self.crl
});
creds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
var pair = new SecurePair(creds,
true,
self.requestCert,
- self.rejectUnauthorized);
+ self.rejectUnauthorized,
+ self.NPNProtocols);
var cleartext = pipe(pair, socket);
cleartext._controlReleased = false;
pair.on('secure', function() {
pair.cleartext.authorized = false;
+ pair.cleartext.npnProtocol = pair.npnProtocol;
if (!self.requestCert) {
cleartext._controlReleased = true;
self.emit('secureConnection', pair.cleartext, pair.encrypted);
} else {
- var verifyError = pair._ssl.verifyError();
+ var verifyError = pair.ssl.verifyError();
if (verifyError) {
pair.cleartext.authorizationError = verifyError;
if (self.rejectUnauthorized) {
socket.destroy();
- pair._destroy();
+ pair.destroy();
} else {
cleartext._controlReleased = true;
self.emit('secureConnection', pair.cleartext, pair.encrypted);
if (options.ca) this.ca = options.ca;
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
if (options.crl) this.crl = options.crl;
+ if (options.ciphers) this.ciphers = options.ciphers;
+ if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
+ if (options.secureOptions) this.secureOptions = options.secureOptions;
+ if (options.NPNProtocols) convertNPNProtocols(options.NPNProtocols, this);
};
var sslcontext = crypto.createCredentials(options);
//sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
- var pair = new SecurePair(sslcontext, false);
+ convertNPNProtocols(options.NPNProtocols, this);
+ var pair = new SecurePair(sslcontext, false, true, false,
+ this.NPNProtocols);
var cleartext = pipe(pair, socket);
socket.connect(port, host);
pair.on('secure', function() {
- var verifyError = pair._ssl.verifyError();
+ var verifyError = pair.ssl.verifyError();
+ cleartext.npnProtocol = pair.npnProtocol;
+
if (verifyError) {
cleartext.authorized = false;
cleartext.authorizationError = verifyError;
static int option_end_index = 0;
static bool use_debug_agent = false;
static bool debug_wait_connect = false;
+static bool cov = false;
static int debug_port=5858;
static int max_stack_size = 0;
return UCS2;
} else if (strcasecmp(*encoding, "binary") == 0) {
return BINARY;
+ } else if (strcasecmp(*encoding, "hex") == 0) {
+ return HEX;
} else if (strcasecmp(*encoding, "raw") == 0) {
fprintf(stderr, "'raw' (array of integers) has been removed. "
"Use 'binary'.\n");
if (encoding == UTF8) return str->Utf8Length();
else if (encoding == UCS2) return str->Length() * 2;
+ else if (encoding == HEX) return str->Length() / 2;
return str->Length();
}
String::Utf8Value trace(try_catch.StackTrace());
- if (trace.length() > 0) {
+ // range errors have a trace member set to undefined
+ if (trace.length() > 0 && !try_catch.StackTrace()->IsUndefined()) {
fprintf(stderr, "%s\n", *trace);
} else {
// this really only happens for RangeErrors, since they're the only
- // kind that won't have all this info in the trace.
+ // kind that won't have all this info in the trace, or when non-Error
+ // objects are thrown manually.
Local<Value> er = try_catch.Exception();
- String::Utf8Value msg(!er->IsObject() ? er->ToString()
+ bool isErrorObject = er->IsObject() &&
+ !(er->ToObject()->Get(String::New("message"))->IsUndefined()) &&
+ !(er->ToObject()->Get(String::New("name"))->IsUndefined());
+
+ if (isErrorObject) {
+ String::Utf8Value name(er->ToObject()->Get(String::New("name")));
+ fprintf(stderr, "%s: ", *name);
+ }
+
+ String::Utf8Value msg(!isErrorObject ? er->ToString()
: er->ToObject()->Get(String::New("message"))->ToString());
fprintf(stderr, "%s\n", *msg);
}
if ((err = getgrnam_r(*grpnam, &grp, getbuf, ARRAY_SIZE(getbuf), &grpp)) ||
grpp == NULL) {
- return ThrowException(ErrnoException(errno, "getgrnam_r"));
+ if (errno == 0)
+ return ThrowException(Exception::Error(
+ String::New("setgid group id does not exist")));
+ else
+ return ThrowException(ErrnoException(errno, "getgrnam_r"));
}
gid = grpp->gr_gid;
if ((err = getpwnam_r(*pwnam, &pwd, getbuf, ARRAY_SIZE(getbuf), &pwdp)) ||
pwdp == NULL) {
- return ThrowException(ErrnoException(errno, "getpwnam_r"));
+ if (errno == 0)
+ return ThrowException(Exception::Error(
+ String::New("setuid user id does not exist")));
+ else
+ return ThrowException(ErrnoException(errno, "getpwnam_r"));
}
uid = pwdp->pw_uid;
}
}
+static Handle<Value> Uptime(const Arguments& args) {
+ HandleScope scope;
+ assert(args.Length() == 0);
+
+ double uptime = Platform::GetUptime(true);
+
+ if (uptime < 0) {
+ return Undefined();
+ }
+
+ return scope.Close(Number::New(uptime));
+}
v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
HandleScope scope;
}
-static void Load(int argc, char *argv[]) {
+Handle<Object> SetupProcessObject(int argc, char *argv[]) {
HandleScope scope;
int i, j;
+ // process.arch
+ process->Set(String::NewSymbol("arch"), String::New(ARCH));
+
// process.platform
process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
process->Set(String::NewSymbol("ENV"), ENV);
process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
+ process->Set(String::NewSymbol("cov"), cov ? True() : False());
// -e, --eval
if (eval_string) {
NODE_SET_METHOD(process, "_kill", Kill);
#endif // __POSIX__
+ NODE_SET_METHOD(process, "uptime", Uptime);
NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
NODE_SET_METHOD(process, "binding", Binding);
process->Set(String::NewSymbol("EventEmitter"),
EventEmitter::constructor_template->GetFunction());
+ return process;
+}
+
+
+static void AtExit() {
+ node::Stdio::Flush();
+ node::Stdio::DisableRawMode(STDIN_FILENO);
+}
+
+
+static void SignalExit(int signal) {
+ Stdio::DisableRawMode(STDIN_FILENO);
+ _exit(1);
+}
+
+
+void Load(Handle<Object> process) {
// Compile, execute the src/node.js file. (Which was included as static C
// string in node_natives.h. 'natve_node' is the string containing that
// source code.)
// The node.js file returns a function 'f'
+ atexit(AtExit);
+
TryCatch try_catch;
Local<Value> f_value = ExecuteString(MainSource(),
" --v8-options print v8 command line options\n"
" --vars print various compiled-in variables\n"
" --max-stack-size=val set max v8 stack size (bytes)\n"
+ " --cov code coverage; writes node-cov.json \n"
"\n"
"Enviromental variables:\n"
"NODE_PATH ':'-separated list of directories\n"
}
// Parse node command line arguments.
-static void ParseArgs(int *argc, char **argv) {
+static void ParseArgs(int argc, char **argv) {
int i;
// TODO use parse opts
- for (i = 1; i < *argc; i++) {
+ for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (strstr(arg, "--debug") == arg) {
ParseDebugOpt(arg);
argv[i] = const_cast<char*>("");
+ } else if (!strcmp(arg, "--cov")) {
+ cov = true;
+ argv[i] = const_cast<char*>("");
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
printf("%s\n", NODE_VERSION);
exit(0);
PrintHelp();
exit(0);
} else if (strcmp(arg, "--eval") == 0 || strcmp(arg, "-e") == 0) {
- if (*argc <= i + 1) {
+ if (argc <= i + 1) {
fprintf(stderr, "Error: --eval requires an argument\n");
exit(1);
}
}
-static void AtExit() {
- node::Stdio::Flush();
- node::Stdio::DisableRawMode(STDIN_FILENO);
-}
-
-
-static void SignalExit(int signal) {
- Stdio::DisableRawMode(STDIN_FILENO);
- _exit(1);
-}
-
-
static void EnableDebug(bool wait_connect) {
// Start the debug thread and it's associated TCP server on port 5858.
bool r = Debug::EnableAgent("node " NODE_VERSION, debug_port);
assert(r);
// Print out some information.
- fprintf(stderr, "debugger listening on port %d\r\n", debug_port);
+ fprintf(stderr, "debugger listening on port %d", debug_port);
}
#endif // __POSIX__
-int Start(int argc, char *argv[]) {
+char** Init(int argc, char *argv[]) {
// Hack aroung with the argv pointer. Used for process.title = "blah".
argv = node::Platform::SetupArgs(argc, argv);
// Parse a few arguments which are specific to Node.
- node::ParseArgs(&argc, argv);
+ node::ParseArgs(argc, argv);
// Parse the rest of the args (up to the 'option_end_index' (where '--' was
// in the command line))
int v8argc = node::option_end_index;
eio_set_max_poll_reqs(10);
}
- V8::Initialize();
- HandleScope handle_scope;
-
V8::SetFatalErrorHandler(node::OnFatalError);
#endif // __POSIX__
}
+ return argv;
+}
+
+
+void EmitExit(v8::Handle<v8::Object> process) {
+ // process.emit('exit')
+ Local<Value> emit_v = process->Get(String::New("emit"));
+ assert(emit_v->IsFunction());
+ Local<Function> emit = Local<Function>::Cast(emit_v);
+ Local<Value> args[] = { String::New("exit") };
+ TryCatch try_catch;
+ emit->Call(process, 1, args);
+ if (try_catch.HasCaught()) {
+ FatalException(try_catch);
+ }
+}
+
+
+int Start(int argc, char *argv[]) {
+ v8::V8::Initialize();
+ v8::HandleScope handle_scope;
+
+ argv = Init(argc, argv);
+
// Create the one and only Context.
Persistent<v8::Context> context = v8::Context::New();
v8::Context::Scope context_scope(context);
- atexit(node::AtExit);
+ Handle<Object> process = SetupProcessObject(argc, argv);
// Create all the objects, load modules, do everything.
// so your next reading stop should be node::Load()!
- node::Load(argc, argv);
+ Load(process);
// TODO Probably don't need to start this each time.
// Avoids failing on test/simple/test-eio-race3.js though
// watchers, it blocks.
ev_loop(EV_DEFAULT_UC_ 0);
-
- // process.emit('exit')
- Local<Value> emit_v = process->Get(String::New("emit"));
- assert(emit_v->IsFunction());
- Local<Function> emit = Local<Function>::Cast(emit_v);
- Local<Value> args[] = { String::New("exit") };
- TryCatch try_catch;
- emit->Call(process, 1, args);
- if (try_catch.HasCaught()) {
- FatalException(try_catch);
- }
-
+ EmitExit(process);
#ifndef NDEBUG
// Clean up.
namespace node {
-int Start (int argc, char *argv[]);
+int Start(int argc, char *argv[]);
+
+char** Init(int argc, char *argv[]);
+v8::Handle<v8::Object> SetupProcessObject(int argc, char *argv[]);
+void Load(v8::Handle<v8::Object> process);
+void EmitExit(v8::Handle<v8::Object> process);
#define NODE_PSYMBOL(s) Persistent<String>::New(String::NewSymbol(s))
/* Converts a unixtime to V8 Date */
#define NODE_UNIXTIME_V8(t) v8::Date::New(1000*static_cast<double>(t))
- #define NODE_V8_UNIXTIME(v) (static_cast<double>((v)->IntegerValue())/1000.0);
+ #define NODE_V8_UNIXTIME(v) (static_cast<double>((v)->NumberValue())/1000.0);
#define NODE_DEFINE_CONSTANT(target, constant) \
(target)->Set(v8::String::NewSymbol(#constant), \
__callback##_TEM); \
} while (0)
-enum encoding {ASCII, UTF8, BASE64, UCS2, BINARY};
+enum encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX};
enum encoding ParseEncoding(v8::Handle<v8::Value> encoding_v,
enum encoding _default = BINARY);
void FatalException(v8::TryCatch &try_catch);
#include <errno.h>
#include <inttypes.h>
#include <sys/types.h>
+ #include <sys/loadavg.h>
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
#define PROCFS_FILE_OFFSET_BITS_HACK 1
using namespace v8;
+double Platform::prog_start_time = Platform::GetUptime();
char** Platform::SetupArgs(int argc, char *argv[]) {
return argv;
return 0.0;
}
-double Platform::GetUptime() {
+double Platform::GetUptimeImpl() {
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *knp;
}
int Platform::GetLoadAvg(Local<Array> *loads) {
+ HandleScope scope;
+ double loadavg[3];
+
+ (void) getloadavg(loadavg, 3);
+ (*loads)->Set(0, Number::New(loadavg[LOADAVG_1MIN]));
+ (*loads)->Set(1, Number::New(loadavg[LOADAVG_5MIN]));
+ (*loads)->Set(2, Number::New(loadavg[LOADAVG_15MIN]));
+
return 0;
}
+Handle<Value> Platform::GetInterfaceAddresses() {
+ HandleScope scope;
+ return scope.Close(Object::New());
+}
+
+
} // namespace node
--- /dev/null
-node.js:134
+ before
+
++node.js:*
+ throw e; // process.nextTick error, or 'error' event on first tick
+ ^
+ RangeError: Maximum call stack size exceeded
--- /dev/null
-node.js:134
+ before
+
++node.js:*
+ throw e; // process.nextTick error, or 'error' event on first tick
+ ^
+ MyCustomError: This is a custom message
--- /dev/null
-node.js:134
+ before
+
++node.js:*
+ throw e; // process.nextTick error, or 'error' event on first tick
+ ^
+ [object Object]
// slice(0,0).length === 0
assert.equal(0, Buffer('hello').slice(0, 0).length);
+// test hex toString
+console.log('Create hex string from buffer');
+var hexb = new Buffer(256);
+for (var i = 0; i < 256; i ++) {
+ hexb[i] = i;
+}
+var hexStr = hexb.toString('hex');
+assert.equal(hexStr,
+ '000102030405060708090a0b0c0d0e0f'+
+ '101112131415161718191a1b1c1d1e1f'+
+ '202122232425262728292a2b2c2d2e2f'+
+ '303132333435363738393a3b3c3d3e3f'+
+ '404142434445464748494a4b4c4d4e4f'+
+ '505152535455565758595a5b5c5d5e5f'+
+ '606162636465666768696a6b6c6d6e6f'+
+ '707172737475767778797a7b7c7d7e7f'+
+ '808182838485868788898a8b8c8d8e8f'+
+ '909192939495969798999a9b9c9d9e9f'+
+ 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf'+
+ 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf'+
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf'+
+ 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'+
+ 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef'+
+ 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
+
+console.log('Create buffer from hex string');
+var hexb2 = new Buffer(hexStr, 'hex');
+for (var i = 0; i < 256; i ++) {
+ assert.equal(hexb2[i], hexb[i]);
+}
+
+// test an invalid slice end.
+console.log('Try to slice off the end of the buffer');
+var b = new Buffer([1,2,3,4,5]);
+var b2 = b.toString('hex', 1, 10000);
+var b3 = b.toString('hex', 1, 5);
+var b4 = b.toString('hex', 1);
+assert.equal(b2, b3);
+assert.equal(b2, b4);
+
// Test slice on SlowBuffer GH-843
var SlowBuffer = process.binding('buffer').SlowBuffer;
assert.equal(2, z.length);
assert.equal(0x66, z[0]);
assert.equal(0x6f, z[1]);
+
+assert.equal(0, Buffer('hello').slice(0, 0).length)
+
+b = new Buffer(50);
+b.fill("h");
+for (var i = 0; i < b.length; i++) {
+ assert.equal("h".charCodeAt(0), b[i]);
+}
+
+b.fill(0);
+for (var i = 0; i < b.length; i++) {
+ assert.equal(0, b[i]);
+}
+
+b.fill(1, 16, 32);
+for (var i = 0; i < 16; i++) assert.equal(0, b[i]);
+for (; i < 32; i++) assert.equal(1, b[i]);
+for (; i < b.length; i++) assert.equal(0, b[i]);
+
+ var b = new SlowBuffer(10);
+ b.write('あいうえお', 'ucs2');
+ assert.equal(b.toString('ucs2'), 'あいうえお');
, dest='openssl_libpath'
)
- opt.add_option( '--oprofile'
- , action='store_true'
- , default=False
- , help="add oprofile support"
- , dest='use_oprofile'
- )
-
opt.add_option( '--gdb'
, action='store_true'
, default=False
conf.env["USE_SHARED_CARES"] = o.shared_cares or o.shared_cares_includes or o.shared_cares_libpath
conf.env["USE_SHARED_LIBEV"] = o.shared_libev or o.shared_libev_includes or o.shared_libev_libpath
- conf.env["USE_OPROFILE"] = o.use_oprofile
conf.env["USE_GDBJIT"] = o.use_gdbjit
- if o.use_oprofile:
- conf.check(lib=['bfd', 'opagent'], uselib_store="OPROFILE")
-
conf.check(lib='dl', uselib_store='DL')
if not sys.platform.startswith("sunos") and not sys.platform.startswith("cygwin") and not sys.platform.startswith("win32"):
conf.env.append_value("CCFLAGS", "-rdynamic")
elif 'DEST_CPU' in conf.env and conf.env['DEST_CPU']:
conf.env['DEST_CPU'] = canonical_cpu_type(conf.env['DEST_CPU'])
- conf.check(lib='rt', uselib_store='RT')
+ have_librt = conf.check(lib='rt', uselib_store='RT')
+
+ have_monotonic = False
+ if have_librt:
+ code = """
+ #include <time.h>
+ int main(void) {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return 0;
+ }
+ """
+ have_monotonic = conf.check_cc(lib="rt", msg="Checking for CLOCK_MONOTONIC", fragment=code)
+
+ if have_monotonic:
+ conf.env.append_value('CPPFLAGS', '-DHAVE_MONOTONIC_CLOCK=1')
+ else:
+ conf.env.append_value('CPPFLAGS', '-DHAVE_MONOTONIC_CLOCK=0')
if sys.platform.startswith("sunos"):
if not conf.check(lib='socket', uselib_store="SOCKET"):
else:
conf.env.append_value('CPPFLAGS', '-DHAVE_FDATASYNC=0')
+ # arch
+ conf.env.append_value('CPPFLAGS', '-DARCH="' + conf.env['DEST_CPU'] + '"')
+
# platform
conf.env.append_value('CPPFLAGS', '-DPLATFORM="' + conf.env['DEST_OS'] + '"')
# Configure default variant
conf.setenv('default')
- conf.env.append_value('CPPFLAGS', '-DNDEBUG')
default_compile_flags = ['-g', '-O3']
conf.env.append_value('CCFLAGS', default_compile_flags)
conf.env.append_value('CXXFLAGS', default_compile_flags)
else:
snapshot = ""
- if bld.env["USE_OPROFILE"]:
- profile = "prof=oprofile"
- else:
- profile = ""
-
- cmd_R = sys.executable + ' "%s" -j %d -C "%s" -Y "%s" visibility=default mode=%s %s toolchain=%s library=static %s %s'
+ cmd_R = sys.executable + ' "%s" -j %d -C "%s" -Y "%s" visibility=default mode=%s %s toolchain=%s library=static %s'
cmd = cmd_R % ( scons
, Options.options.jobs
, arch
, toolchain
, snapshot
- , profile
)
if bld.env["USE_GDBJIT"]:
native_cc_debug = native_cc.clone("debug")
native_cc_debug.rule = javascript_in_c_debug
- native_cc.rule = javascript_in_c
-
+ native_cc.rule = javascript_in_c_debug
+
if bld.env["USE_DTRACE"]:
dtrace = bld.new_task_gen(
name = "dtrace",
, 'CPPFLAGS' : " ".join(program.env["CPPFLAGS"]).replace('"', '\\"')
, 'LIBFLAGS' : " ".join(program.env["LIBFLAGS"]).replace('"', '\\"')
, 'PREFIX' : safe_path(program.env["PREFIX"])
- , 'VERSION' : '0.4.6' # FIXME should not be hard-coded, see NODE_VERSION_STRING in src/node_version.
+ , 'VERSION' : '0.4.7' # FIXME should not be hard-coded, see NODE_VERSION_STRING in src/node_version.
}
return x