http,stream: add writableEnded
This is work towards resolving the response.finished confusion and future deprecation. Note that implementation-wise, streams have both an ending and ended state. However, in this case (in order to avoid confusion in user space) writableEnded is equal to writable.ending. The ending vs ended situation is internal state required for internal stream logic. PR-URL: https://github.com/nodejs/node/pull/28934 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
parent
e4bbbcc84b
commit
6f613d8abb
@ -764,6 +764,27 @@ req.once('response', (res) => {
|
||||
});
|
||||
```
|
||||
|
||||
### request.writableEnded
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* {boolean}
|
||||
|
||||
Is `true` after [`request.end()`][] has been called. This property
|
||||
does not indicate whether the data has been flushed, for this use
|
||||
[`request.writableFinished`][] instead.
|
||||
|
||||
### request.writableFinished
|
||||
<!-- YAML
|
||||
added: v12.7.0
|
||||
-->
|
||||
|
||||
* {boolean}
|
||||
|
||||
Is `true` if all data has been flushed to the underlying system, immediately
|
||||
before the [`'finish'`][] event is emitted.
|
||||
|
||||
### request.write(chunk[, encoding][, callback])
|
||||
<!-- YAML
|
||||
added: v0.1.29
|
||||
@ -1436,6 +1457,17 @@ response.statusMessage = 'Not found';
|
||||
After response header was sent to the client, this property indicates the
|
||||
status message which was sent out.
|
||||
|
||||
### response.writableEnded
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* {boolean}
|
||||
|
||||
Is `true` after [`response.end()`][] has been called. This property
|
||||
does not indicate whether the data has been flushed, for this use
|
||||
[`response.writableFinished`][] instead.
|
||||
|
||||
### response.writableFinished
|
||||
<!-- YAML
|
||||
added: v12.7.0
|
||||
@ -2222,11 +2254,13 @@ not abort the request or do anything besides add a `'timeout'` event.
|
||||
[`request.setTimeout()`]: #http_request_settimeout_timeout_callback
|
||||
[`request.socket.getPeerCertificate()`]: tls.html#tls_tlssocket_getpeercertificate_detailed
|
||||
[`request.socket`]: #http_request_socket
|
||||
[`request.writableFinished`]: #http_request_writablefinished
|
||||
[`request.write(data, encoding)`]: #http_request_write_chunk_encoding_callback
|
||||
[`response.end()`]: #http_response_end_data_encoding_callback
|
||||
[`response.getHeader()`]: #http_response_getheader_name
|
||||
[`response.setHeader()`]: #http_response_setheader_name_value
|
||||
[`response.socket`]: #http_response_socket
|
||||
[`response.writableFinished`]: #http_response_writablefinished
|
||||
[`response.write()`]: #http_response_write_chunk_encoding_callback
|
||||
[`response.write(data, encoding)`]: #http_response_write_chunk_encoding_callback
|
||||
[`response.writeContinue()`]: #http_response_writecontinue
|
||||
|
@ -3271,6 +3271,17 @@ added: v8.4.0
|
||||
|
||||
The [`Http2Stream`][] object backing the response.
|
||||
|
||||
#### response.writableEnded
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* {boolean}
|
||||
|
||||
Is `true` after [`response.end()`][] has been called. This property
|
||||
does not indicate whether the data has been flushed, for this use
|
||||
[`writable.writableFinished`][] instead.
|
||||
|
||||
#### response.write(chunk[, encoding][, callback])
|
||||
<!-- YAML
|
||||
added: v8.4.0
|
||||
@ -3510,3 +3521,4 @@ following additional properties:
|
||||
[`tls.connect()`]: tls.html#tls_tls_connect_options_callback
|
||||
[`tls.createServer()`]: tls.html#tls_tls_createserver_options_secureconnectionlistener
|
||||
[error code]: #error_codes
|
||||
[`writable.writableFinished`]: stream.html#stream_writable_writablefinished
|
||||
|
@ -494,6 +494,17 @@ added: v11.4.0
|
||||
|
||||
Is `true` if it is safe to call [`writable.write()`][stream-write].
|
||||
|
||||
##### writable.writableEnded
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* {boolean}
|
||||
|
||||
Is `true` after [`writable.end()`][] has been called. This property
|
||||
does not indicate whether the data has been flushed, for this use
|
||||
[`writable.writableFinished`][] instead.
|
||||
|
||||
##### writable.writableFinished
|
||||
<!-- YAML
|
||||
added: v12.6.0
|
||||
@ -2707,7 +2718,9 @@ contain multi-byte characters.
|
||||
[`stream.unpipe()`]: #stream_readable_unpipe_destination
|
||||
[`stream.wrap()`]: #stream_readable_wrap_stream
|
||||
[`writable.cork()`]: #stream_writable_cork
|
||||
[`writable.end()`]: #stream_writable_end_chunk_encoding_callback
|
||||
[`writable.uncork()`]: #stream_writable_uncork
|
||||
[`writable.writableFinished`]: #stream_writable_writablefinished
|
||||
[`zlib.createDeflate()`]: zlib.html#zlib_zlib_createdeflate_options
|
||||
[API for Stream Consumers]: #stream_api_for_stream_consumers
|
||||
[API for Stream Implementers]: #stream_api_for_stream_implementers
|
||||
|
@ -575,6 +575,10 @@ Object.defineProperty(OutgoingMessage.prototype, 'headersSent', {
|
||||
get: function() { return !!this._header; }
|
||||
});
|
||||
|
||||
Object.defineProperty(OutgoingMessage.prototype, 'writableEnded', {
|
||||
get: function() { return this.finished; }
|
||||
});
|
||||
|
||||
|
||||
const crlf_buf = Buffer.from('\r\n');
|
||||
OutgoingMessage.prototype.write = function write(chunk, encoding, callback) {
|
||||
|
@ -74,7 +74,7 @@ Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get() {
|
||||
return this._writableState.highWaterMark;
|
||||
return this._writableState && this._writableState.highWaterMark;
|
||||
}
|
||||
});
|
||||
|
||||
@ -94,7 +94,7 @@ Object.defineProperty(Duplex.prototype, 'writableLength', {
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get() {
|
||||
return this._writableState.length;
|
||||
return this._writableState && this._writableState.length;
|
||||
}
|
||||
});
|
||||
|
||||
@ -104,7 +104,17 @@ Object.defineProperty(Duplex.prototype, 'writableFinished', {
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get() {
|
||||
return this._writableState.finished;
|
||||
return this._writableState ? this._writableState.finished : false;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Duplex.prototype, 'writableEnded', {
|
||||
// Making it explicit this property is not enumerable
|
||||
// because otherwise some prototype manipulation in
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get() {
|
||||
return this._writableState ? this._writableState.ending : false;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -352,13 +352,23 @@ function decodeChunk(state, chunk, encoding) {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
Object.defineProperty(Writable.prototype, 'writableEnded', {
|
||||
// Making it explicit this property is not enumerable
|
||||
// because otherwise some prototype manipulation in
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get: function() {
|
||||
return this._writableState ? this._writableState.ending : false;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Writable.prototype, 'writableHighWaterMark', {
|
||||
// Making it explicit this property is not enumerable
|
||||
// because otherwise some prototype manipulation in
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get: function() {
|
||||
return this._writableState.highWaterMark;
|
||||
return this._writableState && this._writableState.highWaterMark;
|
||||
}
|
||||
});
|
||||
|
||||
@ -711,7 +721,7 @@ Object.defineProperty(Writable.prototype, 'writableFinished', {
|
||||
// userland will fail
|
||||
enumerable: false,
|
||||
get() {
|
||||
return this._writableState.finished;
|
||||
return this._writableState ? this._writableState.finished : false;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -454,6 +454,11 @@ class Http2ServerResponse extends Stream {
|
||||
return this.headersSent;
|
||||
}
|
||||
|
||||
get writableEnded() {
|
||||
const state = this[kState];
|
||||
return state.ending;
|
||||
}
|
||||
|
||||
get finished() {
|
||||
const stream = this[kStream];
|
||||
return stream.destroyed ||
|
||||
|
@ -9,12 +9,14 @@ const http = require('http');
|
||||
const server = http.createServer(common.mustCall(function(req, res) {
|
||||
assert.strictEqual(res.writable, true);
|
||||
assert.strictEqual(res.finished, false);
|
||||
assert.strictEqual(res.writableEnded, false);
|
||||
res.end();
|
||||
|
||||
// res.writable is set to false after it has finished sending
|
||||
// Ref: https://github.com/nodejs/node/issues/15029
|
||||
assert.strictEqual(res.writable, true);
|
||||
assert.strictEqual(res.finished, true);
|
||||
assert.strictEqual(res.writableEnded, true);
|
||||
|
||||
server.close();
|
||||
}));
|
||||
|
@ -150,8 +150,10 @@ const {
|
||||
// for http1 compatibility
|
||||
const server = createServer(mustCall((request, response) => {
|
||||
strictEqual(response.finished, true);
|
||||
strictEqual(response.writableEnded, false);
|
||||
response.writeHead(HTTP_STATUS_OK, { foo: 'bar' });
|
||||
response.end('data', mustCall());
|
||||
strictEqual(response.writableEnded, true);
|
||||
}));
|
||||
server.listen(0, mustCall(() => {
|
||||
const { port } = server.address();
|
||||
|
@ -25,8 +25,10 @@ server.listen(0, common.mustCall(() => {
|
||||
}));
|
||||
}));
|
||||
assert.strictEqual(response.finished, false);
|
||||
assert.strictEqual(response.writableEnded, false);
|
||||
response.end();
|
||||
assert.strictEqual(response.finished, true);
|
||||
assert.strictEqual(response.writableEnded, true);
|
||||
}));
|
||||
|
||||
const url = `http://localhost:${port}`;
|
||||
|
@ -9,13 +9,17 @@ const writable = new stream.Writable();
|
||||
|
||||
writable._write = (chunk, encoding, cb) => {
|
||||
assert.strictEqual(writable._writableState.ended, false);
|
||||
assert.strictEqual(writable.writableEnded, false);
|
||||
cb();
|
||||
};
|
||||
|
||||
assert.strictEqual(writable._writableState.ended, false);
|
||||
assert.strictEqual(writable.writableEnded, false);
|
||||
|
||||
writable.end('testing ended state', common.mustCall(() => {
|
||||
assert.strictEqual(writable._writableState.ended, true);
|
||||
assert.strictEqual(writable.writableEnded, true);
|
||||
}));
|
||||
|
||||
assert.strictEqual(writable._writableState.ended, true);
|
||||
assert.strictEqual(writable.writableEnded, true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user