summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannis R <mail@jannisr.de>2021-03-03 13:54:07 +0100
committerJannis R <mail@jannisr.de>2021-03-03 13:55:18 +0100
commitec8e8c67083404440d40067e5a40351521295397 (patch)
treef7f6c603787abc61cd4f669ccb15c384fe884ce8
parentd7b005b9090b6d0a895906cba0cb1c8cc41805f7 (diff)
connect()/request(): add connectTimeout with 60s default
closes #7
-rw-r--r--client.js3
-rw-r--r--connect.js29
-rw-r--r--readme.md4
3 files changed, 36 insertions, 0 deletions
diff --git a/client.js b/client.js
index f5c034a..afe37ee 100644
--- a/client.js
+++ b/client.js
@@ -135,6 +135,7 @@ const sendGeminiRequest = (pathOrUrl, opt, done) => {
useClientCerts,
letUserConfirmClientCertUsage,
clientCertStore,
+ connectTimeout,
tlsOpt,
verifyAlpnId,
} = {
@@ -150,6 +151,7 @@ const sendGeminiRequest = (pathOrUrl, opt, done) => {
useClientCerts: false,
letUserConfirmClientCertUsage: null,
clientCertStore: defaultClientCertStore,
+ connectTimeout: 60 * 1000, // 60s
tlsOpt: {},
...opt,
}
@@ -175,6 +177,7 @@ const sendGeminiRequest = (pathOrUrl, opt, done) => {
let reqOpt = {
hostname: target.hostname || 'localhost',
port: target.port || DEFAULT_PORT,
+ connectTimeout,
tlsOpt,
}
diff --git a/connect.js b/connect.js
index 1c216a5..d508d35 100644
--- a/connect.js
+++ b/connect.js
@@ -16,11 +16,13 @@ const connectToGeminiServer = (opt, cb) => {
hostname,
port,
cert, key, passphrase,
+ connectTimeout,
tlsOpt,
} = {
hostname: '127.0.0.1',
port: DEFAULT_PORT,
cert: null, key: null, passphrase: null,
+ connectTimeout: 60 * 1000, // 60s
tlsOpt: {},
...opt,
}
@@ -34,6 +36,30 @@ const connectToGeminiServer = (opt, cb) => {
...tlsOpt,
})
+ // Sets the socket to timeout after timeout milliseconds of inactivity on
+ // the socket. By default net.Socket do not have a timeout.
+ // When an idle timeout is triggered the socket will receive a 'timeout'
+ // event but the connection will not be severed. The user must manually
+ // call socket.end() or socket.destroy() to end the connection.
+ // https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay
+ let timeoutTimer = null
+ const onTimeout = () => {
+ clearTimeout(timeoutTimer)
+ const err = new Error('connect timeout')
+ err.timeout = connectTimeout
+ err.code = 'ETIMEDOUT' // is it okay to mimic syscall errors?
+ err.errno = -60
+ socket.destroy(err)
+ }
+ socket.once('timeout', onTimeout)
+ if (connectTimeout !== null) {
+ // This sets the timeout for inactivity on the *socket* layer. But the
+ // TLS handshake might also stall. This is why we also set one manually.
+ // see also https://github.com/nodejs/node/issues/5757
+ socket.setTimeout(connectTimeout)
+ timeoutTimer = setTimeout(onTimeout, connectTimeout)
+ }
+
let cbCalled = false
socket.once('error', (err) => {
if (cbCalled) return;
@@ -42,6 +68,9 @@ const connectToGeminiServer = (opt, cb) => {
})
socket.once('secureConnect', () => {
if (cbCalled) return;
+ // If timeout is 0, then the existing idle timeout is disabled.
+ // https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay
+ socket.setTimeout(0)
cbCalled = true
cb(null, socket)
})
diff --git a/readme.md b/readme.md
index 791efe2..3b3ff89 100644
--- a/readme.md
+++ b/readme.md
@@ -135,6 +135,8 @@ request(pathOrUrl, opt = {}, cb)
useClientCerts: false,
letUserConfirmClientCertUsage: null,
clientCertStore: defaultClientCertStore,
+ // time to wait for socket connection & TLS handshake
+ connectTimeout: 60 * 1000, // 60s
// additional options to be passed into `tls.connect`
tlsOpt: {},
}
@@ -155,6 +157,8 @@ connect(opt = {}, cb)
port: 1965,
// client certificate
cert: null, key: null, passphrase: null,
+ // time to wait for socket connection & TLS handshake
+ connectTimeout: 60 * 1000, // 60s
// additional options to be passed into `tls.connect`
tlsOpt: {},
}