Browse Source

Merge branch 'master' into net2

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
07423f3a87
  1. 43
      ChangeLog
  2. 7
      Makefile
  3. 5
      benchmark/http_simple.js
  4. 14
      benchmark/static_http_server.js
  5. 323
      doc/api.txt
  6. 167
      doc/asciidoc-xhtml11.js
  7. 20
      doc/index.html
  8. 157
      lib/file.js
  9. 83
      lib/http.js
  10. 4
      lib/multipart.js
  11. 1
      lib/posix.js
  12. 32
      lib/sys.js
  13. 69
      src/node.cc
  14. 122
      src/node.js
  15. 5
      src/node_file.cc
  16. 6
      src/node_http.cc
  17. 31
      src/node_net.cc
  18. 3
      src/node_net.h
  19. 2
      src/node_timer.cc
  20. 2
      test/mjsunit/common.js
  21. 4
      test/mjsunit/disabled/test-fs-sendfile.js
  22. 1
      test/mjsunit/fixtures/a.js
  23. 4
      test/mjsunit/fixtures/b/c.js
  24. 38
      test/mjsunit/test-buffered-file.js
  25. 20
      test/mjsunit/test-eio-race.js
  26. 4
      test/mjsunit/test-eio-race2.js
  27. 4
      test/mjsunit/test-eio-race3.js
  28. 2
      test/mjsunit/test-eio-race4.js
  29. 2
      test/mjsunit/test-file-read-noexist.js
  30. 4
      test/mjsunit/test-fs-stat.js
  31. 10
      test/mjsunit/test-fs-write.js
  32. 10
      test/mjsunit/test-http-1.0.js
  33. 4
      test/mjsunit/test-http-cat.js
  34. 6
      test/mjsunit/test-http-chunked.js
  35. 20
      test/mjsunit/test-http-client-race.js
  36. 5
      test/mjsunit/test-http-client-reconnect-bug.js
  37. 21
      test/mjsunit/test-http-client-upload.js
  38. 6
      test/mjsunit/test-http-malformed-request.js
  39. 22
      test/mjsunit/test-http-proxy.js
  40. 16
      test/mjsunit/test-http-server.js
  41. 22
      test/mjsunit/test-http-tls.js
  42. 14
      test/mjsunit/test-http-wget.js
  43. 16
      test/mjsunit/test-http.js
  44. 4
      test/mjsunit/test-keep-alive.js
  45. 4
      test/mjsunit/test-mkdir-rmdir.js
  46. 12
      test/mjsunit/test-module-loading.js
  47. 57
      test/mjsunit/test-multipart.js
  48. 15
      test/mjsunit/test-promise-wait.js
  49. 12
      test/mjsunit/test-promise.js
  50. 2
      test/mjsunit/test-readdir.js
  51. 4
      test/mjsunit/test-remote-module-loading.js
  52. 2
      test/mjsunit/test-stdio.js
  53. 5
      test/mjsunit/test-sync-fileread.js
  54. 10
      test/mjsunit/test-sys.js
  55. 14
      test/mjsunit/test-tcp-binary.js
  56. 6
      test/mjsunit/test-tcp-many-clients.js
  57. 12
      test/mjsunit/test-tcp-pingpong-delay.js
  58. 14
      test/mjsunit/test-tcp-pingpong.js
  59. 6
      test/mjsunit/test-tcp-reconnect.js
  60. 6
      test/mjsunit/test-tcp-throttle-kernel-buffer.js
  61. 12
      test/mjsunit/test-tcp-throttle.js
  62. 18
      test/mjsunit/test-tcp-timeout.js
  63. 22
      test/mjsunit/test-tcp-tls.js
  64. 9
      test/mjsunit/test-timers.js
  65. 13
      test/mjsunit/test-watch-file.js
  66. 4
      wscript

43
ChangeLog

@ -1,4 +1,45 @@
2010.02.09, Version 0.1.28
2010.02.17, Version 0.1.29
* Major API Changes
- Remove 'file' module
- require('posix') -----------------> require('fs')
- fs.cat ---------------------------> fs.readFile
- file.write -----------------------> fs.writeFile
- TCP 'receive' event --------------> 'data'
- TCP 'eof' event ------------------> 'end'
- TCP send() -----------------------> write()
- HTTP sendBody() ------------------> write()
- HTTP finish() --------------------> close()
- HTTP 'body' event ----------------> 'data'
- HTTP 'complete' event ------------> 'end'
- http.Client.prototype.close() (formerly finish()) no longer
takes an argument. Add the 'response' listener manually.
- Allow strings for the flag argument to fs.open
("r", "r+", "w", "w+", "a", "a+")
* Added multiple arg support for sys.puts(), print(), etc.
(tj@vision-media.ca)
* sys.inspect(Date) now shows the date value (Mark Hansen)
* Calculate page size with getpagesize for armel (Jérémy Lal)
* Bugfix: stderr flushing.
* Bugfix: Promise late chain (Yuichiro MASUI)
* Bugfix: wait() on fired promises
(Felix Geisendörfer, Jonas Pfenniger)
* Bugfix: Use InstanceTemplate() instead of PrototypeTemplate() for
accessor methods. Was causing a crash with Eclipse debugger.
(Zoran Tomicic)
* Bugfix: Throw from connection.connect if resolving.
(Reported by James Golick)
2010.02.09, Version 0.1.28, 49de41ef463292988ddacfb01a20543b963d9669
* Use Google's jsmin.py which can be used for evil.

7
Makefile

@ -33,6 +33,7 @@ doc/api.html: doc/api.txt
asciidoc --unsafe \
-a theme=pipe \
-a toc \
-a toclevels=1 \
-a linkcss \
-o doc/api.html doc/api.txt
@ -43,7 +44,7 @@ doc/node.1: doc/api.xml
xsltproc --output doc/node.1 --nonet doc/manpage.xsl doc/api.xml
website-upload: doc
scp doc/* linode:~/tinyclouds/node/
scp doc/* ryan@nodejs.org:~/tinyclouds/node/
docclean:
@-rm -f doc/node.1 doc/api.xml doc/api.html
@ -58,11 +59,11 @@ distclean: docclean
check:
@tools/waf-light check
VERSION=$(shell git-describe)
VERSION=$(shell git describe)
TARNAME=node-$(VERSION)
dist: doc/node.1 doc/api.html
git-archive --prefix=$(TARNAME)/ HEAD > $(TARNAME).tar
git archive --prefix=$(TARNAME)/ HEAD > $(TARNAME).tar
mkdir -p $(TARNAME)/doc
cp doc/node.1 $(TARNAME)/doc/node.1
cp doc/api.html $(TARNAME)/doc/api.html

5
benchmark/http_simple.js

@ -52,7 +52,6 @@ http.createServer(function (req, res) {
, "Content-Length": content_length
}
);
res.sendBody(body);
res.finish();
res.write(body);
res.close();
}).listen(8000);

14
benchmark/static_http_server.js

@ -20,15 +20,17 @@ var server = http.createServer(function (req, res) {
"Content-Type": "text/plain",
"Content-Length": body.length
});
res.sendBody(body);
res.finish();
res.write(body);
res.close();
})
server.listen(port);
function responseListener (res) {
res.addListener("complete", function () {
res.addListener("end", function () {
if (requests < n) {
res.client.request("/").finish(responseListener);
var req = res.client.request("/");
req.addListener('response', responseListener);
req.close();
requests++;
}
@ -41,6 +43,8 @@ function responseListener (res) {
for (var i = 0; i < concurrency; i++) {
var client = http.createClient(port);
client.id = i;
client.request("/").finish(responseListener);
var req = client.request("/");
req.addListener('response', responseListener);
req.close();
requests++;
}

323
doc/api.txt

@ -1,7 +1,7 @@
NODE(1)
=======
Ryan Dahl <ry@tinyclouds.org>
Version, 0.1.28, 2010.02.09
Version, 0.1.29, 2010.02.17
== NAME
@ -20,8 +20,8 @@ var sys = require("sys"),
http = require("http");
http.createServer(function (request, response) {
response.sendHeader(200, {"Content-Type": "text/plain"});
response.sendBody("Hello World\n");
response.finish();
response.write("Hello World\n");
response.close();
}).listen(8000);
sys.puts("Server running at http://127.0.0.1:8000/");
----------------------------------------
@ -35,18 +35,15 @@ Server running at http://127.0.0.1:8000/
----------------------------------------
== API
== Encodings
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
them if you can. +"utf8"+ is slower and should be avoided when possible.
Unless otherwise noted, functions are all asynchronous and do not block
execution.
=== Global Objects
== Global Objects
+global+ ::
The global namespace object.
@ -55,7 +52,7 @@ The global namespace object.
The process object. Most stuff lives in here. See the "process object"
section.
+require(path)+ ::
+require()+ ::
See the modules section.
+require.paths+ ::
@ -74,7 +71,7 @@ more information.
=== The +process+ Object
== The +process+ Object
[cols="1,2,10",options="header"]
|=========================================================
@ -171,7 +168,7 @@ process.watchFile(f, function (curr, prev) {
});
-------------------------
+
These stat objects are instances of +posix.Stat+.
These stat objects are instances of +fs.Stat+.
+process.unwatchFile(filename)+::
Stop watching for changes on +filename+.
@ -193,7 +190,7 @@ share structure with the original object(s).
Undefined properties are not copied. However, properties inherited from the
object's prototype will be copied over.
=== System module
== System module
These function are in the module +"sys"+. Use +require("sys")+ to access
them.
@ -227,14 +224,14 @@ sys.exec("ls /").addCallback(function (stdout, stderr) {
=== Events
== Events
Many objects in Node emit events: a TCP server emits an event each time
there is a connection, a child process emits an event when it exits. All
objects which emit events are instances of +events.EventEmitter+.
Events are represented by a camel-cased string. Here are some examples:
+"connection"+, +"receive"+, +"messageBegin"+.
+"connection"+, +"data"+, +"messageBegin"+.
Functions can be then be attached to objects, to be executed when an event
is emitted. These functions are called _listeners_.
@ -243,7 +240,7 @@ Some asynchronous file operations return an +EventEmitter+ called a
_promise_. A promise emits just a single event when the operation is
complete.
==== +events.EventEmitter+
=== +events.EventEmitter+
+require("events")+ to access the events module.
@ -279,7 +276,7 @@ manipulated, e.g. to remove listeners.
+emitter.emit(event, arg1, arg2, ...)+ ::
Execute each of the listeners in order with the supplied arguments.
==== +events.Promise+
=== +events.Promise+
+require("events")+ to access the events module.
@ -371,30 +368,10 @@ promise.addErrback(function(e) {
+
If the +timeout+ parameter is not provided, the current timeout value, if any,
is returned.
+
+promise.wait()+ ::
Blocks futher execution until the promise emits a success or error event.
Events setup before the call to +promise.wait()+ was made may still be
emitted and executed while +promise.wait()+ is blocking.
+
If there was a single argument to the +"success"+ event then it is returned.
If there were multiple arguments to +"success"+ then they are returned as an
array.
+
If +"error"+ was emitted instead, +wait()+ throws an error.
+
*IMPORTANT* +promise.wait()+ is not a true fiber/coroutine. If any other
promises are created and made to wait while the first promise waits, the
first promise's wait will not return until all others return. The benefit of
this is a simple implementation and the event loop does not get blocked.
Disadvantage is the possibility of situations where the promise stack grows
infinitely large because promises keep getting created and keep being told
to wait(). Use +promise.wait()+ sparingly--probably best used only during
program setup, not during busy server activity.
=== Standard I/O
== Standard I/O
Standard I/O is handled through a special object +process.stdio+. stdout and
stdin are fully non-blocking (even when piping to files). stderr is
@ -426,7 +403,7 @@ Write data to stderr. Synchronous.
Close stdin.
=== Modules
== Modules
Node uses the CommonJS module system.
@ -514,13 +491,14 @@ puts("The area of a circle of radius 4 is " + area(4));
=== Timers
== Timers
The following are global variables
+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.
@ -531,7 +509,7 @@ Prevents said timeout from triggering.
+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.
@ -539,13 +517,13 @@ Optionally, you can also pass arguments to the callback.
Stops a interval from triggering.
=== Child Processes
== Child Processes
Node provides a tridirectional +popen(3)+ facility through the class
+process.ChildProcess+. It is possible to stream data through the child's +stdin+,
+stdout+, and +stderr+ in a fully non-blocking way.
==== +process.ChildProcess+
=== +process.ChildProcess+
[cols="1,2,10",options="header"]
|=========================================================
@ -603,68 +581,59 @@ will be sent +"SIGTERM"+. See signal(7) for a list of available signals.
=== POSIX module
== File System
File I/O is provided by simple wrappers around standard POSIX functions. To
use this module do +require("posix")+.
All POSIX wrappers have a similar form. They return a promise
(+events.Promise+). Example of deleting a file:
use this module do +require("fs")+. All the methods have a similar form.
They return a promise (+events.Promise+). Example of deleting a file:
------------------------------------------------------------------------------
var posix = require("posix"),
sys = require("sys");
var fs = require("fs"),
sys = require("sys");
var promise = posix.unlink("/tmp/hello");
var promise = fs.unlink("/tmp/hello");
promise.addCallback(function () {
sys.puts("successfully deleted /tmp/hello");
});
------------------------------------------------------------------------------
There is no guaranteed ordering to the POSIX wrappers. The
following is very much prone to error
This is asynchornous, there is no guaranteed ordering. The following is
prone to error
------------------------------------------------------------------------------
posix.rename("/tmp/hello", "/tmp/world");
posix.stat("/tmp/world").addCallback(function (stats) {
fs.rename("/tmp/hello", "/tmp/world");
fs.stat("/tmp/world").addCallback(function (stats) {
sys.puts("stats: " + JSON.stringify(stats));
});
------------------------------------------------------------------------------
It could be that +stat()+ is executed before the +rename()+.
It could be that +fs.stat+ is executed before +fs.rename+.
The correct way to do this is to chain the promises.
------------------------------------------------------------------------------
posix.rename("/tmp/hello", "/tmp/world").addCallback(function () {
posix.stat("/tmp/world").addCallback(function (stats) {
fs.rename("/tmp/hello", "/tmp/world").addCallback(function () {
fs.stat("/tmp/world").addCallback(function (stats) {
sys.puts("stats: " + JSON.stringify(stats));
});
});
------------------------------------------------------------------------------
Or use the +promise.wait()+ functionality:
------------------------------------------------------------------------------
posix.rename("/tmp/hello", "/tmp/world").wait();
var stats = posix.stat("/tmp/world").wait();
sys.puts("stats: " + JSON.stringify(stats));
------------------------------------------------------------------------------
+posix.rename(path1, path2)+ ::
+fs.rename(path1, path2)+ ::
See rename(2).
- on success: no parameters.
- on error: no parameters.
+posix.truncate(fd, len)+ ::
+fs.truncate(fd, len)+ ::
See ftruncate(2).
- on success: no parameters.
- on error: no parameters.
+posix.stat(path)+ ::
+fs.stat(path)+ ::
See stat(2).
- on success: Returns +posix.Stats+ object. It looks like this:
- on success: Returns +fs.Stats+ object. It looks like this:
+
------------------------------------------------------------------------------
{ dev: 2049, ino: 305352, mode: 16877, nlink: 12, uid: 1000, gid: 1000,
@ -673,49 +642,51 @@ See stat(2).
"2009-06-29T11:11:40Z" }+
------------------------------------------------------------------------------
+
See the +posix.Stats+ section below for more information.
See the +fs.Stats+ section below for more information.
- on error: no parameters.
+posix.unlink(path)+ ::
+fs.unlink(path)+ ::
See unlink(2)
- on success: no parameters.
- on error: no parameters.
+posix.rmdir(path)+ ::
+fs.rmdir(path)+ ::
See rmdir(2)
- on success: no parameters.
- on error: no parameters.
+posix.mkdir(path, mode)+ ::
+fs.mkdir(path, mode)+ ::
See mkdir(2)
- on success: no parameters.
- on error: no parameters.
+posix.readdir(path)+ ::
+fs.readdir(path)+ ::
Reads the contents of a directory.
- on success: One argument, an array containing the names (strings) of the
files in the directory (excluding "." and "..").
- on error: no parameters.
+posix.close(fd)+ ::
+fs.close(fd)+ ::
See close(2)
- on success: no parameters.
- on error: no parameters.
+posix.open(path, flags, mode)+::
+fs.open(path, flags, mode=0666)+::
See open(2). The constants like +O_CREAT+ are defined at +process.O_CREAT+.
Also you can use the strings "r", "r+", "w", "w+", "a", or "a+" as aliases
to the common flag combinations.
- on success: +fd+ is given as the parameter.
- on error: no parameters.
+posix.write(fd, data, position, encoding)+::
+fs.write(fd, data, position, encoding)+::
Write data to the file specified by +fd+. +position+ refers to the offset
from the beginning of the file where this data should be written. If
+position+ is +null+, the data will be written at the current position.
@ -723,7 +694,7 @@ See the +posix.Stats+ section below for more information.
- on success: returns an integer +written+ which specifies how many _bytes_ were written.
- on error: no parameters.
+posix.read(fd, length, position, encoding)+::
+fs.read(fd, length, position, encoding)+::
Read data from the file specified by +fd+.
+
+length+ is an integer specifying the number of
@ -735,11 +706,11 @@ See the +posix.Stats+ section below for more information.
- on success: returns +data, bytes_read+, what was read from the file.
- on error: no parameters.
+posix.cat(filename, encoding="utf8")+::
+fs.readFile(filename, encoding="utf8")+::
Outputs the entire contents of a file. Example:
+
--------------------------------
posix.cat("/etc/passwd").addCallback(function (content) {
fs.readFile("/etc/passwd").addCallback(function (content) {
sys.puts(content);
});
--------------------------------
@ -747,9 +718,21 @@ posix.cat("/etc/passwd").addCallback(function (content) {
- on success: returns +data+, what was read from the file.
- on error: no parameters.
==== +posix.Stats+
+fs.writeFile(filename, data, encoding="utf8")+::
Writes data to a file. Example:
+
--------------------------------
fs.writeFile("message.txt", "Hello Node").addCallback(function () {
sys.puts("It's saved!");
});
--------------------------------
+
- on success: no parameters.
- on error: no parameters.
Objects returned from +posix.stat()+ are of this type.
=== +fs.Stats+
Objects returned from +fs.stat()+ are of this type.
+stats.isFile()+::
@ -765,7 +748,7 @@ Objects returned from +posix.stat()+ are of this type.
+stats.isSocket()+:: ...
=== HTTP
== HTTP
To use the HTTP server and client one must +require("http")+.
@ -793,7 +776,7 @@ parsing only. It parses a message into headers and body but it does not
parse the actual headers or the body.
==== +http.Server+
=== +http.Server+
[cols="1,2,10",options="header"]
|=========================================================
@ -847,7 +830,7 @@ Stops the server from accepting new connections.
==== +http.ServerRequest+
=== +http.ServerRequest+
This object is created internally by a HTTP server--not by
the user--and passed as the first argument to a +"request"+ listener.
@ -856,7 +839,7 @@ the user--and passed as the first argument to a +"request"+ listener.
|=========================================================
|Event | Parameters | Notes
|+"body"+ | +chunk+ | Emitted when a piece of the
|+"data"+ | +chunk+ | Emitted when a piece of the
message body is received. Example: A chunk
of the body is given as the single
argument. The transfer-encoding has been
@ -864,7 +847,7 @@ the user--and passed as the first argument to a +"request"+ listener.
body encoding is set with
+request.setBodyEncoding()+.
|+"complete"+ | (none) | Emitted exactly once for each message.
|+"end"+ | (none) | Emitted exactly once for each message.
No arguments. After emitted no other
events will be emitted on the request.
|=========================================================
@ -947,7 +930,7 @@ Resumes a paused request.
The +http.Connection+ object.
==== +http.ServerResponse+
=== +http.ServerResponse+
This object is created internally by a HTTP server--not by the user. It is
passed as the second parameter to the +"request"+ event.
@ -968,9 +951,9 @@ response.sendHeader(200, {
----------------------------------------
+
This method must only be called once on a message and it must
be called before +response.finish()+ is called.
be called before +response.close()+ is called.
+response.sendBody(chunk, encoding="ascii")+ ::
+response.write(chunk, encoding="ascii")+ ::
This method must be called after +sendHeader+ was
called. It sends a chunk of the response body. This method may
@ -983,22 +966,22 @@ specifies how to encode it into a byte stream. By default the
Note: This is the raw HTTP body and has nothing to do with
higher-level multi-part body encodings that may be used.
+
The first time +sendBody+ is called, it will send the buffered header
information and the first body to the client. The second time
+sendBody+ is called, Node assumes you're going to be streaming data, and
sends that seperately. That is, the response is buffered up to the
The first time +response.write()+ is called, it will send the buffered
header information and the first body to the client. The second time
+response.write()+ is called, Node assumes you're going to be streaming
data, and sends that seperately. That is, the response is buffered up to the
first chunk of body.
+response.finish()+ ::
+response.close()+ ::
This method signals to the server that all of the response headers and body
has been sent; that server should consider this message complete.
The method, +response.finish()+, MUST be called on each
The method, +response.close()+, MUST be called on each
response.
==== +http.Client+
=== +http.Client+
An HTTP client is constructed with a server address as its
argument, the returned handle is then used to issue one or more
@ -1013,14 +996,15 @@ var sys = require("sys"),
http = require("http");
var google = http.createClient(80, "www.google.com");
var request = google.request("GET", "/", {"host": "www.google.com"});
request.finish(function (response) {
request.addListener('response', function (response) {
sys.puts("STATUS: " + response.statusCode);
sys.puts("HEADERS: " + JSON.stringify(response.headers));
response.setBodyEncoding("utf8");
response.addListener("body", function (chunk) {
response.addListener("data", function (chunk) {
sys.puts("BODY: " + chunk);
});
});
request.close();
----------------------------------------
+http.createClient(port, host)+ ::
@ -1046,10 +1030,10 @@ set +Transfer-Encoding: chunked+.
+
NOTE: the request is not complete. This method only sends
the header of the request. One needs to call
+request.finish()+ to finalize the request and retrieve
+request.close()+ to finalize the request and retrieve
the response. (This sounds convoluted but it provides a chance
for the user to stream a body to the server with
+request.sendBody()+.)
+request.write()+.)
+client.setSecure(format_type, ca_certs, crl_list, private_key, certificate)+ ::
Enable TLS for the client connection, with the specified credentials.
@ -1063,18 +1047,48 @@ key for the client, which together with the certificate allows the client to aut
itself to the server.
==== +http.ClientRequest+
=== +http.ClientRequest+
This object is created internally and returned from the request methods of a
+http.Client+. It represents an _in-progress_ request whose header has
already been sent.
To get the response, add a listener for +'response'+ to the request object.
+'response'+ will be emitted from the request object when the response
headers have been received. The +'response'+ event is executed with one
argument which is an instance of +http.ClientResponse+.
During the +'response'+ event, one can add listeners to the
response object; particularly to listen for the +"data"+ event. Note that
the +'response' event is called before any part of the response 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 +'data'+ is added during the +'response'
event, the entire body will be caught.
----------------------------------------
// Good
request.addListener('response', function (response) {
response.addListener("data", function (chunk) {
sys.puts("BODY: " + chunk);
});
});
// Bad - misses all or part of the body
request.addListener('response', function (response) {
setTimeout(function () {
response.addListener("data", function (chunk) {
sys.puts("BODY: " + chunk);
});
}, 10);
});
----------------------------------------
[cols="1,2,10",options="header"]
|=========================================================
|Event | Parameters | Notes
|+"response"+ | +response+ |
Emitted when a response is received to this request. Typically the user will
set a listener to this via the +request.finish()+ method.
Emitted when a response is received to this request.
+
This event is emitted only once.
+
@ -1082,7 +1096,7 @@ The +response+ argument will be an instance of +http.ClientResponse+.
|=========================================================
+request.sendBody(chunk, encoding="ascii")+ ::
+request.write(chunk, encoding="ascii")+ ::
Sends a chunk of the body. By calling this method
many times, the user can stream a request body to a
@ -1100,46 +1114,15 @@ argument should be either +"utf8"+ or
as it is faster.
+request.finish(responseListener)+ ::
+request.close()+ ::
Finishes sending the request. If any parts of the body are
unsent, it will flush them to the socket. If the request is
chunked, this will send the terminating +"0\r\n\r\n"+.
+
The parameter +responseListener+ is a callback which
will be executed when the response headers have been received.
The +responseListener+ callback is executed with one
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 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.
+
----------------------------------------
// Good
request.finish(function (response) {
response.addListener("body", function (chunk) {
sys.puts("BODY: " + chunk);
});
});
// Bad - misses all or part of the body
request.finish(function (response) {
setTimeout(function () {
response.addListener("body", function (chunk) {
sys.puts("BODY: " + chunk);
});
}, 10);
});
----------------------------------------
==== +http.ClientResponse+
=== +http.ClientResponse+
This object is created internally and passed to the +"response"+ event.
@ -1147,13 +1130,13 @@ This object is created internally and passed to the +"response"+ event.
|=========================================================
|Event | Parameters | Notes
|+"body"+ | +chunk+ |
|+"data"+ | +chunk+ |
Emitted when a piece of the 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 a String. The body encoding is set with
+response.setBodyEncoding()+.
|+"complete"+ | |
|+"end"+ | |
Emitted exactly once for each message. No arguments.
After emitted no other events will be emitted on the response.
@ -1182,7 +1165,7 @@ After emitted no other events will be emitted on the response.
+response.client+ ::
A reference to the +http.Client+ that this response belongs to.
=== Multipart Parsing
== Multipart Parsing
A library to parse +multipart+ internet messages is included with
Node. To use it, +require("multipart")+.
@ -1208,13 +1191,12 @@ Node. To use it, +require("multipart")+.
No checking is done to ensure that the file does not overload the memory.
Only use multipart.cat with known and trusted input!
==== +multipart.Stream+
=== +multipart.Stream+
The multipart.Stream class is a streaming parser wrapped around a message.
The Stream also contains the properties described for the +part+ objects below,
and is a reference to the top-level message.
===== Events
[cols="1,2,10",options="header"]
|=========================================================
@ -1228,7 +1210,6 @@ and is a reference to the top-level message.
indicates that the message is malformed.
|=========================================================
===== Properties
+stream.part+::
The current part being processed. This is important, for instance, when responding
@ -1242,20 +1223,16 @@ will be set to +false+.
+stream.parts+::
An array of the parts contained within the message. Each is a +part+ object.
===== Methods
+stream.pause+::
If the underlying message supports pause and resume, then this will pause the stream.
+stream.resume+::
If the underlying message supports pause and resume, then this will resume the paused stream.
==== Part Objects
=== +multipart.Part+
As it parses the message, the Stream object will create +Part+ objects.
===== Properties
+part.parent+::
The message that contains this part.
@ -1286,7 +1263,7 @@ For multipart messages, this is the multipart type specified in the +content-typ
For example, a message with +content-type: multipart/form-data+ will have a +type+
property of +form-data+.
==== Example
=== Example
Here is an example for parsing a +multipart/form-data+ request:
@ -1300,8 +1277,8 @@ http.createServer(function (req, res) {
name, filename;
mp.addListener("error", function (er) {
res.sendHeader(400, {"content-type":"text/plain"});
res.sendBody("You sent a bad message!\n"+er.message);
res.finish();
res.write("You sent a bad message!\n"+er.message);
res.close();
});
mp.addListener("partBegin", function (part) {
name = part.name;
@ -1323,13 +1300,13 @@ http.createServer(function (req, res) {
"content-type" : "text/plain",
"content-length" : response.length
});
res.sendBody(response);
res.finish();
res.write(response);
res.close();
})
});
----------------------------------------
==== Nested Multipart Messages
=== Nested Multipart Messages
Nested multipart parsing is supported. The +stream.part+ object always refers
to the current part. If +part.isMultiPart+ is set, then that part is a
@ -1337,11 +1314,11 @@ multipart message, which contains other parts. You can inspect its +parts+
array to see the list of sub-parts, which may also be multipart, and contain
sub-parts.
=== TCP
== TCP
To use the TCP server and client one must +require("tcp")+.
==== +tcp.Server+
=== +tcp.Server+
Here is an example of a echo server which listens for connections
on port 7000:
@ -1351,13 +1328,13 @@ var tcp = require("tcp");
var server = tcp.createServer(function (socket) {
socket.setEncoding("utf8");
socket.addListener("connect", function () {
socket.send("hello\r\n");
socket.write("hello\r\n");
});
socket.addListener("receive", function (data) {
socket.send(data);
socket.addListener("data", function (data) {
socket.write(data);
});
socket.addListener("eof", function () {
socket.send("goodbye\r\n");
socket.addListener("end", function () {
socket.write("goodbye\r\n");
socket.close();
});
});
@ -1410,7 +1387,7 @@ asynchronous, the server is finally closed when the server emits a +"close"+
event.
==== +tcp.Connection+
=== +tcp.Connection+
This object is used as a TCP client and also as a server-side
socket for +tcp.Server+.
@ -1421,11 +1398,11 @@ socket for +tcp.Server+.
|+"connect"+ | | Call once the connection is established
after a call to +createConnection()+ or
+connect()+.
|+"receive"+ | +data+ | Called when data is received on the
|+"data"+ | +data+ | Called when data is received on the
connection. +data+ will be a string.
Encoding of data is set by
+connection.setEncoding()+.
|+"eof"+ | | Called when the other end of the
|+"end"+ | | Called when the other end of the
connection sends a FIN packet.
After this is emitted the +readyState+
will be +"writeOnly"+. One should probably
@ -1474,7 +1451,7 @@ Either +"closed"+, +"open"+, +"opening"+, +"readOnly"+, or +"writeOnly"+.
+connection.setEncoding(encoding)+::
Sets the encoding (either +"ascii"+, +"utf8"+, or +"binary"+) for data that is received.
+connection.send(data, encoding="ascii")+::
+connection.write(data, encoding="ascii")+::
Sends data on the connection. The second parameter specifies the encoding
in the case of a string--it defaults to ASCII because encoding to UTF8 is
rather slow.
@ -1491,7 +1468,7 @@ Ensures that no more I/O activity happens on this socket. Only
necessary in case of errors (parse error or so).
+connection.readPause()+::
Pauses the reading of data. That is, +"receive"+ events will not be emitted.
Pauses the reading of data. That is, +"data"+ events will not be emitted.
Useful to throttle back an upload.
+connection.readResume()+::
@ -1507,7 +1484,7 @@ If +timeout+ is 0, then the idle timeout is disabled.
+connection.setNoDelay(noDelay=true)+::
Disables the Nagle algorithm. By default TCP connections use the Nagle
algorithm, they buffer data before sending it off. Setting +noDelay+ will
immediately fire off data each time +connection.send()+ is called.
immediately fire off data each time +connection.write()+ is called.
+connection.verifyPeer()+::
Returns an integer indicating the trusted status of the peer in a TLS
@ -1528,7 +1505,7 @@ A format of "DNstring" gives a single string with the combined Distinguished
Name (DN) from the certificate, as comma delimited name=value pairs as defined
in RFC2253. This function is synchronous.
=== DNS module
== DNS module
Use +require("dns")+ to access this module.
@ -1629,7 +1606,7 @@ Each DNS query can return an error code.
- +dns.NOMEM+: out of memory while processing.
- +dns.BADQUERY+: the query is malformed.
=== Assert Module
== Assert Module
This module is used for writing unit tests for your applications, you can access it with +require("assert")+.
@ -1664,7 +1641,7 @@ Expects +block+ to throw an error.
Expects +block+ not to throw an error.
=== Path Module
== Path Module
This module contains utilities for dealing with file paths. Use
+require("path")+ to use it. It provides the following methods:
@ -1744,7 +1721,7 @@ require("path").exists("/etc/passwd", function (exists) {
------------------------------------
=== URL Module
== URL Module
This module has utilities for URL resolution and parsing.
@ -1799,7 +1776,7 @@ Take a parsed URL object, and return a formatted URL string.
Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag.
=== Query String Module
== Query String Module
This module provides utilities for dealing with query strings. It provides the following methods:

167
doc/asciidoc-xhtml11.js

@ -0,0 +1,167 @@
var asciidoc = { // Namespace.
/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////
/* Author: Mihai Bazon, September 2002
* http://students.infoiasi.ro/~mishoo
*
* Table Of Content generator
* Version: 0.4
*
* Feel free to use this script under the terms of the GNU General Public
* License, as long as you do not remove or alter this notice.
*/
/* modified by Troy D. Hanson, September 2006. License: GPL */
/* modified by Stuart Rackham, 2006, 2009. License: GPL */
// toclevels = 1..4.
toc: function (toclevels) {
function getText(el) {
var text = "";
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
text += i.data;
else if (i.firstChild != null)
text += getText(i);
}
return text;
}
function TocEntry(el, text, toclevel) {
this.element = el;
this.text = text;
this.toclevel = toclevel;
}
function tocEntries(el, toclevels) {
var result = new Array;
var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
// Function that scans the DOM tree for header elements (the DOM2
// nodeIterator API would be a better technique but not supported by all
// browsers).
var iterate = function (el) {
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
var mo = re.exec(i.tagName);
if (mo)
result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
iterate(i);
}
}
}
iterate(el);
return result;
}
var toc = document.getElementById("toc");
var entries = tocEntries(document.getElementById("content"), toclevels);
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
if (entry.element.id == "")
entry.element.id = "_toc_" + i;
var a = document.createElement("a");
a.href = "#" + entry.element.id;
a.appendChild(document.createTextNode(entry.text));
var div = document.createElement("div");
div.appendChild(a);
div.className = "toclevel" + entry.toclevel;
toc.appendChild(div);
}
if (entries.length == 0)
toc.parentNode.removeChild(toc);
},
/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////
/* Based on footnote generation code from:
* http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
*/
footnotes: function () {
var cont = document.getElementById("content");
var noteholder = document.getElementById("footnotes");
var spans = cont.getElementsByTagName("span");
var refs = {};
var n = 0;
for (i=0; i<spans.length; i++) {
if (spans[i].className == "footnote") {
n++;
// Use [\s\S] in place of . so multi-line matches work.
// Because JavaScript has no s (dotall) regex flag.
note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
noteholder.innerHTML +=
"<div class='footnote' id='_footnote_" + n + "'>" +
"<a href='#_footnoteref_" + n + "' title='Return to text'>" +
n + "</a>. " + note + "</div>";
spans[i].innerHTML =
"[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
"' title='View footnote' class='footnote'>" + n + "</a>]";
var id =spans[i].getAttribute("id");
if (id != null) refs["#"+id] = n;
}
}
if (n == 0)
noteholder.parentNode.removeChild(noteholder);
else {
// Process footnoterefs.
for (i=0; i<spans.length; i++) {
if (spans[i].className == "footnoteref") {
var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
href = href.match(/#.*/)[0]; // Because IE return full URL.
n = refs[href];
spans[i].innerHTML =
"[<a href='#_footnote_" + n +
"' title='View footnote' class='footnote'>" + n + "</a>]";
}
}
}
}
};
(function() {
var includes = ['sh_main.js', 'sh_javascript.min.js', 'sh_vim-dark.css'];
var head = document.getElementsByTagName("head")[0];
for (var i = 0; i < includes.length; i ++) {
var ext = includes[i].match(/\.([^.]+)$/);
switch (ext[1]) {
case 'js':
var element = document.createElement('script');
element.type = 'text/javascript';
element.src = includes[i];
break;
case 'css':
var element = document.createElement('link');
element.type = 'text/css';
element.rel = 'stylesheet';
element.media = 'screen';
element.href = includes[i];
break;
}
head.appendChild(element);
}
var i = setInterval(function () {
if (window["sh_highlightDocument"]) {
sh_highlightDocument();
try {
var pageTracker = _gat._getTracker("UA-10874194-2");
pageTracker._trackPageview();
} catch(err) {}
clearInterval(i);
}
}, 100);
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
})();

20
doc/index.html

@ -29,7 +29,7 @@
</div>
<div id="content">
<!-- <h1><a href="http://tinyclouds.org/node">Node</a></h1> -->
<!-- <h1><a href="http://nodejs.org/">Node</a></h1> -->
<img id="logo" src="logo.png" alt="node.js"/>
<p id="introduction">
@ -48,8 +48,8 @@ var sys = require('sys'),
http.createServer(function (req, res) {
setTimeout(function () {
res.sendHeader(200, {'Content-Type': 'text/plain'});
res.sendBody('Hello World');
res.finish();
res.write('Hello World');
res.close();
}, 2000);
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/');</pre>
@ -74,13 +74,13 @@ var tcp = require('tcp');
var server = tcp.createServer(function (socket) {
socket.setEncoding("utf8");
socket.addListener("connect", function () {
socket.send("hello\r\n");
socket.write("hello\r\n");
});
socket.addListener("receive", function (data) {
socket.send(data);
socket.write(data);
});
socket.addListener("eof", function () {
socket.send("goodbye\r\n");
socket.write("goodbye\r\n");
socket.close();
});
});
@ -97,9 +97,8 @@ server.listen(7000, "localhost");</pre>
<a href="http://github.com/ry/node/tree/master">git repo</a>
</p>
<p>
2010.02.09
<a
href="http://s3.amazonaws.com/four.livejournal/20100209/node-v0.1.28.tar.gz">node-v0.1.28.tar.gz</a>
2010.02.17
<a href="http://nodejs.org/dist/node-v0.1.29.tar.gz">node-v0.1.29.tar.gz</a>
</p>
<h2 id="build">Build</h2>
@ -110,7 +109,8 @@ server.listen(7000, "localhost");</pre>
tested on <b>Linux</b>, <b>Macintosh</b>, and <b>FreeBSD</b>. The
build system requires Python 2.4 or better. V8, on which Node is
built, supports only IA-32 and ARM processors. V8 is included in the
Node distribution. There are no other dependencies.
Node distribution. To use TLS, GnuTLS and libgpg-error are required.
There are no other dependencies.
</p>
<pre class="sh_none">

157
lib/file.js

@ -1,156 +1 @@
var posix = require("./posix");
var events = require('events');
/*jslint onevar: true, undef: true, eqeqeq: true, plusplus: true, regexp: true, newcap: true, immed: true */
/*globals exports, node, __filename */
exports.debugLevel = 0; // Increase to get more verbose debug output
function debugMessage (msg) {
if (exports.debugLevel > 0) {
process.error(__filename + ": " + msg.toString());
}
}
function debugObject (obj) {
if (exports.debugLevel > 0) {
process.error(__filename + ": " + JSON.stringify(obj));
}
}
exports.read = posix.cat;
exports.write = function (filename, data, encoding) {
var promise = new events.Promise();
encoding = encoding || "utf8"; // default to utf8
posix.open(filename, process.O_WRONLY | process.O_TRUNC | process.O_CREAT, 0666)
.addCallback(function (fd) {
function doWrite (_data) {
posix.write(fd, _data, 0, encoding)
.addErrback(function () {
posix.close(fd);
promise.emitError();
})
.addCallback(function (written) {
if (written === _data.length) {
posix.close(fd);
promise.emitSuccess();
} else {
doWrite(_data.slice(written));
}
});
}
doWrite(data);
})
.addErrback(function () {
promise.emitError();
});
return promise;
};
exports.File = function (filename, mode, options) {
var self = this;
options = options || {};
self.encoding = options.encoding || "utf8";
self.filename = filename;
self.actionQueue = [];
self.currentAction = null;
switch (mode) {
case "r":
self.flags = process.O_RDONLY;
break;
case "r+":
self.flags = process.O_RDWR;
break;
case "w":
self.flags = process.O_CREAT | process.O_TRUNC | process.O_WRONLY;
break;
case "w+":
self.flags = process.O_CREAT | process.O_TRUNC | process.O_RDWR;
break;
case "a":
self.flags = process.O_APPEND | process.O_CREAT | process.O_WRONLY;
break;
case "a+":
self.flags = process.O_APPEND | process.O_CREAT | process.O_RDWR;
break;
default:
throw new Error("Unknown mode");
}
self.open(self.filename, self.flags, 0666).addCallback(function (fd) {
debugMessage(self.filename + " opened. fd = " + fd);
self.fd = fd;
}).addErrback(function () {
self.emit("error", ["open"]);
});
};
var proto = exports.File.prototype;
proto._maybeDispatch = function () {
var self, args, method, promise, userPromise;
self = this;
if (self.currentAction) { return; }
self.currentAction = self.actionQueue.shift();
if (!self.currentAction) { return; }
debugObject(self.currentAction);
args = self.currentAction.args || [];
method = self.currentAction.method;
if (method !== "open") {
args.unshift(self.fd);
}
if (!args[3] && (method === "read" || method === "write")) {
args[3] = self.encoding;
}
promise = posix[method].apply(self, args);
userPromise = self.currentAction.promise;
promise.addCallback(function () {
process.assert(self.currentAction.promise === userPromise);
userPromise.emitSuccess.apply(userPromise, arguments);
self.currentAction = null;
self._maybeDispatch();
}).addErrback(function () {
debugMessage("Error in method " + method);
process.assert(self.currentAction.promise === userPromise);
userPromise.emitError.apply(userPromise, arguments);
self.currentAction = null;
self._maybeDispatch();
});
};
proto._queueAction = function (method, args) {
var userPromise = new events.Promise();
this.actionQueue.push({ method: method, args: args, promise: userPromise });
this._maybeDispatch();
return userPromise;
};
(["open", "write", "read", "close"]).forEach(function (name) {
proto[name] = function () {
return this._queueAction(name, Array.prototype.slice.call(arguments, 0));
};
});
throw new Error("The 'file' module has been removed. 'file.read' is now 'fs.readFile', and 'file.write' is now 'fs.writeFile'.");

83
lib/http.js

@ -114,7 +114,7 @@ function OutgoingMessage () {
sys.inherits(OutgoingMessage, events.EventEmitter);
exports.OutgoingMessage = OutgoingMessage;
OutgoingMessage.prototype.send = function (data, encoding) {
OutgoingMessage.prototype._send = function (data, encoding) {
var length = this.output.length;
if (length === 0) {
@ -200,19 +200,27 @@ OutgoingMessage.prototype.sendHeaderLines = function (first_line, headers) {
message_header += CRLF;
this.send(message_header);
// wait until the first body chunk, or finish(), is sent to flush.
this._send(message_header);
// wait until the first body chunk, or close(), is sent to flush.
};
OutgoingMessage.prototype.sendBody = function (chunk, encoding) {
OutgoingMessage.prototype.sendBody = function () {
throw new Error("sendBody() has been renamed to write(). " +
"The 'body' event has been renamed to 'data' and " +
"the 'complete' event has been renamed to 'end'.");
};
OutgoingMessage.prototype.write = function (chunk, encoding) {
encoding = encoding || "ascii";
if (this.chunked_encoding) {
this.send(process._byteLength(chunk, encoding).toString(16));
this.send(CRLF);
this.send(chunk, encoding);
this.send(CRLF);
this._send(process._byteLength(chunk, encoding).toString(16));
this._send(CRLF);
this._send(chunk, encoding);
this._send(CRLF);
} else {
this.send(chunk, encoding);
this._send(chunk, encoding);
}
if (this.flushing) {
@ -227,7 +235,11 @@ OutgoingMessage.prototype.flush = function () {
};
OutgoingMessage.prototype.finish = function () {
if (this.chunked_encoding) this.send("0\r\n\r\n"); // last chunk
throw new Error("finish() has been renamed to close().");
};
OutgoingMessage.prototype.close = function () {
if (this.chunked_encoding) this._send("0\r\n\r\n"); // last chunk
this.finished = true;
this.flush();
};
@ -267,9 +279,20 @@ function ClientRequest (method, url, headers) {
sys.inherits(ClientRequest, OutgoingMessage);
exports.ClientRequest = ClientRequest;
ClientRequest.prototype.finish = function (responseListener) {
this.addListener("response", responseListener);
OutgoingMessage.prototype.finish.call(this);
ClientRequest.prototype.finish = function () {
throw new Error( "finish() has been renamed to close() and no longer takes "
+ "a response handler as an argument. Manually add a 'response' listener "
+ "to the request object."
);
};
ClientRequest.prototype.close = function () {
if (arguments.length > 0) {
throw new Error( "ClientRequest.prototype.close does not take any arguments. "
+ "Add a response listener manually to the request object."
);
}
OutgoingMessage.prototype.close.call(this);
};
@ -333,11 +356,11 @@ function createIncomingMessageStream (connection, incoming_listener) {
});
connection.addListener("body", function (chunk) {
incoming.emit("body", chunk);
incoming.emit('data', chunk);
});
connection.addListener("messageComplete", function () {
incoming.emit("complete");
incoming.emit('end');
});
return stream;
@ -357,7 +380,7 @@ function flushMessageQueue (connection, queue) {
var data = message.output.shift();
var encoding = message.outputEncodings.shift();
connection.send(data, encoding);
connection.write(data, encoding);
}
if (!message.finished) break;
@ -387,7 +410,7 @@ function connectionListener (connection) {
connection.resetParser();
// is this really needed?
connection.addListener("eof", function () {
connection.addListener("end", function () {
if (responses.length == 0) {
connection.close();
} else {
@ -456,8 +479,8 @@ exports.createClient = function (port, host) {
currentRequest.flush();
});
client.addListener("eof", function () {
//sys.debug("client got eof closing. readyState = " + client.readyState);
client.addListener("end", function () {
//sys.debug("client got end closing. readyState = " + client.readyState);
client.close();
});
@ -486,7 +509,7 @@ exports.createClient = function (port, host) {
createIncomingMessageStream(client, function (res) {
//sys.debug("incoming response!");
res.addListener("complete", function ( ) {
res.addListener('end', function ( ) {
//sys.debug("request complete disconnecting. readyState = " + client.readyState);
client.close();
});
@ -545,27 +568,29 @@ exports.cat = function (url, encoding, headers) {
if (!hasHost) {
headers["Host"] = url.hostname;
}
var content = "";
var client = exports.createClient(url.port || 80, url.hostname);
var req = client.request((url.pathname || "/")+(url.search || "")+(url.hash || ""), headers);
client.addListener("error", function () {
promise.emitError();
});
var content = "";
req.finish(function (res) {
req.addListener('response', function (res) {
if (res.statusCode < 200 || res.statusCode >= 300) {
promise.emitError(res.statusCode);
return;
}
res.setBodyEncoding(encoding);
res.addListener("body", function (chunk) { content += chunk; });
res.addListener("complete", function () {
res.addListener('data', function (chunk) { content += chunk; });
res.addListener('end', function () {
promise.emitSuccess(content);
});
});
client.addListener("error", function () {
promise.emitError();
});
req.close();
return promise;
};

4
lib/multipart.js

@ -69,8 +69,8 @@ function Stream (message) {
w = isMultiPart ? writer(this) : simpleWriter(this),
e = ender(this);
if (message.addListener) {
message.addListener("body", w);
message.addListener("complete", e);
message.addListener("data", w);
message.addListener("end", e);
if (message.pause && message.resume) {
this._pause = message;
}

1
lib/posix.js

@ -0,0 +1 @@
throw new Error("The 'posix' module has been renamed to 'fs'");

32
lib/sys.js

@ -1,11 +1,15 @@
var events = require('events');
exports.print = function (x) {
process.stdio.write(x);
exports.print = function () {
for (var i = 0, len = arguments.length; i < len; ++i) {
process.stdio.write(arguments[i]);
}
};
exports.puts = function (x) {
process.stdio.write(x + "\n");
exports.puts = function () {
for (var i = 0, len = arguments.length; i < len; ++i) {
process.stdio.write(arguments[i] + '\n');
}
};
exports.debug = function (x) {
@ -13,7 +17,9 @@ exports.debug = function (x) {
};
exports.error = function (x) {
process.stdio.writeError(x + "\n");
for (var i = 0, len = arguments.length; i < len; ++i) {
process.stdio.writeError(arguments[i] + '\n');
}
};
/**
@ -53,6 +59,11 @@ exports.inspect = function (obj, showHidden) {
}
}
// Dates without properties can be shortcutted
if (value instanceof Date && keys.length === 0) {
return value.toUTCString();
}
var base, type, braces;
// Determine the object type
if (value instanceof Array) {
@ -69,6 +80,11 @@ exports.inspect = function (obj, showHidden) {
} else {
base = "";
}
// Make dates with properties first say the date
if (value instanceof Date) {
base = ' ' + value.toUTCString();
}
seen.push(value);
@ -116,8 +132,10 @@ exports.inspect = function (obj, showHidden) {
return format(obj);
};
exports.p = function (x) {
exports.error(exports.inspect(x));
exports.p = function () {
for (var i = 0, len = arguments.length; i < len; ++i) {
exports.error(exports.inspect(arguments[i]));
}
};
exports.exec = function (command) {

69
src/node.cc

@ -322,15 +322,15 @@ const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<str conversion failed>";
}
static void ReportException(TryCatch *try_catch, bool show_line = false) {
Handle<Message> message = try_catch->Message();
static void ReportException(TryCatch &try_catch, bool show_line = false) {
Handle<Message> message = try_catch.Message();
if (message.IsEmpty()) {
fprintf(stderr, "Error: (no message)\n");
fflush(stderr);
return;
}
Handle<Value> error = try_catch->Exception();
Handle<Value> error = try_catch.Exception();
Handle<String> stack;
if (error->IsObject()) {
@ -377,13 +377,13 @@ Local<Value> ExecuteString(Local<String> source, Local<Value> filename) {
Local<Script> script = Script::Compile(source, filename);
if (script.IsEmpty()) {
ReportException(&try_catch);
ReportException(try_catch);
exit(1);
}
Local<Value> result = script->Run();
if (result.IsEmpty()) {
ReportException(&try_catch);
ReportException(try_catch);
exit(1);
}
@ -428,15 +428,15 @@ static Handle<Value> Unloop(const Arguments& args) {
static Handle<Value> Chdir(const Arguments& args) {
HandleScope scope;
if (args.Length() != 1 || !args[0]->IsString()) {
return ThrowException(Exception::Error(String::New("Bad argument.")));
}
String::Utf8Value path(args[0]->ToString());
int r = chdir(*path);
if (r != 0) {
return ThrowException(Exception::Error(String::New(strerror(errno))));
}
@ -460,13 +460,13 @@ static Handle<Value> Cwd(const Arguments& args) {
static Handle<Value> Umask(const Arguments& args){
HandleScope scope;
if(args.Length() < 1 || !args[0]->IsInt32()) {
if(args.Length() < 1 || !args[0]->IsInt32()) {
return ThrowException(Exception::TypeError(
String::New("argument must be an integer.")));
}
unsigned int mask = args[0]->Uint32Value();
unsigned int old = umask((mode_t)mask);
return scope.Close(Uint32::New(old));
}
@ -596,7 +596,6 @@ error:
#include <mach/mach_init.h>
int getmem(size_t *rss, size_t *vsize) {
task_t task = MACH_PORT_NULL;
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
@ -617,7 +616,6 @@ int getmem(size_t *rss, size_t *vsize) {
#ifdef __linux__
# define HAVE_GETMEM 1
# include <sys/param.h> /* for MAXPATHLEN */
# include <sys/user.h> /* for PAGE_SIZE */
int getmem(size_t *rss, size_t *vsize) {
FILE *f = fopen("/proc/self/stat", "r");
@ -626,6 +624,7 @@ int getmem(size_t *rss, size_t *vsize) {
int itmp;
char ctmp;
char buffer[MAXPATHLEN];
size_t page_size = getpagesize();
/* PID */
if (fscanf(f, "%d ", &itmp) == 0) goto error;
@ -678,7 +677,7 @@ int getmem(size_t *rss, size_t *vsize) {
/* Resident set size */
if (fscanf (f, "%u ", &itmp) == 0) goto error;
*rss = (size_t) itmp * PAGE_SIZE;
*rss = (size_t) itmp * page_size;
/* rlim */
if (fscanf (f, "%u ", &itmp) == 0) goto error;
@ -740,11 +739,11 @@ v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
v8::Handle<v8::Value> Kill(const v8::Arguments& args) {
HandleScope scope;
if (args.Length() < 1 || !args[0]->IsNumber()) {
return ThrowException(Exception::Error(String::New("Bad argument.")));
}
pid_t pid = args[0]->IntegerValue();
int sig = SIGTERM;
@ -828,7 +827,7 @@ Handle<Value> Compile(const Arguments& args) {
Local<Script> script = Script::Compile(source, filename);
if (try_catch.HasCaught()) {
// Hack because I can't get a proper stacktrace on SyntaxError
ReportException(&try_catch, true);
ReportException(try_catch, true);
exit(1);
}
@ -854,7 +853,7 @@ void FatalException(TryCatch &try_catch) {
// Check if uncaught_exception_counter indicates a recursion
if (uncaught_exception_counter > 0) {
ReportException(&try_catch);
ReportException(try_catch);
exit(1);
}
@ -880,7 +879,7 @@ void FatalException(TryCatch &try_catch) {
uint32_t length = listener_array->Length();
// Report and exit if process has no "uncaughtException" listener
if (length == 0) {
ReportException(&try_catch);
ReportException(try_catch);
exit(1);
}
@ -906,7 +905,7 @@ static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
HandleScope scope;
assert(watcher == &debug_watcher);
assert(revents == EV_ASYNC);
ExecuteString(String::New("1+1;"), String::New("debug_poll"));
Debug::ProcessDebugMessages();
}
static void DebugMessageDispatch(void) {
@ -919,10 +918,6 @@ static void DebugMessageDispatch(void) {
}
static void ExecuteNativeJS(const char *filename, const char *data) {
HandleScope scope;
}
static void Load(int argc, char *argv[]) {
HandleScope scope;
@ -1042,40 +1037,41 @@ static void Load(int argc, char *argv[]) {
// 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'
#ifndef NDEBUG
TryCatch try_catch;
#endif
#endif
Local<Value> f_value = ExecuteString(String::New(native_node),
String::New("node.js"));
#ifndef NDEBUG
if (try_catch.HasCaught()) {
ReportException(&try_catch);
ReportException(try_catch);
exit(10);
}
#endif
#endif
assert(f_value->IsFunction());
Local<Function> f = Local<Function>::Cast(f_value);
// Now we call 'f' with the 'process' variable that we've built up with
// all our bindings. Inside node.js we'll take care of assigning things to
// their places.
// We start the process this way in order to be more modular. Developers
// who do not like how 'src/node.js' setups the module system but do like
// Node's I/O bindings may want to replace 'f' with their own function.
f->Call(global, 1, &Local<Value>::New(process));
Local<Value> args[1] = { Local<Value>::New(process) };
f->Call(global, 1, args);
#ifndef NDEBUG
if (try_catch.HasCaught()) {
ReportException(&try_catch);
ReportException(try_catch);
exit(11);
}
#endif
#endif
}
static void PrintHelp() {
@ -1084,7 +1080,7 @@ static void PrintHelp() {
" --debug enable remote debugging\n" // TODO specify port
" --cflags print pre-processor and compiler flags\n"
" --v8-options print v8 command line options\n\n"
"Documentation can be found at http://tinyclouds.org/node/api.html"
"Documentation can be found at http://nodejs.org/api.html"
" or with 'man node'\n");
}
@ -1162,18 +1158,15 @@ int main(int argc, char *argv[]) {
V8::SetFatalErrorHandler(node::OnFatalError);
#define AUTO_BREAK_FLAG "--debugger_auto_break"
// If the --debug flag was specified then initialize the debug thread.
if (node::use_debug_agent) {
// First apply --debugger_auto_break setting to V8. This is so we can
// enter V8 by just executing any bit of javascript
V8::SetFlagsFromString(AUTO_BREAK_FLAG, sizeof(AUTO_BREAK_FLAG));
// Initialize the async watcher for receiving messages from the debug
// thread and marshal it into the main thread. DebugMessageCallback()
// is called from the main thread to execute a random bit of javascript
// - which will give V8 control so it can handle whatever new message
// had been received on the debug thread.
ev_async_init(&node::debug_watcher, node::DebugMessageCallback);
ev_set_priority(&node::debug_watcher, EV_MAXPRI);
// Set the callback DebugMessageDispatch which is called from the debug
// thread.
Debug::SetDebugMessageDispatchHandler(node::DebugMessageDispatch);

122
src/node.js

@ -48,12 +48,12 @@ function Module (id, parent) {
this.exports = {};
this.parent = parent;
this.moduleCache = {};
if (parent) {
process.mixin(this.moduleCache, parent.moduleCache);
this.moduleCache[parent.id] = parent;
this.moduleCache = parent.moduleCache;
} else {
this.moduleCache = {};
}
this.moduleCache[this.id] = this;
this.filename = null;
this.loaded = false;
@ -263,7 +263,7 @@ var eventsModule = createInternalModule('events', function (exports) {
exports.Promise.prototype.addCallback = function (listener) {
if (this.hasFired === 'success') {
return listener.apply(this, this._values);
listener.apply(this, this._values);
}
return this.addListener("success", listener);
@ -296,6 +296,18 @@ var eventsModule = createInternalModule('events', function (exports) {
var ret;
var hadError = false;
if (this.hasFired) {
ret = (this._values.length == 1)
? this._values[0]
: this.values;
if (this.hasFired == 'success') {
return ret;
} else if (this.hasFired == 'error') {
throw ret;
}
}
self.addCallback(function () {
if (arguments.length == 1) {
ret = arguments[0];
@ -339,7 +351,8 @@ var events = eventsModule.exports;
var nextTickQueue = [];
var nextTickWatcher = new process.IdleWatcher();
nextTickWatcher.setPriority(process.EVMAXPRI); // max priority
// Only debugger has maximum priority. Below that is the nextTickWatcher.
nextTickWatcher.setPriority(process.EVMAXPRI-1);
nextTickWatcher.callback = function () {
var l = nextTickQueue.length;
@ -500,7 +513,7 @@ function debug (x) {
var posixModule = createInternalModule("posix", function (exports) {
var fsModule = createInternalModule("fs", function (exports) {
exports.Stats = process.Stats;
function callback (promise) {
@ -513,6 +526,23 @@ var posixModule = createInternalModule("posix", function (exports) {
}
};
}
// Used by fs.open and friends
function stringToFlags(flag) {
// Only mess with strings
if (typeof flag !== 'string') {
return flag;
}
switch (flag) {
case "r": return process.O_RDONLY;
case "r+": return process.O_RDWR;
case "w": return process.O_CREAT | process.O_TRUNC | process.O_WRONLY;
case "w+": return process.O_CREAT | process.O_TRUNC | process.O_RDWR;
case "a": return process.O_APPEND | process.O_CREAT | process.O_WRONLY;
case "a+": return process.O_APPEND | process.O_CREAT | process.O_RDWR;
default: throw new Error("Unknown file open flag: " + flag);
}
}
// Yes, the follow could be easily DRYed up but I provide the explicit
// list to make the arguments clear.
@ -528,13 +558,15 @@ var posixModule = createInternalModule("posix", function (exports) {
};
exports.open = function (path, flags, mode) {
if (mode === undefined) { mode = 0666; }
var promise = new events.Promise();
process.fs.open(path, flags, mode, callback(promise));
process.fs.open(path, stringToFlags(flags), mode, callback(promise));
return promise;
};
exports.openSync = function (path, flags, mode) {
return process.fs.open(path, flags, mode);
if (mode === undefined) { mode = 0666; }
return process.fs.open(path, stringToFlags(flags), mode);
};
exports.read = function (fd, length, position, encoding) {
@ -641,13 +673,54 @@ var posixModule = createInternalModule("posix", function (exports) {
return process.fs.unlink(path);
};
exports.writeFile = function (path, data, encoding) {
var promise = new events.Promise();
encoding = encoding || "utf8"; // default to utf8
exports.cat = function (path, encoding) {
fs.open(path, "w")
.addCallback(function (fd) {
function doWrite (_data) {
fs.write(fd, _data, 0, encoding)
.addErrback(function () {
fs.close(fd);
promise.emitError();
})
.addCallback(function (written) {
if (written === _data.length) {
fs.close(fd);
promise.emitSuccess();
} else {
doWrite(_data.slice(written));
}
});
}
doWrite(data);
})
.addErrback(function () {
promise.emitError();
});
return promise;
};
exports.writeFileSync = function (path, data, encoding) {
encoding = encoding || "utf8"; // default to utf8
var fd = exports.openSync(path, "w");
return process.fs.write(fd, data, 0, encoding);
};
exports.cat = function () {
throw new Error("fs.cat is deprecated. Please use fs.readFile instead.");
};
exports.readFile = function (path, encoding) {
var promise = new events.Promise();
encoding = encoding || "utf8"; // default to utf8
exports.open(path, process.O_RDONLY, 0666).addCallback(function (fd) {
exports.open(path, "r").addCallback(function (fd) {
var content = "", pos = 0;
function readChunk () {
@ -675,9 +748,30 @@ var posixModule = createInternalModule("posix", function (exports) {
});
return promise;
};
exports.catSync = function () {
throw new Error("fs.catSync is deprecated. Please use fs.readFileSync instead.");
};
exports.readFileSync = function (path, encoding) {
encoding = encoding || "utf8"; // default to utf8
var
fd = exports.openSync(path, "r"),
content = '',
pos = 0,
r;
while ((r = exports.readSync(fd, 16*1024, pos, encoding)) && r[0]) {
content += r[0];
pos += r[1]
}
return content;
};
});
var posix = posixModule.exports;
var fs = fsModule.exports;
var pathModule = createInternalModule("path", function (exports) {
@ -739,7 +833,7 @@ var pathModule = createInternalModule("path", function (exports) {
};
exports.exists = function (path, callback) {
var p = posix.stat(path);
var p = fs.stat(path);
p.addCallback(function () { callback(true); });
p.addErrback(function () { callback(false); });
};
@ -909,7 +1003,7 @@ function cat (id, loadPromise) {
loadPromise.emitError(new Error("could not load core module \"http\""));
});
} else {
promise = posix.cat(id);
promise = fs.readFile(id);
}
return promise;

5
src/node_file.cc

@ -412,7 +412,10 @@ static Handle<Value> Read(const Arguments& args) {
ret = pread(fd, buf, MIN(len, READ_BUF_LEN), offset);
}
if (ret < 0) return ThrowException(errno_exception(errno));
return scope.Close(Integer::New(ret));
Local<Array> a = Array::New(2);
a->Set(Integer::New(0), Encode(buf, ret, encoding));
a->Set(Integer::New(1), Integer::New(ret));
return scope.Close(a);
}
}

6
src/node_http.cc

@ -27,7 +27,7 @@ static Persistent<String> header_field_symbol;
static Persistent<String> header_value_symbol;
static Persistent<String> header_complete_symbol;
static Persistent<String> body_symbol;
static Persistent<String> eof_symbol;
static Persistent<String> end_symbol;
static Persistent<String> delete_sym;
static Persistent<String> get_sym;
@ -66,7 +66,7 @@ HTTPConnection::Initialize (Handle<Object> target)
NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "resetParser", ResetParser);
server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection"));
eof_symbol = NODE_PSYMBOL("eof");
end_symbol = NODE_PSYMBOL("end");
}
@ -123,7 +123,7 @@ HTTPConnection::OnEOF ()
assert(refs_);
size_t nparsed;
nparsed = http_parser_execute(&parser_, NULL, 0);
Emit(eof_symbol, 0, NULL);
Emit(end_symbol, 0, NULL);
}
int

31
src/node_net.cc

@ -32,12 +32,12 @@ static Persistent<String> write_only_symbol;
static Persistent<String> closing_symbol;
static Persistent<String> closed_symbol;
static Persistent<String> receive_symbol;
static Persistent<String> data_symbol;
static Persistent<String> connection_symbol;
static Persistent<String> connect_symbol;
static Persistent<String> timeout_symbol;
static Persistent<String> drain_symbol;
static Persistent<String> eof_symbol;
static Persistent<String> end_symbol;
static Persistent<String> close_symbol;
static const struct addrinfo server_tcp_hints =
@ -76,12 +76,12 @@ void Connection::Initialize(v8::Handle<v8::Object> target) {
closing_symbol = NODE_PSYMBOL("closing");
closed_symbol = NODE_PSYMBOL("closed");
receive_symbol = NODE_PSYMBOL("receive");
data_symbol = NODE_PSYMBOL("data");
connection_symbol = NODE_PSYMBOL("connection");
connect_symbol = NODE_PSYMBOL("connect");
timeout_symbol = NODE_PSYMBOL("timeout");
drain_symbol = NODE_PSYMBOL("drain");
eof_symbol = NODE_PSYMBOL("eof");
end_symbol = NODE_PSYMBOL("end");
close_symbol = NODE_PSYMBOL("close");
Local<FunctionTemplate> t = FunctionTemplate::New(New);
@ -96,6 +96,7 @@ void Connection::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "connect", Connect);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "send", Send);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "write", Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", Close);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "forceClose", ForceClose);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "setEncoding", SetEncoding);
@ -112,12 +113,12 @@ void Connection::Initialize(v8::Handle<v8::Object> target) {
#endif
// Getter for connection.readyState
constructor_template->PrototypeTemplate()->SetAccessor(
constructor_template->InstanceTemplate()->SetAccessor(
ready_state_symbol,
ReadyStateGetter);
// Getter for connection.readyState
constructor_template->PrototypeTemplate()->SetAccessor(
constructor_template->InstanceTemplate()->SetAccessor(
fd_symbol,
FDGetter);
@ -225,7 +226,7 @@ Handle<Value> Connection::Connect(const Arguments& args) {
}
// If connect() is called on an open connection, raise an error.
if (connection->ReadyState() != EVCOM_INITIALIZED) {
if (connection->ReadyState() != EVCOM_INITIALIZED || connection->resolving_) {
Local<Value> exception = Exception::Error(
String::New("Socket is not in CLOSED state."));
return ThrowException(exception);
@ -586,7 +587,17 @@ Handle<Value> Connection::SetNoDelay(const Arguments& args) {
return Undefined();
}
Handle<Value> Connection::Send(const Arguments& args) {
HandleScope scope;
return ThrowException(Exception::Error(String::New(
"connection.send() has been renamed to connection.write(). "
"(Also the 'receive' event has been renamed to 'data' and "
"the 'eof' event has been renamed to 'end'.)")));
}
Handle<Value> Connection::Write(const Arguments& args) {
HandleScope scope;
Connection *connection = ObjectWrap::Unwrap<Connection>(args.Holder());
assert(connection);
@ -609,7 +620,7 @@ Handle<Value> Connection::Send(const Arguments& args) {
char * buf = new char[len];
ssize_t written = DecodeWrite(buf, len, args[0], enc);
assert(written == len);
connection->Send(buf, written);
connection->Write(buf, written);
delete [] buf;
return scope.Close(Integer::New(written));
@ -618,7 +629,7 @@ Handle<Value> Connection::Send(const Arguments& args) {
void Connection::OnReceive(const void *buf, size_t len) {
HandleScope scope;
Local<Value> data = Encode(buf, len, encoding_);
Emit(receive_symbol, 1, &data);
Emit(data_symbol, 1, &data);
}
void Connection::OnClose() {
@ -656,7 +667,7 @@ void Connection::OnDrain() {
void Connection::OnEOF() {
HandleScope scope;
Emit(eof_symbol, 0, NULL);
Emit(end_symbol, 0, NULL);
}
Persistent<FunctionTemplate> Server::constructor_template;

3
src/node_net.h

@ -27,6 +27,7 @@ class Connection : public EventEmitter {
static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> Connect(const v8::Arguments& args);
static v8::Handle<v8::Value> Send(const v8::Arguments& args);
static v8::Handle<v8::Value> Write(const v8::Arguments& args);
static v8::Handle<v8::Value> SendUtf8(const v8::Arguments& args);
static v8::Handle<v8::Value> Close(const v8::Arguments& args);
static v8::Handle<v8::Value> ForceClose(const v8::Arguments& args);
@ -61,7 +62,7 @@ class Connection : public EventEmitter {
return evcom_stream_connect(&stream_, address);
}
void Send(const char *buf, size_t len) {
void Write(const char *buf, size_t len) {
evcom_stream_write(&stream_, buf, len);
}

2
src/node_timer.cc

@ -27,7 +27,7 @@ Timer::Initialize (Handle<Object> target)
NODE_SET_PROTOTYPE_METHOD(constructor_template, "start", Timer::Start);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "stop", Timer::Stop);
constructor_template->PrototypeTemplate()->SetAccessor(repeat_symbol,
constructor_template->InstanceTemplate()->SetAccessor(repeat_symbol,
RepeatGetter, RepeatSetter);
target->Set(String::NewSymbol("Timer"), constructor_template->GetFunction());

2
test/mjsunit/common.js

@ -11,5 +11,5 @@ var sys = require("sys");
process.mixin(exports, sys);
exports.assert = require('assert');
exports.posix = require("posix");
exports.fs = require("fs");
exports.path = path;

4
test/mjsunit/disabled/test-fs-sendfile.js

@ -19,8 +19,8 @@ server.listen(PORT);
var client = tcp.createConnection(PORT);
client.addListener("connect", function () {
posix.open(x,process.O_RDONLY, 0666).addCallback(function (fd) {
posix.sendfile(client.fd, fd, 0, expected.length).addCallback(function (size) {
fs.open(x, 'r').addCallback(function (fd) {
fs.sendfile(client.fd, fd, 0, expected.length).addCallback(function (size) {
assert.equal(expected.length, size);
});
});

1
test/mjsunit/fixtures/a.js

@ -4,6 +4,7 @@ debug("load fixtures/a.js");
var string = "A";
exports.SomeClass = c.SomeClass;
exports.A = function () {
return string;

4
test/mjsunit/fixtures/b/c.js

@ -10,6 +10,10 @@ debug("load fixtures/b/c.js");
var string = "C";
exports.SomeClass = function() {
};
exports.C = function () {
return string;
};

38
test/mjsunit/test-buffered-file.js

@ -1,38 +0,0 @@
process.mixin(require("./common"));
var testTxt = path.join(fixturesDir, "test.txt");
var libDir = path.join(testDir, "../../lib");
require.paths.unshift(libDir);
process.mixin(require("file"));
var fileUnlinked = false;
var file = new File(testTxt, "w+");
file.write("hello\n");
file.write("world\n");
setTimeout(function () {
file.write("hello\n");
file.write("world\n");
file.close().addCallback(function () {
error("file closed...");
var out = posix.cat(testTxt).wait();
print("the file contains: ");
p(out);
assert.equal("hello\nworld\nhello\nworld\n", out);
var file2 = new File(testTxt, "r");
file2.read(5).addCallback(function (data) {
puts("read(5): " + JSON.stringify(data));
assert.equal("hello", data);
posix.unlink(testTxt).addCallback(function () {
fileUnlinked = true;
});
});
file2.close();
});
}, 10);
process.addListener("exit", function () {
assert.equal(true, fileUnlinked);
puts("done");
});

20
test/mjsunit/test-eio-race.js

@ -2,18 +2,18 @@ process.mixin(require("./common"));
var
count = 100,
posix = require('posix');
fs = require('fs');
function tryToKillEventLoop() {
puts('trying to kill event loop ...');
posix.stat(__filename)
fs.stat(__filename)
.addCallback(function() {
puts('first posix.stat succeeded ...');
puts('first fs.stat succeeded ...');
posix.stat(__filename)
fs.stat(__filename)
.addCallback(function() {
puts('second posix.stat succeeded ...');
puts('second fs.stat succeeded ...');
puts('could not kill event loop, retrying...');
setTimeout(function () {
@ -25,26 +25,26 @@ function tryToKillEventLoop() {
}, 1);
})
.addErrback(function() {
throw new Exception('second posix.stat failed')
throw new Exception('second fs.stat failed')
})
})
.addErrback(function() {
throw new Exception('first posix.stat failed')
throw new Exception('first fs.stat failed')
});
}
// Generate a lot of thread pool events
var pos = 0;
posix.open('/dev/zero', process.O_RDONLY, 0666).addCallback(function (rd) {
fs.open('/dev/zero', "r").addCallback(function (rd) {
function readChunk () {
posix.read(rd, 1024, pos, 'binary').addCallback(function (chunk, bytesRead) {
fs.read(rd, 1024, pos, 'binary').addCallback(function (chunk, bytesRead) {
if (chunk) {
pos += bytesRead;
//puts(pos);
readChunk();
} else {
posix.close(rd);
fs.close(rd);
throw new Exception(BIG_FILE+' should not end before the issue shows up');
}
}).addErrback(function () {

4
test/mjsunit/test-eio-race2.js

@ -1,6 +1,6 @@
process.mixin(require("./common"));
var testTxt = path.join(fixturesDir, "x.txt");
var posix = require('posix');
var fs = require('fs');
setTimeout(function () {
// put this in a timeout, just so it doesn't get bunched up with the
@ -8,7 +8,7 @@ setTimeout(function () {
N = 30;
for (var i=0; i < N; i++) {
puts("start " + i);
posix.cat(testTxt).addCallback(function(data) {
fs.readFile(testTxt).addCallback(function(data) {
puts("finish");
}).addErrback(function (e) {
puts("error! " + e);

4
test/mjsunit/test-eio-race3.js

@ -2,10 +2,10 @@ process.mixin(require("./common"));
puts('first stat ...');
posix.stat(__filename)
fs.stat(__filename)
.addCallback( function(stats) {
puts('second stat ...');
posix.stat(__filename)
fs.stat(__filename)
.timeout(1000)
.wait();

2
test/mjsunit/test-eio-race4.js

@ -4,7 +4,7 @@ var N = 100;
var j = 0;
for (var i = 0; i < N; i++) {
posix.stat("does-not-exist-" + i) // these files don't exist
fs.stat("does-not-exist-" + i) // these files don't exist
.addErrback(function (e) {
j++; // only makes it to about 17
puts("finish " + j);

2
test/mjsunit/test-file-cat-noexist.js → test/mjsunit/test-file-read-noexist.js

@ -2,7 +2,7 @@ process.mixin(require("./common"));
var got_error = false;
var filename = path.join(fixturesDir, "does_not_exist.txt");
var promise = posix.cat(filename, "raw");
var promise = fs.readFile(filename, "raw");
promise.addCallback(function (content) {
debug("cat returned some content: " + content);

4
test/mjsunit/test-fs-stat.js

@ -4,7 +4,7 @@ var got_error = false;
var success_count = 0;
var stats;
var promise = posix.stat(".");
var promise = fs.stat(".");
promise.addCallback(function (_stats) {
stats = _stats;
@ -17,7 +17,7 @@ promise.addErrback(function () {
});
puts("stating: " + __filename);
posix.stat(__filename).addCallback(function (s) {
fs.stat(__filename).addCallback(function (s) {
p(s);
success_count++;

10
test/mjsunit/test-fs-write.js

@ -4,12 +4,12 @@ var fn = path.join(fixturesDir, "write.txt");
var expected = "hello";
var found;
posix.open(fn, process.O_WRONLY | process.O_TRUNC | process.O_CREAT, 0644).addCallback(function (file) {
posix.write(file, expected, 0, "utf8").addCallback(function() {
posix.close(file).addCallback(function() {
posix.cat(fn, process.UTF8).addCallback(function(contents) {
fs.open(fn, 'w', 0644).addCallback(function (file) {
fs.write(file, expected, 0, "utf8").addCallback(function() {
fs.close(file).addCallback(function() {
fs.readFile(fn, process.UTF8).addCallback(function(contents) {
found = contents;
posix.unlink(fn).wait();
fs.unlink(fn).wait();
});
});
});

10
test/mjsunit/test-http-1.0.js

@ -10,8 +10,8 @@ var client_got_eof = false;
var server = http.createServer(function (req, res) {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody(body);
res.finish();
res.write(body);
res.close();
})
server.listen(port);
@ -20,15 +20,15 @@ var c = tcp.createConnection(port);
c.setEncoding("utf8");
c.addListener("connect", function () {
c.send( "GET / HTTP/1.0\r\n\r\n" );
c.write( "GET / HTTP/1.0\r\n\r\n" );
});
c.addListener("receive", function (chunk) {
c.addListener("data", function (chunk) {
puts(chunk);
server_response += chunk;
});
c.addListener("eof", function () {
c.addListener("end", function () {
client_got_eof = true;
c.close();
server.close();

4
test/mjsunit/test-http-cat.js

@ -9,8 +9,8 @@ var server = http.createServer(function (req, res) {
["Content-Length", body.length],
["Content-Type", "text/plain"]
]);
res.sendBody(body);
res.finish();
res.write(body);
res.close();
});
server.listen(PORT);

6
test/mjsunit/test-http-chunked.js

@ -6,8 +6,8 @@ var UTF8_STRING = "Il était tué";
var server = http.createServer(function(req, res) {
res.sendHeader(200, {"Content-Type": "text/plain; charset=utf8"});
res.sendBody(UTF8_STRING, 'utf8');
res.finish();
res.write(UTF8_STRING, 'utf8');
res.close();
});
server.listen(PORT);
@ -19,4 +19,4 @@ http.cat("http://localhost:"+PORT+"/", "utf8")
.addErrback(function() {
assert.ok(false, 'http.cat should succeed in < 1000ms');
})
.timeout(1000);
.timeout(1000);

20
test/mjsunit/test-http-client-race.js

@ -11,8 +11,8 @@ var server = http.createServer(function (req, res) {
res.sendHeader(200, { "Content-Type": "text/plain"
, "Content-Length": body.length
});
res.sendBody(body);
res.finish();
res.write(body);
res.close();
});
server.listen(PORT);
@ -21,21 +21,25 @@ var client = http.createClient(PORT);
var body1 = "";
var body2 = "";
client.request("/1").finish(function (res1) {
var req1 = client.request("/1")
req1.addListener('response', function (res1) {
res1.setBodyEncoding("utf8");
res1.addListener("body", function (chunk) {
res1.addListener('data', function (chunk) {
body1 += chunk;
});
res1.addListener("complete", function () {
client.request("/2").finish(function (res2) {
res1.addListener('end', function () {
var req2 = client.request("/2");
req2.addListener('response', function (res2) {
res2.setBodyEncoding("utf8");
res2.addListener("body", function (chunk) { body2 += chunk; });
res2.addListener("complete", function () { server.close(); });
res2.addListener('data', function (chunk) { body2 += chunk; });
res2.addListener('end', function () { server.close(); });
});
req2.close();
});
});
req1.close();
process.addListener("exit", function () {
assert.equal(body1_s, body1);

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

@ -21,15 +21,16 @@ client.addListener("error", function() {
errorCount++;
});
client.addListener("eof", function() {
client.addListener("end", function() {
sys.puts("EOF!");
eofCount++;
});
var request = client.request("GET", "/", {"host": "localhost"});
request.finish(function(response) {
request.addListener('response', function(response) {
sys.puts("STATUS: " + response.statusCode);
});
request.close();
setTimeout(function () {
server.close();

21
test/mjsunit/test-http-client-upload.js

@ -10,17 +10,17 @@ var server = http.createServer(function(req, res) {
assert.equal("POST", req.method);
req.setBodyEncoding("utf8");
req.addListener("body", function (chunk) {
req.addListener('data', function (chunk) {
puts("server got: " + JSON.stringify(chunk));
sent_body += chunk;
});
req.addListener("complete", function () {
req.addListener('end', function () {
server_req_complete = true;
puts("request complete from server");
res.sendHeader(200, {'Content-Type': 'text/plain'});
res.sendBody('hello\n');
res.finish();
res.write('hello\n');
res.close();
});
});
server.listen(PORT);
@ -28,21 +28,22 @@ server.listen(PORT);
var client = http.createClient(PORT);
var req = client.request('POST', '/');
req.sendBody('1\n');
req.sendBody('2\n');
req.sendBody('3\n');
req.write('1\n');
req.write('2\n');
req.write('3\n');
puts("client finished sending request");
req.finish(function(res) {
req.addListener('response', function(res) {
res.setBodyEncoding("utf8");
res.addListener('body', function(chunk) {
res.addListener('data', function(chunk) {
puts(chunk);
});
res.addListener('complete', function() {
res.addListener('end', function() {
client_res_complete = true;
server.close();
});
});
req.close();
process.addListener("exit", function () {
assert.equal("1\n2\n3\n", sent_body);

6
test/mjsunit/test-http-malformed-request.js

@ -14,8 +14,8 @@ var s = http.createServer(function (req, res) {
puts("req: " + JSON.stringify(url.parse(req.url)));
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("Hello World");
res.finish();
res.write("Hello World");
res.close();
if (++nrequests_completed == nrequests_expected) s.close();
});
@ -23,7 +23,7 @@ s.listen(port);
var c = tcp.createConnection(port);
c.addListener("connect", function () {
c.send("GET /hello?foo=%99bar HTTP/1.1\r\n\r\n");
c.write("GET /hello?foo=%99bar HTTP/1.1\r\n\r\n");
c.close();
});

22
test/mjsunit/test-http-proxy.js

@ -8,8 +8,8 @@ var BACKEND_PORT = 8870;
var backend = http.createServer(function (req, res) {
// debug("backend");
res.sendHeader(200, {"content-type": "text/plain"});
res.sendBody("hello world\n");
res.finish();
res.write("hello world\n");
res.close();
});
// debug("listen backend")
backend.listen(BACKEND_PORT);
@ -18,16 +18,17 @@ var proxy_client = http.createClient(BACKEND_PORT);
var proxy = http.createServer(function (req, res) {
debug("proxy req headers: " + JSON.stringify(req.headers));
var proxy_req = proxy_client.request(url.parse(req.url).pathname);
proxy_req.finish(function(proxy_res) {
proxy_req.addListener('response', function(proxy_res) {
res.sendHeader(proxy_res.statusCode, proxy_res.headers);
proxy_res.addListener("body", function(chunk) {
res.sendBody(chunk);
proxy_res.addListener("data", function(chunk) {
res.write(chunk);
});
proxy_res.addListener("complete", function() {
res.finish();
proxy_res.addListener("end", function() {
res.close();
// debug("proxy res");
});
});
proxy_req.close();
});
// debug("listen proxy")
proxy.listen(PROXY_PORT);
@ -37,17 +38,18 @@ var body = "";
var client = http.createClient(PROXY_PORT);
var req = client.request("/test");
// debug("client req")
req.finish(function (res) {
req.addListener('response', function (res) {
// debug("got res");
assert.equal(200, res.statusCode);
res.setBodyEncoding("utf8");
res.addListener("body", function (chunk) { body += chunk; });
res.addListener("complete", function () {
res.addListener('data', function (chunk) { body += chunk; });
res.addListener('end', function () {
proxy.close();
backend.close();
// debug("closed both");
});
});
req.close();
process.addListener("exit", function () {
assert.equal(body, "hello world\n");

16
test/mjsunit/test-http-server.js

@ -39,8 +39,8 @@ http.createServer(function (req, res) {
setTimeout(function () {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody(url.parse(req.url).pathname);
res.finish();
res.write(url.parse(req.url).pathname);
res.close();
}, 1);
}).listen(port);
@ -50,21 +50,21 @@ var c = tcp.createConnection(port);
c.setEncoding("utf8");
c.addListener("connect", function () {
c.send( "GET /hello?hello=world&foo=b==ar HTTP/1.1\r\n\r\n" );
c.write( "GET /hello?hello=world&foo=b==ar HTTP/1.1\r\n\r\n" );
requests_sent += 1;
});
c.addListener("receive", function (chunk) {
c.addListener("data", function (chunk) {
server_response += chunk;
if (requests_sent == 1) {
c.send("POST /quit HTTP/1.1\r\n\r\n");
c.write("POST /quit HTTP/1.1\r\n\r\n");
requests_sent += 1;
}
if (requests_sent == 2) {
c.send("GET / HTTP/1.1\r\nX-X: foo\r\n\r\n"
+"GET / HTTP/1.1\r\nX-X: bar\r\n\r\n");
c.write("GET / HTTP/1.1\r\nX-X: foo\r\n\r\n"
+"GET / HTTP/1.1\r\nX-X: bar\r\n\r\n");
c.close();
assert.equal(c.readyState, "readOnly");
requests_sent += 2;
@ -72,7 +72,7 @@ c.addListener("receive", function (chunk) {
});
c.addListener("eof", function () {
c.addListener("end", function () {
client_got_eof = true;
});

22
test/mjsunit/test-http-tls.js

@ -21,9 +21,9 @@ var responses_sent = 0;
var responses_recvd = 0;
var body0 = "";
var body1 = "";
var caPem = posix.cat(fixturesDir+"/test_ca.pem").wait();
var certPem = posix.cat(fixturesDir+"/test_cert.pem").wait();
var keyPem = posix.cat(fixturesDir+"/test_key.pem").wait();
var caPem = fs.readFile(fixturesDir+"/test_ca.pem").wait();
var certPem = fs.readFile(fixturesDir+"/test_cert.pem").wait();
var keyPem = fs.readFile(fixturesDir+"/test_key.pem").wait();
var http_server=http.createServer(function (req, res) {
@ -51,10 +51,10 @@ var http_server=http.createServer(function (req, res) {
this.close();
}
req.addListener("complete", function () {
req.addListener('end', function () {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("The path was " + url.parse(req.url).pathname);
res.finish();
res.write("The path was " + url.parse(req.url).pathname);
res.close();
responses_sent += 1;
});
@ -66,7 +66,7 @@ http_server.listen(PORT);
var client = http.createClient(PORT, HOST);
client.setSecure("x509_PEM", caPem, 0, keyPem, certPem);
var req = client.request("/hello", {"Accept": "*/*", "Foo": "bar"});
req.finish(function (res) {
req.addListener('response', function (res) {
var verified = res.connection.verifyPeer();
var peerDN = res.connection.getPeerCertificate("DNstring");
assert.equal(verified, 1);
@ -75,13 +75,14 @@ req.finish(function (res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("ascii");
res.addListener("body", function (chunk) { body0 += chunk; });
res.addListener('data', function (chunk) { body0 += chunk; });
debug("Got /hello response");
});
req.close();
setTimeout(function () {
req = client.request("POST", "/world");
req.finish(function (res) {
req.addListener('response', function (res) {
var verified = res.connection.verifyPeer();
var peerDN = res.connection.getPeerCertificate("DNstring");
assert.equal(verified, 1);
@ -90,9 +91,10 @@ setTimeout(function () {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("utf8");
res.addListener("body", function (chunk) { body1 += chunk; });
res.addListener('data', function (chunk) { body1 += chunk; });
debug("Got /world response");
});
req.close();
}, 1);
process.addListener("exit", function () {

14
test/mjsunit/test-http-wget.js

@ -25,9 +25,9 @@ var connection_was_closed = false;
var server = http.createServer(function (req, res) {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("hello ");
res.sendBody("world\n");
res.finish();
res.write("hello ");
res.write("world\n");
res.close();
})
server.listen(port);
@ -36,18 +36,18 @@ var c = tcp.createConnection(port);
c.setEncoding("utf8");
c.addListener("connect", function () {
c.send( "GET / HTTP/1.0\r\n" +
c.write("GET / HTTP/1.0\r\n" +
"Connection: Keep-Alive\r\n\r\n");
});
c.addListener("receive", function (chunk) {
c.addListener("data", function (chunk) {
puts(chunk);
server_response += chunk;
});
c.addListener("eof", function () {
c.addListener("end", function () {
client_got_eof = true;
puts('got eof');
puts('got end');
c.close();
});

16
test/mjsunit/test-http.js

@ -27,10 +27,10 @@ http.createServer(function (req, res) {
this.close();
}
req.addListener("complete", function () {
req.addListener('end', function () {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("The path was " + url.parse(req.url).pathname);
res.finish();
res.write("The path was " + url.parse(req.url).pathname);
res.close();
responses_sent += 1;
});
@ -39,23 +39,25 @@ http.createServer(function (req, res) {
var client = http.createClient(PORT);
var req = client.request("/hello", {"Accept": "*/*", "Foo": "bar"});
req.finish(function (res) {
req.addListener('response', function (res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("ascii");
res.addListener("body", function (chunk) { body0 += chunk; });
res.addListener('data', function (chunk) { body0 += chunk; });
debug("Got /hello response");
});
req.close();
setTimeout(function () {
req = client.request("POST", "/world");
req.finish(function (res) {
req.addListener('response',function (res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("utf8");
res.addListener("body", function (chunk) { body1 += chunk; });
res.addListener('data', function (chunk) { body1 += chunk; });
debug("Got /world response");
});
req.close();
}, 1);
process.addListener("exit", function () {

4
test/mjsunit/test-keep-alive.js

@ -10,8 +10,8 @@ server = http.createServer(function (req, res) {
"Content-Length": body.length,
"Content-Type": "text/plain",
});
res.sendBody(body);
res.finish();
res.write(body);
res.close();
});
server.listen(PORT);

4
test/mjsunit/test-mkdir-rmdir.js

@ -7,10 +7,10 @@ var d = path.join(fixtures, "dir");
var mkdir_error = false;
var rmdir_error = false;
posix.mkdir(d, 0x666).addCallback(function () {
fs.mkdir(d, 0x666).addCallback(function () {
puts("mkdir okay!");
posix.rmdir(d).addCallback(function () {
fs.rmdir(d).addCallback(function () {
puts("rmdir okay!");
}).addErrback(function (e) {

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

@ -3,6 +3,7 @@ process.mixin(require("./common"));
debug("load test-module-loading.js");
var a = require("./fixtures/a");
var c = require("./fixtures/b/c");
var d = require("./fixtures/b/d");
var d2 = require("./fixtures/b/d");
// Absolute
@ -33,6 +34,8 @@ assert.equal("D", d3.D());
assert.equal(true, d4.D instanceof Function);
assert.equal("D", d4.D());
assert.ok((new a.SomeClass) instanceof c.SomeClass);
debug("test index.js modules ids and relative loading")
var one = require("./fixtures/nested-index/one"),
two = require("./fixtures/nested-index/two");
@ -41,6 +44,7 @@ assert.notEqual(one.hello, two.hello);
debug("test cycles containing a .. path");
var root = require("./fixtures/cycles/root"),
foo = require("./fixtures/cycles/folder/foo");
assert.equal(root.foo, foo);
assert.equal(root.sayHello(), root.hello);
var errorThrown = false;
@ -53,6 +57,14 @@ try {
assert.equal(require('path').dirname(__filename), __dirname);
require.async('./fixtures/a')
.addCallback(function(a) {
assert.equal("A", a.A());
})
.addErrback(function() {
assert.ok(false, 'async loading broken?');
});
process.addListener("exit", function () {
assert.equal(true, a.A instanceof Function);
assert.equal("A done", a.A());

57
test/mjsunit/test-multipart.js

@ -22,13 +22,18 @@ var emails = fixture.messages.slice(0),
firstPart = new (events.Promise);
// test streaming messages through directly, as if they were in a file or something.
sys.puts("test "+emails.length+" emails");
(function testEmails () {
var email = emails.pop(),
curr = 0;
if (!email) {
sys.puts("done testing emails");
firstPart.emitSuccess();
return;
}
sys.puts("testing email "+emails.length);
var expect = email.expect;
var message = new (events.EventEmitter);
@ -36,20 +41,22 @@ var emails = fixture.messages.slice(0),
var mp = multipart.parse(message);
mp.addListener("partBegin", function (part) {
sys.puts(">> testing part #"+curr);
testPart(email.expect[curr ++], part);
});
mp.addListener("complete", function () {
sys.puts("done with email "+emails.length);
process.nextTick(testEmails);
});
// stream it through in chunks.
var emailBody = email.body;
process.nextTick(function s () {
if (emailBody) {
message.emit("body", emailBody.substr(0, chunkSize));
message.emit("data", emailBody.substr(0, chunkSize));
emailBody = emailBody.substr(chunkSize);
process.nextTick(s);
} else {
message.emit("complete");
message.emit("end");
}
});
})();
@ -57,23 +64,29 @@ var emails = fixture.messages.slice(0),
// run good HTTP messages test after previous test ends.
var secondPart = new (events.Promise),
server = http.createServer(function (req, res) {
sys.puts("HTTP mp request");
var mp = multipart.parse(req),
curr = 0;
req.setBodyEncoding("binary");
if (req.url !== "/bad") {
sys.puts("expected to be good");
mp.addListener("partBegin", function (part) {
sys.puts(">> testing part #"+curr);
testPart(message.expect[curr ++], part);
});
} else {
sys.puts("expected to be bad");
}
mp.addListener("error", function (er) {
sys.puts("!! error occurred");
res.sendHeader(400, {});
res.sendBody("bad");
res.finish();
res.write("bad");
res.close();
});
mp.addListener("complete", function () {
res.sendHeader(200, {});
res.sendBody("ok");
res.finish();
res.write("ok");
res.close();
});
}),
message,
@ -83,41 +96,47 @@ server.listen(PORT);
// could dry these two up a bit.
firstPart.addCallback(function testGoodMessages () {
var httpMessages = fixture.messages.slice(0);
process.nextTick(function testHTTP () {
sys.puts("testing "+httpMessages.length+" good messages");
(function testHTTP () {
message = httpMessages.pop();
if (!message) {
secondPart.emitSuccess();
return;
}
sys.puts("test message "+httpMessages.length);
var req = client.request("POST", "/", message.headers);
req.sendBody(message.body, "binary");
req.finish(function (res) {
req.write(message.body, "binary");
req.addListener('response', function (res) {
var buff = "";
res.addListener("body", function (chunk) { buff += chunk });
res.addListener("complete", function () {
res.addListener("data", function (chunk) { buff += chunk });
res.addListener("end", function () {
assert.equal(buff, "ok");
process.nextTick(testHTTP);
});
});
});
req.close();
})();
});
secondPart.addCallback(function testBadMessages () {
var httpMessages = fixture.badMessages.slice(0);
process.nextTick(function testHTTP () {
sys.puts("testing "+httpMessages.length+" bad messages");
(function testHTTP () {
message = httpMessages.pop();
if (!message) {
server.close()
return;
}
sys.puts("test message "+httpMessages.length);
var req = client.request("POST", "/bad", message.headers);
req.sendBody(message.body, "binary");
req.finish(function (res) {
req.write(message.body, "binary");
req.addListener('response', function (res) {
var buff = "";
res.addListener("body", function (chunk) { buff += chunk });
res.addListener("complete", function () {
res.addListener("data", function (chunk) { buff += chunk });
res.addListener("end", function () {
assert.equal(buff, "bad");
process.nextTick(testHTTP);
});
});
});
});
req.close();
})();
});

15
test/mjsunit/test-promise-wait.js

@ -45,6 +45,9 @@ p5.addCallback(function () {
}, 100);
});
var p6 = new events.Promise();
var p7 = new events.Promise();
p7.addErrback(function() {});
p2.emitSuccess();
@ -74,6 +77,18 @@ assert.deepEqual(["a","b","c"], ret4);
assert.equal(true, p4_done);
p6.emitSuccess("something");
assert.equal("something", p6.wait());
p7.emitError("argh!");
var goterr;
try {
p7.wait();
} catch(err) {
goterr = err;
}
assert.equal("argh!", goterr.toString());
process.addListener("exit", function () {
assert.equal(true, p1_done);
assert.equal(true, p2_done);

12
test/mjsunit/test-promise.js

@ -24,13 +24,13 @@ a.addErrback(function(error) {
});
a.emitSuccess(TEST_VALUE);
a.addCallback(function(value) {
assert.ok(a.addCallback(function(value) {
assert.equal(TEST_VALUE, value);
expectedCallbacks.a2--;
});
a.addErrback(function(error) {
}));
assert.ok(a.addErrback(function(error) {
assert.notEqual(TEST_VALUE, error, 'late');
});
}));
// Test regular & late errback binding
var b = new Promise();
@ -48,10 +48,10 @@ b.addErrback(function(value) {
// Test late errback binding
var c = new Promise();
c.emitError(TEST_VALUE);
c.addErrback(function(value) {
assert.ok(c.addErrback(function(value) {
assert.equal(TEST_VALUE, value);
expectedCallbacks.c1--;
});
}));
// Test errback exceptions
var d = new Promise();

2
test/mjsunit/test-readdir.js

@ -2,7 +2,7 @@ process.mixin(require("./common"));
var got_error = false;
var promise = posix.readdir(fixturesDir);
var promise = fs.readdir(fixturesDir);
puts("readdir " + fixturesDir);
promise.addCallback(function (files) {

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

@ -12,8 +12,8 @@ var server = http.createServer(function(req, res) {
'};';
res.sendHeader(200, {'Content-Type': 'text/javascript'});
res.sendBody(body);
res.finish();
res.write(body);
res.close();
});
server.listen(PORT);

2
test/mjsunit/test-stdio.js

@ -24,7 +24,7 @@ child.addListener("output", function (data){
child.close();
}
} else {
puts('child eof');
puts('child end');
}
});

5
test/mjsunit/test-sync-fileread.js

@ -0,0 +1,5 @@
process.mixin(require('./common'));
var fixture = path.join(__dirname, "fixtures/x.txt");
assert.equal("xyz\n", fs.readFileSync(fixture));

10
test/mjsunit/test-sys.js

@ -10,6 +10,8 @@ assert.equal("[Function]", inspect(function() {}));
assert.equal('undefined', inspect(undefined));
assert.equal('null', inspect(null));
assert.equal('/foo(bar\\n)?/gi', inspect(/foo(bar\n)?/gi));
assert.equal('Sun, 14 Feb 2010 11:48:40 GMT',
inspect(new Date("Sun, 14 Feb 2010 11:48:40 GMT")));
assert.equal("\"\\n\\u0001\"", inspect("\n\u0001"));
@ -79,3 +81,11 @@ assert.equal(
"{ /123/gi\n \"aprop\": 42\n}",
inspect(value)
);
// Dates with properties
value = new Date("Sun, 14 Feb 2010 11:48:40 GMT");
value.aprop = 42;
assert.equal(
"{ Sun, 14 Feb 2010 11:48:40 GMT\n \"aprop\": 42\n}",
inspect(value)
);

14
test/mjsunit/test-tcp-binary.js

@ -21,11 +21,11 @@ for (var i = 255; i >= 0; i--) {
var echoServer = tcp.createServer(function (connection) {
connection.setEncoding("binary");
connection.addListener("receive", function (chunk) {
connection.addListener("data", function (chunk) {
error("recved: " + JSON.stringify(chunk));
connection.send(chunk, "binary");
connection.write(chunk, "binary");
});
connection.addListener("eof", function () {
connection.addListener("end", function () {
connection.close();
});
});
@ -37,10 +37,10 @@ var j = 0;
var c = tcp.createConnection(PORT);
c.setEncoding("binary");
c.addListener("receive", function (chunk) {
c.addListener("data", function (chunk) {
if (j < 256) {
error("send " + j);
c.send(String.fromCharCode(j), "binary");
error("write " + j);
c.write(String.fromCharCode(j), "binary");
j++;
} else {
c.close();
@ -49,7 +49,7 @@ c.addListener("receive", function (chunk) {
});
c.addListener("connect", function () {
c.send(binaryString, "binary");
c.write(binaryString, "binary");
});
c.addListener("close", function () {

6
test/mjsunit/test-tcp-many-clients.js

@ -18,7 +18,7 @@ var server = tcp.createServer(function (c) {
c.addListener("connect", function () {
total_connections++;
print("#");
c.send(body);
c.write(body);
c.close();
});
});
@ -35,11 +35,11 @@ function runClient (callback) {
client.connections += 1;
});
client.addListener("receive", function (chunk) {
client.addListener("data", function (chunk) {
this.recved += chunk;
});
client.addListener("eof", function (had_error) {
client.addListener("end", function (had_error) {
client.close();
});

12
test/mjsunit/test-tcp-pingpong-delay.js

@ -13,14 +13,14 @@ function pingPongTest (port, host, on_complete) {
var server = tcp.createServer(function (socket) {
socket.setEncoding("utf8");
socket.addListener("receive", function (data) {
socket.addListener("data", function (data) {
puts(data);
assert.equal("PING", data);
assert.equal("open", socket.readyState);
assert.equal(true, count <= N);
setTimeout(function () {
assert.equal("open", socket.readyState);
socket.send("PONG");
socket.write("PONG");
}, DELAY);
});
@ -29,7 +29,7 @@ function pingPongTest (port, host, on_complete) {
assert.equal(false, true);
});
socket.addListener("eof", function () {
socket.addListener("end", function () {
puts("server-side socket EOF");
assert.equal("writeOnly", socket.readyState);
socket.close();
@ -50,10 +50,10 @@ function pingPongTest (port, host, on_complete) {
client.addListener("connect", function () {
assert.equal("open", client.readyState);
client.send("PING");
client.write("PING");
});
client.addListener("receive", function (data) {
client.addListener("data", function (data) {
puts(data);
assert.equal("PONG", data);
assert.equal("open", client.readyState);
@ -61,7 +61,7 @@ function pingPongTest (port, host, on_complete) {
setTimeout(function () {
assert.equal("open", client.readyState);
if (count++ < N) {
client.send("PING");
client.write("PING");
} else {
puts("closing client");
client.close();

14
test/mjsunit/test-tcp-pingpong.js

@ -21,16 +21,16 @@ function pingPongTest (port, host, on_complete) {
socket.setNoDelay();
socket.timeout = 0;
socket.addListener("receive", function (data) {
socket.addListener("data", function (data) {
puts("server got: " + JSON.stringify(data));
assert.equal("open", socket.readyState);
assert.equal(true, count <= N);
if (/PING/.exec(data)) {
socket.send("PONG");
socket.write("PONG");
}
});
socket.addListener("eof", function () {
socket.addListener("end", function () {
assert.equal("writeOnly", socket.readyState);
socket.close();
});
@ -49,10 +49,10 @@ function pingPongTest (port, host, on_complete) {
client.addListener("connect", function () {
assert.equal("open", client.readyState);
client.send("PING");
client.write("PING");
});
client.addListener("receive", function (data) {
client.addListener("data", function (data) {
assert.equal("PONG", data);
count += 1;
@ -64,10 +64,10 @@ function pingPongTest (port, host, on_complete) {
}
if (count < N) {
client.send("PING");
client.write("PING");
} else {
sent_final_ping = true;
client.send("PING");
client.write("PING");
client.close();
}
});

6
test/mjsunit/test-tcp-reconnect.js

@ -9,10 +9,10 @@ var disconnect_count = 0;
var server = tcp.createServer(function (socket) {
socket.addListener("connect", function () {
socket.send("hello\r\n");
socket.write("hello\r\n");
});
socket.addListener("eof", function () {
socket.addListener("end", function () {
socket.close();
});
@ -31,7 +31,7 @@ client.addListener("connect", function () {
puts("client connected.");
});
client.addListener("receive", function (chunk) {
client.addListener("data", function (chunk) {
client_recv_count += 1;
puts("client_recv_count " + client_recv_count);
assert.equal("hello\r\n", chunk);

6
test/mjsunit/test-tcp-throttle-kernel-buffer.js

@ -13,7 +13,7 @@ puts("start server on port " + PORT);
server = tcp.createServer(function (connection) {
connection.addListener("connect", function () {
connection.send(body);
connection.write(body);
connection.close();
});
});
@ -27,7 +27,7 @@ npauses = 0;
var paused = false;
client = tcp.createConnection(PORT);
client.setEncoding("ascii");
client.addListener("receive", function (d) {
client.addListener("data", function (d) {
chars_recved += d.length;
puts("got " + chars_recved);
if (!paused) {
@ -45,7 +45,7 @@ client.addListener("receive", function (d) {
}
});
client.addListener("eof", function () {
client.addListener("end", function () {
server.close();
client.close();
});

12
test/mjsunit/test-tcp-throttle.js

@ -4,17 +4,17 @@ PORT = 20443;
N = 200;
server = tcp.createServer(function (connection) {
function send (j) {
function write (j) {
if (j >= N) {
connection.close();
return;
}
setTimeout(function () {
connection.send("C");
send(j+1);
connection.write("C");
write(j+1);
}, 10);
}
send(0);
write(0);
});
server.listen(PORT);
@ -24,7 +24,7 @@ chars_recved = 0;
client = tcp.createConnection(PORT);
client.setEncoding("ascii");
client.addListener("receive", function (d) {
client.addListener("data", function (d) {
print(d);
recv += d;
});
@ -57,7 +57,7 @@ setTimeout(function () {
}, 500);
client.addListener("eof", function () {
client.addListener("end", function () {
server.close();
client.close();
});

18
test/mjsunit/test-tcp-timeout.js

@ -15,12 +15,12 @@ var echo_server = tcp.createServer(function (socket) {
p(timeouttime);
});
socket.addListener("receive", function (d) {
socket.addListener("data", function (d) {
p(d);
socket.send(d);
socket.write(d);
});
socket.addListener("eof", function () {
socket.addListener("end", function () {
socket.close();
});
});
@ -33,15 +33,15 @@ client.setEncoding("UTF8");
client.setTimeout(0); // disable the timeout for client
client.addListener("connect", function () {
puts("client connected.");
client.send("hello\r\n");
client.write("hello\r\n");
});
client.addListener("receive", function (chunk) {
client.addListener("data", function (chunk) {
assert.equal("hello\r\n", chunk);
if (exchanges++ < 5) {
setTimeout(function () {
puts("client send 'hello'");
client.send("hello\r\n");
puts("client write 'hello'");
client.write("hello\r\n");
}, 500);
if (exchanges == 5) {
@ -57,8 +57,8 @@ client.addListener("timeout", function () {
assert.equal(false, true);
});
client.addListener("eof", function () {
puts("client eof");
client.addListener("end", function () {
puts("client end");
client.close();
});

22
test/mjsunit/test-tcp-tls.js

@ -1,6 +1,6 @@
process.mixin(require("./common"));
tcp = require("tcp");
posix=require("posix");
fs=require("fs");
var tests_run = 0;
@ -21,7 +21,7 @@ function tlsTest (port, host, caPem, keyPem, certPem) {
socket.setNoDelay();
socket.timeout = 0;
socket.addListener("receive", function (data) {
socket.addListener("data", function (data) {
var verified = socket.verifyPeer();
var peerDN = socket.getPeerCertificate("DNstring");
assert.equal(verified, 1);
@ -31,11 +31,11 @@ function tlsTest (port, host, caPem, keyPem, certPem) {
assert.equal("open", socket.readyState);
assert.equal(true, count <= N);
if (/PING/.exec(data)) {
socket.send("PONG");
socket.write("PONG");
}
});
socket.addListener("eof", function () {
socket.addListener("end", function () {
assert.equal("writeOnly", socket.readyState);
socket.close();
});
@ -62,10 +62,10 @@ function tlsTest (port, host, caPem, keyPem, certPem) {
assert.equal(verified, 1);
assert.equal(peerDN, "C=UK,ST=Acknack Ltd,L=Rhys Jones,O=node.js,"
+ "OU=Test TLS Certificate,CN=localhost");
client.send("PING");
client.write("PING");
});
client.addListener("receive", function (data) {
client.addListener("data", function (data) {
assert.equal("PONG", data);
count += 1;
@ -79,10 +79,10 @@ function tlsTest (port, host, caPem, keyPem, certPem) {
}
if (count < N) {
client.send("PING");
client.write("PING");
} else {
sent_final_ping = true;
client.send("PING");
client.write("PING");
client.close();
}
});
@ -105,9 +105,9 @@ try {
}
if (have_tls) {
var caPem = posix.cat(fixturesDir+"/test_ca.pem").wait();
var certPem = posix.cat(fixturesDir+"/test_cert.pem").wait();
var keyPem = posix.cat(fixturesDir+"/test_key.pem").wait();
var caPem = fs.readFile(fixturesDir+"/test_ca.pem").wait();
var certPem = fs.readFile(fixturesDir+"/test_cert.pem").wait();
var keyPem = fs.readFile(fixturesDir+"/test_key.pem").wait();
/* All are run at once, so run on different ports */
tlsTest(20443, "localhost", caPem, keyPem, certPem);

9
test/mjsunit/test-timers.js

@ -7,12 +7,11 @@ var setTimeout_called = false;
assert.equal(true, setTimeout instanceof Function);
var starttime = new Date;
setTimeout(function () {
var endtime = new Date;
var diff = endtime - starttime;
if (diff < 0) diff = -diff;
assert.ok(diff > 0);
puts("diff: " + diff);
assert.equal(true, 1000 - WINDOW < diff && diff < 1000 + WINDOW);
@ -28,7 +27,7 @@ setInterval(function () {
var endtime = new Date;
var diff = endtime - starttime;
if (diff < 0) diff = -diff;
assert.ok(diff > 0);
puts("diff: " + diff);
var t = interval_count * 1000;
@ -50,7 +49,7 @@ var interval_count2 = 0;
setInterval(function(param){
++interval_count2;
assert.equal("test param", param);
if(interval_count2 == 3)
clearInterval(this);
}, 1000, "test param");
@ -67,7 +66,7 @@ setInterval(function(param1, param2){
++interval_count3;
assert.equal("param1", param1);
assert.equal("param2", param2);
if(interval_count3 == 3)
clearInterval(this);
}, 1000, "param1", "param2");

13
test/mjsunit/test-stat-handler.js → test/mjsunit/test-watch-file.js

@ -11,18 +11,17 @@ var changes = 0;
process.watchFile(f, function (curr, prev) {
puts(f + " change");
changes++;
assert.equal(true, curr.mtime != prev.mtime);
assert.ok(curr.mtime != prev.mtime);
process.unwatchFile(f);
});
var File = require("file").File;
var file = new File(f, 'w+');
file.write('xyz\n');
file.close().wait();
var fs = require("fs");
var fd = fs.openSync(f, "w+");
fs.writeSync(fd, 'xyz\n');
fs.closeSync(fd);
process.addListener("exit", function () {
assert.equal(true, changes > 0);
assert.ok(changes > 0);
});

4
wscript

@ -7,7 +7,7 @@ from os.path import join, dirname, abspath
from logging import fatal
cwd = os.getcwd()
VERSION="0.1.28"
VERSION="0.1.29"
APPNAME="node.js"
import js2c
@ -133,7 +133,7 @@ def configure(conf):
#libpath=['/usr/lib', '/usr/local/lib'],
uselib_store='GNUTLS'):
if conf.check(lib='gpg-error',
libpath=['/usr/lib', '/usr/local/lib'],
libpath=['/usr/lib', '/usr/local/lib', '/opt/local/lib'],
uselib_store='GPGERROR'):
conf.env.append_value("CCFLAGS", "-DEVCOM_HAVE_GNUTLS=1")
conf.env.append_value("CXXFLAGS", "-DEVCOM_HAVE_GNUTLS=1")

Loading…
Cancel
Save