diff --git a/ChangeLog b/ChangeLog index 00f11cca2a..dcd6fd18ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,45 @@ -2010.02.09, Version 0.1.28 +2010.02.17, Version 0.1.29 + + * Major API Changes + - Remove 'file' module + - require('posix') -----------------> require('fs') + - fs.cat ---------------------------> fs.readFile + - file.write -----------------------> fs.writeFile + - TCP 'receive' event --------------> 'data' + - TCP 'eof' event ------------------> 'end' + - TCP send() -----------------------> write() + - HTTP sendBody() ------------------> write() + - HTTP finish() --------------------> close() + - HTTP 'body' event ----------------> 'data' + - HTTP 'complete' event ------------> 'end' + - http.Client.prototype.close() (formerly finish()) no longer + takes an argument. Add the 'response' listener manually. + - Allow strings for the flag argument to fs.open + ("r", "r+", "w", "w+", "a", "a+") + + * Added multiple arg support for sys.puts(), print(), etc. + (tj@vision-media.ca) + + * sys.inspect(Date) now shows the date value (Mark Hansen) + + * Calculate page size with getpagesize for armel (Jérémy Lal) + + * Bugfix: stderr flushing. + + * Bugfix: Promise late chain (Yuichiro MASUI) + + * Bugfix: wait() on fired promises + (Felix Geisendörfer, Jonas Pfenniger) + + * Bugfix: Use InstanceTemplate() instead of PrototypeTemplate() for + accessor methods. Was causing a crash with Eclipse debugger. + (Zoran Tomicic) + + * Bugfix: Throw from connection.connect if resolving. + (Reported by James Golick) + + +2010.02.09, Version 0.1.28, 49de41ef463292988ddacfb01a20543b963d9669 * Use Google's jsmin.py which can be used for evil. diff --git a/Makefile b/Makefile index 5d77e2080e..6b4827979f 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ doc/api.html: doc/api.txt asciidoc --unsafe \ -a theme=pipe \ -a toc \ + -a toclevels=1 \ -a linkcss \ -o doc/api.html doc/api.txt @@ -43,7 +44,7 @@ doc/node.1: doc/api.xml xsltproc --output doc/node.1 --nonet doc/manpage.xsl doc/api.xml website-upload: doc - scp doc/* linode:~/tinyclouds/node/ + scp doc/* ryan@nodejs.org:~/tinyclouds/node/ docclean: @-rm -f doc/node.1 doc/api.xml doc/api.html @@ -58,11 +59,11 @@ distclean: docclean check: @tools/waf-light check -VERSION=$(shell git-describe) +VERSION=$(shell git describe) TARNAME=node-$(VERSION) dist: doc/node.1 doc/api.html - git-archive --prefix=$(TARNAME)/ HEAD > $(TARNAME).tar + git archive --prefix=$(TARNAME)/ HEAD > $(TARNAME).tar mkdir -p $(TARNAME)/doc cp doc/node.1 $(TARNAME)/doc/node.1 cp doc/api.html $(TARNAME)/doc/api.html diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 37429bf56e..75295affb2 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -52,7 +52,6 @@ http.createServer(function (req, res) { , "Content-Length": content_length } ); - res.sendBody(body); - - res.finish(); + res.write(body); + res.close(); }).listen(8000); diff --git a/benchmark/static_http_server.js b/benchmark/static_http_server.js index da62434cdb..3e04ae59e7 100644 --- a/benchmark/static_http_server.js +++ b/benchmark/static_http_server.js @@ -20,15 +20,17 @@ var server = http.createServer(function (req, res) { "Content-Type": "text/plain", "Content-Length": body.length }); - res.sendBody(body); - res.finish(); + res.write(body); + res.close(); }) server.listen(port); function responseListener (res) { - res.addListener("complete", function () { + res.addListener("end", function () { if (requests < n) { - res.client.request("/").finish(responseListener); + var req = res.client.request("/"); + req.addListener('response', responseListener); + req.close(); requests++; } @@ -41,6 +43,8 @@ function responseListener (res) { for (var i = 0; i < concurrency; i++) { var client = http.createClient(port); client.id = i; - client.request("/").finish(responseListener); + var req = client.request("/"); + req.addListener('response', responseListener); + req.close(); requests++; } diff --git a/doc/api.txt b/doc/api.txt index 87af8b0f6e..45bdcc147a 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -1,7 +1,7 @@ NODE(1) ======= Ryan Dahl -Version, 0.1.28, 2010.02.09 +Version, 0.1.29, 2010.02.17 == NAME @@ -20,8 +20,8 @@ var sys = require("sys"), http = require("http"); http.createServer(function (request, response) { response.sendHeader(200, {"Content-Type": "text/plain"}); - response.sendBody("Hello World\n"); - response.finish(); + response.write("Hello World\n"); + response.close(); }).listen(8000); sys.puts("Server running at http://127.0.0.1:8000/"); ---------------------------------------- @@ -35,18 +35,15 @@ Server running at http://127.0.0.1:8000/ ---------------------------------------- -== API +== Encodings Node supports 3 string encodings. UTF-8 (+"utf8"+), ASCII (+"ascii"+), and Binary (+"binary"+). +"ascii"+ and +"binary"+ only look at the first 8 bits of the 16bit JavaScript string characters. Both are relatively fast--use them if you can. +"utf8"+ is slower and should be avoided when possible. -Unless otherwise noted, functions are all asynchronous and do not block -execution. - -=== Global Objects +== Global Objects +global+ :: The global namespace object. @@ -55,7 +52,7 @@ The global namespace object. The process object. Most stuff lives in here. See the "process object" section. -+require(path)+ :: ++require()+ :: See the modules section. +require.paths+ :: @@ -74,7 +71,7 @@ more information. -=== The +process+ Object +== The +process+ Object [cols="1,2,10",options="header"] |========================================================= @@ -171,7 +168,7 @@ process.watchFile(f, function (curr, prev) { }); ------------------------- + -These stat objects are instances of +posix.Stat+. +These stat objects are instances of +fs.Stat+. +process.unwatchFile(filename)+:: Stop watching for changes on +filename+. @@ -193,7 +190,7 @@ share structure with the original object(s). Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over. -=== System module +== System module These function are in the module +"sys"+. Use +require("sys")+ to access them. @@ -227,14 +224,14 @@ sys.exec("ls /").addCallback(function (stdout, stderr) { -=== Events +== Events Many objects in Node emit events: a TCP server emits an event each time there is a connection, a child process emits an event when it exits. All objects which emit events are instances of +events.EventEmitter+. Events are represented by a camel-cased string. Here are some examples: -+"connection"+, +"receive"+, +"messageBegin"+. ++"connection"+, +"data"+, +"messageBegin"+. Functions can be then be attached to objects, to be executed when an event is emitted. These functions are called _listeners_. @@ -243,7 +240,7 @@ Some asynchronous file operations return an +EventEmitter+ called a _promise_. A promise emits just a single event when the operation is complete. -==== +events.EventEmitter+ +=== +events.EventEmitter+ +require("events")+ to access the events module. @@ -279,7 +276,7 @@ manipulated, e.g. to remove listeners. +emitter.emit(event, arg1, arg2, ...)+ :: Execute each of the listeners in order with the supplied arguments. -==== +events.Promise+ +=== +events.Promise+ +require("events")+ to access the events module. @@ -371,30 +368,10 @@ promise.addErrback(function(e) { + If the +timeout+ parameter is not provided, the current timeout value, if any, is returned. -+ -+promise.wait()+ :: -Blocks futher execution until the promise emits a success or error event. -Events setup before the call to +promise.wait()+ was made may still be -emitted and executed while +promise.wait()+ is blocking. -+ -If there was a single argument to the +"success"+ event then it is returned. -If there were multiple arguments to +"success"+ then they are returned as an -array. -+ -If +"error"+ was emitted instead, +wait()+ throws an error. -+ -*IMPORTANT* +promise.wait()+ is not a true fiber/coroutine. If any other -promises are created and made to wait while the first promise waits, the -first promise's wait will not return until all others return. The benefit of -this is a simple implementation and the event loop does not get blocked. -Disadvantage is the possibility of situations where the promise stack grows -infinitely large because promises keep getting created and keep being told -to wait(). Use +promise.wait()+ sparingly--probably best used only during -program setup, not during busy server activity. -=== Standard I/O +== Standard I/O Standard I/O is handled through a special object +process.stdio+. stdout and stdin are fully non-blocking (even when piping to files). stderr is @@ -426,7 +403,7 @@ Write data to stderr. Synchronous. Close stdin. -=== Modules +== Modules Node uses the CommonJS module system. @@ -514,13 +491,14 @@ puts("The area of a circle of radius 4 is " + area(4)); -=== Timers +== Timers +The following are global variables +setTimeout(callback, delay, [arg, ...])+:: To schedule execution of +callback+ after +delay+ milliseconds. Returns a +timeoutId+ for possible use with +clearTimeout()+. - ++ Optionally, you can also pass arguments to the callback. @@ -531,7 +509,7 @@ Prevents said timeout from triggering. +setInterval(callback, delay, [arg, ...])+:: To schedule the repeated execution of +callback+ every +delay+ milliseconds. Returns a +intervalId+ for possible use with +clearInterval()+. - ++ Optionally, you can also pass arguments to the callback. @@ -539,13 +517,13 @@ Optionally, you can also pass arguments to the callback. Stops a interval from triggering. -=== Child Processes +== Child Processes Node provides a tridirectional +popen(3)+ facility through the class +process.ChildProcess+. It is possible to stream data through the child's +stdin+, +stdout+, and +stderr+ in a fully non-blocking way. -==== +process.ChildProcess+ +=== +process.ChildProcess+ [cols="1,2,10",options="header"] |========================================================= @@ -603,68 +581,59 @@ will be sent +"SIGTERM"+. See signal(7) for a list of available signals. -=== POSIX module +== File System File I/O is provided by simple wrappers around standard POSIX functions. To -use this module do +require("posix")+. - -All POSIX wrappers have a similar form. They return a promise -(+events.Promise+). Example of deleting a file: +use this module do +require("fs")+. All the methods have a similar form. +They return a promise (+events.Promise+). Example of deleting a file: ------------------------------------------------------------------------------ -var posix = require("posix"), - sys = require("sys"); +var fs = require("fs"), + sys = require("sys"); -var promise = posix.unlink("/tmp/hello"); +var promise = fs.unlink("/tmp/hello"); promise.addCallback(function () { sys.puts("successfully deleted /tmp/hello"); }); ------------------------------------------------------------------------------ -There is no guaranteed ordering to the POSIX wrappers. The -following is very much prone to error +This is asynchornous, there is no guaranteed ordering. The following is +prone to error ------------------------------------------------------------------------------ -posix.rename("/tmp/hello", "/tmp/world"); -posix.stat("/tmp/world").addCallback(function (stats) { +fs.rename("/tmp/hello", "/tmp/world"); +fs.stat("/tmp/world").addCallback(function (stats) { sys.puts("stats: " + JSON.stringify(stats)); }); ------------------------------------------------------------------------------ -It could be that +stat()+ is executed before the +rename()+. +It could be that +fs.stat+ is executed before +fs.rename+. The correct way to do this is to chain the promises. ------------------------------------------------------------------------------ -posix.rename("/tmp/hello", "/tmp/world").addCallback(function () { - posix.stat("/tmp/world").addCallback(function (stats) { +fs.rename("/tmp/hello", "/tmp/world").addCallback(function () { + fs.stat("/tmp/world").addCallback(function (stats) { sys.puts("stats: " + JSON.stringify(stats)); }); }); ------------------------------------------------------------------------------ -Or use the +promise.wait()+ functionality: - ------------------------------------------------------------------------------- -posix.rename("/tmp/hello", "/tmp/world").wait(); -var stats = posix.stat("/tmp/world").wait(); -sys.puts("stats: " + JSON.stringify(stats)); ------------------------------------------------------------------------------- -+posix.rename(path1, path2)+ :: ++fs.rename(path1, path2)+ :: See rename(2). - on success: no parameters. - on error: no parameters. -+posix.truncate(fd, len)+ :: ++fs.truncate(fd, len)+ :: See ftruncate(2). - on success: no parameters. - on error: no parameters. -+posix.stat(path)+ :: ++fs.stat(path)+ :: See stat(2). -- on success: Returns +posix.Stats+ object. It looks like this: +- on success: Returns +fs.Stats+ object. It looks like this: + ------------------------------------------------------------------------------ { dev: 2049, ino: 305352, mode: 16877, nlink: 12, uid: 1000, gid: 1000, @@ -673,49 +642,51 @@ See stat(2). "2009-06-29T11:11:40Z" }+ ------------------------------------------------------------------------------ + -See the +posix.Stats+ section below for more information. +See the +fs.Stats+ section below for more information. - on error: no parameters. -+posix.unlink(path)+ :: ++fs.unlink(path)+ :: See unlink(2) - on success: no parameters. - on error: no parameters. -+posix.rmdir(path)+ :: ++fs.rmdir(path)+ :: See rmdir(2) - on success: no parameters. - on error: no parameters. -+posix.mkdir(path, mode)+ :: ++fs.mkdir(path, mode)+ :: See mkdir(2) - on success: no parameters. - on error: no parameters. -+posix.readdir(path)+ :: ++fs.readdir(path)+ :: Reads the contents of a directory. - on success: One argument, an array containing the names (strings) of the files in the directory (excluding "." and ".."). - on error: no parameters. -+posix.close(fd)+ :: ++fs.close(fd)+ :: See close(2) - on success: no parameters. - on error: no parameters. -+posix.open(path, flags, mode)+:: ++fs.open(path, flags, mode=0666)+:: See open(2). The constants like +O_CREAT+ are defined at +process.O_CREAT+. + Also you can use the strings "r", "r+", "w", "w+", "a", or "a+" as aliases + to the common flag combinations. - on success: +fd+ is given as the parameter. - on error: no parameters. -+posix.write(fd, data, position, encoding)+:: ++fs.write(fd, data, position, encoding)+:: Write data to the file specified by +fd+. +position+ refers to the offset from the beginning of the file where this data should be written. If +position+ is +null+, the data will be written at the current position. @@ -723,7 +694,7 @@ See the +posix.Stats+ section below for more information. - on success: returns an integer +written+ which specifies how many _bytes_ were written. - on error: no parameters. -+posix.read(fd, length, position, encoding)+:: ++fs.read(fd, length, position, encoding)+:: Read data from the file specified by +fd+. + +length+ is an integer specifying the number of @@ -735,11 +706,11 @@ See the +posix.Stats+ section below for more information. - on success: returns +data, bytes_read+, what was read from the file. - on error: no parameters. -+posix.cat(filename, encoding="utf8")+:: ++fs.readFile(filename, encoding="utf8")+:: Outputs the entire contents of a file. Example: + -------------------------------- -posix.cat("/etc/passwd").addCallback(function (content) { +fs.readFile("/etc/passwd").addCallback(function (content) { sys.puts(content); }); -------------------------------- @@ -747,9 +718,21 @@ posix.cat("/etc/passwd").addCallback(function (content) { - on success: returns +data+, what was read from the file. - on error: no parameters. -==== +posix.Stats+ ++fs.writeFile(filename, data, encoding="utf8")+:: +Writes data to a file. Example: ++ +-------------------------------- +fs.writeFile("message.txt", "Hello Node").addCallback(function () { + sys.puts("It's saved!"); +}); +-------------------------------- ++ +- on success: no parameters. +- on error: no parameters. -Objects returned from +posix.stat()+ are of this type. +=== +fs.Stats+ + +Objects returned from +fs.stat()+ are of this type. +stats.isFile()+:: @@ -765,7 +748,7 @@ Objects returned from +posix.stat()+ are of this type. +stats.isSocket()+:: ... -=== HTTP +== HTTP To use the HTTP server and client one must +require("http")+. @@ -793,7 +776,7 @@ parsing only. It parses a message into headers and body but it does not parse the actual headers or the body. -==== +http.Server+ +=== +http.Server+ [cols="1,2,10",options="header"] |========================================================= @@ -847,7 +830,7 @@ Stops the server from accepting new connections. -==== +http.ServerRequest+ +=== +http.ServerRequest+ This object is created internally by a HTTP server--not by the user--and passed as the first argument to a +"request"+ listener. @@ -856,7 +839,7 @@ the user--and passed as the first argument to a +"request"+ listener. |========================================================= |Event | Parameters | Notes -|+"body"+ | +chunk+ | Emitted when a piece of the +|+"data"+ | +chunk+ | Emitted when a piece of the message body is received. Example: A chunk of the body is given as the single argument. The transfer-encoding has been @@ -864,7 +847,7 @@ the user--and passed as the first argument to a +"request"+ listener. body encoding is set with +request.setBodyEncoding()+. -|+"complete"+ | (none) | Emitted exactly once for each message. +|+"end"+ | (none) | Emitted exactly once for each message. No arguments. After emitted no other events will be emitted on the request. |========================================================= @@ -947,7 +930,7 @@ Resumes a paused request. The +http.Connection+ object. -==== +http.ServerResponse+ +=== +http.ServerResponse+ This object is created internally by a HTTP server--not by the user. It is passed as the second parameter to the +"request"+ event. @@ -968,9 +951,9 @@ response.sendHeader(200, { ---------------------------------------- + This method must only be called once on a message and it must -be called before +response.finish()+ is called. +be called before +response.close()+ is called. -+response.sendBody(chunk, encoding="ascii")+ :: ++response.write(chunk, encoding="ascii")+ :: This method must be called after +sendHeader+ was called. It sends a chunk of the response body. This method may @@ -983,22 +966,22 @@ specifies how to encode it into a byte stream. By default the Note: This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used. + -The first time +sendBody+ is called, it will send the buffered header -information and the first body to the client. The second time -+sendBody+ is called, Node assumes you're going to be streaming data, and -sends that seperately. That is, the response is buffered up to the +The first time +response.write()+ is called, it will send the buffered +header information and the first body to the client. The second time ++response.write()+ is called, Node assumes you're going to be streaming +data, and sends that seperately. That is, the response is buffered up to the first chunk of body. -+response.finish()+ :: ++response.close()+ :: This method signals to the server that all of the response headers and body has been sent; that server should consider this message complete. -The method, +response.finish()+, MUST be called on each +The method, +response.close()+, MUST be called on each response. -==== +http.Client+ +=== +http.Client+ An HTTP client is constructed with a server address as its argument, the returned handle is then used to issue one or more @@ -1013,14 +996,15 @@ var sys = require("sys"), http = require("http"); var google = http.createClient(80, "www.google.com"); var request = google.request("GET", "/", {"host": "www.google.com"}); -request.finish(function (response) { +request.addListener('response', function (response) { sys.puts("STATUS: " + response.statusCode); sys.puts("HEADERS: " + JSON.stringify(response.headers)); response.setBodyEncoding("utf8"); - response.addListener("body", function (chunk) { + response.addListener("data", function (chunk) { sys.puts("BODY: " + chunk); }); }); +request.close(); ---------------------------------------- +http.createClient(port, host)+ :: @@ -1046,10 +1030,10 @@ set +Transfer-Encoding: chunked+. + NOTE: the request is not complete. This method only sends the header of the request. One needs to call -+request.finish()+ to finalize the request and retrieve ++request.close()+ to finalize the request and retrieve the response. (This sounds convoluted but it provides a chance for the user to stream a body to the server with -+request.sendBody()+.) ++request.write()+.) +client.setSecure(format_type, ca_certs, crl_list, private_key, certificate)+ :: Enable TLS for the client connection, with the specified credentials. @@ -1063,18 +1047,48 @@ key for the client, which together with the certificate allows the client to aut itself to the server. -==== +http.ClientRequest+ +=== +http.ClientRequest+ This object is created internally and returned from the request methods of a +http.Client+. It represents an _in-progress_ request whose header has already been sent. +To get the response, add a listener for +'response'+ to the request object. ++'response'+ will be emitted from the request object when the response +headers have been received. The +'response'+ event is executed with one +argument which is an instance of +http.ClientResponse+. + +During the +'response'+ event, one can add listeners to the +response object; particularly to listen for the +"data"+ event. Note that +the +'response' event is called before any part of the response body is received, +so there is no need to worry about racing to catch the first part of the +body. As long as a listener for +'data'+ is added during the +'response' +event, the entire body will be caught. + +---------------------------------------- +// Good +request.addListener('response', function (response) { + response.addListener("data", function (chunk) { + sys.puts("BODY: " + chunk); + }); +}); + +// Bad - misses all or part of the body +request.addListener('response', function (response) { + setTimeout(function () { + response.addListener("data", function (chunk) { + sys.puts("BODY: " + chunk); + }); + }, 10); +}); +---------------------------------------- + + [cols="1,2,10",options="header"] |========================================================= |Event | Parameters | Notes |+"response"+ | +response+ | -Emitted when a response is received to this request. Typically the user will -set a listener to this via the +request.finish()+ method. +Emitted when a response is received to this request. + This event is emitted only once. + @@ -1082,7 +1096,7 @@ The +response+ argument will be an instance of +http.ClientResponse+. |========================================================= -+request.sendBody(chunk, encoding="ascii")+ :: ++request.write(chunk, encoding="ascii")+ :: Sends a chunk of the body. By calling this method many times, the user can stream a request body to a @@ -1100,46 +1114,15 @@ argument should be either +"utf8"+ or as it is faster. -+request.finish(responseListener)+ :: ++request.close()+ :: Finishes sending the request. If any parts of the body are unsent, it will flush them to the socket. If the request is chunked, this will send the terminating +"0\r\n\r\n"+. -+ -The parameter +responseListener+ is a callback which -will be executed when the response headers have been received. -The +responseListener+ callback is executed with one -argument which is an instance of +http.ClientResponse+. -+ -In the +responseListener+ callback, one can add more listeners to the -response, in particular listening for the +"body"+ event. Note that -the +responseListener+ is called before any part of the body is received, -so there is no need to worry about racing to catch the first part of the -body. As long as a listener for +"body"+ is added during the -+responseListener+ callback, the entire body will be caught. -+ ----------------------------------------- -// Good -request.finish(function (response) { - response.addListener("body", function (chunk) { - sys.puts("BODY: " + chunk); - }); -}); - -// Bad - misses all or part of the body -request.finish(function (response) { - setTimeout(function () { - response.addListener("body", function (chunk) { - sys.puts("BODY: " + chunk); - }); - }, 10); -}); ----------------------------------------- - -==== +http.ClientResponse+ +=== +http.ClientResponse+ This object is created internally and passed to the +"response"+ event. @@ -1147,13 +1130,13 @@ This object is created internally and passed to the +"response"+ event. |========================================================= |Event | Parameters | Notes -|+"body"+ | +chunk+ | +|+"data"+ | +chunk+ | Emitted when a piece of the message body is received. Example: A chunk of the body is given as the single argument. The transfer-encoding has been decoded. The body chunk a String. The body encoding is set with +response.setBodyEncoding()+. -|+"complete"+ | | +|+"end"+ | | Emitted exactly once for each message. No arguments. After emitted no other events will be emitted on the response. @@ -1182,7 +1165,7 @@ After emitted no other events will be emitted on the response. +response.client+ :: A reference to the +http.Client+ that this response belongs to. -=== Multipart Parsing +== Multipart Parsing A library to parse +multipart+ internet messages is included with Node. To use it, +require("multipart")+. @@ -1208,13 +1191,12 @@ Node. To use it, +require("multipart")+. No checking is done to ensure that the file does not overload the memory. Only use multipart.cat with known and trusted input! -==== +multipart.Stream+ +=== +multipart.Stream+ The multipart.Stream class is a streaming parser wrapped around a message. The Stream also contains the properties described for the +part+ objects below, and is a reference to the top-level message. -===== Events [cols="1,2,10",options="header"] |========================================================= @@ -1228,7 +1210,6 @@ and is a reference to the top-level message. indicates that the message is malformed. |========================================================= -===== Properties +stream.part+:: The current part being processed. This is important, for instance, when responding @@ -1242,20 +1223,16 @@ will be set to +false+. +stream.parts+:: An array of the parts contained within the message. Each is a +part+ object. -===== Methods - +stream.pause+:: If the underlying message supports pause and resume, then this will pause the stream. +stream.resume+:: If the underlying message supports pause and resume, then this will resume the paused stream. -==== Part Objects +=== +multipart.Part+ As it parses the message, the Stream object will create +Part+ objects. -===== Properties - +part.parent+:: The message that contains this part. @@ -1286,7 +1263,7 @@ For multipart messages, this is the multipart type specified in the +content-typ For example, a message with +content-type: multipart/form-data+ will have a +type+ property of +form-data+. -==== Example +=== Example Here is an example for parsing a +multipart/form-data+ request: @@ -1300,8 +1277,8 @@ http.createServer(function (req, res) { name, filename; mp.addListener("error", function (er) { res.sendHeader(400, {"content-type":"text/plain"}); - res.sendBody("You sent a bad message!\n"+er.message); - res.finish(); + res.write("You sent a bad message!\n"+er.message); + res.close(); }); mp.addListener("partBegin", function (part) { name = part.name; @@ -1323,13 +1300,13 @@ http.createServer(function (req, res) { "content-type" : "text/plain", "content-length" : response.length }); - res.sendBody(response); - res.finish(); + res.write(response); + res.close(); }) }); ---------------------------------------- -==== Nested Multipart Messages +=== Nested Multipart Messages Nested multipart parsing is supported. The +stream.part+ object always refers to the current part. If +part.isMultiPart+ is set, then that part is a @@ -1337,11 +1314,11 @@ multipart message, which contains other parts. You can inspect its +parts+ array to see the list of sub-parts, which may also be multipart, and contain sub-parts. -=== TCP +== TCP To use the TCP server and client one must +require("tcp")+. -==== +tcp.Server+ +=== +tcp.Server+ Here is an example of a echo server which listens for connections on port 7000: @@ -1351,13 +1328,13 @@ var tcp = require("tcp"); var server = tcp.createServer(function (socket) { socket.setEncoding("utf8"); socket.addListener("connect", function () { - socket.send("hello\r\n"); + socket.write("hello\r\n"); }); - socket.addListener("receive", function (data) { - socket.send(data); + socket.addListener("data", function (data) { + socket.write(data); }); - socket.addListener("eof", function () { - socket.send("goodbye\r\n"); + socket.addListener("end", function () { + socket.write("goodbye\r\n"); socket.close(); }); }); @@ -1410,7 +1387,7 @@ asynchronous, the server is finally closed when the server emits a +"close"+ event. -==== +tcp.Connection+ +=== +tcp.Connection+ This object is used as a TCP client and also as a server-side socket for +tcp.Server+. @@ -1421,11 +1398,11 @@ socket for +tcp.Server+. |+"connect"+ | | Call once the connection is established after a call to +createConnection()+ or +connect()+. -|+"receive"+ | +data+ | Called when data is received on the +|+"data"+ | +data+ | Called when data is received on the connection. +data+ will be a string. Encoding of data is set by +connection.setEncoding()+. -|+"eof"+ | | Called when the other end of the +|+"end"+ | | Called when the other end of the connection sends a FIN packet. After this is emitted the +readyState+ will be +"writeOnly"+. One should probably @@ -1474,7 +1451,7 @@ Either +"closed"+, +"open"+, +"opening"+, +"readOnly"+, or +"writeOnly"+. +connection.setEncoding(encoding)+:: Sets the encoding (either +"ascii"+, +"utf8"+, or +"binary"+) for data that is received. -+connection.send(data, encoding="ascii")+:: ++connection.write(data, encoding="ascii")+:: Sends data on the connection. The second parameter specifies the encoding in the case of a string--it defaults to ASCII because encoding to UTF8 is rather slow. @@ -1491,7 +1468,7 @@ Ensures that no more I/O activity happens on this socket. Only necessary in case of errors (parse error or so). +connection.readPause()+:: -Pauses the reading of data. That is, +"receive"+ events will not be emitted. +Pauses the reading of data. That is, +"data"+ events will not be emitted. Useful to throttle back an upload. +connection.readResume()+:: @@ -1507,7 +1484,7 @@ If +timeout+ is 0, then the idle timeout is disabled. +connection.setNoDelay(noDelay=true)+:: Disables the Nagle algorithm. By default TCP connections use the Nagle algorithm, they buffer data before sending it off. Setting +noDelay+ will -immediately fire off data each time +connection.send()+ is called. +immediately fire off data each time +connection.write()+ is called. +connection.verifyPeer()+:: Returns an integer indicating the trusted status of the peer in a TLS @@ -1528,7 +1505,7 @@ A format of "DNstring" gives a single string with the combined Distinguished Name (DN) from the certificate, as comma delimited name=value pairs as defined in RFC2253. This function is synchronous. -=== DNS module +== DNS module Use +require("dns")+ to access this module. @@ -1629,7 +1606,7 @@ Each DNS query can return an error code. - +dns.NOMEM+: out of memory while processing. - +dns.BADQUERY+: the query is malformed. -=== Assert Module +== Assert Module This module is used for writing unit tests for your applications, you can access it with +require("assert")+. @@ -1664,7 +1641,7 @@ Expects +block+ to throw an error. Expects +block+ not to throw an error. -=== Path Module +== Path Module This module contains utilities for dealing with file paths. Use +require("path")+ to use it. It provides the following methods: @@ -1744,7 +1721,7 @@ require("path").exists("/etc/passwd", function (exists) { ------------------------------------ -=== URL Module +== URL Module This module has utilities for URL resolution and parsing. @@ -1799,7 +1776,7 @@ Take a parsed URL object, and return a formatted URL string. Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag. -=== Query String Module +== Query String Module This module provides utilities for dealing with query strings. It provides the following methods: diff --git a/doc/asciidoc-xhtml11.js b/doc/asciidoc-xhtml11.js new file mode 100644 index 0000000000..a0f935be63 --- /dev/null +++ b/doc/asciidoc-xhtml11.js @@ -0,0 +1,167 @@ +var asciidoc = { // Namespace. + +///////////////////////////////////////////////////////////////////// +// Table Of Contents generator +///////////////////////////////////////////////////////////////////// + +/* Author: Mihai Bazon, September 2002 + * http://students.infoiasi.ro/~mishoo + * + * Table Of Content generator + * Version: 0.4 + * + * Feel free to use this script under the terms of the GNU General Public + * License, as long as you do not remove or alter this notice. + */ + + /* modified by Troy D. Hanson, September 2006. License: GPL */ + /* modified by Stuart Rackham, 2006, 2009. License: GPL */ + +// toclevels = 1..4. +toc: function (toclevels) { + + function getText(el) { + var text = ""; + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants. + text += i.data; + else if (i.firstChild != null) + text += getText(i); + } + return text; + } + + function TocEntry(el, text, toclevel) { + this.element = el; + this.text = text; + this.toclevel = toclevel; + } + + function tocEntries(el, toclevels) { + var result = new Array; + var re = new RegExp('[hH]([2-'+(toclevels+1)+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo) + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i" + + "" + + n + ". " + note + ""; + spans[i].innerHTML = + "[" + n + "]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i" + n + "]"; + } + } + } +} + +}; + +(function() { + var includes = ['sh_main.js', 'sh_javascript.min.js', 'sh_vim-dark.css']; + var head = document.getElementsByTagName("head")[0]; + + for (var i = 0; i < includes.length; i ++) { + var ext = includes[i].match(/\.([^.]+)$/); + switch (ext[1]) { + case 'js': + var element = document.createElement('script'); + element.type = 'text/javascript'; + element.src = includes[i]; + break; + case 'css': + var element = document.createElement('link'); + element.type = 'text/css'; + element.rel = 'stylesheet'; + element.media = 'screen'; + element.href = includes[i]; + break; + } + + head.appendChild(element); + } + var i = setInterval(function () { + if (window["sh_highlightDocument"]) { + sh_highlightDocument(); + + try { + var pageTracker = _gat._getTracker("UA-10874194-2"); + pageTracker._trackPageview(); + } catch(err) {} + + clearInterval(i); + } + }, 100); + + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); +})(); diff --git a/doc/index.html b/doc/index.html index 79bc44ed23..22ac939f3a 100644 --- a/doc/index.html +++ b/doc/index.html @@ -29,7 +29,7 @@
- +

@@ -48,8 +48,8 @@ var sys = require('sys'), http.createServer(function (req, res) { setTimeout(function () { res.sendHeader(200, {'Content-Type': 'text/plain'}); - res.sendBody('Hello World'); - res.finish(); + res.write('Hello World'); + res.close(); }, 2000); }).listen(8000); sys.puts('Server running at http://127.0.0.1:8000/'); @@ -74,13 +74,13 @@ var tcp = require('tcp'); var server = tcp.createServer(function (socket) { socket.setEncoding("utf8"); socket.addListener("connect", function () { - socket.send("hello\r\n"); + socket.write("hello\r\n"); }); socket.addListener("receive", function (data) { - socket.send(data); + socket.write(data); }); socket.addListener("eof", function () { - socket.send("goodbye\r\n"); + socket.write("goodbye\r\n"); socket.close(); }); }); @@ -97,9 +97,8 @@ server.listen(7000, "localhost"); git repo

- 2010.02.09 - node-v0.1.28.tar.gz + 2010.02.17 + node-v0.1.29.tar.gz

Build

@@ -110,7 +109,8 @@ server.listen(7000, "localhost"); tested on Linux, Macintosh, and FreeBSD. The build system requires Python 2.4 or better. V8, on which Node is built, supports only IA-32 and ARM processors. V8 is included in the - Node distribution. There are no other dependencies. + Node distribution. To use TLS, GnuTLS and libgpg-error are required. + There are no other dependencies.

diff --git a/lib/file.js b/lib/file.js
index 93025870f2..d8c1a6c7c2 100644
--- a/lib/file.js
+++ b/lib/file.js
@@ -1,156 +1 @@
-var posix = require("./posix");
-var events = require('events');
-/*jslint onevar: true, undef: true, eqeqeq: true, plusplus: true, regexp: true, newcap: true, immed: true */
-/*globals exports, node, __filename */
-
-exports.debugLevel = 0; // Increase to get more verbose debug output
-
-function debugMessage (msg) {
-  if (exports.debugLevel > 0) {
-    process.error(__filename + ": " + msg.toString());
-  }
-}
-
-function debugObject (obj) {
-  if (exports.debugLevel > 0) {
-    process.error(__filename + ": " + JSON.stringify(obj));
-  }
-}
-
-exports.read = posix.cat;
-
-exports.write = function (filename, data, encoding) {
-  var promise = new events.Promise();
-
-  encoding = encoding || "utf8"; // default to utf8
-
-  posix.open(filename, process.O_WRONLY | process.O_TRUNC | process.O_CREAT, 0666)
-    .addCallback(function (fd) {
-      function doWrite (_data) {
-        posix.write(fd, _data, 0, encoding)
-          .addErrback(function () {
-            posix.close(fd);
-            promise.emitError();
-          })
-          .addCallback(function (written) {
-            if (written === _data.length) {
-              posix.close(fd);
-              promise.emitSuccess();
-            } else {
-              doWrite(_data.slice(written));
-            }
-          });
-      }
-      doWrite(data);
-    })
-    .addErrback(function () {
-      promise.emitError();
-    });
-
-  return promise;
-};
-
-exports.File = function (filename, mode, options) {
-  var self = this;
-
-  options = options || {};
-  self.encoding = options.encoding || "utf8";
-
-  self.filename = filename;
-
-  self.actionQueue = [];
-  self.currentAction = null;
-
-  switch (mode) {
-    case "r":
-      self.flags = process.O_RDONLY;
-      break;
-
-    case "r+":
-      self.flags = process.O_RDWR;
-      break;
-
-    case "w":
-      self.flags = process.O_CREAT | process.O_TRUNC | process.O_WRONLY;
-      break;
-
-    case "w+":
-      self.flags = process.O_CREAT | process.O_TRUNC | process.O_RDWR;
-      break;
-
-    case "a":
-      self.flags = process.O_APPEND | process.O_CREAT | process.O_WRONLY; 
-      break;
-
-    case "a+":
-      self.flags = process.O_APPEND | process.O_CREAT | process.O_RDWR; 
-      break;
-
-    default:
-      throw new Error("Unknown mode");
-  }
-
-  self.open(self.filename, self.flags, 0666).addCallback(function (fd) {
-    debugMessage(self.filename + " opened. fd = " + fd);
-    self.fd = fd;
-  }).addErrback(function () {
-    self.emit("error", ["open"]);
-  });
-};
-
-var proto = exports.File.prototype;
-
-proto._maybeDispatch = function () {
-  var self, args, method, promise, userPromise;
-  
-  self = this;
-
-  if (self.currentAction) { return; }
-  self.currentAction = self.actionQueue.shift();
-  if (!self.currentAction) { return; }
-
-  debugObject(self.currentAction);
-
-  args = self.currentAction.args || [];
-  method = self.currentAction.method;
-
-
-  if (method !== "open") {
-    args.unshift(self.fd);
-  }
-
-  if (!args[3] && (method === "read" || method === "write")) {
-    args[3] = self.encoding;
-  }
-  promise = posix[method].apply(self, args);
-
-  userPromise = self.currentAction.promise;
-
-  promise.addCallback(function () {
-    process.assert(self.currentAction.promise === userPromise);
-    userPromise.emitSuccess.apply(userPromise, arguments);
-    self.currentAction = null;
-    self._maybeDispatch();
-  }).addErrback(function () {
-    debugMessage("Error in method " + method);
-    process.assert(self.currentAction.promise === userPromise);
-    userPromise.emitError.apply(userPromise, arguments);
-    self.currentAction = null;
-    self._maybeDispatch();
-  });
-};
-
-proto._queueAction = function (method, args) {
-  var userPromise = new events.Promise();
-  this.actionQueue.push({ method: method, args: args, promise: userPromise });
-  this._maybeDispatch();
-  return userPromise;
-};
-
-
-(["open", "write", "read", "close"]).forEach(function (name) {
-  proto[name] = function () {
-    return this._queueAction(name, Array.prototype.slice.call(arguments, 0));
-  };
-});
-
+throw new Error("The 'file' module has been removed. 'file.read' is now 'fs.readFile', and 'file.write' is now 'fs.writeFile'.");
diff --git a/lib/http.js b/lib/http.js
index dcb152e987..59f8112fe5 100644
--- a/lib/http.js
+++ b/lib/http.js
@@ -114,7 +114,7 @@ function OutgoingMessage () {
 sys.inherits(OutgoingMessage, events.EventEmitter);
 exports.OutgoingMessage = OutgoingMessage;
 
-OutgoingMessage.prototype.send = function (data, encoding) {
+OutgoingMessage.prototype._send = function (data, encoding) {
   var length = this.output.length;
 
   if (length === 0) {
@@ -200,19 +200,27 @@ OutgoingMessage.prototype.sendHeaderLines = function (first_line, headers) {
 
   message_header += CRLF;
 
-  this.send(message_header);
-  // wait until the first body chunk, or finish(), is sent to flush.
+  this._send(message_header);
+  // wait until the first body chunk, or close(), is sent to flush.
 };
 
-OutgoingMessage.prototype.sendBody = function (chunk, encoding) {
+
+OutgoingMessage.prototype.sendBody = function () {
+  throw new Error("sendBody() has been renamed to write(). " + 
+                  "The 'body' event has been renamed to 'data' and " +
+                  "the 'complete' event has been renamed to 'end'.");
+};
+
+
+OutgoingMessage.prototype.write = function (chunk, encoding) {
   encoding = encoding || "ascii";
   if (this.chunked_encoding) {
-    this.send(process._byteLength(chunk, encoding).toString(16));
-    this.send(CRLF);
-    this.send(chunk, encoding);
-    this.send(CRLF);
+    this._send(process._byteLength(chunk, encoding).toString(16));
+    this._send(CRLF);
+    this._send(chunk, encoding);
+    this._send(CRLF);
   } else {
-    this.send(chunk, encoding);
+    this._send(chunk, encoding);
   }
 
   if (this.flushing) {
@@ -227,7 +235,11 @@ OutgoingMessage.prototype.flush = function () {
 };
 
 OutgoingMessage.prototype.finish = function () {
-  if (this.chunked_encoding) this.send("0\r\n\r\n"); // last chunk
+  throw new Error("finish() has been renamed to close().");
+};
+
+OutgoingMessage.prototype.close = function () {
+  if (this.chunked_encoding) this._send("0\r\n\r\n"); // last chunk
   this.finished = true;
   this.flush();
 };
@@ -267,9 +279,20 @@ function ClientRequest (method, url, headers) {
 sys.inherits(ClientRequest, OutgoingMessage);
 exports.ClientRequest = ClientRequest;
 
-ClientRequest.prototype.finish = function (responseListener) {
-  this.addListener("response", responseListener);
-  OutgoingMessage.prototype.finish.call(this);
+ClientRequest.prototype.finish = function () {
+  throw new Error( "finish() has been renamed to close() and no longer takes "
+                 + "a response handler as an argument. Manually add a 'response' listener "
+                 + "to the request object."
+                 );
+};
+
+ClientRequest.prototype.close = function () {
+  if (arguments.length > 0) {
+    throw new Error( "ClientRequest.prototype.close does not take any arguments. "
+                   + "Add a response listener manually to the request object."
+                   );
+  }
+  OutgoingMessage.prototype.close.call(this);
 };
 
 
@@ -333,11 +356,11 @@ function createIncomingMessageStream (connection, incoming_listener) {
   });
 
   connection.addListener("body", function (chunk) {
-    incoming.emit("body", chunk);
+    incoming.emit('data', chunk);
   });
 
   connection.addListener("messageComplete", function () {
-    incoming.emit("complete");
+    incoming.emit('end');
   });
 
   return stream;
@@ -357,7 +380,7 @@ function flushMessageQueue (connection, queue) {
       var data = message.output.shift();
       var encoding = message.outputEncodings.shift();
 
-      connection.send(data, encoding);
+      connection.write(data, encoding);
     }
 
     if (!message.finished) break;
@@ -387,7 +410,7 @@ function connectionListener (connection) {
   connection.resetParser();
 
   // is this really needed?
-  connection.addListener("eof", function () {
+  connection.addListener("end", function () {
     if (responses.length == 0) {
       connection.close();
     } else {
@@ -456,8 +479,8 @@ exports.createClient = function (port, host) {
     currentRequest.flush();
   });
 
-  client.addListener("eof", function () {
-    //sys.debug("client got eof closing. readyState = " + client.readyState);
+  client.addListener("end", function () {
+    //sys.debug("client got end closing. readyState = " + client.readyState);
     client.close();
   });
 
@@ -486,7 +509,7 @@ exports.createClient = function (port, host) {
   createIncomingMessageStream(client, function (res) {
    //sys.debug("incoming response!");
 
-    res.addListener("complete", function ( ) {
+    res.addListener('end', function ( ) {
       //sys.debug("request complete disconnecting. readyState = " + client.readyState);
       client.close();
     });
@@ -545,27 +568,29 @@ exports.cat = function (url, encoding, headers) {
   if (!hasHost) {
     headers["Host"] = url.hostname;
   }
+
+  var content = "";
   
   var client = exports.createClient(url.port || 80, url.hostname);
   var req = client.request((url.pathname || "/")+(url.search || "")+(url.hash || ""), headers);
 
-  client.addListener("error", function () {
-    promise.emitError();
-  });
-
-  var content = "";
-
-  req.finish(function (res) {
+  req.addListener('response', function (res) {
     if (res.statusCode < 200 || res.statusCode >= 300) {
       promise.emitError(res.statusCode);
       return;
     }
     res.setBodyEncoding(encoding);
-    res.addListener("body", function (chunk) { content += chunk; });
-    res.addListener("complete", function () {
+    res.addListener('data', function (chunk) { content += chunk; });
+    res.addListener('end', function () {
       promise.emitSuccess(content);
     });
   });
 
+  client.addListener("error", function () {
+    promise.emitError();
+  });
+
+  req.close();
+
   return promise;
 };
diff --git a/lib/multipart.js b/lib/multipart.js
index 15fb0681b4..9dff309ecb 100644
--- a/lib/multipart.js
+++ b/lib/multipart.js
@@ -69,8 +69,8 @@ function Stream (message) {
     w = isMultiPart ? writer(this) : simpleWriter(this),
     e = ender(this);
   if (message.addListener) {
-    message.addListener("body", w);
-    message.addListener("complete", e);
+    message.addListener("data", w);
+    message.addListener("end", e);
     if (message.pause && message.resume) {
       this._pause = message;
     }
diff --git a/lib/posix.js b/lib/posix.js
new file mode 100644
index 0000000000..d705b0ee20
--- /dev/null
+++ b/lib/posix.js
@@ -0,0 +1 @@
+throw new Error("The 'posix' module has been renamed to 'fs'");
diff --git a/lib/sys.js b/lib/sys.js
index 461a12c8a1..65badcdc05 100644
--- a/lib/sys.js
+++ b/lib/sys.js
@@ -1,11 +1,15 @@
 var events = require('events');
 
-exports.print = function (x) {
-  process.stdio.write(x);
+exports.print = function () {
+  for (var i = 0, len = arguments.length; i < len; ++i) {
+    process.stdio.write(arguments[i]);
+  }
 };
 
-exports.puts = function (x) {
-  process.stdio.write(x + "\n");
+exports.puts = function () {
+  for (var i = 0, len = arguments.length; i < len; ++i) {
+    process.stdio.write(arguments[i] + '\n');
+  }
 };
 
 exports.debug = function (x) {
@@ -13,7 +17,9 @@ exports.debug = function (x) {
 };
 
 exports.error = function (x) {
-  process.stdio.writeError(x + "\n");
+  for (var i = 0, len = arguments.length; i < len; ++i) {
+    process.stdio.writeError(arguments[i] + '\n');
+  }
 };
 
 /**
@@ -53,6 +59,11 @@ exports.inspect = function (obj, showHidden) {
       }
     }
 
+    // Dates without properties can be shortcutted
+    if (value instanceof Date && keys.length === 0) {
+        return value.toUTCString();
+    }
+
     var base, type, braces;
     // Determine the object type
     if (value instanceof Array) {
@@ -69,6 +80,11 @@ exports.inspect = function (obj, showHidden) {
     } else {
       base = "";
     }
+    
+    // Make dates with properties first say the date
+    if (value instanceof Date) {
+      base = ' ' + value.toUTCString();
+    }
 
     seen.push(value);
 
@@ -116,8 +132,10 @@ exports.inspect = function (obj, showHidden) {
   return format(obj);
 };
 
-exports.p = function (x) {
-  exports.error(exports.inspect(x));
+exports.p = function () {
+  for (var i = 0, len = arguments.length; i < len; ++i) {
+    exports.error(exports.inspect(arguments[i]));
+  }
 };
 
 exports.exec = function (command) {
diff --git a/src/node.cc b/src/node.cc
index a4fd638f6c..8996f59fdd 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -322,15 +322,15 @@ const char* ToCString(const v8::String::Utf8Value& value) {
   return *value ? *value : "";
 }
 
-static void ReportException(TryCatch *try_catch, bool show_line = false) {
-  Handle message = try_catch->Message();
+static void ReportException(TryCatch &try_catch, bool show_line = false) {
+  Handle message = try_catch.Message();
   if (message.IsEmpty()) {
     fprintf(stderr, "Error: (no message)\n");
     fflush(stderr);
     return;
   }
 
-  Handle error = try_catch->Exception();
+  Handle error = try_catch.Exception();
   Handle stack;
 
   if (error->IsObject()) {
@@ -377,13 +377,13 @@ Local ExecuteString(Local source, Local filename) {
 
   Local