-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
async_wrap: add asyncReset
to TLSWrap
#13092
Conversation
CI: https://ci.nodejs.org/job/node-test-commit/9967/ |
asyncReset
to TLSWrap
|
||
const req = https.request(clientOptions, common.mustCall((res) => { | ||
assert.strictEqual(res.statusCode, 200); | ||
res.on('error', common.mustNotCall()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to add this listener? If there is an error in the future I think it would be better to see that error than an AssertionError('must not throw')
message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 and put assert.ifError
?
Ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will just throw by default, which will cause the test to fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then you don't get which line... And since there are two almost identical calls it's a PITA (just been there while writing this test)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I think the ifError
approach is fine then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of nits with the test, but mostly LGTM
'use strict'; | ||
const common = require('../common'); | ||
|
||
// checks for the issue in https://github.com/nodejs/node/issues/13045 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
checks for the issue in -> Refs:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack
|
||
const req = https.request(clientOptions, common.mustCall((res) => { | ||
assert.strictEqual(res.statusCode, 200); | ||
res.on('error', assert.ifError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you replace the uses of assert.ifError()
with common.mustNotCall()
. You can provide a custom message with the latter if you'd like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #13092 (comment)
@AndreasMadsen suggested that we might want to see the actual error.
(Maybe we need mustNotErr
like assert.doesNotThrow
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, you might want to use assert.fail()
instead. ifError()
implies that there might not be an error, but in this case, we know that there is one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a factory method mustNotErr
that calls assert.fail
so the fail point will appear in the stack
try { | ||
req2 = https.request(clientOptions); | ||
} catch (e) { | ||
assert.ifError(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this redundant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a sense yes, I just wanted to be explicit about the pain point.
I could replace this with a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't you drop the try...catch
completely, and if it happens to throw, it will fail the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack. Replaced with a comment
'use strict'; | ||
const common = require('../common'); | ||
|
||
// Checks for the issue in Refs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if my previous comment was unclear. I just meant to write this as:
Refs: #13045
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack
const fs = require('fs'); | ||
|
||
// arrow factory so fail point will appear in the stack | ||
function mustNotErr() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why you need this. You can just pass assert.fail
(without the parens) as the handler, everywhere you use mustNotErr()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried it, then there is no frame for the line with the failing assert (Actually the factory is not a solution I need explicit (err) => assert.fail(err)
)
Generated error by setting port: port + 1
with (err) => assert.fail(err)
assert.js:92
throw new AssertionError({
^
AssertionError [ERR_ASSERTION]: Error: write EPROTO 101057795:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:openssl\ssl\s23_clnt.c:794:
at ClientRequest.req.on (D:\code\node-cur\test\parallel\test-async-wrap-GH13045.js:63:35)
at emitOne (events.js:115:13)
at ClientRequest.emit (events.js:210:7)
at TLSSocket.socketErrorListener (_http_client.js:397:9)
at emitOne (events.js:115:13)
at TLSSocket.emit (events.js:210:7)
at onwriteError (_stream_writable.js:359:10)
at onwrite (_stream_writable.js:377:5)
at fireErrorCallbacks (net.js:522:13)
at TLSSocket.Socket._destroy (net.js:563:3)
with just assert.fail
assert.js:92
throw new AssertionError({
^
AssertionError [ERR_ASSERTION]: Error: write EPROTO 101057795:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:openssl\ssl\s23_clnt.c:794:
at emitOne (events.js:115:13)
at ClientRequest.emit (events.js:210:7)
at TLSSocket.socketErrorListener (_http_client.js:397:9)
at emitOne (events.js:115:13)
at TLSSocket.emit (events.js:210:7)
at onwriteError (_stream_writable.js:359:10)
at onwrite (_stream_writable.js:377:5)
at fireErrorCallbacks (net.js:522:13)
at TLSSocket.Socket._destroy (net.js:563:3)
at WriteWrap.afterWrite [as oncomplete] (net.js:857:10)
Sounds correct to me. |
Can we get a CITGM run? that has been the main blocker for me. |
}); | ||
})); | ||
|
||
req.on('error', (err) => assert.fail(err)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this more or less equivalent to just not adding an 'error'
listener? Similarly with the 'error'
handlers above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #13092 (comment) and #13092 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, I'm -0 on it.
// This is the pain point. Internally the Agent will call | ||
// `socket._handle.asyncReset()` and if the _handle does not implement | ||
// `asyncReset` this will throw TypeError | ||
const req2 = https.request(clientOptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the response handler as a second argument here for consistency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto about switching to https.get()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack, ack.
ca: fs.readFileSync(`${common.fixturesDir}/keys/ca1-cert.pem`) | ||
}; | ||
|
||
const server = https.createServer(serverOptions, (req, res) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
common.mustCall((req, res) => { ... }, 2)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack.
agent: new https.Agent({ | ||
keepAlive: true, | ||
maxSockets: 50, | ||
rejectUnauthorized: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these last two options necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just last one: AssertionError [ERR_ASSERTION]: Error: self signed certificate in certificate chain
method: 'GET' | ||
}; | ||
|
||
const req = https.request(clientOptions, common.mustCall((res) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think method: 'GET'
could be dropped and .request()
changed to .get()
to avoid the need to req.end()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
}), | ||
hostname: common.localhostIPv4, | ||
port: port, | ||
path: '/', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed, it's even the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Pre land CI:https://ci.nodejs.org/job/node-test-commit/10006/ Ping @trevnorris any comments? I would like to land this in a few hours. |
Landed in 6bfdeed |
Post land CI: https://ci.nodejs.org/job/node-test-commit/10031/ |
@refack Thanks for taking care of this. |
Thank you @refack. 🎉 |
This should likely be included in a larger async_wrap backport if it were to happen |
When using an Agent for HTTPS,
TLSSocket
s are reused and need tohave the ability to
asyncReset
from JS.Fixes: #13045
(Not a complete solution. Does not solve custom Agent use case)
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
async_wrap