Browse Source

Merge branch 'master' into net2

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
49451c1dab
  1. 2
      ChangeLog
  2. 223
      doc/api.txt
  3. 1
      lib/assert.js
  4. 39
      lib/dns.js
  5. 9
      lib/http.js
  6. 8
      lib/url.js
  7. 12
      src/node.js
  8. 183
      src/node_dns.cc
  9. 29
      test/mjsunit/disabled/test-dns.js
  10. 119
      test/mjsunit/test-dns.js
  11. 42
      test/mjsunit/test-http-client-reconnect-bug.js
  12. 4
      test/mjsunit/test-module-loading.js
  13. 6
      test/mjsunit/test-promise.js
  14. 23
      tools/osx-dist.sh
  15. 65
      tools/osx-pkg-dmg-create.sh

2
ChangeLog

@ -18,7 +18,7 @@
* Upgrade V8 to 2.0.6.1
* Solaris port
* Solaris port (Erich Ocean)
2010.01.09, Version 0.1.25, 39ca93549af91575ca9d4cbafd1e170fbcef3dfa

223
doc/api.txt

@ -6,7 +6,7 @@ Version, 0.1.26, 2010.01.20
== NAME
node - evented I/O for V8 javascript
node - evented I/O for V8 JavaScript
@ -39,7 +39,7 @@ Server running at http://127.0.0.1:8000/
Node supports 3 string encodings. UTF-8 (+"utf8"+), ASCII (+"ascii"+), and
Binary (+"binary"+). +"ascii"+ and +"binary"+ only look at the first 8 bits
of the 16bit javascript string characters. Both are relatively fast--use
of the 16bit JavaScript string characters. Both are relatively fast--use
them if you can. +"utf8"+ is slower and should be avoided when possible.
Unless otherwise noted, functions are all asynchronous and do not block
@ -64,6 +64,9 @@ The search path for absolute path arguments to +require()+.
+__filename+ ::
The filename of the script being executed.
+__dirname+ ::
The dirname of the script being executed.
+module+ ::
A reference to the current module (of type +process.Module+). In particular
+module.exports+ is the same as the +exports+ object. See +src/process.js+ for
@ -79,7 +82,7 @@ more information.
| +"exit"+ | +code+ | Made when the process exits.
A listener on this event should not try to perform
I/O since the process will forcibly exit in less
than microsecond. However, it is a good hook to
than a microsecond. However, it is a good hook to
perform constant time checks of the module's
state (like for unit tests).
+
@ -212,7 +215,7 @@ in a promise callback.
----------------------------------------
var sys = require("sys");
sys.exec("ls /").addCallback(function (stdout, stderr) {
puts(stdout);
sys.puts(stdout);
});
----------------------------------------
+
@ -239,7 +242,7 @@ complete.
==== +events.EventEmitter+
+require('events')+ to access the events module.
+require("events")+ to access the events module.
All EventEmitters emit the event +"newListener"+ when new listeners are
added.
@ -258,7 +261,7 @@ Adds a listener to the end of the listeners array for the specified event.
+
----------------------------------------
server.addListener("connection", function (socket) {
puts("someone connected!");
sys.puts("someone connected!");
});
----------------------------------------
@ -275,9 +278,9 @@ Execute each of the listeners in order with the supplied arguments.
==== +events.Promise+
+require('events')+ to access the events module.
+require("events")+ to access the events module.
+events.Promise+ inherits from +process.eventEmitter+. A promise emits one of two
+events.Promise+ inherits from +process.EventEmitter+. A promise emits one of two
events: +"success"+ or +"error"+. After emitting its event, it will not
emit anymore events.
@ -304,7 +307,7 @@ If you created the promise (by doing +new events.Promise()+) then call
the moment due to a bug; use +emitSuccess+ instead.)
+promise.emitError(arg1, arg2, ...)+ ::
Emits the +"error"+ event. If a no error handler is attached to the promise
Emits the +"error"+ event. If no error handler is attached to the promise
between +promise.emitError()+ and +process.nextTick()+, an exception is
thrown.
+
@ -348,10 +351,10 @@ setTimeout(function() {
+promise.timeout(timeout = undefined)+ ::
If the +timeout+ parameter is provided, the promise will emit an +"error"+
event after the given amount of millseconds. The timeout is canceled by any
+"success"+ or +"error"+ event being emitted by the Promise.
event after the given amount of milliseconds. The timeout is canceled by any
+"success"+ or +"error"+ event being emitted by the promise.
+
To tell apart a timeout from a regular "error" event, use the following test:
To tell a timeout apart from a regular "error" event, use the following test:
+
----------------------------------------
promise.addErrback(function(e) {
@ -422,7 +425,7 @@ Close stdin.
=== Modules
Node uses the CommonJS module system
Node uses the CommonJS module system.
Node has a simple module loading system. In Node, files and modules are in
one-to-one correspondence. As an example, +foo.js+ loads the module
@ -495,14 +498,14 @@ Modules; see the section below about addons. +"index.js"+ allows one to
package a module as a directory.
+require.paths+ can be modified at runtime by simply unshifting new
paths on to it and at startup with the +NODE_PATH+ environmental
paths onto it, or at startup with the +NODE_PATH+ environmental
variable (which should be a list of paths, colon separated).
Use +process.mixin()+ to include modules into the global namespace.
----------------------------------------
process.mixin(GLOBAL, require("./circle"), require("sys"));
puts("The area of a cirlce of radius 4 is " + area(4));
puts("The area of a circle of radius 4 is " + area(4));
----------------------------------------
@ -511,8 +514,8 @@ puts("The area of a cirlce of radius 4 is " + area(4));
=== Timers
+setTimeout(callback, delay)+::
To schedule execution of callback after delay milliseconds. Returns a
+setTimeout(callback, delay, [arg, ...])+::
To schedule execution of +callback+ after +delay+ milliseconds. Returns a
+timeoutId+ for possible use with +clearTimeout()+.
Optionally, you can also pass arguments to the callback.
@ -522,8 +525,8 @@ Optionally, you can also pass arguments to the callback.
Prevents said timeout from triggering.
+setInterval(callback, delay)+::
To schedule the repeated execution of callback every +delay+ milliseconds. Returns
+setInterval(callback, delay, [arg, ...])+::
To schedule the repeated execution of +callback+ every +delay+ milliseconds. Returns
a +intervalId+ for possible use with +clearInterval()+.
Optionally, you can also pass arguments to the callback.
@ -547,7 +550,7 @@ Node provides a tridirectional +popen(3)+ facility through the class
| +"output"+ | +data+ | Each time the child process
sends data to its +stdout+, this event is
emitted. +data+ is a string. + If the child
emitted. +data+ is a string. If the child
process closes its +stdout+ stream (a common
thing to do on exit), this event will be emitted
with +data === null+.
@ -569,7 +572,7 @@ environmental variables. For example:
----------------------------------------
var ls = process.createChildProcess("ls", ["-lh", "/usr"]);
ls.addListener("output", function (data) {
puts(data);
sys.puts(data);
});
----------------------------------------
+
@ -651,16 +654,21 @@ sys.puts("stats: " + JSON.stringify(stats));
- on error: no parameters.
+posix.stat(path)+ ::
See stat(2).
- on success: Returns +posix.Stats+ object. It looks like this:
+{ dev: 2049, ino: 305352, mode: 16877, nlink: 12, uid: 1000, gid: 1000,
rdev: 0, size: 4096, blksize: 4096, blocks: 8, atime:
"2009-06-29T11:11:55Z", mtime: "2009-06-29T11:11:40Z", ctime:
"2009-06-29T11:11:40Z" }+
See the +posix.Stats+ section below for more information.
- on error: no parameters.
See stat(2).
- on success: Returns +posix.Stats+ object. It looks like this:
+
------------------------------------------------------------------------------
{ dev: 2049, ino: 305352, mode: 16877, nlink: 12, uid: 1000, gid: 1000,
rdev: 0, size: 4096, blksize: 4096, blocks: 8, atime:
"2009-06-29T11:11:55Z", mtime: "2009-06-29T11:11:40Z", ctime:
"2009-06-29T11:11:40Z" }+
------------------------------------------------------------------------------
+
See the +posix.Stats+ section below for more information.
- on error: no parameters.
+posix.unlink(path)+ ::
See unlink(2)
@ -673,11 +681,13 @@ sys.puts("stats: " + JSON.stringify(stats));
- on success: no parameters.
- on error: no parameters.
+posix.mkdir(path, mode)+ ::
See mkdir(2)
- on success: no parameters.
- on error: no parameters.
+posix.readdir(path)+ ::
Reads the contents of a directory.
- on success: One argument, an array containing the names (strings) of the
@ -706,25 +716,23 @@ sys.puts("stats: " + JSON.stringify(stats));
- on error: no parameters.
+posix.read(fd, length, position, encoding)+::
Read data from the file specified by +fd+.
+
+length+ is an integer specifying the number of
bytes to read.
+
+position+ is an integer specifying where to begin
reading from in the file.
+
- on success: returns +data, bytes_read+, what was read from the file.
- on error: no parameters.
Read data from the file specified by +fd+.
+
+length+ is an integer specifying the number of
bytes to read.
+
+position+ is an integer specifying where to begin
reading from in the file.
+
- on success: returns +data, bytes_read+, what was read from the file.
- on error: no parameters.
+posix.cat(filename, encoding="utf8")+::
Outputs the entire contents of a file. Example:
+
--------------------------------
posix.cat("/etc/passwd").addCallback(function (content) {
puts(content);
sys.puts(content);
});
--------------------------------
+
@ -759,20 +767,22 @@ In particular, large, possibly chunk-encoded, messages. The interface is
careful to never buffer entire requests or responses--the
user is able to stream data.
HTTP message headers are represented by an object like this
HTTP message headers are represented by an object like this:
----------------------------------------
{ "Content-Length": "123"
, "Content-Type": "text/plain"
, "Connection": "keep-alive"
, "Accept": "*/*"
{ "content-length": "123"
, "content-type": "text/plain"
, "connection": "keep-alive"
, "accept": "*/*"
}
----------------------------------------
In order to support the full spectrum of possible HTTP applications, Node"s
Keys are lowercased. Values are not modified.
In order to support the full spectrum of possible HTTP applications, Node's
HTTP API is very low-level. It deals with connection handling and message
parsing only. It parses a message into headers and body but it does not
parse the actual headers or the body.
parse the actual headers or the body.
==== +http.Server+
@ -799,12 +809,12 @@ parse the actual headers or the body.
|=========================================================
+http.createServer(request_listener, options);+ ::
+http.createServer(request_listener, [options]);+ ::
Returns a new web server object.
+
The +options+ argument is optional. The
+options+ argument accepts the same values as the
options argument for +tcp.Server+ does.
options argument for +tcp.Server+.
+
The +request_listener+ is a function which is automatically
added to the +"request"+ event.
@ -812,12 +822,12 @@ added to the +"request"+ event.
+server.setSecure(format_type, ca_certs, crl_list, private_key, certificate)+ ::
Enable TLS for all incoming connections, with the specified credentials.
+
format_type currently has to be "X509_PEM", and each of the ca, crl, key and
+format_type+ currently has to be "X509_PEM", and each of the ca, crl, key and
cert parameters are in the format of PEM strings.
+
The ca_certs is a string that holds a number of CA certificates for use in accepting
+ca_certs+ is a string that holds a number of CA certificates for use in accepting
client connections that authenticate themselves with a client certificate.
The private_key is a PEM string of the unencrypted key for the server.
+private_key+ is a PEM string of the unencrypted key for the server.
+server.listen(port, hostname)+ ::
Begin accepting connections on the specified port and hostname.
@ -842,7 +852,7 @@ the user--and passed as the first argument to a +"request"+ listener.
message body is received. Example: A chunk
of the body is given as the single
argument. The transfer-encoding has been
decoded. The body chunk is a String. The
decoded. The body chunk is a string. The
body encoding is set with
+request.setBodyEncoding()+.
@ -858,7 +868,7 @@ The request method as a string. Read only. Example:
+request.url+ ::
Request URL string. This contains only the URL that is
present in the actual HTTP request. If the request is
present in the actual HTTP request. If the request is:
+
----------------------------------------
GET /status?name=ryan HTTP/1.1\r\n
@ -866,7 +876,7 @@ Accept: text/plain\r\n
\r\n
----------------------------------------
+
Then +request.url+ will be
Then +request.url+ will be:
+
----------------------------------------
"/status?name=ryan"
@ -912,7 +922,7 @@ The HTTP protocol version as a string. Read only. Examples:
+"1.1"+, +"1.0"+
+request.setBodyEncoding(encoding)+ ::
+request.setBodyEncoding(encoding="binary")+ ::
Set the encoding for the request body. Either +"utf8"+ or +"binary"+. Defaults
to +"binary"+.
@ -937,7 +947,7 @@ passed as the second parameter to the +"request"+ event.
+response.sendHeader(statusCode, headers)+ ::
Sends a response header to the request. The status code is a 3-digit HTTP
status code, like +404+. The second argument, +headers+ are the response headers.
status code, like +404+. The second argument, +headers+, are the response headers.
+
Example:
+
@ -1036,11 +1046,11 @@ for the user to stream a body to the server with
+client.setSecure(format_type, ca_certs, crl_list, private_key, certificate)+ ::
Enable TLS for the client connection, with the specified credentials.
+
format_type currently has to be "X509_PEM", and each of the ca, crl, key and
+format_type+ currently has to be "X509_PEM", and each of the ca, crl, key and
cert parameters are in the format of PEM strings, and optional.
+
The ca_certs is a string that holds a number of CA certificates for use in deciding the
authenticity of the remote server. The private_key is a PEM string of the unencrypted
+ca_certs+ is a string that holds a number of CA certificates for use in deciding the
authenticity of the remote server. +private_key+ is a PEM string of the unencrypted
key for the client, which together with the certificate allows the client to authenticate
itself to the server.
@ -1095,7 +1105,7 @@ argument which is an instance of +http.ClientResponse+.
+
In the +responseListener+ callback, one can add more listeners to the
response, in particular listening for the +"body"+ event. Note that
the +responseListener+ is called before any part of the body is receieved,
the +responseListener+ is called before any part of the body is received,
so there is no need to worry about racing to catch the first part of the
body. As long as a listener for +"body"+ is added during the
+responseListener+ callback, the entire body will be caught.
@ -1104,7 +1114,7 @@ body. As long as a listener for +"body"+ is added during the
// Good
request.finish(function (response) {
response.addListener("body", function (chunk) {
puts("BODY: " + chunk);
sys.puts("BODY: " + chunk);
});
});
@ -1112,7 +1122,7 @@ request.finish(function (response) {
request.finish(function (response) {
setTimeout(function () {
response.addListener("body", function (chunk) {
puts("BODY: " + chunk);
sys.puts("BODY: " + chunk);
});
}, 10);
});
@ -1241,7 +1251,7 @@ To use the TCP server and client one must +require("tcp")+.
==== +tcp.Server+
Here is an example of a echo server which listens for connections
on port 7000
on port 7000:
----------------------------------------
var tcp = require("tcp");
@ -1282,12 +1292,12 @@ the +"connection"+ event.
+server.setSecure(format_type, ca_certs, crl_list, private_key, certificate)+ ::
Enable TLS for all incoming connections, with the specified credentials.
+
format_type currently has to be "X509_PEM", and each of the ca, crl, key and
+format_type+ currently has to be "X509_PEM", and each of the ca, crl, key and
cert parameters are in the format of PEM strings.
+
The ca_certs is a string that holds a number of CA certificates for use in accepting
+ca_certs+ is a string that holds a number of CA certificates for use in accepting
client connections that authenticate themselves with a client certificate.
The private_key is a PEM string of the unencrypted key for the server.
+private_key+ is a PEM string of the unencrypted key for the server.
+server.listen(port, host=null, backlog=128)+ ::
Tells the server to listen for TCP connections to +port+ and +host+.
@ -1427,54 +1437,83 @@ in RFC2253. This function is synchronous.
=== DNS module
Use +require("dns")+ to access this module
Use +require("dns")+ to access this module.
Here is an example of which resolves +"www.google.com"+ then reverse
Here is an example which resolves +"www.google.com"+ then reverse
resolves the IP addresses which are returned.
-------------------------------------------------------------------------
var dns = require("dns");
var dns = require("dns"),
sys = require("sys");
var resolution = dns.resolve4("www.google.com");
resolution.addCallback(function (addresses, ttl, cname) {
puts("addresses: " + JSON.stringify(addresses));
puts("ttl: " + JSON.stringify(ttl));
puts("cname: " + JSON.stringify(cname));
sys.puts("addresses: " + JSON.stringify(addresses));
sys.puts("ttl: " + JSON.stringify(ttl));
sys.puts("cname: " + JSON.stringify(cname));
for (var i = 0; i < addresses.length; i++) {
var a = addresses[i];
var reversing = dns.reverse(a);
reversing.addCallback( function (domains, ttl, cname) {
puts("reverse for " + a + ": " + JSON.stringify(domains));
sys.puts("reverse for " + a + ": " + JSON.stringify(domains));
});
reversing.addErrback( function (code, msg) {
puts("reverse for " + a + " failed: " + msg);
sys.puts("reverse for " + a + " failed: " + msg);
});
}
});
resolution.addErrback(function (code, msg) {
puts("error: " + msg);
sys.puts("error: " + msg);
});
-------------------------------------------------------------------------
+dns.resolve(domain, rrtype = 'A')+::
+dns.resolve4(domain)+::
Resolves a domain (e.g. +"google.com"+) into an array of IPv4 addresses (e.g.
+["74.125.79.104", "74.125.79.105", "74.125.79.106"]+).
Resolves a domain (e.g. +"google.com"+) into an array of the record types
specified by rrtype. Valid rrtypes are +A+ (IPV4 addresses), +AAAA+ (IPV6
addresses), +MX+ (mail exchange records), +TXT+ (text records), +SRV+
(SRV records), and +PTR+ (used for reverse IP lookups).
This function returns a promise.
- on success: returns +addresses, ttl, cname+. +ttl+ (time-to-live) is an integer
specifying the number of seconds this result is valid for. +cname+ is the
canonical name for the query.
The type of each item in +addresses+ is determined by the record type, and
described in the documentation for the corresponding lookup methods below.
- on error: returns +code, msg+. +code+ is one of the error codes listed
below and +msg+ is a string describing the error in English.
+dns.resolve4(domain)+::
The same as +dns.resolve()+, but only for IPv4 queries (+A+ records).
+addresses+ is an array of IPv4 addresses (e.g. +["74.125.79.104",
"74.125.79.105", "74.125.79.106"]+).
+dns.resolve6(domain)+::
The same as +dns.resolve4()+ except for IPv6 queries (an +AAAA+ query).
+dns.resolveMx(domain)+::
The same as +dns.resolve()+, but only for mail exchange queries (+MX+ records).
+addresses+ is an array of MX records, each with a priority and an exchange
attribute (e.g. +[{"priority": 10, "exchange": "mx.example.com"},...]+).
+dns.resolveTxt(domain)+::
The same as +dns.resolve()+, but only for text queries (+TXT+ records).
+addresses+ is an array of the text records available for +domain+ (e.g.,
+["v=spf1 ip4:0.0.0.0 ~all"]+).
+dns.resolveSrv(domain)+::
The same as +dns.resolve()+, but only for service records (+SRV+ records).
+addresses+ is an array of the SRV records available for +domain+. Properties
of SRV records are priority, weight, port, and name (e.g., +[{"priority": 10,
{"weight": 5, "port": 21223, "name": "service.example.com"}, ...]+).
+dns.reverse(ip)+::
Reverse resolves an ip address to an array of domain names.
@ -1518,10 +1557,10 @@ Tests for deep equality.
Tests for any deep inequality.
+assert.strictEqual(actual, expected, message)+::
Tests strict equality, as determined by bitwise equality operator ( +===+ )
Tests strict equality, as determined by the strict equality operator ( +===+ )
+assert.notStrictEqual(actual, expected, message)+::
Tests strict non-equality, as determined by bitwise not equal operator ( +!==+ )
Tests strict non-equality, as determined by the strict not equal operator ( +!==+ )
+assert.throws(block, error, message)+::
Expects +block+ to throw an error.
@ -1533,7 +1572,7 @@ Expects +block+ not to throw an error.
=== Path Module
This module contains utilities for dealing with file paths. Use
+require('path')+ to use it. It provides the following methods:
+require("path")+ to use it. It provides the following methods:
+path.join(/* path1, path2, ... */)+::
Join all arguments together and resolve the resulting path. Example:
@ -1581,9 +1620,9 @@ node> require("path").dirname("/foo/bar/baz/asdf/quux")
Return the last portion of a path. Similar to the Unix +basename+ command. Example:
+
------------------------------------
node> require("path").filename("/foo/bar/baz/asdf/quux.html")
node> require("path").basename("/foo/bar/baz/asdf/quux.html")
"quux.html"
node> require("path").filename("/foo/bar/baz/asdf/quux.html", ".html")
node> require("path").basename("/foo/bar/baz/asdf/quux.html", ".html")
"quux"
------------------------------------
+
@ -1650,7 +1689,7 @@ Either the "params" portion of the query string, or a querystring-parsed object.
+"query=string"+ or +{"query":"string"}+
+hash+::
The portion of the URL after the pound-sign. Example: +"#hash"+
The "fragment" portion of the URL including the pound-sign. Example: +"#hash"+
The following methods are provided by the URL module:
@ -1697,10 +1736,10 @@ node> require("querystring").parse("foo=bar&baz%5Bquux%5D=asdf&baz%5Boof%5D=rab&
------------------------------------
+
+querystring.escape+
+querystring.escape+::
The escape function used by +querystring.stringify+, provided so that it could be overridden if necessary.
+querystring.unescape+
+querystring.unescape+::
The unescape function used by +querystring.parse+, provided so that it could be overridden if necessary.
== REPL
@ -1746,7 +1785,7 @@ Addons are dynamically linked shared objects. They can provide glue to C and
C++ libraries. The API (at the moment) is rather complex, involving
knowledge of several libraries:
- V8 Javascript, a C++ library. Used for interfacing with Javascript:
- V8 JavaScript, a C++ library. Used for interfacing with JavaScript:
creating objects, calling functions, etc. Documented mostly in the
+v8.h+ header file (+deps/v8/include/v8.h+ in the Node source tree).

1
lib/assert.js

@ -47,6 +47,7 @@ assert.AssertionError = function AssertionError (options) {
Error.captureStackTrace(this, stackStartFunction);
}
};
process.inherits(assert.AssertionError, Error);
assert.AssertionError.prototype.toString = function() {
if (this.message) {

39
lib/dns.js

@ -10,6 +10,18 @@ function callback (promise) {
}
}
exports.resolve = function (domain, type) {
type = (type || 'a').toUpperCase();
var resolveFunc = resolveMap[type];
if (typeof(resolveFunc) == 'function') {
return resolveFunc(domain);
} else {
return undefined;
}
}
exports.resolve4 = function (domain) {
var promise = new events.Promise();
process.dns.resolve4(domain, callback(promise));
@ -22,6 +34,24 @@ exports.resolve6 = function (domain) {
return promise;
};
exports.resolveMx = function (domain) {
var promise = new process.Promise();
process.dns.resolveMx(domain, callback(promise));
return promise;
};
exports.resolveTxt = function (domain) {
var promise = new process.Promise();
process.dns.resolveTxt(domain, callback(promise));
return promise;
};
exports.resolveSrv = function (domain) {
var promise = new process.Promise();
process.dns.resolveSrv(domain, callback(promise));
return promise;
}
exports.reverse = function (ip) {
var promise = new events.Promise();
process.dns.reverse(ip, callback(promise));
@ -47,3 +77,12 @@ exports.NOMEM = process.dns.NOMEM;
// the query is malformed.
exports.BADQUERY = process.dns.BADQUERY;
resolveMap = {
'A': exports.resolve4,
'AAAA': exports.resolve6,
'MX': exports.resolveMx,
'TXT': exports.resolveTxt,
'SRV': exports.resolveSrv,
'PTR': exports.reverse,
};

9
lib/http.js

@ -418,6 +418,7 @@ exports.createClient = function (port, host) {
var secure_credentials={ secure : false };
var requests = [];
var currentRequest;
client._pushRequest = function (req) {
req.addListener("flush", function () {
@ -434,7 +435,7 @@ exports.createClient = function (port, host) {
return;
}
//sys.debug("client flush readyState = " + client.readyState);
if (req == requests[0]) flushMessageQueue(client, [req]);
if (req == currentRequest) flushMessageQueue(client, [req]);
});
requests.push(req);
};
@ -451,7 +452,8 @@ exports.createClient = function (port, host) {
client.addListener("connect", function () {
client.resetParser();
requests[0].flush();
currentRequest = requests.shift();
currentRequest.flush();
});
client.addListener("eof", function () {
@ -489,8 +491,7 @@ exports.createClient = function (port, host) {
client.close();
});
var req = requests.shift();
req.emit("response", res);
currentRequest.emit("response", res);
});
return client;

8
lib/url.js

@ -1,4 +1,3 @@
exports.parse = url_parse;
exports.resolve = url_resolve;
exports.resolveObject = url_resolveObject;
@ -17,7 +16,7 @@ var protocolPattern = /^([a-z0-9]+:)/,
"http:":true, "https:":true, "ftp:":true, "gopher:":true, "file:":true
},
path = require("path"), // internal module, guaranteed to be loaded already.
querystring; // don't load unless necessary.
querystring = require('querystring');
function url_parse (url, parseQueryString) {
if (url && typeof(url) === "object" && url.href) return url;
@ -75,9 +74,6 @@ function url_parse (url, parseQueryString) {
out.search = rest.substr(qm);
out.query = rest.substr(qm+1);
if (parseQueryString) {
if (!querystring) {
querystring = require("querystring");
}
out.query = querystring.parse(out.query);
}
rest = rest.slice(0, qm);
@ -105,7 +101,7 @@ function url_format (obj) {
search = obj.search || (
obj.query && ( "?" + (
typeof(obj.query) === "object"
? require("querystring").stringify(obj.query)
? querystring.stringify(obj.query)
: String(obj.query)
))
) || "",

12
src/node.js

@ -233,7 +233,7 @@ var eventsModule = createInternalModule('events', function (exports) {
exports.Promise.prototype.emitSuccess = function() {
if (this.hasFired) return;
this.hasFired = true;
this.hasFired = 'success';
this._clearTimeout();
this._values = Array.prototype.slice.call(arguments);
@ -242,7 +242,7 @@ var eventsModule = createInternalModule('events', function (exports) {
exports.Promise.prototype.emitError = function() {
if (this.hasFired) return;
this.hasFired = true;
this.hasFired = 'error';
this._clearTimeout();
this._values = Array.prototype.slice.call(arguments);
@ -261,7 +261,7 @@ var eventsModule = createInternalModule('events', function (exports) {
};
exports.Promise.prototype.addCallback = function (listener) {
if (this.hasFired) {
if (this.hasFired === 'success') {
return listener.apply(this, this._values);
}
@ -269,7 +269,7 @@ var eventsModule = createInternalModule('events', function (exports) {
};
exports.Promise.prototype.addErrback = function (listener) {
if (this.hasFired) {
if (this.hasFired === 'error') {
listener.apply(this, this._values);
}
@ -919,13 +919,13 @@ Module.prototype.loadScript = function (filename, loadPromise) {
require.async = requireAsync;
require.main = process.mainModule;
// create wrapper function
var wrapper = "var __wrap__ = function (exports, require, module, __filename) { "
var wrapper = "var __wrap__ = function (exports, require, module, __filename, __dirname) { "
+ content
+ "\n}; __wrap__;";
try {
var compiledWrapper = process.compile(wrapper, filename);
compiledWrapper.apply(self.exports, [self.exports, require, self, filename]);
compiledWrapper.apply(self.exports, [self.exports, require, self, filename, path.dirname(filename)]);
} catch (e) {
loadPromise.emitError(e);
return;

183
src/node_dns.cc

@ -21,6 +21,11 @@ static ev_io io_watcher;
static ev_timer timer_watcher;
static Persistent<String> errno_symbol;
static Persistent<String> exchange_symbol;
static Persistent<String> priority_symbol;
static Persistent<String> weight_symbol;
static Persistent<String> port_symbol;
static Persistent<String> name_symbol;
static inline void set_timeout() {
int maxwait = 20;
@ -157,6 +162,145 @@ static void AfterResolveA6(struct dns_ctx *ctx,
cb_destroy(cb);
}
static void AfterResolveMX(struct dns_ctx *ctx,
struct dns_rr_mx *result,
void *data) {
assert(ctx == &dns_defctx);
HandleScope scope;
Persistent<Function> *cb = cb_unwrap(data);
if (result == NULL) {
ResolveError(cb);
cb_destroy(cb);
return;
}
/* canonical name */
Local<String> cname = String::New(result->dnsmx_cname);
/* Time-To-Live (TTL) value */
Local<Integer> ttl = Integer::New(result->dnsmx_ttl);
Local<Array> exchanges = Array::New(result->dnsmx_nrr);
for (int i = 0; i < result->dnsmx_nrr; i++) {
HandleScope loop_scope;
Local<Object> exchange = Object::New();
struct dns_mx *mx = &(result->dnsmx_mx[i]);
exchange->Set(exchange_symbol, String::New(mx->name));
exchange->Set(priority_symbol, Integer::New(mx->priority));
exchanges->Set(Integer::New(i), exchange);
}
Local<Value> argv[3] = { exchanges, ttl, cname };
TryCatch try_catch;
(*cb)->Call(Context::GetCurrent()->Global(), 3, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
cb_destroy(cb);
}
static void AfterResolveTXT(struct dns_ctx *ctx,
struct dns_rr_txt *result,
void *data) {
assert(ctx == &dns_defctx);
HandleScope scope;
Persistent<Function> *cb = cb_unwrap(data);
if (result == NULL) {
ResolveError(cb);
cb_destroy(cb);
return;
}
/* canonical name */
Local<String> cname = String::New(result->dnstxt_cname);
/* Time-To-Live (TTL) value */
Local<Integer> ttl = Integer::New(result->dnstxt_ttl);
Local<Array> records = Array::New(result->dnstxt_nrr);
for (int i = 0; i < result->dnstxt_nrr; i++) {
HandleScope loop_scope;
struct dns_txt *record = &(result->dnstxt_txt[i]);
const char *txt = (const char *)record->txt;
records->Set(Integer::New(i), String::New(txt));
}
Local<Value> argv[3] = { records, ttl, cname };
TryCatch try_catch;
(*cb)->Call(Context::GetCurrent()->Global(), 3, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
cb_destroy(cb);
}
static void AfterResolveSRV(struct dns_ctx *ctx,
struct dns_rr_srv *result,
void *data) {
assert(ctx == &dns_defctx);
HandleScope scope;
Persistent<Function> *cb = cb_unwrap(data);
if (result == NULL) {
ResolveError(cb);
cb_destroy(cb);
return;
}
/* canonical name */
Local<String> cname = String::New(result->dnssrv_cname);
/* Time-To-Live (TTL) value */
Local<Integer> ttl = Integer::New(result->dnssrv_ttl);
Local<Array> records = Array::New(result->dnssrv_nrr);
for (int i = 0; i < result->dnssrv_nrr; i++) {
HandleScope loop_scope;
Local<Object> record = Object::New();
struct dns_srv *srv = &(result->dnssrv_srv[i]);
record->Set(priority_symbol, Integer::New(srv->priority));
record->Set(weight_symbol, Integer::New(srv->weight));
record->Set(port_symbol, Integer::New(srv->port));
record->Set(name_symbol, String::New(srv->name));
records->Set(Integer::New(i), record);
}
Local<Value> argv[3] = { records, ttl, cname };
TryCatch try_catch;
(*cb)->Call(Context::GetCurrent()->Global(), 3, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
cb_destroy(cb);
}
static Handle<Value> ResolveA(int type, const Arguments& args) {
HandleScope scope;
@ -177,6 +321,18 @@ static Handle<Value> ResolveA(int type, const Arguments& args) {
query = dns_submit_a6(NULL, *name, 0, AfterResolveA6, cb_persist(args[1]));
break;
case DNS_T_MX:
query = dns_submit_mx(NULL, *name, 0, AfterResolveMX, cb_persist(args[1]));
break;
case DNS_T_TXT:
query = dns_submit_txt(NULL, *name, DNS_C_IN, 0, AfterResolveTXT, cb_persist(args[1]));
break;
case DNS_T_SRV:
query = dns_submit_srv(NULL, *name, NULL, NULL, 0, AfterResolveSRV, cb_persist(args[1]));
break;
default:
return ThrowException(Exception::Error(String::New("Unsupported type")));
}
@ -196,6 +352,18 @@ static Handle<Value> ResolveA6(const Arguments& args) {
return ResolveA(DNS_T_AAAA, args);
}
static Handle<Value> ResolveMX(const Arguments& args) {
return ResolveA(DNS_T_MX, args);
}
static Handle<Value> ResolveTXT(const Arguments& args) {
return ResolveA(DNS_T_TXT, args);
}
static Handle<Value> ResolveSRV(const Arguments& args) {
return ResolveA(DNS_T_SRV, args);
}
static void AfterReverse(struct dns_ctx *ctx,
struct dns_rr_ptr *result,
void *data) {
@ -295,6 +463,12 @@ void DNS::Initialize(Handle<Object> target) {
errno_symbol = NODE_PSYMBOL("errno");
exchange_symbol = NODE_PSYMBOL("exchange");
priority_symbol = NODE_PSYMBOL("priority");
weight_symbol = NODE_PSYMBOL("weight");
port_symbol = NODE_PSYMBOL("port");
name_symbol = NODE_PSYMBOL("name");
target->Set(String::NewSymbol("TEMPFAIL"), Integer::New(DNS_E_TEMPFAIL));
target->Set(String::NewSymbol("PROTOCOL"), Integer::New(DNS_E_PROTOCOL));
target->Set(String::NewSymbol("NXDOMAIN"), Integer::New(DNS_E_NXDOMAIN));
@ -308,6 +482,15 @@ void DNS::Initialize(Handle<Object> target) {
Local<FunctionTemplate> resolve6 = FunctionTemplate::New(ResolveA6);
target->Set(String::NewSymbol("resolve6"), resolve6->GetFunction());
Local<FunctionTemplate> resolveMx = FunctionTemplate::New(ResolveMX);
target->Set(String::NewSymbol("resolveMx"), resolveMx->GetFunction());
Local<FunctionTemplate> resolveTxt = FunctionTemplate::New(ResolveTXT);
target->Set(String::NewSymbol("resolveTxt"), resolveTxt->GetFunction());
Local<FunctionTemplate> resolveSrv = FunctionTemplate::New(ResolveSRV);
target->Set(String::NewSymbol("resolveSrv"), resolveSrv->GetFunction());
Local<FunctionTemplate> reverse = FunctionTemplate::New(Reverse);
target->Set(String::NewSymbol("reverse"), reverse->GetFunction());
}

29
test/mjsunit/disabled/test-dns.js

@ -1,29 +0,0 @@
process.mixin(require("../common"));
var dns = require("dns");
for (var i = 2; i < process.ARGV.length; i++) {
var name = process.ARGV[i]
puts("looking up " + name);
var resolution = dns.resolve4(name);
resolution.addCallback(function (addresses, ttl, cname) {
puts("addresses: " + JSON.stringify(addresses));
puts("ttl: " + JSON.stringify(ttl));
puts("cname: " + JSON.stringify(cname));
for (var i = 0; i < addresses.length; i++) {
var a = addresses[i];
var reversing = dns.reverse(a);
reversing.addCallback( function (domains, ttl, cname) {
puts("reverse for " + a + ": " + JSON.stringify(domains));
});
reversing.addErrback( function (code, msg) {
puts("reverse for " + a + " failed: " + msg);
});
}
});
resolution.addErrback(function (code, msg) {
puts("error: " + msg);
});
}

119
test/mjsunit/test-dns.js

@ -0,0 +1,119 @@
process.mixin(require("./common"));
var dns = require("dns"),
sys = require("sys");
var hosts = ['example.com', 'example.org',
'ietf.org', // AAAA
'google.com', // MX, multiple A records
'_xmpp-client._tcp.google.com', // SRV
'oakalynhall.co.uk']; // Multiple PTR replies
var records = ['A', 'AAAA', 'MX', 'TXT', 'SRV'];
var i = hosts.length;
while (i--) {
var j = records.length;
while (j--) {
var hostCmd = "dig -t " + records[j] + " " + hosts[i] +
"| grep '^" + hosts[i] + "\\.\\W.*IN.*" + records[j] + "'" +
"| sed -E 's/[[:space:]]+/ /g' | cut -d ' ' -f 5- " +
"| sed -e 's/\\.$//'";
sys.exec(hostCmd).addCallback(checkDnsRecord(hosts[i], records[j]));
}
}
function checkDnsRecord(host, record) {
var myHost = host,
myRecord = record;
return function(stdout) {
var expected = stdout.substr(0, stdout.length - 1).split("\n");
var resolution = dns.resolve(myHost, myRecord);
switch (myRecord) {
case "A":
case "AAAA":
resolution.addCallback(function (result, ttl, cname) {
cmpResults(expected, result, ttl, cname);
// do reverse lookup check
var ll = result.length;
while (ll--) {
var ip = result[ll];
var reverseCmd = "host " + ip +
"| cut -d \" \" -f 5-" +
"| sed -e 's/\\.$//'";
sys.exec(reverseCmd).addCallback(checkReverse(ip));
}
});
break;
case "MX":
resolution.addCallback(function (result, ttl, cname) {
var strResult = [];
var ll = result.length;
while (ll--) {
strResult.push(result[ll].priority + " " + result[ll].exchange);
}
cmpResults(expected, strResult, ttl, cname);
});
break;
case "TXT":
resolution.addCallback(function (result, ttl, cname) {
var strResult = [];
var ll = result.length;
while (ll--) {
strResult.push('"' + result[ll] + '"');
}
cmpResults(expected, strResult, ttl, cname);
});
break;
case "SRV":
resolution.addCallback(function (result, ttl, cname) {
var strResult = [];
var ll = result.length;
while (ll--) {
strResult.push(result[ll].priority + " " +
result[ll].weight + " " +
result[ll].port + " " +
result[ll].name);
}
cmpResults(expected, strResult, ttl, cname);
});
break;
}
}
}
function checkReverse(ip) {
var myIp = ip;
return function (stdout) {
var expected = stdout.substr(0, stdout.length - 1).split("\n");
var reversing = dns.reverse(myIp);
reversing.addCallback(
function (domains, ttl, cname) {
cmpResults(expected, domains, ttl, cname);
});
}
}
function cmpResults(expected, result, ttl, cname) {
assert.equal(expected.length, result.length);
expected.sort();
result.sort();
ll = expected.length;
while (ll--) {
assert.equal(result[ll], expected[ll]);
// puts("Result " + result[ll] + " was equal to expected " + expected[ll]);
}
}

42
test/mjsunit/test-http-client-reconnect-bug.js

@ -0,0 +1,42 @@
process.mixin(require("./common"));
var tcp = require("tcp"),
sys = require("sys"),
http = require("http");
var PORT = 2143;
var errorCount = 0;
var eofCount = 0;
var server = tcp.createServer(function(socket) {
socket.close();
});
server.listen(PORT);
var client = http.createClient(PORT);
client.addListener("error", function() {
sys.puts("ERROR!");
errorCount++;
});
client.addListener("eof", function() {
sys.puts("EOF!");
eofCount++;
});
var request = client.request("GET", "/", {"host": "localhost"});
request.finish(function(response) {
sys.puts("STATUS: " + response.statusCode);
});
setTimeout(function () {
server.close();
}, 500);
process.addListener('exit', function () {
assert.equal(0, errorCount);
assert.equal(1, eofCount);
});

4
test/mjsunit/test-module-loading.js

@ -6,7 +6,7 @@ var a = require("./fixtures/a");
var d = require("./fixtures/b/d");
var d2 = require("./fixtures/b/d");
// Absolute
var d3 = require(require('path').dirname(__filename)+"/fixtures/b/d");
var d3 = require(__dirname+"/fixtures/b/d");
// Relative
var d4 = require("../mjsunit/fixtures/b/d");
@ -52,6 +52,8 @@ try {
assert.equal("blah", e.message);
}
assert.equal(require('path').dirname(__filename), __dirname);
process.addListener("exit", function () {
assert.equal(true, a.A instanceof Function);
assert.equal("A done", a.A());

6
test/mjsunit/test-promise.js

@ -19,12 +19,18 @@ a.addCallback(function(value) {
assert.equal(TEST_VALUE, value);
expectedCallbacks.a1--;
});
a.addErrback(function(error) {
assert.notEqual(TEST_VALUE, error, 'normal');
});
a.emitSuccess(TEST_VALUE);
a.addCallback(function(value) {
assert.equal(TEST_VALUE, value);
expectedCallbacks.a2--;
});
a.addErrback(function(error) {
assert.notEqual(TEST_VALUE, error, 'late');
});
// Test regular & late errback binding
var b = new Promise();

23
tools/osx-dist.sh

@ -0,0 +1,23 @@
#!/bin/sh
TOOLS=`dirname $0`
ROOT=$TOOLS/..
VERSION=`git describe`
CONTENTS=dist-osx/nodejs-$VERSION
# go build it in the root of the git repository
pushd $ROOT
./configure --prefix=/usr/local/nodejs
make
make install DESTDIR="$CONTENTS"
mkdir -p "$CONTENTS/usr/local/bin"
pushd "$CONTENTS/usr/local/bin"
ln -s ../nodejs/bin/* .
popd # $CONTENTS/usr/local/bin
popd # $ROOT
"$TOOLS/osx-pkg-dmg-create.sh" "$ROOT/$CONTENTS" NodeJS $VERSION 'org.nodejs'

65
tools/osx-pkg-dmg-create.sh

@ -0,0 +1,65 @@
#!/bin/bash
# Create a complete OS .dmg file (it needs the Apple Developers Tools installed)
# usage:
# pkg-create.sh <contents-root-folder> <package-name> <package-version> <vendor-string>
#
CONTENTS=$1
shift
NAME=$1
shift
VERSION=$1
shift
VENDOR=$1
PKGID="$VENDOR.$NAME-$VERSION"
# unused pkg-info entries so far
#
# <key>CFBundleExecutable</key>
# <string>$NAME</string>
# <key>CFBundleSignature</key>
# <string>????</string>
#
# Need the .plist file in order for the packagemaker to create a package which the
# pkgutil --packages later on would return an entry about. pkgutil can then --unlink
# and --forget about the package nicely.
#
cat > "$CONTENTS.plist" <<PINFO
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<pkg-info version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIdentifier</key>
<string>$PKGID</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$NAME</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>CFBundleVersion</key>
<string>$VERSION</string>
</dict>
</pkg-info>
PINFO
packagemaker=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker
$packagemaker \
--id "$PKGID" \
--info "$CONTENTS.plist" \
--root "$CONTENTS" \
--target 10.5 \
--out "$CONTENTS".pkg
hdiutil create "$CONTENTS.dmg" \
-format UDZO -ov \
-volname "$NAME $VERSION" \
-srcfolder $CONTENTS.pkg
Loading…
Cancel
Save