diff --git a/doc/api.txt b/doc/api.txt index 9ddca51b92..cdd6f13ee3 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -21,7 +21,7 @@ var sys = require("sys"), http.createServer(function (request, response) { response.sendHeader(200, {"Content-Type": "text/plain"}); response.write("Hello World\n"); - response.finish(); + response.close(); }).listen(8000); sys.puts("Server running at http://127.0.0.1:8000/"); ---------------------------------------- @@ -982,7 +982,7 @@ 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.write(chunk, encoding="ascii")+ :: @@ -1004,10 +1004,10 @@ 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. @@ -1027,7 +1027,7 @@ 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"); @@ -1035,6 +1035,7 @@ request.finish(function (response) { sys.puts("BODY: " + chunk); }); }); +request.close(); ---------------------------------------- +http.createClient(port, host)+ :: @@ -1060,7 +1061,7 @@ 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.write()+.) @@ -1083,12 +1084,42 @@ 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. + @@ -1114,42 +1145,11 @@ 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 +"data"+ 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 +"data"+ is added during the -+responseListener+ callback, the entire body will be caught. -+ ----------------------------------------- -// Good -request.finish(function (response) { - response.addListener("data", function (chunk) { - sys.puts("BODY: " + chunk); - }); -}); - -// Bad - misses all or part of the body -request.finish(function (response) { - setTimeout(function () { - response.addListener("data", function (chunk) { - sys.puts("BODY: " + chunk); - }); - }, 10); -}); ----------------------------------------- - @@ -1315,7 +1315,7 @@ http.createServer(function (req, res) { mp.addListener("error", function (er) { res.sendHeader(400, {"content-type":"text/plain"}); res.write("You sent a bad message!\n"+er.message); - res.finish(); + res.close(); }); mp.addListener("partBegin", function (part) { name = part.name; @@ -1338,7 +1338,7 @@ http.createServer(function (req, res) { "content-length" : response.length }); res.write(response); - res.finish(); + res.close(); }) }); ---------------------------------------- diff --git a/doc/index.html b/doc/index.html index 5c6539d035..56333d43b8 100644 --- a/doc/index.html +++ b/doc/index.html @@ -49,7 +49,7 @@ http.createServer(function (req, res) { setTimeout(function () { res.sendHeader(200, {'Content-Type': 'text/plain'}); res.write('Hello World'); - res.finish(); + res.close(); }, 2000); }).listen(8000); sys.puts('Server running at http://127.0.0.1:8000/'); diff --git a/lib/http.js b/lib/http.js index d37cd1ebe8..59f8112fe5 100644 --- a/lib/http.js +++ b/lib/http.js @@ -201,7 +201,7 @@ 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. + // wait until the first body chunk, or close(), is sent to flush. }; @@ -235,6 +235,10 @@ OutgoingMessage.prototype.flush = function () { }; OutgoingMessage.prototype.finish = function () { + 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(); @@ -275,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); }; @@ -553,17 +568,13 @@ 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; @@ -575,5 +586,11 @@ exports.cat = function (url, encoding, headers) { }); }); + client.addListener("error", function () { + promise.emitError(); + }); + + req.close(); + return promise; }; diff --git a/test/mjsunit/test-http-1.0.js b/test/mjsunit/test-http-1.0.js index 1fd1cf212e..ba845e8b3c 100644 --- a/test/mjsunit/test-http-1.0.js +++ b/test/mjsunit/test-http-1.0.js @@ -11,7 +11,7 @@ var client_got_eof = false; var server = http.createServer(function (req, res) { res.sendHeader(200, {"Content-Type": "text/plain"}); res.write(body); - res.finish(); + res.close(); }) server.listen(port); diff --git a/test/mjsunit/test-http-cat.js b/test/mjsunit/test-http-cat.js index 1c962ebe47..f38bd7dd6d 100644 --- a/test/mjsunit/test-http-cat.js +++ b/test/mjsunit/test-http-cat.js @@ -10,7 +10,7 @@ var server = http.createServer(function (req, res) { ["Content-Type", "text/plain"] ]); res.write(body); - res.finish(); + res.close(); }); server.listen(PORT); diff --git a/test/mjsunit/test-http-chunked.js b/test/mjsunit/test-http-chunked.js index f566117e04..c15bd132d8 100644 --- a/test/mjsunit/test-http-chunked.js +++ b/test/mjsunit/test-http-chunked.js @@ -7,7 +7,7 @@ var UTF8_STRING = "Il était tué"; var server = http.createServer(function(req, res) { res.sendHeader(200, {"Content-Type": "text/plain; charset=utf8"}); res.write(UTF8_STRING, 'utf8'); - res.finish(); + res.close(); }); server.listen(PORT); diff --git a/test/mjsunit/test-http-client-race.js b/test/mjsunit/test-http-client-race.js index 79422db35b..b055331b2e 100644 --- a/test/mjsunit/test-http-client-race.js +++ b/test/mjsunit/test-http-client-race.js @@ -12,7 +12,7 @@ var server = http.createServer(function (req, res) { , "Content-Length": body.length }); res.write(body); - res.finish(); + res.close(); }); server.listen(PORT); @@ -21,7 +21,8 @@ var client = http.createClient(PORT); var body1 = ""; var body2 = ""; -client.request("/1").finish(function (res1) { +var req1 = client.request("/1") +req1.addListener('response', function (res1) { res1.setBodyEncoding("utf8"); res1.addListener('data', function (chunk) { @@ -29,13 +30,16 @@ client.request("/1").finish(function (res1) { }); res1.addListener('end', function () { - client.request("/2").finish(function (res2) { + var req2 = client.request("/2"); + req2.addListener('response', function (res2) { res2.setBodyEncoding("utf8"); res2.addListener('data', function (chunk) { body2 += chunk; }); res2.addListener('end', function () { server.close(); }); }); + req2.close(); }); }); +req1.close(); process.addListener("exit", function () { assert.equal(body1_s, body1); diff --git a/test/mjsunit/test-http-client-reconnect-bug.js b/test/mjsunit/test-http-client-reconnect-bug.js index c8d2999434..29a9feecff 100644 --- a/test/mjsunit/test-http-client-reconnect-bug.js +++ b/test/mjsunit/test-http-client-reconnect-bug.js @@ -27,9 +27,10 @@ client.addListener("end", function() { }); var request = client.request("GET", "/", {"host": "localhost"}); -request.finish(function(response) { +request.addListener('response', function(response) { sys.puts("STATUS: " + response.statusCode); }); +request.close(); setTimeout(function () { server.close(); diff --git a/test/mjsunit/test-http-client-upload.js b/test/mjsunit/test-http-client-upload.js index 83710c2ad6..317457c500 100644 --- a/test/mjsunit/test-http-client-upload.js +++ b/test/mjsunit/test-http-client-upload.js @@ -20,7 +20,7 @@ var server = http.createServer(function(req, res) { puts("request complete from server"); res.sendHeader(200, {'Content-Type': 'text/plain'}); res.write('hello\n'); - res.finish(); + res.close(); }); }); server.listen(PORT); @@ -33,7 +33,7 @@ req.write('2\n'); req.write('3\n'); puts("client finished sending request"); -req.finish(function(res) { +req.addListener('response', function(res) { res.setBodyEncoding("utf8"); res.addListener('data', function(chunk) { puts(chunk); @@ -43,6 +43,7 @@ req.finish(function(res) { server.close(); }); }); +req.close(); process.addListener("exit", function () { assert.equal("1\n2\n3\n", sent_body); diff --git a/test/mjsunit/test-http-malformed-request.js b/test/mjsunit/test-http-malformed-request.js index d3b1131881..123cfe7f32 100644 --- a/test/mjsunit/test-http-malformed-request.js +++ b/test/mjsunit/test-http-malformed-request.js @@ -15,7 +15,7 @@ var s = http.createServer(function (req, res) { res.sendHeader(200, {"Content-Type": "text/plain"}); res.write("Hello World"); - res.finish(); + res.close(); if (++nrequests_completed == nrequests_expected) s.close(); }); diff --git a/test/mjsunit/test-http-proxy.js b/test/mjsunit/test-http-proxy.js index b61aada2c2..cfc33d60a5 100644 --- a/test/mjsunit/test-http-proxy.js +++ b/test/mjsunit/test-http-proxy.js @@ -9,7 +9,7 @@ var backend = http.createServer(function (req, res) { // debug("backend"); res.sendHeader(200, {"content-type": "text/plain"}); res.write("hello world\n"); - res.finish(); + res.close(); }); // debug("listen backend") backend.listen(BACKEND_PORT); @@ -18,16 +18,17 @@ var proxy_client = http.createClient(BACKEND_PORT); var proxy = http.createServer(function (req, res) { debug("proxy req headers: " + JSON.stringify(req.headers)); var proxy_req = proxy_client.request(url.parse(req.url).pathname); - proxy_req.finish(function(proxy_res) { + proxy_req.addListener('response', function(proxy_res) { res.sendHeader(proxy_res.statusCode, proxy_res.headers); proxy_res.addListener("data", function(chunk) { res.write(chunk); }); proxy_res.addListener("end", function() { - res.finish(); + res.close(); // debug("proxy res"); }); }); + proxy_req.close(); }); // debug("listen proxy") proxy.listen(PROXY_PORT); @@ -37,7 +38,7 @@ var body = ""; var client = http.createClient(PROXY_PORT); var req = client.request("/test"); // debug("client req") -req.finish(function (res) { +req.addListener('response', function (res) { // debug("got res"); assert.equal(200, res.statusCode); res.setBodyEncoding("utf8"); @@ -48,6 +49,7 @@ req.finish(function (res) { // debug("closed both"); }); }); +req.close(); process.addListener("exit", function () { assert.equal(body, "hello world\n"); diff --git a/test/mjsunit/test-http-server.js b/test/mjsunit/test-http-server.js index e1c295374c..9caaec0ad6 100644 --- a/test/mjsunit/test-http-server.js +++ b/test/mjsunit/test-http-server.js @@ -40,7 +40,7 @@ http.createServer(function (req, res) { setTimeout(function () { res.sendHeader(200, {"Content-Type": "text/plain"}); res.write(url.parse(req.url).pathname); - res.finish(); + res.close(); }, 1); }).listen(port); diff --git a/test/mjsunit/test-http-tls.js b/test/mjsunit/test-http-tls.js index f55060a898..861b2812d1 100644 --- a/test/mjsunit/test-http-tls.js +++ b/test/mjsunit/test-http-tls.js @@ -54,7 +54,7 @@ var http_server=http.createServer(function (req, res) { req.addListener('end', function () { res.sendHeader(200, {"Content-Type": "text/plain"}); res.write("The path was " + url.parse(req.url).pathname); - res.finish(); + res.close(); responses_sent += 1; }); @@ -66,7 +66,7 @@ http_server.listen(PORT); var client = http.createClient(PORT, HOST); client.setSecure("x509_PEM", caPem, 0, keyPem, certPem); var req = client.request("/hello", {"Accept": "*/*", "Foo": "bar"}); -req.finish(function (res) { +req.addListener('response', function (res) { var verified = res.connection.verifyPeer(); var peerDN = res.connection.getPeerCertificate("DNstring"); assert.equal(verified, 1); @@ -78,10 +78,11 @@ req.finish(function (res) { res.addListener('data', function (chunk) { body0 += chunk; }); debug("Got /hello response"); }); +req.close(); setTimeout(function () { req = client.request("POST", "/world"); - req.finish(function (res) { + req.addListener('response', function (res) { var verified = res.connection.verifyPeer(); var peerDN = res.connection.getPeerCertificate("DNstring"); assert.equal(verified, 1); @@ -93,6 +94,7 @@ setTimeout(function () { res.addListener('data', function (chunk) { body1 += chunk; }); debug("Got /world response"); }); + req.close(); }, 1); process.addListener("exit", function () { diff --git a/test/mjsunit/test-http-wget.js b/test/mjsunit/test-http-wget.js index 1ae258cb7b..947c3dff29 100644 --- a/test/mjsunit/test-http-wget.js +++ b/test/mjsunit/test-http-wget.js @@ -27,7 +27,7 @@ var server = http.createServer(function (req, res) { res.sendHeader(200, {"Content-Type": "text/plain"}); res.write("hello "); res.write("world\n"); - res.finish(); + res.close(); }) server.listen(port); diff --git a/test/mjsunit/test-http.js b/test/mjsunit/test-http.js index 64baf9c106..a248e1afc9 100644 --- a/test/mjsunit/test-http.js +++ b/test/mjsunit/test-http.js @@ -30,7 +30,7 @@ http.createServer(function (req, res) { req.addListener('end', function () { res.sendHeader(200, {"Content-Type": "text/plain"}); res.write("The path was " + url.parse(req.url).pathname); - res.finish(); + res.close(); responses_sent += 1; }); @@ -39,23 +39,25 @@ http.createServer(function (req, res) { var client = http.createClient(PORT); var req = client.request("/hello", {"Accept": "*/*", "Foo": "bar"}); -req.finish(function (res) { +req.addListener('response', function (res) { assert.equal(200, res.statusCode); responses_recvd += 1; res.setBodyEncoding("ascii"); res.addListener('data', function (chunk) { body0 += chunk; }); debug("Got /hello response"); }); +req.close(); setTimeout(function () { req = client.request("POST", "/world"); - req.finish(function (res) { + req.addListener('response',function (res) { assert.equal(200, res.statusCode); responses_recvd += 1; res.setBodyEncoding("utf8"); res.addListener('data', function (chunk) { body1 += chunk; }); debug("Got /world response"); }); + req.close(); }, 1); process.addListener("exit", function () { diff --git a/test/mjsunit/test-keep-alive.js b/test/mjsunit/test-keep-alive.js index dcf1ac2409..2307cd3bf4 100644 --- a/test/mjsunit/test-keep-alive.js +++ b/test/mjsunit/test-keep-alive.js @@ -11,7 +11,7 @@ server = http.createServer(function (req, res) { "Content-Type": "text/plain", }); res.write(body); - res.finish(); + res.close(); }); server.listen(PORT); diff --git a/test/mjsunit/test-multipart.js b/test/mjsunit/test-multipart.js index 878c190e7a..4e5ac7cc27 100644 --- a/test/mjsunit/test-multipart.js +++ b/test/mjsunit/test-multipart.js @@ -81,12 +81,12 @@ var secondPart = new (events.Promise), sys.puts("!! error occurred"); res.sendHeader(400, {}); res.write("bad"); - res.finish(); + res.close(); }); mp.addListener("complete", function () { res.sendHeader(200, {}); res.write("ok"); - res.finish(); + res.close(); }); }), message, @@ -106,7 +106,7 @@ firstPart.addCallback(function testGoodMessages () { sys.puts("test message "+httpMessages.length); var req = client.request("POST", "/", message.headers); req.write(message.body, "binary"); - req.finish(function (res) { + req.addListener('response', function (res) { var buff = ""; res.addListener("data", function (chunk) { buff += chunk }); res.addListener("end", function () { @@ -114,6 +114,7 @@ firstPart.addCallback(function testGoodMessages () { process.nextTick(testHTTP); }); }); + req.close(); })(); }); secondPart.addCallback(function testBadMessages () { @@ -128,7 +129,7 @@ secondPart.addCallback(function testBadMessages () { sys.puts("test message "+httpMessages.length); var req = client.request("POST", "/bad", message.headers); req.write(message.body, "binary"); - req.finish(function (res) { + req.addListener('response', function (res) { var buff = ""; res.addListener("data", function (chunk) { buff += chunk }); res.addListener("end", function () { @@ -136,5 +137,6 @@ secondPart.addCallback(function testBadMessages () { process.nextTick(testHTTP); }); }); + req.close(); })(); }); diff --git a/test/mjsunit/test-remote-module-loading.js b/test/mjsunit/test-remote-module-loading.js index 61963b9630..2978f72add 100644 --- a/test/mjsunit/test-remote-module-loading.js +++ b/test/mjsunit/test-remote-module-loading.js @@ -13,7 +13,7 @@ var server = http.createServer(function(req, res) { res.sendHeader(200, {'Content-Type': 'text/javascript'}); res.write(body); - res.finish(); + res.close(); }); server.listen(PORT);