Node.js: changed the 'data' event calling sequence for the request.

The problem is caused by Promises' inconsistency.
The 'date' event could have been triggered before the user has started
listening for it.  To resolve the issue, we override the 'on' method of
the request's emitter.
This commit is contained in:
Alexander Borisov
2018-12-19 15:55:58 +03:00
parent de3c062c6e
commit 13c9ebccca

View File

@@ -288,6 +288,28 @@ ServerRequest.prototype.resume = function resume() {
return [];
};
/*
* The "on" method is overridden to defer reading data until user code is
* ready, that is (ev === "data"). This can occur after req.emit("end") is
* executed, since the user code can be scheduled asynchronously by Promises
* and so on. Passing the data is postponed by process.nextTick() until
* the "on" method caller completes.
*/
ServerRequest.prototype.on = function on(ev, fn) {
Server.prototype.on.call(this, ev, fn);
if (ev === "data") {
process.nextTick(function () {
if (this.server.buffer.length !== 0) {
this.emit("data", this.server.buffer);
}
}.bind(this));
}
};
ServerRequest.prototype.addListener = ServerRequest.prototype.on;
function Server(requestListener) {
EventEmitter.call(this);
@@ -321,22 +343,20 @@ Server.prototype.listen = function () {
};
Server.prototype.run_events = function (server, req, res) {
req.server = server;
res.server = server;
req.res = res;
res.req = req;
server.buffer = server.unit._read(req.socket.req_pointer);
/* Important!!! setImmediate starts the next iteration in Node.js loop. */
setImmediate(function () {
server.emit("request", req, res);
Promise.resolve().then(() => {
let buf = server.unit._read(req.socket.req_pointer);
if (buf.length != 0) {
req.emit("data", buf);
}
req.emit("end");
});
Promise.resolve().then(() => {
req.emit("finish");
req.emit("end");
if (res.finished) {
unit_lib.unit_response_end(res);