diff options
-rwxr-xr-x | configure | 13 | ||||
-rw-r--r-- | website/api.html | 1101 | ||||
-rw-r--r-- | website/api.txt | 1009 |
3 files changed, 1018 insertions, 1105 deletions
@@ -96,13 +96,18 @@ uninstall: test: all python tools/test.py --mode=release - -test-debug: all - python tools/test.py --mode=debug test-all: all python tools/test.py --mode=debug,release +website: website/api.html website/index.html + +website/api.html: website/api.txt + asciidoc -a toc -o website/api.html website/api.txt + +website-upload: website + scp website/* linode:~/tinyclouds/node/ + clean: @$WAF clean @@ -118,7 +123,7 @@ check: dist: @$WAF dist -.PHONY: clean dist distclean check uninstall install all test +.PHONY: clean dist distclean check uninstall install all test test-all website website-upload EOF } diff --git a/website/api.html b/website/api.html deleted file mode 100644 index 4b059e4e0..000000000 --- a/website/api.html +++ /dev/null @@ -1,1101 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> - <script type="text/javascript" src="sh_main.js"></script> - <script type="text/javascript" src="sh_javascript.min.js"></script> - <link type="text/css" rel="stylesheet" href="style.css" /> - <link type="text/css" rel="stylesheet" href="sh_vim-dark.css" /> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - - <title>node.js</title> -</head> -<body onload="sh_highlightDocument();"> -<div id="toc"> - <ol> - <li><a href="#timers">Timers</a></li> - <li><a href="#processes">Processes</a></li> - <li> - <a href="#files">File I/O</a> - <ol> - <li><a href="#file_wrappers">Wrappers</a></li> - <li><a href="#file_file">File</a></li> - </ol> - </li> - <li> - <a href="#tcp">TCP</a> - <ol> - <li><a href="#tcp_server">Server</a></li> - <li><a href="#tcp_connection">Connection</a></li> - </ol> - </li> - <li> - <a href="#http">HTTP</a> - <ol> - <li> - <a href="#http_server">Server</a> - <ol> - <li><a href="#http_server_request">Request</a></li> - <li><a href="#http_server_response">Response</a></li> - </ol> - </li> - <li> - <a href="#http_client">Client</a> - <ol> - <li><a href="#http_client_request">Request</a></li> - <li><a href="#http_client_response">Response</a></li> - </ol> - </li> - </ol> - </li> - <li><a href="#modules">Modules</a> - <ol> - <li><a href="#onload">onLoad</a></li> - <li><a href="#onexit">onExit</a></li> - </ol> - </ol> -</div> - -<div id="content"> - <h1 id="api">Node API</h1> - <p> - Conventions: Callbacks are object members which are prefixed with - <code>on</code>. All methods and members are camel cased. Constructors - always have a capital first letter. - </p> - - <p> - Node supports 3 byte-string encodings: ASCII (<code>"ascii"</code>), - UTF-8 (<code>"utf8"</code>), and raw binary (<code>"raw"</code>). - 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 - <a href="http://code.google.com/p/v8/issues/detail?id=270"> - V8 supports Blob objects - </a>. - </p> - - <p>The following are global functions:</p> - - <dl> - <dt><code>puts(string, callback)</code></dt> - <dd> - Alias for <code>stdout.puts()</code>. Outputs the - <code>string</code> and a trailing new-line to - <code>stdout</code>. - - <p> - The <code>callback</code> argument is optional and mostly - useless: it will notify the user when the operation has - completed. Everything in node is asynchronous; - <code>puts()</code> is no exception. This might seem ridiculous - but, if for example, one is piping <code>stdout</code> into an - NFS file, <code>printf()</code> will block from network latency. - There is an internal queue for <code>puts()</code> output, so - you can be assured that output will be displayed in the order - it was called. - </p> - </dd> - - <dt><code>print(string, callback)</code></dt> - <dd>Like <code>puts()</code> but without the trailing new-line.</dd> - - <dt><code>node.debug(string)</code></dt> - <dd> - A synchronous output function. Will <i>block</i> the process and - output the string immediately to stdout. Use with care. - </dd> - - <dt><code>node.exit(code)</code></dt> - <dd>Immediately ends the process with the specified code.</dd> - - <dt><code>ARGV</code></dt> - <dd>An array containing the command line arguments.</dd> - - <dt><code>stdout</code>, - <code>stderr</code>, and - <code>stdin</code> - </dt> - <dd>Objects of type <code>node.fs.File</code>. (See below)</dd> - </dl> - - <h2 id="timers">Timers</h2> - - <dl> - <dt><code>setTimeout(callback, delay)</code></dt> - <dd> - To schedule execution of <code>callback</code> after - <code>delay</code> milliseconds. Returns a <code>timeoutId</code> - for possible use with <code>clearTimeout()</code>. - </dd> - - <dt><code>clearTimeout(timeoutId)</code></dt> - <dd>Prevents said timeout from triggering.</dd> - - <dt><code>setInterval(callback, delay)</code></dt> - <dd> - To schedule the repeated execution of <code>callback</code> - every<code>delay</code> milliseconds. Returns a - <code>intervalId</code> for possible use with - <code>clearInterval()</code>. - </dd> - - <dt><code>clearInterval(intervalId)</code></dt> - <dd>Stops a interval from triggering.</dd> - </dl> - - <h2 id="processes">Processes and IPC</h2> - - <p> - Node provides a tridirectional <code>popen(3)</code> facility. - It is possible to stream data through the child's <code>stdin</code>, - <code>stdout</code>, and <code>stderr</code> in a fully non-blocking - way. - </p> - - <dl> - <dt><code>new node.Process(command)</code></dt> - <dd>Launches a new process with the given <code>command</code>. For example: - <pre>var ls = new Process("ls -lh /usr");</pre> - </dd> - - <dt><code>process.pid</code></dt> - <dd>The PID of the child process.</dd> - - <dt><code>process.onOutput = function (chunk) { };</code></dt> - <dd>A callback to receive output from the process's <code>stdout</code>. - At the moment the received data is always a string and utf8 encoded. - (More encodings will be supported in the future.) - - <p>If the process closes its <code>stdout</code>, this callback will - be issued with <code>null</code> as an argument. Be prepared for this - possibility. - </dd> - - <dt><code>process.onError = function (chunk) { };</code></dt> - <dd>A callback to receive output from the process's <code>stderr</code>. - At the moment the received data is always a string and utf8 encoded. - (More encodings will be supported in the future.) - - <p>If the process closes its <code>stderr</code>, this callback will - be issued with <code>null</code> as an argument. Be prepared for this - possibility. - </dd> - - <dt><code>process.onExit = function (exit_code) { };</code></dt> - <dd>A callback which is called when the child process terminates. - The argument is the exit status of the child. - </dd> - - <dt><code>process.write(data, encoding="ascii");</code></dt> - <dd>Write data to the child process's <code>stdin</code>. The second - argument is optional and specifies the encoding: possible values are - <code>"utf8"</code>, <code>"ascii"</code>, and <code>"raw"</code>. - </dd> - - <dt><code>process.close();</code></dt> - <dd>Closes the process's <code>stdin</code> stream.</dd> - - <dt><code>process.kill(signal=node.SIGTERM);</code></dt> - <dd>Kills the child process with the given signal. If no argument is - given, the process will be sent <code>node.SIGTERM</code>. The standard - POSIX signals are defined under the <code>node</code> namespace (e.g. - <code>node.SIGINT</code>, <code>node.SIGUSR1</code>). - </dd> - </dl> - - <h2 id="files"><code>node.fs</code></h2> - - <p> - File I/O is tricky because there are not simple non-blocking ways - to do it. Node handles file I/O by employing - <a href="http://software.schmorp.de/pkg/libeio.html"> - an internal thread pool - </a> to execute file system calls. - </p> - - <p> - This part of the API is split into two parts: simple wrappers - around standard POSIX file I/O functions and a user-friendly - <code>File</code> object. - </p> - - <h3 id="file_wrappers">POSIX Wrappers</h3> - - <p> - All POSIX wrappers have a similar form. They return - <code>undefined</code> and have a callback called - <code>on_completion</code> as their last argument. The - <code>on_completion</code> callback may be passed many parameters, - but the first parameter is always an integer indicating the error - status. If the status integer is zero, then the call was successful. - Example: - </p> - <pre> -node.fs.unlink("/tmp/hello", function (status) { - if (status == 0) - puts("successfully deleted /tmp/hello"); -});</pre> - - <p> - There is no guaranteed ordering to the POSIX wrappers. The - following is very much prone to error - </p> - <pre> -node.fs.rename("/tmp/hello", "/tmp/world"); -node.fs.stat("/tmp/world", function (status, stats) { - puts("stats: " + JSON.stringify(stats)); -});</pre> - <p> - because it could be that <code>stat()</code> is executed before - the <code>rename()</code>. The correct way to do this, is use the - <code>on_completion</code> callback for <code>rename()</code> - </p> - <pre> -node.fs.rename("/tmp/hello", "/tmp/world", function (status) { - if (status != 0) return; - node.fs.stat("/tmp/world", function (status, stats) { - puts("stats: " + JSON.stringify(stats)); - }); -});</pre> - - <dl> - <dt><code>node.fs.rename(path1, path2, on_completion(status))</code></dt> - <dd> <a href="http://opengroup.org/onlinepubs/007908799/xsh/rename.html">rename(2)</a> </dd> - - <dt><code>node.fs.stat(path, on_completion(status, stats))</code></dt> - <dd> <a href="http://opengroup.org/onlinepubs/007908799/xsh/stat.html">stat(2)</a> </dd> - - <dt><code>node.fs.unlink(path, on_completion(status))</code></dt> - <dd> <a href="http://opengroup.org/onlinepubs/007908799/xsh/unlink.html">unlink(2)</a> </dd> - - <dt><code>node.fs.rmdir(path, on_completion(status))</code></dt> - <dd> <a href="http://opengroup.org/onlinepubs/007908799/xsh/rmdir.html">rmdir(2)</a> </dd> - - <dt><code>node.fs.close(fd, on_completion(status))</code></dt> - <dd> <a href="http://opengroup.org/onlinepubs/007908799/xsh/close.html">close(2)</a> </dd> - - <dt><code>node.fs.open(path, flags, mode, on_completion(status, fd))</code></dt> - <dd> - <a href="http://opengroup.org/onlinepubs/007908799/xsh/open.html">open(2)</a> - <p> - The constants like <code>O_CREAT</code> are defined at - <code>node.O_CREAT</code>. - </p> - </dd> - - <dt><code>node.fs.write(fd, data, position, on_completion(status, written))</code></dt> - <dd> - Write data to the file specified by <code>fd</code>. - <p> - <code>data</code> is either an array of integer (for raw - data) or a string for UTF-8 encoded characters. - </p> - <p> - <code>position</code> refers to the offset from the beginning - of the file where this data should be written. If - <code>null</code>, the data will be written at the current - position. - </p> - <p>See also - <a href="http://opengroup.org/onlinepubs/007908799/xsh/pwrite.html">pwrite(2)</a> - </p> - </dd> - - <dt><code>node.fs.read(fd, length, position, encoding, on_completion(status, data))</code></dt> - <dd> - Read data from the file specified by <code>fd</code>. - - <p> - <code>length</code> is an integer specifying the number of - bytes to read. - </p> - - <p> - <code>position</code> is an integer specifying where to begin - reading from in the file. - </p> - - <p> - <code>encoding</code> is either <code>node.UTF8</code> - or <code>node.RAW</code>. - </p> - </dd> - </dl> - - <h3 id="file_file"><code>node.fs.File</code></h3> - - <p>Easy buffered file object.</p> - - <p> - Internal request queues exist for each file object so that - multiple commands can be issued at once without worry that they - will be executed out-of-order. Thus the following is safe: - </p> - - <pre> -var file = new node.fs.File(); -file.open("/tmp/blah", "w+"); -file.write("hello"); -file.write("world"); -file.close();</pre> - - <p> - Request queues are local to a single file. If one does - </p> - <pre> -fileA.write("hello"); -fileB.write("world");</pre> - <p> - it could be that <code>fileB</code> gets written to before - <code>fileA</code> is written to. If a certain operation order - is needed involving multiple files, use the completion callbacks: - </p> - <pre> -fileA.write("hello", function () { - fileB.write("world"); -});</pre> - - <dl> - <dt><code>new node.fs.File(options={})</code></dt> - <dd> - Creates a new file object. - - <p> - The <code>options</code> argument is optional. It can contain - the following fields - </p> - <ul> - <li><code>fd</code> — a file descriptor for the file.</li> - <li> - <code>encoding</code> — how <code>file.read()</code> - should return data. Either <code>"raw"</code> or - <code>"utf8"</code>. Defaults to raw. - </li> - </ul> - </dd> - - <dt><code>file.onError = function (method, errno, msg) { }</code></dt> - <dd> - Callback. This is called internally anytime an error occurs with - this file. There are three arguments: the method name, the POSIX - errno, and a string describing the error. - - <p>Example</p> - <pre> -var path = "/some/path/that/doesnt/exist"; -var file = new node.fs.File(); -file.onError = function (method, errno, msg) { - stderr.puts("An error occurred calling " + method); - stderr.puts(msg); - node.exit(1); -} -file.open(path, "w+")</pre> - </dd> - - <dt><code>file.open(path, mode, on_completion())</code></dt> - <dd> - Opens the file at <code>path</code>. - <p> - <code>mode</code> is a string: <code>"r"</code> open for - reading and writing. <code>"r+"</code> open for only reading. - <code>"w"</code> create a new file for reading and writing; - if it already exists truncate it. <code>"w+"</code> create a - new file for writing only; if it already exists truncate it. - <code>"a"</code> create a new file for writing and reading. - Writes append to the end of the file. - <!-- TODO: Describe mode a+ --> - <code>"a+"</code> - <!-- TODO: Describe mode a+ --> - </p> - <p> - The <code>on_completion</code> is a callback that is made - without arguments when the operation completes. It is optional. - If an error occurred the <code>on_completion</code> callback - will not be called, but the <code>file.onError</code> will be - called. - </p> - </dd> - - <dt><code>file.read(length, position, on_completion(data))</code></dt> - <dd></dd> - - <dt><code>file.write(data, position, on_completion(written))</code></dt> - <dd></dd> - - <dt><code>file.close(on_completion())</code></dt> - <dd></dd> - </dl> - - <h2 id="tcp"><code>node.tcp</code></h2> - - <h3 id="tcp_server"><code>node.tcp.Server</code></h3> - - <p> - Here is an example of a echo server which listens for connections - on port 7000 - </p> - <pre> -function Echo (socket) { - socket.setEncoding("utf8"); - socket.onConnect = function () { - socket.send("hello\r\n"); - }; - socket.onReceive = function (data) { - socket.send(data); - }; - socket.onEOF = function () { - socket.send("goodbye\r\n"); - socket.close(); - }; -} -var server = new node.tcp.Server(Echo, {backlog: 1024}); -server.listen(7000, "localhost");</pre> - - <dl> - <dt><code>new node.tcp.Server(connection_handler(socket), options={});</code></dt> - <dd> - Creates a new TCP server. - - <p> - <code>connection_handler</code> is a callback which is called - on each connection. It is given one argument: an instance of - <code>node.tcp.Connection</code>. - </p> - - <p> - <code>options</code> for now only supports one option: - <code>backlog</code> which should be an integer and describes - how large of a connection backlog the operating system should - maintain for this server. The <code>backlog</code> defaults - to 1024. - </p> - </dd> - - <dt><code>server.listen(port, host=null)</code></dt> - <dd> - Tells the server to listen for TCP connections to <code>port</code> - and <code>host</code>. Note, <code>host</code> is optional. If - <code>host</code> is not specified the server will accept - connections to any IP address on the specified port. - </dd> - - <dt><code>server.close()</code></dt> - <dd> Stops the server from accepting new connections. </dd> - </dl> - - <h3 id="tcp_connection"><code>node.tcp.Connection</code></h3> - - <p> - This object is used as a TCP client and also as a server-side - socket for <code>node.tcp.Server</code>s. - </p> - - <dl> - <dt><code>new node.tcp.Connection()</code></dt> - <dd>Creates a new connection object.</dd> - - <dt><code>connection.connect(port, host="127.0.0.1")</code></dt> - <dd> - Opens a connection to the specified <code>port</code> and - <code>host</code>. If the second parameter is omitted, localhost is - assumed. - </dd> - - <dt><code>connection.remoteAddress</code></dt> - <dd> - The string representation of the remote IP address. For example, - <code>"74.125.127.100"</code> or <code>"2001:4860:a005::68"</code>. - - <p>This member is only present in server-side connections.</p> - </dd> - - <dt><code>connection.readyState</code></dt> - <dd> - Either <code>"closed"</code>, <code>"open"</code>, <code>"opening"</code> - <code>"readOnly"</code>, or <code>"writeOnly"</code>. - </dd> - - <dt><code>connection.setEncoding(encoding)</code></dt> - <dd> - Sets the encoding (either <code>"utf8"</code> or - <code>"raw"</code>) for data that is received. - </dd> - - <dt><code>connection.send(data, encoding="ascii")</code></dt> - <dd> - 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. - </dd> - - <dt><code>connection.close()</code></dt> - <dd> - Half-closes the connection. I.E. sends a FIN packet. It is - possible the server will still send some data. After calling - this <code>readyState</code> will be <code>"readOnly"</code>. - </dd> - - <dt><code>connection.fullClose()</code></dt> - <dd> - 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 <code>close()</code>. - </dd> - - <dt><code>connection.forceClose()</code></dt> - <dd> - Ensures that no more I/O activity happens on this socket. Only - necessary in case of errors (parse error or so). - </dd> - - <dt><code>connection.onConnect = function () { };</code></dt> - <dd>Call once the connection is established.</dd> - - <dt><code>connection.onReceive = function (data) { };</code></dt> - <dd> - Called when data is received on the connection. Encoding of data - is set by <code>connection.setEncoding()</code>. - <code>data</code> will either be a string, in the case of utf8, - or an array of integer in the case of raw encoding. - </dd> - - <dt><code>connection.onEOF = function () { };</code></dt> - <dd> - Called when the other end of the connection sends a FIN packet. - <code>onReceive</code> will not be called after this. After - receiving this <code>readyState</code> will be - <code>"writeOnly"</code>. You should probably just call - <code>connection.close()</code> in this callback. - </dd> - - <dt><code>connection.onDisconnect = function (had_error) { };</code></dt> - <dd> - Called once the connection is fully disconnected. - - <p> - The callback is passed one boolean argument <code>had_error</code>. - This lets one know if the connect was closed due to an error. - (TODO: look up error codes.) - </p> - </dd> - - <dt><code>connection.onError = function () { };</code></dt> - <dd>Called on an error.</dd> - </dl> - - <h2 id="http"><code>node.http</code></h2> - - <p> - The HTTP interfaces here are designed to support many features - of the protocol which have been traditionally difficult to handle. - In particular, large, possibly chunked, messages. The interface is - careful to never buffer entire requests or responses—the - user is able to stream data. - </p> - - <p> - HTTP message headers are represented by an array of 2-element - arrays like this - </p> - <pre> -[ ["Content-Length", "123"] -, ["Content-Type", "text/plain"] -, ["Connection", "keep-alive"] -, ["Accept", "*/*"] -]</pre> - <p><i> - Dictionary-like objects are popularly used to represent HTTP - headers but they are an incorrect abstraction. It is rare, but - possible, to have multiple header lines with the same field. - Setting multiple cookies in a single response, for example, can - only be done with multiple <code>Cookie</code> lines. - </i></p> - - <p> - Node's HTTP abstraction deals with connection handling and message - parsing only. It parses the message into headers and body - but it does - not parse any of the headers or the body. This is left to the user. That - means, for example, that Node does not (and will never) provide API - to access or manipulate Cookies or multi-part bodies. - </p> - - <h3 id="http_server"><code>node.http.Server</code></h3> - - <dl> - <dt><code>new node.http.Server(request_handler, options);</code></dt> - <dd> - <p>Creates a new web server.</p> - - <p> - The <code>options</code> argument is optional. The - <code>options</code> argument accepts the same values as the - options argument for <code>node.tcp.Server</code> does. - </p> - - <p> - The <code>request_handler</code> is a callback which is made - on each request with a <code>ServerRequest</code> and - <code>ServerResponse</code> arguments. - </p> - </dd> - - <dt><code>server.listen(port, hostname)</code></dt> - <dd> - <p> - Begin accepting connections on the specified port and hostname. - If the hostname is omitted, the server will accept connections - directed to any address. - </p> - </dd> - - <dt><code>server.close()</code></dt> - <dd> - <p>Stops the server from accepting new connections.</p> - </dd> - </dl> - - <h3 id="http_server_request"><code>node.http.ServerRequest</code></h3> - - <p> - This object is created internally by a HTTP server—not by - the user. It is passed to the user as the first argument to the - <code>request_handler</code> callback. - </p> - - <dl> - <dt><code>req.method</code></dt> - <dd>The request method as a string. Read only. Example: - <code>"GET"</code>, <code>"DELETE"</code>. - </dd> - - <dt><code>req.uri</code></dt> - <dd> Request URI Object. This contains only the parameters that are - present in the actual http request. That is, if the request is -<pre class="sh_none">GET /status?name=ryan HTTP/1.1\r\n -Accept: */*\r\n -\r\n -</pre> - Then <code>req.uri</code> will be -<pre> -{ path: "/status", - file: "status", - directory: "/", - params: { "name" : "ryan" } -}</pre> - In particular, note that <code>req.uri.protocol</code> is - <code>undefined</code>. This is because there was no URI protocol given - in the actual HTTP Request. - </dd> - - <dt><code>req.uri.anchor</code></dt> - <dt><code>req.uri.query</code></dt> - <dt><code>req.uri.file</code></dt> - <dt><code>req.uri.directory</code></dt> - <dt><code>req.uri.path</code></dt> - <dt><code>req.uri.relative</code></dt> - <dt><code>req.uri.port</code></dt> - <dt><code>req.uri.host</code></dt> - <dt><code>req.uri.password</code></dt> - <dt><code>req.uri.user</code></dt> - <dt><code>req.uri.authority</code></dt> - <dt><code>req.uri.protocol</code></dt> - <dt><code>req.uri.params</code></dt> - <dt><code>req.uri.toString()</code>, <code>req.uri.source</code> </dt> - - <dt><code>req.headers</code></dt> - <dd> - The request headers expressed as an array of 2-element arrays. - Read only. - </dd> - - <dt><code>req.httpVersion</code></dt> - <dd> - The HTTP protocol version as a string. Read only. Examples: - <code>"1.1"</code>, <code>"1.0"</code> - </dd> - - <dt><code>req.onBody = function (chunk) { }; </code></dt> - <dd> - Callback. Should be set by the user to be informed of when a - piece of the message body is received. Example: - <pre> -req.onBody = function (chunk) { - puts("part of the body: " + chunk); -};</pre> - A chunk of the body is given as the single argument. The - transfer-encoding has been decoded. - - <p> - 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 <code>req.setBodyEncoding()</code>. - </p> - </dd> - - <dt><code>req.onBodyComplete = function () { };</code></dt> - <dd> - Callback. Made exactly once for each message. No arguments. - After <code>onBodyComplete</code> is executed - <code>onBody</code> will no longer be called. - </dd> - - <dt><code>req.setBodyEncoding(encoding)</code></dt> - <dd> - Set the encoding for the request body. Either <code>"utf8"</code> - or <code>"raw"</code>. Defaults to raw. - </dd> - - <dt><code>req.interrupt()</code></dt> - <dd> - Interrupt the request. You will not receive anymore callbacks. - This is useful if, for example someone is streaming up a file but it - is too large and neesd to be stopped. The connection to the client - will be closed immediately. - </dd> - </dl> - - <h3 id="http_server_response"><code>node.http.ServerResponse</code></h3> - - <p> - This object is created internally by a HTTP server—not by - the user. It is passed to the user as the second argument to the - <code>request_handler</code> callback. - </p> - - <dl> - <dt><code>res.sendHeader(statusCode, headers)</code></dt> - <dd> - Sends a response header to the request. The status code is a - 3-digit HTTP status code, like <code>404</code>. The second - argument, <code>headers</code>, should be an array of 2-element - arrays, representing the response headers. - - <p>Example:</p> - <pre> -var body = "hello world"; -res.sendHeader(200, [ ["Content-Length", body.length] - , ["Content-Type", "text/plain"] - ]);</pre> - <p> - This method must only be called once on a message and it must - be called before <code>res.finish()</code> is called. - </p> - </dd> - - <dt><code>res.sendBody(chunk, encoding="ascii")</code></dt> - <dd> - This method must be called after <code>sendHeader</code> was - called. It sends a chunk of the response body. This method may - be called multiple times to provide successive parts of the body. - - <p> - If <code>chunk</code> is a string, the second parameter - specifies how to encode it into a byte stream. By default the - <code>encoding</code> is <code>"ascii"</code>. - </p> - - <p> - Note: This is the raw HTTP body and has nothing to do with - higher-level multi-part body encodings that may be used. - </p> - </dd> - - <dt><code>res.finish()</code></dt> - <dd> - This method signals that all of the response headers and body - has been sent; that server should consider this message complete. - The method, <code>res.finish()</code>, MUST be called on each - response. - </dd> - </dl> - - <h3 id="http_client"><code>node.http.Client</code></h3> - - <p> - 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. <i>Currently the implementation does not pipeline requests.</i> - </p> - - <p> Example of connecting to <code>google.com</code></p> - <pre> -var google = new node.http.Client(80, "google.com"); -var req = google.get("/"); -req.finish(function (res) { - puts("STATUS: " + res.statusCode); - puts("HEADERS: " + JSON.stringify(res.headers)); - res.setBodyEncoding("utf8"); - res.onBody = function (chunk) { - puts("BODY: " + chunk); - }; -});</pre> - - <dl> - <dt><code>new node.http.Client(port, host);</code></dt> - <dd> - Constructs a new HTTP client. <code>port</code> and - <code>host</code> refer to the server to be connected to. A - connection is not established until a request is issued. - </dd> - - <dt><code>client.get(path, request_headers);</code></dt> - <dt><code>client.head(path, request_headers);</code></dt> - <dt><code>client.post(path, request_headers);</code></dt> - <dt><code>client.del(path, request_headers);</code></dt> - <dt><code>client.put(path, request_headers);</code></dt> - <dd> - Issues a request; if necessary establishes connection. - - <p> - <code>request_headers</code> is optional. - <code>request_headers</code> should be an array of 2-element - arrays. Additional request headers might be added internally - by Node. Returns a <code>ClientRequest</code> object. - </p> - - <p> - Do remember to include the <code>Content-Length</code> header if you - plan on sending a body. If you plan on streaming the body, perhaps - set <code>Transfer-Encoding: chunked</code>. - </p> - - <p> - Important: the request is not complete. This method only sends - the header of the request. One needs to call - <code>req.finish()</code> 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 - <code>req.sendBody()</code>.) - </p> - - <p><i> - <code>GET</code> and <code>HEAD</code> requests normally are - without bodies but HTTP does not forbid it, so neither do we. - </i></p> - </dd> - </dl> - - <h3 id="http_client_request"><code>node.http.ClientRequest</code></h3> - - <p> - This object is created internally and returned from the request - methods of a <code>node.http.Client</code>. It represents an - <i>in-progress</i> request whose header has already been sent. - </p> - - <dl> - <dt><code>req.sendBody(chunk, encoding="ascii")</code></dt> - <dd> - 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 - <code>["Transfer-Encoding", "chunked"]</code> header line when - creating the request. - - <p> - The <code>chunk</code> argument should be an array of integers - or a string. - </p> - - <p> - The <code>encoding</code> argument is optional and only - applies when <code>chunk</code> is a string. The encoding - argument should be either <code>"utf8"</code> or - <code>"ascii"</code>. By default the body uses ASCII encoding, - as it is faster. - </p> - </dd> - <dt><code>req.finish(response_handler)</code></dt> - <dd> - 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 <code>"0\r\n\r\n"</code>. - - <p> - The parameter <code>response_handler</code> is a user-supplied - callback which will be executed exactly once when the server - response headers have been received. The - <code>response_handler</code> callback is executed with one - argument: a <code>ClientResponse</code> object. - </p> - </dd> - </dl> - - <h3 id="http_client_response"><code>node.http.ClientResponse</code></h3> - - <p> - This object is created internally and passed to the - <code>response_handler</code> callback (is given to the client in - <code>req.finish</code> function). The response object appears - exactly as the header is completely received but before any part - of the response body has been read. - </p> - - <dl> - <dt><code>res.statusCode</code></dt> - <dd>The 3-digit HTTP response status code. E.G. <code>404</code>.</dd> - - <dt><code>res.httpVersion</code></dt> - <dd> - The HTTP version of the connected-to server. Probably either - <code>"1.1"</code> or <code>"1.0"</code>. - </dd> - - <dt><code>res.headers</code></dt> - <dd>The response headers. An Array of 2-element arrays.</dd> - - <dt><code>res.onBody</code></dt> - <dd> - Callback. Should be set by the user to be informed of when a - piece of the response body is received. A chunk of the body is - given as the single argument. The transfer-encoding has been - removed. - - <p> - The body chunk is either a <code>String</code> in the case of - UTF-8 encoding or an array of numbers in the case of raw - encoding. The body encoding is set with <code>res.setBodyEncoding()</code>. - </p> - </dd> - - <dt><code>res.onBodyComplete</code></dt> - <dd> - Callback. Made exactly once for each message. No arguments. - After <code>onBodyComplete</code> is executed - <code>onBody</code> will no longer be called. - </dd> - - <dt><code>res.setBodyEncoding(encoding)</code></dt> - <dd> - Set the encoding for the response body. Either - <code>"utf8"</code> or <code>"raw"</code>. Defaults to raw. - </dd> - </dl> - - <h2 id="modules">Modules</h2> - - <p> - Node has a simple module loading system. In Node, files and - modules are in one-to-one correspondence. As an example, - <code>foo.js</code> loads the module <code>mjsunit.js</code>. - </p> - - <p>The contents of <code>foo.js</code>:</p> - - <pre> -include("mjsunit.js"); -function onLoad () { - assertEquals(1, 2); -}</pre> - <p>The contents of <code>mjsunit.js</code>:</p> - - <pre> -function fail (expected, found, name_opt) { - // ... -} -function deepEquals (a, b) { - // ... -} -exports.assertEquals = function (expected, found, name_opt) { - if (!deepEquals(found, expected)) { - fail(expected, found, name_opt); - } -};</pre> - - <p> - The module <code>mjsunit.js</code> has exported a function - <code>assertEquals()</code>. <code>mjsunit.js</code> must be - in the same directory as <code>foo.js</code> for - <code>include()</code> to find it. The module path is relative - to the file calling <code>include()</code>. - </p> - - <p>Alternatively one can use HTTP URLs to load modules. For example, - - <pre>include("http://tinyclouds.org/node/mjsunit.js");</pre> - - <p> - <code>include()</code> inserts the exported objects from the - specified module into the global namespace. - </p> - - <h3 id="onload"><code>onLoad</code></h3> - - <p> - Because module loading does not happen instantaneously, and - because Node has a policy of never blocking, a callback - <code>onLoad</code> can be set that will notify the user when the - included modules are loaded. Each file/module can have an - <code>onLoad</code> callback. - </p> - - <p> - To export an object, add to the special <code>exports</code> - object. - The functions <code>fail</code> and - <code>deepEquals</code> are not exported and remain private to - the module. - - Alternatively, one can use <code>this</code> instead of - <code>exports</code>. - </p> - - <p> - <code>require()</code> is like <code>include()</code> except - does not polute the global namespace. It returns a namespace - object. The exported objects can only be guaranteed to exist - after the <code>onLoad()</code> callback is made. For example: - </p> - <pre> -var mjsunit = require("mjsunit.js"); -function onLoad () { - mjsunit.assertEquals(1, 2); -}</pre> - - <p> - <code>include()</code> and <code>require()</code> cannot be - used after <code>onLoad()</code> is called. - </p> - - <h3 id="onexit"><code>onExit</code></h3> - - <p> - When the program exits a callback <code>onExit()</code> will be - called for each module (children first). - </p> - - <p> - The <code>onExit()</code> callback cannot perform I/O as the process is - going to forcably exit in several microseconds, however it is a good - hook to perform some constant time checks of the module's state. - It's useful for unit tests. - </p> - -<pre> -include("mjsunit.js"); - -var timer_executed = false; - -setTimeout(function () { - timer_executed = true -}, 1000); - -function onExit () { - assertTrue(timer_executed); -} -</pre> - - <p> - Just to reiterate: <code>onExit()</code>, is not the place to close - files or shutdown servers. The process will exit before they get - performed. - </p> - -</div> -</body> -</html> diff --git a/website/api.txt b/website/api.txt new file mode 100644 index 000000000..7ca8c61b0 --- /dev/null +++ b/website/api.txt @@ -0,0 +1,1009 @@ +NODE(1) +======= +Ryan Dahl <ry@tinyclouds.org> +Version, 0.1.0, 2009.06.28 + + +== 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 + +Callbacks are object members which are prefixed with ++on+. All methods and members are camel cased. Constructors +always have a capital first letter. + +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+ + +.Events +[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. + +|========================================================= + ++new node.Process(command)+:: +Launches a new process with the given +command+. For example: ++ +---------------------------------------- +var ls = new node.Process("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+, 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+. + +|========================================================= + ++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. + + + +=== 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+. +|========================================================= + ++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.) +|========================================================= + ++new node.tcp.Connection()+:: + Creates a new connection object. + + ++connection.connect(port, host="127.0.0.1")+:: + 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: |