Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: end with data should emit write after end error #28666

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 27 additions & 20 deletions lib/_http_outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -620,17 +620,20 @@ OutgoingMessage.prototype.write = function write(chunk, encoding, callback) {
return ret;
};

function writeAfterEnd(msg, callback) {
const err = new ERR_STREAM_WRITE_AFTER_END();
const triggerAsyncId = msg.socket ? msg.socket[async_id_symbol] : undefined;
defaultTriggerAsyncIdScope(triggerAsyncId,
process.nextTick,
writeAfterEndNT,
msg,
err,
callback);
}

function write_(msg, chunk, encoding, callback, fromEnd) {
if (msg.finished) {
const err = new ERR_STREAM_WRITE_AFTER_END();
const triggerAsyncId = msg.socket ? msg.socket[async_id_symbol] : undefined;
defaultTriggerAsyncIdScope(triggerAsyncId,
process.nextTick,
writeAfterEndNT,
msg,
err,
callback);

writeAfterEnd(msg, callback);
return true;
}

Expand Down Expand Up @@ -724,17 +727,6 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
encoding = null;
}

if (this.finished) {
if (typeof callback === 'function') {
if (!this.writableFinished) {
this.on('finish', callback);
} else {
callback(new ERR_STREAM_ALREADY_FINISHED('end'));
}
}
return this;
}

if (this.socket) {
this.socket.cork();
}
Expand All @@ -743,13 +735,28 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
throw new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
}

if (this.finished) {
writeAfterEnd(this, callback);
lpinca marked this conversation as resolved.
Show resolved Hide resolved
return this;
}

if (!this._header) {
if (typeof chunk === 'string')
this._contentLength = Buffer.byteLength(chunk, encoding);
else
this._contentLength = chunk.length;
}
write_(this, chunk, encoding, null, true);
} else if (this.finished) {
if (typeof callback === 'function') {
if (!this.writableFinished) {
this.on('finish', callback);
} else {
callback(new ERR_STREAM_ALREADY_FINISHED('end'));
}
}
return this;
} else if (!this._header) {
this._contentLength = 0;
this._implicitHeader();
Expand Down
27 changes: 27 additions & 0 deletions test/parallel/test-http-server-write-end-after-end.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

const common = require('../common');
const http = require('http');

const server = http.createServer(handle);

function handle(req, res) {
res.on('error', common.mustCall((err) => {
common.expectsError({
code: 'ERR_STREAM_WRITE_AFTER_END',
name: 'Error'
})(err);
server.close();
}));

res.write('hello');
res.end();

setImmediate(common.mustCall(() => {
res.end('world');
}));
}

server.listen(0, common.mustCall(() => {
http.get(`http://localhost:${server.address().port}`);
}));