net: make readable/writable start as true

`net.Socket` is slightly breaking stream invariants by
having readable/writable going from `false` to `true`.
Streams assume that readable/writable starts out `true`
and then goes to `false` through `push(null)`/`end()`
after which it never goes back to `true`, e.g. once a
stream is `writable == false` it is assumed it will
never become `true`.

This PR changes 2 things:

Unless explicitly set to `false` through options:

- starts as `readable`/`writable` `true` by default.
- uses `push(null)`/`end()` to set `readable`/`writable`
  to `false`. Note that this would cause the socket to
  emit the `'end'`/`'finish'` events, which it did not
  do previously.

In the case it is explicitly set to `false` through
options` it is assumed to never become `true`.

PR-URL: https://github.com/nodejs/node/pull/32272
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Robert Nagy
2020-03-14 23:14:52 +01:00
parent 96f06e6482
commit eeccd52b4e
6 changed files with 35 additions and 33 deletions

View File

@@ -23,7 +23,6 @@
const {
ArrayIsArray,
Boolean,
NumberIsInteger,
NumberIsNaN,
ObjectDefineProperties,
@@ -1061,9 +1060,12 @@ ObjectDefineProperties(Readable.prototype, {
readable: {
get() {
const r = this._readableState;
if (!r) return false;
if (r.readable !== undefined) return r.readable && !r.endEmitted;
return Boolean(!r.destroyed && !r.errorEmitted && !r.endEmitted);
// r.readable === false means that this is part of a Duplex stream
// where the readable side was disabled upon construction.
// Compat. The user might manually disable readable side through
// deprecated setter.
return !!r && r.readable !== false && !r.destroyed && !r.errorEmitted &&
!r.endEmitted;
},
set(val) {
// Backwards compat.

View File

@@ -27,7 +27,6 @@
const {
Array,
Boolean,
FunctionPrototype,
ObjectDefineProperty,
ObjectDefineProperties,
@@ -744,9 +743,12 @@ ObjectDefineProperties(Writable.prototype, {
writable: {
get() {
const w = this._writableState;
if (!w) return false;
if (w.writable !== undefined) return w.writable && !w.ended;
return Boolean(!w.destroyed && !w.errored && !w.ending);
// w.writable === false means that this is part of a Duplex stream
// where the writable side was disabled upon construction.
// Compat. The user might manually disable writable side through
// deprecated setter.
return !!w && w.writable !== false && !w.destroyed && !w.errored &&
!w.ending;
},
set(val) {
// Backwards compatible.

View File

@@ -494,9 +494,7 @@ function TLSSocket(socket, opts) {
handle: this._wrapHandle(wrap),
allowHalfOpen: socket ? socket.allowHalfOpen : tlsOptions.allowHalfOpen,
pauseOnCreate: tlsOptions.pauseOnConnect,
// The readable flag is only needed if pauseOnCreate will be handled.
readable: tlsOptions.pauseOnConnect,
writable: false
manualStart: true
});
// Proxy for API compatibility
@@ -506,11 +504,6 @@ function TLSSocket(socket, opts) {
this._init(socket, wrap);
// Make sure to setup all required properties like: `connecting` before
// starting the flow of the data
this.readable = true;
this.writable = true;
if (enableTrace && this._handle)
this._handle.enableTrace();

View File

@@ -285,8 +285,6 @@ function Socket(options) {
else
options = { ...options };
options.readable = options.readable || false;
options.writable = options.writable || false;
const { allowHalfOpen } = options;
// Prevent the "no-half-open enforcer" from being inherited from `Duplex`.
@@ -655,8 +653,6 @@ Socket.prototype._destroy = function(exception, cb) {
this.connecting = false;
this.readable = this.writable = false;
for (let s = this; s !== null; s = s._parent) {
clearTimeout(s[kTimeout]);
}
@@ -1120,9 +1116,13 @@ function afterConnect(status, handle, req, readable, writable) {
self._sockname = null;
if (status === 0) {
self.readable = readable;
if (!self._writableState.ended)
self.writable = writable;
if (self.readable && !readable) {
self.push(null);
self.read();
}
if (self.writable && !writable) {
self.end();
}
self._unrefTimer();
self.emit('connect');