|
|
|
NODE(1)
|
|
|
|
=======
|
|
|
|
Ryan Dahl <ry@tinyclouds.org>
|
|
|
|
Version, 0.1.0, 2009.06.30
|
|
|
|
|
|
|
|
|
|
|
|
== NAME
|
|
|
|
|
|
|
|
node - purely event-based I/O for V8 javascript
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
== SYNOPSIS
|
|
|
|
|
|
|
|
An example of a web server written with Node which responds with "Hello
|
|
|
|
World" after waiting two seconds:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
node.http.createServer(function (request, response) {
|
|
|
|
setTimeout(function () {
|
|
|
|
response.sendHeader(200, [["Content-Type", "text/plain"]]);
|
|
|
|
response.sendBody("Hello World");
|
|
|
|
response.finish();
|
|
|
|
}, 2000);
|
|
|
|
}).listen(8000);
|
|
|
|
puts("Server running at http://127.0.0.1:8000/");
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
To run the server, put the code into a file called +example.js+ and execute
|
|
|
|
it with the node program
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
> node example.js
|
|
|
|
Server running at http://127.0.0.1:8000/
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
== DESCRIPTION
|
|
|
|
|
|
|
|
Node provides an easy way to build scalable network programs. In the above
|
|
|
|
example, the 2 second delay does not prevent the server from handling new
|
|
|
|
requests. Node tells the operating system (through +epoll+, +kqueue+,
|
|
|
|
+/dev/poll+, or +select+) that it should be notified when the 2 seconds are
|
|
|
|
up or if a new connection is made--then it goes to sleep. If someone new
|
|
|
|
connects, then it executes the callback, if the timeout expires, it executes
|
|
|
|
the inner callback. Each connection is only a small heap allocation.
|
|
|
|
|
|
|
|
This is in contrast to today's more common model where OS threads are employed
|
|
|
|
for concurrency. Thread-based networking
|
|
|
|
http://www.sics.se/~joe/apachevsyaws.html[is]
|
|
|
|
http://www.kegel.com/c10k.html[relatively]
|
|
|
|
http://bulk.fefe.de/scalable-networking.pdf[inefficient]
|
|
|
|
and very difficult to use. Node will show much better memory efficiency
|
|
|
|
under high-loads than systems which allocate 2mb thread stacks for each
|
|
|
|
connection. Furthermore, users of Node are free from worries of
|
|
|
|
dead-locking the process--there are no locks. In fact, no function in Node
|
|
|
|
directly performs I/O. Because nothing blocks, less-than-expert programmers
|
|
|
|
are able to develop fast systems.
|
|
|
|
|
|
|
|
Node is similar in design to systems like Ruby's
|
|
|
|
http://rubyeventmachine.com/[Event Machine]
|
|
|
|
or Python's http://twistedmatrix.com/[Twisted].
|
|
|
|
Node takes the event model a bit further. For example, in other systems there
|
|
|
|
is always a blocking call to start the event-loop. Typically one defines
|
|
|
|
behavior through callbacks at the beginning of a script and at the end starts a
|
|
|
|
server through a call like +EventMachine::run()+. In Node it works differently.
|
|
|
|
By default Node enters the event loop after executing the input script. Node
|
|
|
|
exits the event loop when there are no more callbacks to perform. Like in
|
|
|
|
traditional browser javascript, the event loop is hidden from the user.
|
|
|
|
|
|
|
|
Node's HTTP API has grown out of my difficulties developing and working with
|
|
|
|
web servers. For example, streaming data through most web frameworks is
|
|
|
|
impossible. Or the oft-made false assumption that all message headers have
|
|
|
|
unique fields. Node attempts to correct these and other problems in its API.
|
|
|
|
Coupled with Node's purely evented infrastructure, it will make a more
|
|
|
|
comprehensive foundation for future web libraries/frameworks.
|
|
|
|
|
|
|
|
_But what about multiple-processor concurrency? Threads are necessary to scale
|
|
|
|
programs to multi-core computers._ The name _Node_ should give some hint at how
|
|
|
|
it is envisioned being used. Processes are necessary to scale to multi-core
|
|
|
|
computers, not memory-sharing threads. The fundamentals of scalable systems are
|
|
|
|
fast networking and non-blocking design--the rest is message passing. In the
|
|
|
|
future, I'd like Node to be able to spawn new processes (probably using the
|
|
|
|
http://www.whatwg.org/specs/web-workers/current-work/[Web Workers API]),
|
|
|
|
but this is something that fits well into the current design.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
== API
|
|
|
|
|
|
|
|
Node supports 3 byte-string encodings: ASCII (+"ascii"+), UTF-8 (+"utf8"+),
|
|
|
|
and raw binary (+"raw"+). It uses strings to represent ASCII and UTF-8
|
|
|
|
encoded data. For the moment, arrays of integers are used to represent raw
|
|
|
|
binary data--this representation is rather inefficient. This will
|
|
|
|
change in the future, when
|
|
|
|
http://code.google.com/p/v8/issues/detail?id=270[V8 supports Blob objects].
|
|
|
|
|
|
|
|
Unless otherwise noted, functions are all asynchronous and do not block
|
|
|
|
execution.
|
|
|
|
|
|
|
|
|
|
|
|
=== Helpers
|
|
|
|
|
|
|
|
+puts(string)+::
|
|
|
|
Alias for +stdout.puts()+. Outputs the +string+ and a trailing new-line to
|
|
|
|
+stdout+.
|
|
|
|
+
|
|
|
|
Everything in node is asynchronous; +puts()+ is no exception. This might
|
|
|
|
seem ridiculous but, if for example, one is piping +stdout+ into an NFS
|
|
|
|
file, +printf()+ will block from network latency. There is an internal
|
|
|
|
queue for +puts()+ output, so you can be assured that output will be
|
|
|
|
displayed in the order it was called.
|
|
|
|
|
|
|
|
|
|
|
|
+node.debug(string)+::
|
|
|
|
A synchronous output function. Will block the process and
|
|
|
|
output the string immediately to stdout.
|
|
|
|
|
|
|
|
|
|
|
|
+p(object)+ ::
|
|
|
|
Print the JSON representation of +object+ to the standard output.
|
|
|
|
|
|
|
|
|
|
|
|
+print(string)+::
|
|
|
|
Like +puts()+ but without the trailing new-line.
|
|
|
|
|
|
|
|
|
|
|
|
+node.exit(code)+::
|
|
|
|
Immediately ends the process with the specified code.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== Global Variables
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ARGV+ ::
|
|
|
|
An array containing the command line arguments.
|
|
|
|
|
|
|
|
|
|
|
|
+stdout+, +stderr+, and +stdin+ ::
|
|
|
|
Objects of type +node.fs.File+. (See below.)
|
|
|
|
|
|
|
|
+__filename+ ::
|
|
|
|
The filename of the script being executed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== 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 are instances of +node.EventEmitter+.
|
|
|
|
|
|
|
|
Events are represented by a snakecased string. Here are some examples:
|
|
|
|
+"connection"+, +"receive"+, +"message_begin"+.
|
|
|
|
|
|
|
|
Functions can be then be attached to objects, to be executed when an event
|
|
|
|
is emitted. These functions are called _listeners_.
|
|
|
|
|
|
|
|
Some asynchronous file operations return an +EventEmitter+ called a
|
|
|
|
_promise_. A promise emits just a single event when the operation is
|
|
|
|
complete.
|
|
|
|
|
|
|
|
==== +node.EventEmitter+
|
|
|
|
|
|
|
|
+emitter.addListener(event, listener)+ ::
|
|
|
|
Adds a listener to the end of the listeners array for the specified event.
|
|
|
|
+
|
|
|
|
----------------------------------------
|
|
|
|
server.addListener("connection", function (socket) {
|
|
|
|
puts("someone connected!");
|
|
|
|
});
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
+emitter.listeners(event)+ ::
|
|
|
|
Returns an array of listeners for the specified event. This array can be
|
|
|
|
manipulated, e.g. to remove listeners.
|
|
|
|
|
|
|
|
+emitter.emit(event, args)+ ::
|
|
|
|
Execute each of the listeners in order with the array +args+ as arguments.
|
|
|
|
|
|
|
|
==== +node.Promise+
|
|
|
|
|
|
|
|
+node.Promise+ inherits from +node.eventEmitter+. A promise emits one of two
|
|
|
|
events: +"success"+ or +"error"+. After emitting its event, it will not
|
|
|
|
emit anymore events.
|
|
|
|
|
|
|
|
+promise.addCallback(listener)+ ::
|
|
|
|
Adds a listener for the +"success"+ event. Returns the same promise object.
|
|
|
|
|
|
|
|
+promise.addErrback(listener)+ ::
|
|
|
|
Adds a listener for the +"error"+ event. Returns the same promise object.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== Modules
|
|
|
|
|
|
|
|
Node has a simple module loading system. In Node, files and modules are in
|
|
|
|
one-to-one correspondence. As an example, +foo.js+ loads the module
|
|
|
|
+circle.js+.
|
|
|
|
|
|
|
|
The contents of +foo.js+:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
var circle = require("circle.js");
|
|
|
|
function onLoad () {
|
|
|
|
puts("The area of a cirlce of radius 4 is " + circle.area(4));
|
|
|
|
}
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
The contents of +circle.js+:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
var PI = 3.14;
|
|
|
|
|
|
|
|
exports.area = function (r) {
|
|
|
|
return PI * r * r;
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.circumference = function (r) {
|
|
|
|
return 2 * PI * r;
|
|
|
|
};
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
The module +circle.js+ has exported the functions +area()+ and
|
|
|
|
+circumference()+. To export an object, add to the special +exports+
|
|
|
|
object. (Alternatively, one can use +this+ instead of +exports+.) Variables
|
|
|
|
local to the module will be private. In this example the variable +PI+ is
|
|
|
|
private to +circle.js+.
|
|
|
|
|
|
|
|
The module path is relative to the file calling +require()+. That is,
|
|
|
|
+circle.js+ must be in the same directory as +foo.js+ for +require()+ to
|
|
|
|
find it.
|
|
|
|
|
|
|
|
HTTP URLs can also be used to load modules. For example,
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
var circle = require("http://tinyclouds.org/node/circle.js");
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
Like +require()+ the function +include()+ also loads a module. Instead of
|
|
|
|
returning a namespace object, +include()+ will add the module's exports into
|
|
|
|
the global namespace. For example:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
include("circle.js");
|
|
|
|
function onLoad () {
|
|
|
|
puts("The area of a cirlce of radius 4 is " + area(4));
|
|
|
|
}
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
==== +onLoad()+
|
|
|
|
|
|
|
|
Because module loading does not happen instantaneously and because Node has
|
|
|
|
a policy of never blocking, a callback +onLoad+ can be set that will notify
|
|
|
|
the user when the included modules are loaded. Each file/module can have
|
|
|
|
its own +onLoad+ callback.
|
|
|
|
|
|
|
|
+include()+ and +require()+ cannot be used after +onLoad()+ is called.
|
|
|
|
|
|
|
|
|
|
|
|
==== +onExit()+
|
|
|
|
|
|
|
|
When the program exits a callback +onExit()+ will be called for each module
|
|
|
|
(children first).
|
|
|
|
|
|
|
|
The +onExit()+ callback cannot perform I/O since the process is going to
|
|
|
|
forcably exit in less than microsecond. However, it is a good hook to
|
|
|
|
perform constant time checks of the module's state. E.G. for unit tests:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
include("asserts.js");
|
|
|
|
|
|
|
|
var timer_executed = false;
|
|
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
timer_executed = true
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
function onExit () {
|
|
|
|
assertTrue(timer_executed);
|
|
|
|
}
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
Just to reiterate: +onExit()+, is not the place to close files or shutdown
|
|
|
|
servers. The process will exit before they get performed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== Timers
|
|
|
|
|
|
|
|
|
|
|
|
+setTimeout(callback, delay)+::
|
|
|
|
To schedule execution of callback after delay milliseconds. Returns a
|
|
|
|
+timeoutId+ for possible use with +clearTimeout()+.
|
|
|
|
|
|
|
|
|
|
|
|
+clearTimeout(timeoutId)+::
|
|
|
|
Prevents said timeout from triggering.
|
|
|
|
|
|
|
|
|
|
|
|
+setInterval(callback, delay)+::
|
|
|
|
To schedule the repeated execution of callback everydelay milliseconds. Returns
|
|
|
|
a +intervalId+ for possible use with +clearInterval()+.
|
|
|
|
|
|
|
|
|
|
|
|
+clearInterval(intervalId)+::
|
|
|
|
Stops a interval from triggering.
|
|
|
|
|
|
|
|
|
|
|
|
=== Child Processes
|
|
|
|
|
|
|
|
Node provides a tridirectional +popen(3)+ facility through the class
|
|
|
|
+node.Process+. It is possible to stream data through the child's +stdin+,
|
|
|
|
+stdout+, and +stderr+ in a fully non-blocking way.
|
|
|
|
|
|
|
|
==== +node.Process+
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event |Parameters |Notes
|
|
|
|
|
|
|
|
|+"output"+ | +data+ |
|
|
|
|
Each time the child process sends data to its +stdout+, this event is
|
|
|
|
triggered. +data+ is a string. At the moment all data passed to +stdout+ is
|
|
|
|
interrpreted as UTF-8 encoded.
|
|
|
|
+
|
|
|
|
If the child process closes its +stdout+ stream (a common thing to do on
|
|
|
|
exit), this event will be emitted with +data === null+.
|
|
|
|
|
|
|
|
|
|
|
|
|+"error"+ | +data+ |
|
|
|
|
Identical to the +"output"+ event except for +stderr+ instead of +stdout+.
|
|
|
|
|
|
|
|
|+"exit"+ | +code+ |
|
|
|
|
This event is emitted after the child process ends. +code+ is the final exit
|
|
|
|
code of the process. One can be assured that after this event is emitted
|
|
|
|
that the +"output"+ and +"error"+ callbacks will no longer be made.
|
|
|
|
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+node.createProcess(command)+::
|
|
|
|
Launches a new process with the given +command+. For example:
|
|
|
|
+
|
|
|
|
----------------------------------------
|
|
|
|
var ls = node.createProcess("ls -lh /usr");
|
|
|
|
ls.addListener("output", function (data) {
|
|
|
|
puts(data);
|
|
|
|
});
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
+process.pid+ ::
|
|
|
|
The PID of the child process.
|
|
|
|
|
|
|
|
|
|
|
|
+process.write(data, encoding="ascii")+ ::
|
|
|
|
Write data to the child process's +stdin+. The second argument is optional and
|
|
|
|
specifies the encoding: possible values are +"utf8"+, +"ascii"+, and +"raw"+.
|
|
|
|
|
|
|
|
|
|
|
|
+process.close()+ ::
|
|
|
|
Closes the process's +stdin+ stream.
|
|
|
|
|
|
|
|
|
|
|
|
+process.kill(signal=node.SIGTERM)+ ::
|
|
|
|
Send a single to the child process. If no argument is given, the process
|
|
|
|
will be sent +node.SIGTERM+. The standard POSIX signals are defined under
|
|
|
|
the +node+ namespace (+node.SIGINT+, +node.SIGUSR1+, ...).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== File I/O
|
|
|
|
|
|
|
|
This part of the API is split into two parts: simple wrappers
|
|
|
|
around standard POSIX file I/O functions and a user-friendly
|
|
|
|
+File+ object.
|
|
|
|
|
|
|
|
==== POSIX Wrappers
|
|
|
|
|
|
|
|
All POSIX wrappers have a similar form.
|
|
|
|
They return a promise (+node.Promise+). Example:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
var promise = node.fs.unlink("/tmp/hello");
|
|
|
|
promise.addCallback(function () {
|
|
|
|
puts("successfully deleted /tmp/hello");
|
|
|
|
});
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
There is no guaranteed ordering to the POSIX wrappers. The
|
|
|
|
following is very much prone to error
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
node.fs.rename("/tmp/hello", "/tmp/world");
|
|
|
|
node.fs.stat("/tmp/world").addCallback(function (stats) {
|
|
|
|
puts("stats: " + JSON.stringify(stats));
|
|
|
|
});
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
It could be that +stat()+ is executed before the +rename()+.
|
|
|
|
The correct way to do this is to chain the promises.
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
node.fs.rename("/tmp/hello", "/tmp/world")
|
|
|
|
.addCallback(function () {
|
|
|
|
node.fs.stat("/tmp/world")
|
|
|
|
.addCallback(function (stats) {
|
|
|
|
puts("stats: " + JSON.stringify(stats));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.rename(path1, path2)+ ::
|
|
|
|
See rename(2).
|
|
|
|
- on success: no parameters.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.stat(path)+ ::
|
|
|
|
See stat(2).
|
|
|
|
- on success: Returns +stats+ object. It looks like this:
|
|
|
|
+{ dev: 2049, ino: 305352, mode: 16877, nlink: 12, uid: 1000, gid: 1000,
|
|
|
|
rdev: 0, size: 4096, blksize: 4096, blocks: 8, atime:
|
|
|
|
"2009-06-29T11:11:55Z", mtime: "2009-06-29T11:11:40Z", ctime:
|
|
|
|
"2009-06-29T11:11:40Z" }+
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
+node.fs.unlink(path)+ ::
|
|
|
|
See unlink(2)
|
|
|
|
- on success: no parameters.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.rmdir(path)+ ::
|
|
|
|
See rmdir(2)
|
|
|
|
- on success: no parameters.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.close(fd)+ ::
|
|
|
|
See close(2)
|
|
|
|
- on success: no parameters.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.open(path, flags, mode)+::
|
|
|
|
See open(2). The constants like +O_CREAT+ are defined at +node.O_CREAT+.
|
|
|
|
- on success: +fd+ is given as the parameter.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.write(fd, data, position)+::
|
|
|
|
Write data to the file specified by +fd+. +data+ is either an array of
|
|
|
|
integers (for raw data) or a string for UTF-8 encoded characters.
|
|
|
|
+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. See pwrite(2).
|
|
|
|
- on success: returns an integer +written+ which specifies how many _bytes_ were written.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
+node.fs.read(fd, length, position, encoding)+::
|
|
|
|
|
|
|
|
Read data from the file specified by +fd+.
|
|
|
|
+
|
|
|
|
+length+ is an integer specifying the number of
|
|
|
|
bytes to read.
|
|
|
|
+
|
|
|
|
+position+ is an integer specifying where to begin
|
|
|
|
reading from in the file.
|
|
|
|
+
|
|
|
|
+encoding+ is either +node.UTF8+
|
|
|
|
or +node.RAW+.
|
|
|
|
+
|
|
|
|
- on success: returns +data, bytes_read+, what was read from the file.
|
|
|
|
- on error: no parameters.
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.fs.File+
|
|
|
|
|
|
|
|
A buffered file object.
|
|
|
|
|
|
|
|
Internal request queues exist for each instance of +node.fs.File+ so that
|
|
|
|
multiple commands can be issued at once. Thus the following is safe:
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
var file = new node.fs.File();
|
|
|
|
file.open("/tmp/blah", "w+");
|
|
|
|
file.write("hello");
|
|
|
|
file.write("world");
|
|
|
|
file.close();
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event |Parameters | Notes
|
|
|
|
|+"error"+ | | Emitted if an error happens.
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+new node.fs.File(options={})+::
|
|
|
|
Creates a new file object.
|
|
|
|
+
|
|
|
|
The +options+ argument is optional. It can contain
|
|
|
|
the following fields
|
|
|
|
+
|
|
|
|
- +fd+: a file descriptor for the file.
|
|
|
|
- +encoding+: how +file.read()+ should return data. Either +"raw"+ or +"utf8"+.
|
|
|
|
Defaults to +"raw"+.
|
|
|
|
|
|
|
|
|
|
|
|
+file.open(path, mode)+::
|
|
|
|
Opens the file at +path+.
|
|
|
|
+
|
|
|
|
+mode+ is a string:
|
|
|
|
+
|
|
|
|
- "r", open for reading and writing.
|
|
|
|
- "r+", open for only reading.
|
|
|
|
- "w", create a new file for reading and writing; if it already exists truncate it.
|
|
|
|
- "w+", create a new file for writing only; if it already exists truncate it.
|
|
|
|
- "a", create a new file for writing and reading. Writes append to the end of the file.
|
|
|
|
- "a+"
|
|
|
|
|
|
|
|
|
|
|
|
+file.read(length, position)+::
|
|
|
|
Reads +length+ bytes from the file at +position+. +position+ can be omitted
|
|
|
|
to write at the current file position.
|
|
|
|
|
|
|
|
|
|
|
|
+file.write(data, position)+::
|
|
|
|
Writes +data+ to the file. +position+ can be omitted to write at the current
|
|
|
|
file position.
|
|
|
|
|
|
|
|
|
|
|
|
+file.close()+::
|
|
|
|
Closes the file.
|
|
|
|
|
|
|
|
|
|
|
|
=== HTTP
|
|
|
|
|
|
|
|
The HTTP interfaces in Node are designed to support many features
|
|
|
|
of the protocol which have been traditionally difficult to use.
|
|
|
|
In particular, large, possibly chunk-encoded, messages. The interface is
|
|
|
|
careful to never buffer entire requests or responses--the
|
|
|
|
user is able to stream data.
|
|
|
|
|
|
|
|
HTTP message headers are represented by an array of 2-element
|
|
|
|
arrays like this
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
[ ["Content-Length", "123"]
|
|
|
|
, ["Content-Type", "text/plain"]
|
|
|
|
, ["Connection", "keep-alive"]
|
|
|
|
, ["Accept", "*/*"]
|
|
|
|
]
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
In order to support the full spectrum of possible HTTP applications, Node's
|
|
|
|
HTTP API is very low-level. It deals with connection handling and message
|
|
|
|
parsing only. It parses a message into headers and body but it does not
|
|
|
|
parse the actual headers or the body. That means, for example, that Node
|
|
|
|
does not, and will never, provide API to access or manipulate Cookies or
|
|
|
|
multi-part bodies. _This is left to the user._
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.http.Server+
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event | Parameters | Notes
|
|
|
|
|
|
|
|
|+"request"+ | +request, response+ |
|
|
|
|
+request+ is an instance of +node.http.ServerRequest+
|
|
|
|
+
|
|
|
|
+response+ is an instance of +node.http.ServerResponse+
|
|
|
|
|
|
|
|
|+"connection"+ | +connection+ |
|
|
|
|
When a new TCP connection is established.
|
|
|
|
+connection+ is an object of type +node.http.Connection+. Usually users will not
|
|
|
|
want to access this event. The +connection+ can also be accessed at
|
|
|
|
+request.connection+.
|
|
|
|
|
|
|
|
|+"close"+ | +errorno+ | Emitted when the server closes. +errorno+
|
|
|
|
is an integer which indicates what, if any,
|
|
|
|
error caused the server to close. If no
|
|
|
|
error occured +errorno+ will be 0.
|
|
|
|
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+node.http.createServer(request_listener, options);+ ::
|
|
|
|
Returns a new web server object.
|
|
|
|
+
|
|
|
|
The +options+ argument is optional. The
|
|
|
|
+options+ argument accepts the same values as the
|
|
|
|
options argument for +node.tcp.Server+ does.
|
|
|
|
+
|
|
|
|
The +request_listener+ is a function which is automatically
|
|
|
|
added to the +"request"+ event.
|
|
|
|
|
|
|
|
+server.listen(port, hostname)+ ::
|
|
|
|
Begin accepting connections on the specified port and hostname.
|
|
|
|
If the hostname is omitted, the server will accept connections
|
|
|
|
directed to any address.
|
|
|
|
|
|
|
|
+server.close()+ ::
|
|
|
|
Stops the server from accepting new connections.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.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.
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event | Parameters | Notes
|
|
|
|
|
|
|
|
|+"body"+ | +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 is either a String in the case of UTF-8 encoding or
|
|
|
|
an array of numbers in the case of raw encoding. The body encoding is set
|
|
|
|
with +request.setBodyEncoding()+.
|
|
|
|
|
|
|
|
|+"complete"+ | |
|
|
|
|
Emitted exactly once for each message. No arguments.
|
|
|
|
After emitted no other events will be emitted on the request.
|
|
|
|
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+request.method+ ::
|
|
|
|
The request method as a string. Read only. Example:
|
|
|
|
+"GET"+, +"DELETE"+.
|
|
|
|
|
|
|
|
|
|
|
|
+request.uri+ ::
|
|
|
|
Request URI Object. This contains only the parameters that are
|
|
|
|
present in the actual http request. That is, if the request is
|
|
|
|
+
|
|
|
|
----------------------------------------
|
|
|
|
GET /status?name=ryan HTTP/1.1\r\n
|
|
|
|
Accept: */*\r\n
|
|
|
|
\r\n
|
|
|
|
----------------------------------------
|
|
|
|
+
|
|
|
|
Then +request.uri+ will be
|
|
|
|
+
|
|
|
|
----------------------------------------
|
|
|
|
{ path: "/status",
|
|
|
|
file: "status",
|
|
|
|
directory: "/",
|
|
|
|
params: { "name" : "ryan" }
|
|
|
|
}
|
|
|
|
----------------------------------------
|
|
|
|
+
|
|
|
|
In particular, note that +request.uri.protocol+ is
|
|
|
|
+undefined+. This is because there was no URI protocol given
|
|
|
|
in the actual HTTP Request.
|
|
|
|
+
|
|
|
|
+request.uri.anchor+, +request.uri.query+, +request.uri.file+, +request.uri.directory+, +request.uri.path+, +request.uri.relative+, +request.uri.port+, +request.uri.host+, +request.uri.password+, +request.uri.user+, +request.uri.authority+, +request.uri.protocol+, +request.uri.params+, +request.uri.toString()+, +request.uri.source+
|
|
|
|
|
|
|
|
|
|
|
|
+request.headers+ ::
|
|
|
|
The request headers expressed as an array of 2-element arrays.
|
|
|
|
Read only.
|
|
|
|
|
|
|
|
|
|
|
|
+request.httpVersion+ ::
|
|
|
|
The HTTP protocol version as a string. Read only. Examples:
|
|
|
|
+"1.1"+, +"1.0"+
|
|
|
|
|
|
|
|
|
|
|
|
+request.setBodyEncoding(encoding)+ ::
|
|
|
|
Set the encoding for the request body. Either +"utf8"+ or +"raw"+. Defaults
|
|
|
|
to raw.
|
|
|
|
|
|
|
|
+request.connection+ ::
|
|
|
|
The +node.http.Connection+ object.
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.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.
|
|
|
|
|
|
|
|
+response.sendHeader(statusCode, headers)+ ::
|
|
|
|
|
|
|
|
Sends a response header to the request. The status code is a 3-digit HTTP
|
|
|
|
status code, like +404+. The second argument, +headers+, should be an array
|
|
|
|
of 2-element arrays, representing the response headers.
|
|
|
|
+
|
|
|
|
Example:
|
|
|
|
+
|
|
|
|
----------------------------------------
|
|
|
|
var body = "hello world";
|
|
|
|
response.sendHeader(200, [
|
|
|
|
["Content-Length", body.length],
|
|
|
|
["Content-Type", "text/plain"]
|
|
|
|
]);
|
|
|
|
----------------------------------------
|
|
|
|
+
|
|
|
|
This method must only be called once on a message and it must
|
|
|
|
be called before +response.finish()+ is called.
|
|
|
|
|
|
|
|
+response.sendBody(chunk, encoding="ascii")+ ::
|
|
|
|
|
|
|
|
This method must be called after +sendHeader+ was
|
|
|
|
called. It sends a chunk of the response body. This method may
|
|
|
|
be called multiple times to provide successive parts of the body.
|
|
|
|
+
|
|
|
|
If +chunk+ is a string, the second parameter
|
|
|
|
specifies how to encode it into a byte stream. By default the
|
|
|
|
+encoding+ is +"ascii"+.
|
|
|
|
+
|
|
|
|
Note: This is the raw HTTP body and has nothing to do with
|
|
|
|
higher-level multi-part body encodings that may be used.
|
|
|
|
|
|
|
|
|
|
|
|
+response.finish()+ ::
|
|
|
|
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
|
|
|
|
response.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.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
|
|
|
|
requests. Depending on the server connected to, the client might
|
|
|
|
pipeline the requests or reestablish the connection after each
|
|
|
|
connection. _Currently the implementation does not pipeline requests._
|
|
|
|
|
|
|
|
Example of connecting to +google.com+
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
var google = node.http.createClient(80, "google.com");
|
|
|
|
var request = google.get("/");
|
|
|
|
request.finish(function (response) {
|
|
|
|
puts("STATUS: " + response.statusCode);
|
|
|
|
puts("HEADERS: " + JSON.stringify(response.headers));
|
|
|
|
response.setBodyEncoding("utf8");
|
|
|
|
response.addListener("body", function (chunk) {
|
|
|
|
puts("BODY: " + chunk);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
+node.http.createClient(port, host)+ ::
|
|
|
|
|
|
|
|
Constructs a new HTTP client. +port+ and
|
|
|
|
+host+ refer to the server to be connected to. A
|
|
|
|
connection is not established until a request is issued.
|
|
|
|
|
|
|
|
+client.get(path, request_headers)+, +client.head(path, request_headers)+, +client.post(path, request_headers)+, +client.del(path, request_headers)+, +client.put(path, request_headers)+ ::
|
|
|
|
|
|
|
|
Issues a request; if necessary establishes connection. Returns a +node.http.ClientRequest+ instance.
|
|
|
|
+
|
|
|
|
+request_headers+ is optional.
|
|
|
|
+request_headers+ should be an array of 2-element
|
|
|
|
arrays. Additional request headers might be added internally
|
|
|
|
by Node. Returns a +ClientRequest+ object.
|
|
|
|
+
|
|
|
|
Do remember to include the +Content-Length+ header if you
|
|
|
|
plan on sending a body. If you plan on streaming the body, perhaps
|
|
|
|
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
|
|
|
|
the response. (This sounds convoluted but it provides a chance
|
|
|
|
for the user to stream a body to the server with
|
|
|
|
+request.sendBody()+.)
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.http.ClientRequest+
|
|
|
|
|
|
|
|
This object is created internally and returned from the request methods of a
|
|
|
|
+node.http.Client+. It represents an _in-progress_ request whose header has
|
|
|
|
already been sent.
|
|
|
|
|
|
|
|
[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.
|
|
|
|
+
|
|
|
|
This event is emitted only once.
|
|
|
|
+
|
|
|
|
The +response+ argument will be an instance of +node.http.ClientResponse+.
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
|
|
|
|
+request.sendBody(chunk, encoding="ascii")+ ::
|
|
|
|
|
|
|
|
Sends a sucessive peice of the body. By calling this method
|
|
|
|
many times, the user can stream a request body to a
|
|
|
|
server—in that case it is suggested to use the
|
|
|
|
+["Transfer-Encoding", "chunked"]+ header line when
|
|
|
|
creating the request.
|
|
|
|
+
|
|
|
|
The +chunk+ argument should be an array of integers
|
|
|
|
or a string.
|
|
|
|
+
|
|
|
|
The +encoding+ argument is optional and only
|
|
|
|
applies when +chunk+ is a string. The encoding
|
|
|
|
argument should be either +"utf8"+ or
|
|
|
|
+"ascii"+. By default the body uses ASCII encoding,
|
|
|
|
as it is faster.
|
|
|
|
|
|
|
|
|
|
|
|
+request.finish(response_listener)+ ::
|
|
|
|
|
|
|
|
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 +response_listener+ is a callback which
|
|
|
|
will be executed when the response headers have been received.
|
|
|
|
The +response_listener+ callback is executed with one
|
|
|
|
argument which is an instance of +node.http.ClientResponse+.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.http.ClientResponse+
|
|
|
|
|
|
|
|
This object is created internally and passed to the +"response"+ event.
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event | Parameters | Notes
|
|
|
|
|
|
|
|
|+"body"+ | +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 is either a String in the case of UTF-8 encoding or
|
|
|
|
an array of numbers in the case of raw encoding. The body encoding is set
|
|
|
|
with +response.setBodyEncoding()+.
|
|
|
|
|
|
|
|
|+"complete"+ | |
|
|
|
|
Emitted exactly once for each message. No arguments.
|
|
|
|
After emitted no other events will be emitted on the response.
|
|
|
|
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+response.statusCode+ ::
|
|
|
|
The 3-digit HTTP response status code. E.G. +404+.
|
|
|
|
|
|
|
|
+response.httpVersion+ ::
|
|
|
|
The HTTP version of the connected-to server. Probably either
|
|
|
|
+"1.1"+ or +"1.0"+.
|
|
|
|
|
|
|
|
+response.headers+ ::
|
|
|
|
The response headers. An Array of 2-element arrays.
|
|
|
|
|
|
|
|
+response.setBodyEncoding(encoding)+ ::
|
|
|
|
Set the encoding for the response body. Either +"utf8"+ or +"raw"+.
|
|
|
|
Defaults to raw.
|
|
|
|
|
|
|
|
+response.client+ ::
|
|
|
|
A reference to the +node.http.Client+ that this response belongs to.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== TCP
|
|
|
|
|
|
|
|
==== +node.tcp.Server+
|
|
|
|
|
|
|
|
Here is an example of a echo server which listens for connections
|
|
|
|
on port 7000
|
|
|
|
|
|
|
|
----------------------------------------
|
|
|
|
function echo (socket) {
|
|
|
|
socket.setEncoding("utf8");
|
|
|
|
socket.addListener("connect", function () {
|
|
|
|
socket.send("hello\r\n");
|
|
|
|
});
|
|
|
|
socket.addListener("receive", function (data) {
|
|
|
|
socket.send(data);
|
|
|
|
});
|
|
|
|
socket.addListener("eof", function () {
|
|
|
|
socket.send("goodbye\r\n");
|
|
|
|
socket.close();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
var server = node.tcp.createServer(echo, {backlog: 1024});
|
|
|
|
server.listen(7000, "localhost");
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event | Parameters | Notes
|
|
|
|
|+"connection"+ | +connection+ | Emitted when a new connection is made.
|
|
|
|
+connection+ is an instance of +node.tcp.Connection+.
|
|
|
|
|+"close"+ | +errorno+ | Emitted when the server closes. +errorno+
|
|
|
|
is an integer which indicates what, if any,
|
|
|
|
error caused the server to close. If no
|
|
|
|
error occured +errorno+ will be 0.
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+node.tcp.createServer(connection_listener, options={});+ ::
|
|
|
|
Creates a new TCP server.
|
|
|
|
+
|
|
|
|
The +connection_listener+ argument is automatically set as a listener for
|
|
|
|
the +"connection"+ event.
|
|
|
|
+
|
|
|
|
+options+ for now only supports one option:
|
|
|
|
+backlog+ which should be an integer and describes
|
|
|
|
how large of a connection backlog the operating system should
|
|
|
|
maintain for this server. The +backlog+ defaults
|
|
|
|
to 1024.
|
|
|
|
|
|
|
|
|
|
|
|
+server.listen(port, host=null)+ ::
|
|
|
|
Tells the server to listen for TCP connections to +port+
|
|
|
|
and +host+. Note, +host+ is optional. If
|
|
|
|
+host+ is not specified the server will accept
|
|
|
|
connections to any IP address on the specified port.
|
|
|
|
|
|
|
|
|
|
|
|
+server.close()+::
|
|
|
|
Stops the server from accepting new connections.
|
|
|
|
|
|
|
|
|
|
|
|
==== +node.tcp.Connection+
|
|
|
|
|
|
|
|
This object is used as a TCP client and also as a server-side
|
|
|
|
socket for +node.tcp.Server+.
|
|
|
|
|
|
|
|
[cols="1,2,10",options="header"]
|
|
|
|
|=========================================================
|
|
|
|
|Event | Parameters | Notes
|
|
|
|
|+"connect"+ | | Call once the connection is established.
|
|
|
|
|+"receive"+ | +data+ | Called when data is received on the
|
|
|
|
connection. Encoding of data is set
|
|
|
|
by +connection.setEncoding()+. +data+
|
|
|
|
will either be a string, in the case of
|
|
|
|
utf8, or an array of integer in the case
|
|
|
|
of raw encoding.
|
|
|
|
|+"eof"+ | | Called when the other end of the
|
|
|
|
connection sends a FIN packet.
|
|
|
|
After this is emitted the +readyState+
|
|
|
|
will be +"writeOnly"+. One should probably
|
|
|
|
just call +connection.close()+ when this
|
|
|
|
event is emitted.
|
|
|
|
|+"disconnect"+ | +had_error+ | Emitted once the connection is fully
|
|
|
|
disconnected. The argument +had_error+
|
|
|
|
is a boolean which says if the connection
|
|
|
|
was closed due to a transmission error.
|
|
|
|
(TODO: access error codes.)
|
|
|
|
|=========================================================
|
|
|
|
|
|
|
|
+node.tcp.createConnection(port, host="127.0.0.1")+::
|
|
|
|
Creates a new connection object and
|
|
|
|
opens a connection to the specified +port+ and
|
|
|
|
+host+. If the second parameter is omitted, localhost is
|
|
|
|
assumed.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.remoteAddress+::
|
|
|
|
The string representation of the remote IP address. For example,
|
|
|
|
+"74.125.127.100"+ or +"2001:4860:a005::68"+.
|
|
|
|
+
|
|
|
|
This member is only present in server-side connections.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.readyState+::
|
|
|
|
Either +"closed"+, +"open"+, +"opening"+, +"readOnly"+, or +"writeOnly"+.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.setEncoding(encoding)+::
|
|
|
|
Sets the encoding (either +"utf8"+ or +"raw"+) for data that is received.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.send(data, encoding="ascii")+::
|
|
|
|
Sends data on the connection. The data should be eithre an array
|
|
|
|
of integers (for raw binary) or a string (for utf8 or ascii).
|
|
|
|
The second parameter specifies the encoding in the case of a
|
|
|
|
string--it defaults to ASCII because encoding to UTF8 is
|
|
|
|
rather slow.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.close()+::
|
|
|
|
Half-closes the connection. I.E. sends a FIN packet. It is
|
|
|
|
possible the server will still send some data. After calling
|
|
|
|
this +readyState+ will be +"readOnly"+.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.fullClose()+::
|
|
|
|
Close both ends of the connection. Data that is received
|
|
|
|
after this call is responded to with RST packets. If you don't
|
|
|
|
know about this, just use +close()+.
|
|
|
|
|
|
|
|
|
|
|
|
+connection.forceClose()+::
|
|
|
|
Ensures that no more I/O activity happens on this socket. Only
|
|
|
|
necessary in case of errors (parse error or so).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// vim: set syntax=asciidoc:
|