Browse Source

API: Make request/response object closer to stream interface

- sendBody() renamed to write()
- 'body' event renamed to 'data'
- 'complete' event renamed to 'end'
v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
ae85d9af97
  1. 2
      benchmark/http_simple.js
  2. 4
      benchmark/static_http_server.js
  3. 38
      doc/api.txt
  4. 2
      doc/index.html
  5. 36
      lib/http.js
  6. 4
      lib/multipart.js
  7. 2
      test/mjsunit/test-http-1.0.js
  8. 2
      test/mjsunit/test-http-cat.js
  9. 4
      test/mjsunit/test-http-chunked.js
  10. 10
      test/mjsunit/test-http-client-race.js
  11. 16
      test/mjsunit/test-http-client-upload.js
  12. 2
      test/mjsunit/test-http-malformed-request.js
  13. 12
      test/mjsunit/test-http-proxy.js
  14. 2
      test/mjsunit/test-http-server.js
  15. 8
      test/mjsunit/test-http-tls.js
  16. 4
      test/mjsunit/test-http-wget.js
  17. 8
      test/mjsunit/test-http.js
  18. 2
      test/mjsunit/test-keep-alive.js
  19. 22
      test/mjsunit/test-multipart.js
  20. 2
      test/mjsunit/test-remote-module-loading.js

2
benchmark/http_simple.js

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

4
benchmark/static_http_server.js

@ -20,13 +20,13 @@ var server = http.createServer(function (req, res) {
"Content-Type": "text/plain",
"Content-Length": body.length
});
res.sendBody(body);
res.write(body);
res.finish();
})
server.listen(port);
function responseListener (res) {
res.addListener("complete", function () {
res.addListener("end", function () {
if (requests < n) {
res.client.request("/").finish(responseListener);
requests++;

38
doc/api.txt

@ -20,7 +20,7 @@ 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.write("Hello World\n");
response.finish();
}).listen(8000);
sys.puts("Server running at http://127.0.0.1:8000/");
@ -856,7 +856,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 +864,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.
|=========================================================
@ -970,7 +970,7 @@ response.sendHeader(200, {
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")+ ::
+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,10 +983,10 @@ 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.
@ -1017,7 +1017,7 @@ request.finish(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);
});
});
@ -1049,7 +1049,7 @@ 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()+.)
+request.write()+.)
+client.setSecure(format_type, ca_certs, crl_list, private_key, certificate)+ ::
Enable TLS for the client connection, with the specified credentials.
@ -1082,7 +1082,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
@ -1112,16 +1112,16 @@ 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
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 +"body"+ is added during 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("body", function (chunk) {
response.addListener("data", function (chunk) {
sys.puts("BODY: " + chunk);
});
});
@ -1129,7 +1129,7 @@ request.finish(function (response) {
// Bad - misses all or part of the body
request.finish(function (response) {
setTimeout(function () {
response.addListener("body", function (chunk) {
response.addListener("data", function (chunk) {
sys.puts("BODY: " + chunk);
});
}, 10);
@ -1147,13 +1147,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.
@ -1300,7 +1300,7 @@ 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.write("You sent a bad message!\n"+er.message);
res.finish();
});
mp.addListener("partBegin", function (part) {
@ -1323,7 +1323,7 @@ http.createServer(function (req, res) {
"content-type" : "text/plain",
"content-length" : response.length
});
res.sendBody(response);
res.write(response);
res.finish();
})
});

2
doc/index.html

@ -48,7 +48,7 @@ var sys = require('sys'),
http.createServer(function (req, res) {
setTimeout(function () {
res.sendHeader(200, {'Content-Type': 'text/plain'});
res.sendBody('Hello World');
res.write('Hello World');
res.finish();
}, 2000);
}).listen(8000);

36
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);
this._send(message_header);
// wait until the first body chunk, or finish(), 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,7 @@ OutgoingMessage.prototype.flush = function () {
};
OutgoingMessage.prototype.finish = function () {
if (this.chunked_encoding) this.send("0\r\n\r\n"); // last chunk
if (this.chunked_encoding) this._send("0\r\n\r\n"); // last chunk
this.finished = true;
this.flush();
};
@ -333,11 +341,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;
@ -486,7 +494,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();
});
@ -561,8 +569,8 @@ exports.cat = function (url, encoding, headers) {
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);
});
});

4
lib/multipart.js

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

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

@ -10,7 +10,7 @@ var client_got_eof = false;
var server = http.createServer(function (req, res) {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody(body);
res.write(body);
res.finish();
})
server.listen(port);

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

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

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

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

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

@ -11,7 +11,7 @@ var server = http.createServer(function (req, res) {
res.sendHeader(200, { "Content-Type": "text/plain"
, "Content-Length": body.length
});
res.sendBody(body);
res.write(body);
res.finish();
});
server.listen(PORT);
@ -24,15 +24,15 @@ var body2 = "";
client.request("/1").finish(function (res1) {
res1.setBodyEncoding("utf8");
res1.addListener("body", function (chunk) {
res1.addListener('data', function (chunk) {
body1 += chunk;
});
res1.addListener("complete", function () {
res1.addListener('end', function () {
client.request("/2").finish(function (res2) {
res2.setBodyEncoding("utf8");
res2.addListener("body", function (chunk) { body2 += chunk; });
res2.addListener("complete", function () { server.close(); });
res2.addListener('data', function (chunk) { body2 += chunk; });
res2.addListener('end', function () { server.close(); });
});
});
});

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

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

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

@ -14,7 +14,7 @@ var s = http.createServer(function (req, res) {
puts("req: " + JSON.stringify(url.parse(req.url)));
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("Hello World");
res.write("Hello World");
res.finish();
if (++nrequests_completed == nrequests_expected) s.close();

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

@ -8,7 +8,7 @@ var BACKEND_PORT = 8870;
var backend = http.createServer(function (req, res) {
// debug("backend");
res.sendHeader(200, {"content-type": "text/plain"});
res.sendBody("hello world\n");
res.write("hello world\n");
res.finish();
});
// debug("listen backend")
@ -20,10 +20,10 @@ var proxy = http.createServer(function (req, res) {
var proxy_req = proxy_client.request(url.parse(req.url).pathname);
proxy_req.finish(function(proxy_res) {
res.sendHeader(proxy_res.statusCode, proxy_res.headers);
proxy_res.addListener("body", function(chunk) {
res.sendBody(chunk);
proxy_res.addListener("data", function(chunk) {
res.write(chunk);
});
proxy_res.addListener("complete", function() {
proxy_res.addListener("end", function() {
res.finish();
// debug("proxy res");
});
@ -41,8 +41,8 @@ req.finish(function (res) {
// debug("got res");
assert.equal(200, res.statusCode);
res.setBodyEncoding("utf8");
res.addListener("body", function (chunk) { body += chunk; });
res.addListener("complete", function () {
res.addListener('data', function (chunk) { body += chunk; });
res.addListener('end', function () {
proxy.close();
backend.close();
// debug("closed both");

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

@ -39,7 +39,7 @@ http.createServer(function (req, res) {
setTimeout(function () {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody(url.parse(req.url).pathname);
res.write(url.parse(req.url).pathname);
res.finish();
}, 1);

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

@ -51,9 +51,9 @@ var http_server=http.createServer(function (req, res) {
this.close();
}
req.addListener("complete", function () {
req.addListener('end', function () {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("The path was " + url.parse(req.url).pathname);
res.write("The path was " + url.parse(req.url).pathname);
res.finish();
responses_sent += 1;
});
@ -75,7 +75,7 @@ req.finish(function (res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("ascii");
res.addListener("body", function (chunk) { body0 += chunk; });
res.addListener('data', function (chunk) { body0 += chunk; });
debug("Got /hello response");
});
@ -90,7 +90,7 @@ setTimeout(function () {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("utf8");
res.addListener("body", function (chunk) { body1 += chunk; });
res.addListener('data', function (chunk) { body1 += chunk; });
debug("Got /world response");
});
}, 1);

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

@ -25,8 +25,8 @@ var connection_was_closed = false;
var server = http.createServer(function (req, res) {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("hello ");
res.sendBody("world\n");
res.write("hello ");
res.write("world\n");
res.finish();
})
server.listen(port);

8
test/mjsunit/test-http.js

@ -27,9 +27,9 @@ http.createServer(function (req, res) {
this.close();
}
req.addListener("complete", function () {
req.addListener('end', function () {
res.sendHeader(200, {"Content-Type": "text/plain"});
res.sendBody("The path was " + url.parse(req.url).pathname);
res.write("The path was " + url.parse(req.url).pathname);
res.finish();
responses_sent += 1;
});
@ -43,7 +43,7 @@ req.finish(function (res) {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("ascii");
res.addListener("body", function (chunk) { body0 += chunk; });
res.addListener('data', function (chunk) { body0 += chunk; });
debug("Got /hello response");
});
@ -53,7 +53,7 @@ setTimeout(function () {
assert.equal(200, res.statusCode);
responses_recvd += 1;
res.setBodyEncoding("utf8");
res.addListener("body", function (chunk) { body1 += chunk; });
res.addListener('data', function (chunk) { body1 += chunk; });
debug("Got /world response");
});
}, 1);

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

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

22
test/mjsunit/test-multipart.js

@ -52,11 +52,11 @@ sys.puts("test "+emails.length+" emails");
var emailBody = email.body;
process.nextTick(function s () {
if (emailBody) {
message.emit("body", emailBody.substr(0, chunkSize));
message.emit("data", emailBody.substr(0, chunkSize));
emailBody = emailBody.substr(chunkSize);
process.nextTick(s);
} else {
message.emit("complete");
message.emit("end");
}
});
})();
@ -80,12 +80,12 @@ var secondPart = new (events.Promise),
mp.addListener("error", function (er) {
sys.puts("!! error occurred");
res.sendHeader(400, {});
res.sendBody("bad");
res.write("bad");
res.finish();
});
mp.addListener("complete", function () {
res.sendHeader(200, {});
res.sendBody("ok");
res.write("ok");
res.finish();
});
}),
@ -105,11 +105,11 @@ firstPart.addCallback(function testGoodMessages () {
}
sys.puts("test message "+httpMessages.length);
var req = client.request("POST", "/", message.headers);
req.sendBody(message.body, "binary");
req.write(message.body, "binary");
req.finish(function (res) {
var buff = "";
res.addListener("body", function (chunk) { buff += chunk });
res.addListener("complete", function () {
res.addListener("data", function (chunk) { buff += chunk });
res.addListener("end", function () {
assert.equal(buff, "ok");
process.nextTick(testHTTP);
});
@ -127,14 +127,14 @@ secondPart.addCallback(function testBadMessages () {
}
sys.puts("test message "+httpMessages.length);
var req = client.request("POST", "/bad", message.headers);
req.sendBody(message.body, "binary");
req.write(message.body, "binary");
req.finish(function (res) {
var buff = "";
res.addListener("body", function (chunk) { buff += chunk });
res.addListener("complete", function () {
res.addListener("data", function (chunk) { buff += chunk });
res.addListener("end", function () {
assert.equal(buff, "bad");
process.nextTick(testHTTP);
});
});
})();
});
});

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

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

Loading…
Cancel
Save