oracledb 6.0.2 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -17
- package/SECURITY.md +1 -1
- package/build/Release/oracledb-6.1.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-darwin-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.1.0-win32-x64.node-buildinfo.txt +1 -0
- package/examples/example.js +0 -1
- package/lib/aqQueue.js +40 -26
- package/lib/connection.js +15 -3
- package/lib/errors.js +15 -10
- package/lib/impl/connection.js +9 -0
- package/lib/impl/resultset.js +7 -4
- package/lib/oracledb.js +15 -12
- package/lib/pool.js +11 -2
- package/lib/settings.js +1 -1
- package/lib/sodaCollection.js +1 -1
- package/lib/thin/connection.js +92 -30
- package/lib/thin/dbObject.js +2 -2
- package/lib/thin/lob.js +2 -2
- package/lib/thin/pool.js +153 -71
- package/lib/thin/protocol/buffer.js +24 -6
- package/lib/thin/protocol/constants.js +8 -18
- package/lib/thin/protocol/encryptDecrypt.js +17 -17
- package/lib/thin/protocol/messages/auth.js +27 -31
- package/lib/thin/protocol/messages/base.js +30 -53
- package/lib/thin/protocol/messages/connectionCookie.js +76 -0
- package/lib/thin/protocol/messages/dataType.js +13 -9
- package/lib/thin/protocol/messages/execute.js +11 -11
- package/lib/thin/protocol/messages/index.js +2 -0
- package/lib/thin/protocol/messages/lobOp.js +3 -3
- package/lib/thin/protocol/messages/protocol.js +31 -20
- package/lib/thin/protocol/messages/withData.js +60 -53
- package/lib/thin/protocol/oson.js +4 -4
- package/lib/thin/protocol/packet.js +51 -28
- package/lib/thin/protocol/protocol.js +12 -7
- package/lib/thin/protocol/utils.js +2 -2
- package/lib/thin/resultSet.js +6 -6
- package/lib/thin/sqlnet/connStrategy.js +134 -7
- package/lib/thin/sqlnet/constants.js +2 -0
- package/lib/thin/sqlnet/ezConnectResolver.js +29 -24
- package/lib/thin/sqlnet/navNodes.js +35 -28
- package/lib/thin/sqlnet/networkSession.js +45 -40
- package/lib/thin/sqlnet/ntTcp.js +70 -35
- package/lib/thin/sqlnet/nvStrToNvPair.js +16 -16
- package/lib/thin/sqlnet/packet.js +17 -10
- package/lib/thin/sqlnet/paramParser.js +9 -9
- package/lib/thin/sqlnet/sessionAtts.js +4 -0
- package/lib/thin/statement.js +4 -3
- package/lib/thin/util.js +28 -8
- package/lib/transformer.js +3 -1
- package/lib/util.js +0 -13
- package/lib/version.js +2 -2
- package/package.json +1 -1
- package/build/Release/oracledb-6.0.2-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.0.2-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.0.2-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-linux-x64.node +0 -0
- package/build/Release/oracledb-6.0.2-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.0.2-win32-x64.node +0 -0
- package/build/Release/oracledb-6.0.2-win32-x64.node-buildinfo.txt +0 -1
|
@@ -37,7 +37,7 @@ const { Buffer } = require('buffer');
|
|
|
37
37
|
const EzConnect = require("./ezConnectResolver.js");
|
|
38
38
|
const { NLParamParser, tnsnamesFilePath } = require("./paramParser.js");
|
|
39
39
|
const process = require('process');
|
|
40
|
-
|
|
40
|
+
const downHostInstance = require("./connStrategy.js").SOLE_INST_DHCACHE;
|
|
41
41
|
/**
|
|
42
42
|
*
|
|
43
43
|
* @param {string} userConfig
|
|
@@ -45,19 +45,20 @@ const process = require('process');
|
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
47
|
async function getConnectionInfo(userConfig) {
|
|
48
|
-
|
|
48
|
+
const connStr = await resolveConnectStr(userConfig.connectString, userConfig.configDir);
|
|
49
49
|
let nvpair;
|
|
50
50
|
if (typeof connStr === 'string')
|
|
51
51
|
nvpair = createNVPair(connStr);
|
|
52
52
|
else
|
|
53
53
|
nvpair = connStr;//Already a NVPair
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
const serverVal = findValue(nvpair, ["DESCRIPTION", "CONNECT_DATA", "SERVER"]);
|
|
56
|
+
const connClass = findValue(nvpair, ["DESCRIPTION", "CONNECT_DATA", "POOL_CONNECTION_CLASS"]);
|
|
57
|
+
const svcname = findValue(nvpair, ["DESCRIPTION", "CONNECT_DATA", "SERVICE_NAME"]);
|
|
58
|
+
const sid = findValue(nvpair, ["DESCRIPTION", "CONNECT_DATA", "SID"]);
|
|
59
|
+
const poolPurity = findValue(nvpair, ["DESCRIPTION", "CONNECT_DATA", "POOL_PURITY"]);
|
|
59
60
|
|
|
60
|
-
return [serverVal, connClass, svcname, poolPurity ];
|
|
61
|
+
return [serverVal, connClass, svcname, poolPurity, sid ];
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/**
|
|
@@ -65,20 +66,20 @@ async function getConnectionInfo(userConfig) {
|
|
|
65
66
|
* @param {String} connStr Connect string
|
|
66
67
|
* @returns AddressNode
|
|
67
68
|
*/
|
|
68
|
-
|
|
69
|
+
const nlParamParser = new NLParamParser;
|
|
69
70
|
async function resolveConnectStr(connectString, configDir) {
|
|
70
|
-
|
|
71
|
+
const connStr = connectString.trim();
|
|
71
72
|
let resolvedVal = connStr;
|
|
72
73
|
if ((connStr.indexOf(')') == -1) || (connStr.indexOf('(') != 0)) {
|
|
73
74
|
try {
|
|
74
75
|
/* Try through ezconnect */
|
|
75
|
-
|
|
76
|
+
const ezcnObj = new EzConnect(connStr);
|
|
76
77
|
resolvedVal = await ezcnObj.getResolvedUrl();
|
|
77
78
|
} catch (err) {
|
|
78
79
|
try {
|
|
79
80
|
/* try tns alias */
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
const namesFilePath = tnsnamesFilePath(configDir);
|
|
82
|
+
const p = await nlParamParser.initializeNlpa(namesFilePath);
|
|
82
83
|
resolvedVal = p.get(connStr.toUpperCase());
|
|
83
84
|
if (!resolvedVal)
|
|
84
85
|
errors.throwErr(errors.ERR_TNS_ENTRY_NOT_FOUND, connStr, configDir ? configDir + '/tnsnames.ora' : process.env.TNS_ADMIN + '/tnsnames.ora');
|
|
@@ -96,7 +97,7 @@ async function resolveConnectStr(connectString, configDir) {
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
async function resolveAddress(connStr, configDir) {
|
|
99
|
-
|
|
100
|
+
const connstr = await resolveConnectStr(connStr, configDir);
|
|
100
101
|
return createNode(connstr);
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -140,23 +141,24 @@ class NetworkSession {
|
|
|
140
141
|
|
|
141
142
|
async getAddress(addressNode, userConfig) {
|
|
142
143
|
/* Get the next address */
|
|
143
|
-
|
|
144
|
+
const address = await addressNode.execute(userConfig);
|
|
144
145
|
/* Prepare connection attributes */
|
|
145
|
-
|
|
146
|
+
const uuid = this.sAtts ? this.sAtts.uuid : null;
|
|
146
147
|
this.sAtts = new SessionAtts(uuid);
|
|
147
148
|
this.sAtts.setFrom(userConfig);
|
|
148
149
|
this.sAtts.setFrom(address.desc.params); /* Resolve attributes from Connect String */
|
|
149
150
|
await this.sAtts.prepare(address.protocol);
|
|
150
151
|
|
|
151
152
|
/* Insert Connection ID */
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
const rootNVPair = createNVPair(address.CNdata.join(""));
|
|
154
|
+
const cdataNVPair = findNVPairRecurse(rootNVPair, "CONNECT_DATA");
|
|
155
|
+
const connidStr = `(CONNECTION_ID=${this.sAtts.connectionId})`;
|
|
156
|
+
const childNVPair = createNVPair(connidStr);
|
|
156
157
|
cdataNVPair.addListElement(childNVPair);
|
|
157
158
|
|
|
158
159
|
this.cData = Buffer.from(rootNVPair.toString(), 'ascii');
|
|
159
160
|
this.cDataNVPair = rootNVPair;
|
|
161
|
+
this.sAtts.nt.cDataNVPair = rootNVPair;
|
|
160
162
|
|
|
161
163
|
return (address);
|
|
162
164
|
}
|
|
@@ -165,6 +167,9 @@ class NetworkSession {
|
|
|
165
167
|
* Make the transport level connection
|
|
166
168
|
*/
|
|
167
169
|
async transportConnect(address) {
|
|
170
|
+
if (address.protocol.toUpperCase() == 'TCP' && address.httpsProxy) {
|
|
171
|
+
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_PARAMETERS, 'https proxy requires protocol as', 'tcps ');
|
|
172
|
+
}
|
|
168
173
|
if (address.protocol && (address.protocol.toUpperCase() == 'TCP' || address.protocol.toUpperCase() == 'TCPS')) {
|
|
169
174
|
this.ntAdapter = new NTTCP(this.sAtts.nt);
|
|
170
175
|
} else {
|
|
@@ -173,8 +178,8 @@ class NetworkSession {
|
|
|
173
178
|
await this.ntAdapter.connect(address);
|
|
174
179
|
this.ntAdapter.startRead();
|
|
175
180
|
this.sAtts.ntCha = this.ntAdapter.cha;
|
|
176
|
-
this.sndDatapkt = new Packet.DataPacket(this.sAtts.
|
|
177
|
-
this.rcvDatapkt = new Packet.DataPacket(this.sAtts.
|
|
181
|
+
this.sndDatapkt = new Packet.DataPacket(this.sAtts.largeSDU);
|
|
182
|
+
this.rcvDatapkt = new Packet.DataPacket(this.sAtts.largeSDU);
|
|
178
183
|
}
|
|
179
184
|
|
|
180
185
|
/**
|
|
@@ -207,7 +212,7 @@ class NetworkSession {
|
|
|
207
212
|
|
|
208
213
|
/* Transport connect */
|
|
209
214
|
if (this.sAtts.transportConnectTimeout) {
|
|
210
|
-
|
|
215
|
+
const asyncPromise = this.transportConnect(address);
|
|
211
216
|
await timeout(asyncPromise, this.sAtts.transportConnectTimeout, "transportConnectTimeout", address, this.sAtts.connectionId);
|
|
212
217
|
} else {
|
|
213
218
|
await this.transportConnect(address);
|
|
@@ -227,9 +232,9 @@ class NetworkSession {
|
|
|
227
232
|
await this._recvPacket();
|
|
228
233
|
this.refusePkt.dataBuf = this.rcvDatapkt.buf.subarray(this.rcvDatapkt.offset, this.rcvDatapkt.len).toString();
|
|
229
234
|
}
|
|
230
|
-
|
|
235
|
+
const nvpair = createNVPair(this.refusePkt.dataBuf);
|
|
231
236
|
this.refusePkt = null;
|
|
232
|
-
|
|
237
|
+
const err = findValue(nvpair, ["DESCRIPTION", "ERR"]);
|
|
233
238
|
if (err == "12514") {
|
|
234
239
|
errors.throwErr(errors.ERR_INVALID_SERVICE_NAME, this.getOption(constants.SVCNAME), address.host, address.port, this.sAtts.connectionId);
|
|
235
240
|
} else if (err == "12505") {
|
|
@@ -246,7 +251,7 @@ class NetworkSession {
|
|
|
246
251
|
}
|
|
247
252
|
this._sendConnect(connectPkt);
|
|
248
253
|
} else if (packet.type === constants.NSPTRD) { /* REDIRECT */
|
|
249
|
-
let adrLen, adrStr,
|
|
254
|
+
let adrLen, adrStr, redirConnData;
|
|
250
255
|
|
|
251
256
|
/* Read and connect to Redirect address */
|
|
252
257
|
if (this.redirectPkt.overflow) {
|
|
@@ -263,8 +268,8 @@ class NetworkSession {
|
|
|
263
268
|
redirConnData = this.cData;
|
|
264
269
|
}
|
|
265
270
|
|
|
266
|
-
redirAddressNode = await resolveAddress(adrStr);
|
|
267
|
-
|
|
271
|
+
const redirAddressNode = await resolveAddress(adrStr);
|
|
272
|
+
const host = address.hostname;
|
|
268
273
|
address = await redirAddressNode.execute();
|
|
269
274
|
if (address.desc)
|
|
270
275
|
this.sAtts.setFrom(address.desc.params); /* Add on attributes from redirect connect String */
|
|
@@ -273,24 +278,23 @@ class NetworkSession {
|
|
|
273
278
|
this.ntAdapter.disconnect(constants.NSFIMM);
|
|
274
279
|
|
|
275
280
|
if (this.sAtts.transportConnectTimeout) {
|
|
276
|
-
|
|
281
|
+
const asyncPromise = this.transportConnect(address);
|
|
277
282
|
await timeout(asyncPromise, this.sAtts.transportConnectTimeout, "transportConnectTimeout", address, this.sAtts.connectionId);
|
|
278
283
|
} else {
|
|
279
284
|
await this.transportConnect(address);
|
|
280
285
|
}
|
|
281
286
|
|
|
282
287
|
connectPkt = new Packet.ConnectPacket(redirConnData, this.sAtts, constants.NSPFRDR);
|
|
288
|
+
this.sndDatapkt = new Packet.DataPacket(this.sAtts.largeSDU);
|
|
283
289
|
this._sendConnect(connectPkt);
|
|
284
290
|
}
|
|
285
291
|
}
|
|
286
292
|
|
|
287
293
|
/* Accepted */
|
|
288
294
|
this.connected = true;
|
|
289
|
-
this.
|
|
290
|
-
this.
|
|
291
|
-
this.
|
|
292
|
-
this.sndDatapkt = new Packet.DataPacket(this.sAtts.sdu, this.sAtts.largeSDU);
|
|
293
|
-
this.sndDatapkt.createPacket();
|
|
295
|
+
this.cData = null;
|
|
296
|
+
this.sndDatapkt = new Packet.DataPacket(this.sAtts.largeSDU);
|
|
297
|
+
this.sndDatapkt.createPacket(constants.NSPDADAT); //Currently only used for disconnect
|
|
294
298
|
this.sndDatapkt.offset = this.sndDatapkt.dataPtr;
|
|
295
299
|
this.sndDatapkt.len = this.sndDatapkt.bufLen;
|
|
296
300
|
this.markerPkt = new Packet.MarkerPacket(this.sAtts.largeSDU);
|
|
@@ -309,13 +313,14 @@ class NetworkSession {
|
|
|
309
313
|
do {
|
|
310
314
|
try {
|
|
311
315
|
if (this.sAtts.connectTimeout) {
|
|
312
|
-
|
|
316
|
+
const asyncPromise = this.connect2(address);
|
|
313
317
|
connected = await timeout(asyncPromise, this.sAtts.connectTimeout, "connectTimeout", address, this.sAtts.connectionId);
|
|
314
318
|
} else {
|
|
315
319
|
connected = await this.connect2(address);
|
|
316
320
|
}
|
|
317
321
|
} catch (err) {
|
|
318
|
-
if (err.message.startsWith('NJS-510')) {
|
|
322
|
+
if (err.message.startsWith('NJS-510') && !this.ntAdapter.connected) {
|
|
323
|
+
downHostInstance.markDownHost(address.host, Date.now()); // mark the host as down
|
|
319
324
|
this.ntAdapter.connected = true; // Pretend as connected
|
|
320
325
|
}
|
|
321
326
|
if (this.ntAdapter) {
|
|
@@ -354,6 +359,8 @@ class NetworkSession {
|
|
|
354
359
|
break;
|
|
355
360
|
case constants.NSPTAC: /* ACCEPT */
|
|
356
361
|
Packet.AcceptPacket(packet, this.sAtts);
|
|
362
|
+
this.dbUUID = packet.dbUUID;
|
|
363
|
+
packet.dbUUID = null;
|
|
357
364
|
break;
|
|
358
365
|
case constants.NSPTRF: /* REFUSE */
|
|
359
366
|
this.refusePkt = new Packet.RefusePacket(packet);
|
|
@@ -466,7 +473,7 @@ class NetworkSession {
|
|
|
466
473
|
let bytesCopied = 0;
|
|
467
474
|
|
|
468
475
|
this.sndDatapkt.dataLen = this.sndDatapkt.offset;
|
|
469
|
-
if (this.sndDatapkt.dataLen < this.sndDatapkt.bufLen) {
|
|
476
|
+
if (this.sndDatapkt.dataLen < this.sndDatapkt.bufLen || !this.sndDatapkt.bufLen) {
|
|
470
477
|
bytesCopied = this.sndDatapkt.fillBuf(userBuf, offset, len);
|
|
471
478
|
len -= bytesCopied;
|
|
472
479
|
offset += bytesCopied;
|
|
@@ -508,8 +515,8 @@ class NetworkSession {
|
|
|
508
515
|
* Establish network connection
|
|
509
516
|
*/
|
|
510
517
|
async connect(userConfig) {
|
|
511
|
-
|
|
512
|
-
|
|
518
|
+
const connStr = userConfig.connectString ? userConfig.connectString : userConfig.connectionString;
|
|
519
|
+
const addressNode = await resolveAddress(connStr, userConfig.configDir);
|
|
513
520
|
let address;
|
|
514
521
|
try {
|
|
515
522
|
address = await this.getAddress(addressNode, userConfig);
|
|
@@ -591,7 +598,6 @@ class NetworkSession {
|
|
|
591
598
|
let error = 0;
|
|
592
599
|
if (this.controlPkt.errno) { /* Control pkt already read */
|
|
593
600
|
error = this.controlPkt.errno;
|
|
594
|
-
this.controlPkt.clear(); /* Clear error */
|
|
595
601
|
return (error);
|
|
596
602
|
} else if (!this.getOption(constants.HEALTHCHECK)) {
|
|
597
603
|
return errors.ERR_CONNECTION_CLOSED;
|
|
@@ -602,7 +608,6 @@ class NetworkSession {
|
|
|
602
608
|
if (packet.type == constants.NSPTCNL) {
|
|
603
609
|
this.controlPkt.fromPacket(packet);
|
|
604
610
|
error = this.controlPkt.errno;
|
|
605
|
-
this.controlPkt.clear(); /* Clear error */
|
|
606
611
|
return (error);
|
|
607
612
|
} else {
|
|
608
613
|
this.ntAdapter.packets.unshift(packet); /* Push packet back */
|
package/lib/thin/sqlnet/ntTcp.js
CHANGED
|
@@ -34,6 +34,7 @@ const http = require("http");
|
|
|
34
34
|
const Timers = require('timers');
|
|
35
35
|
const constants = require("./constants.js");
|
|
36
36
|
const errors = require("../../errors.js");
|
|
37
|
+
const { findValue } = require("./nvStrToNvPair.js");
|
|
37
38
|
|
|
38
39
|
const PACKET_HEADER_SIZE = 8;
|
|
39
40
|
const DEFAULT_PORT = 1521;
|
|
@@ -47,6 +48,8 @@ const TCPCHA = 1 << 1 | /* ASYNC support */
|
|
|
47
48
|
1 << 9 | /* Full Duplex support */
|
|
48
49
|
1 << 12; /* SIGPIPE Support */
|
|
49
50
|
|
|
51
|
+
let streamNum = 1;
|
|
52
|
+
|
|
50
53
|
/**
|
|
51
54
|
* Network Transport TCP/TCPS adapter
|
|
52
55
|
* @param {Address} address Destination Address
|
|
@@ -63,28 +66,42 @@ class NTTCP {
|
|
|
63
66
|
this.numPacketsSinceLastWait = 0;
|
|
64
67
|
this.secure = false;
|
|
65
68
|
this.largeSDU = false;
|
|
69
|
+
this.streamNum = streamNum++;
|
|
70
|
+
this.packetNum = 1;
|
|
71
|
+
this.doDNMatch = true;
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
/**
|
|
69
75
|
* DN matching funciton(used with TLS)
|
|
70
76
|
*/
|
|
71
77
|
dnMatch(serverName, cert) {
|
|
72
|
-
if (this.atts.sslServerDNMatch) {
|
|
73
|
-
|
|
78
|
+
if (this.atts.sslServerDNMatch && this.doDNMatch) {
|
|
79
|
+
const toObject = str =>str .split(',').map(x => x.split('=').map(y => y.trim())).reduce((a, x) => {
|
|
74
80
|
a[x[0]] = x[1];
|
|
75
81
|
return a;
|
|
76
82
|
}, {});
|
|
77
83
|
if (this.atts.sslServerCertDN) { /* Full DN Match */
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
const obj = toObject(this.atts.sslServerCertDN);
|
|
85
|
+
if (Object.keys(obj).length == Object.keys(cert.subject).length) {
|
|
86
|
+
for (const key in obj) {
|
|
87
|
+
if (obj[key] != cert.subject[key]) {
|
|
88
|
+
return (errors.getErr(errors.ERR_TLS_DNMATCH_FAILURE));
|
|
89
|
+
}
|
|
82
90
|
}
|
|
91
|
+
} else {
|
|
92
|
+
return (errors.getErr(errors.ERR_TLS_DNMATCH_FAILURE));
|
|
83
93
|
}
|
|
84
94
|
} else {
|
|
85
95
|
if (tls.checkServerIdentity(this.hostName, cert) && (!this.originHost || tls.checkServerIdentity(this.originHost, cert))) { /* Hostname match */
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
if (this.atts.sslAllowWeakDNMatch) {
|
|
97
|
+
const serviceName = findValue(this.atts.cDataNVPair, ["DESCRIPTION", "CONNECT_DATA", "SERVICE_NAME"]); /* Service Name match */
|
|
98
|
+
if (serviceName != cert.subject.CN) {
|
|
99
|
+
return (errors.getErr(errors.ERR_TLS_DNMATCH_FAILURE));
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
const hostName = this.hostName + " " + (this.originHost ? "or " + this.originHost : "");
|
|
103
|
+
return (errors.getErr(errors.ERR_TLS_HOSTMATCH_FAILURE, hostName));
|
|
104
|
+
}
|
|
88
105
|
}
|
|
89
106
|
}
|
|
90
107
|
}
|
|
@@ -132,7 +149,7 @@ class NTTCP {
|
|
|
132
149
|
}
|
|
133
150
|
|
|
134
151
|
let connectErrCause, proxyConnectErrCause, req;
|
|
135
|
-
|
|
152
|
+
const httpsProxy = address.httpsProxy || this.atts.httpsProxy;
|
|
136
153
|
let httpsProxyPort = address.httpsProxyPort || this.atts.httpsProxyPort;
|
|
137
154
|
|
|
138
155
|
await new Promise((resolve) => {
|
|
@@ -207,6 +224,8 @@ class NTTCP {
|
|
|
207
224
|
if (address.protocol.toUpperCase() == "TCPS") {
|
|
208
225
|
let secureContext;
|
|
209
226
|
this.secure = true;
|
|
227
|
+
if (this.atts.sslAllowWeakDNMatch)
|
|
228
|
+
this.doDNMatch = false; //Don't match initial connect
|
|
210
229
|
try {
|
|
211
230
|
secureContext = tls.createSecureContext({
|
|
212
231
|
cert : this.atts.wallet,
|
|
@@ -240,7 +259,8 @@ class NTTCP {
|
|
|
240
259
|
}
|
|
241
260
|
this.stream = null;
|
|
242
261
|
this.connected = false;
|
|
243
|
-
this.
|
|
262
|
+
this.drainWaiter = null;
|
|
263
|
+
this.readWaiter = null;
|
|
244
264
|
}
|
|
245
265
|
|
|
246
266
|
/**
|
|
@@ -254,7 +274,7 @@ class NTTCP {
|
|
|
254
274
|
const block = buffer.slice(i, i + 8);
|
|
255
275
|
const hexDumpValues = [];
|
|
256
276
|
const printableValues = [];
|
|
257
|
-
for (
|
|
277
|
+
for (const hexByte of block) {
|
|
258
278
|
hexDumpValues.push(hexByte.toString(16).toUpperCase().padStart(2, '0'));
|
|
259
279
|
if (hexByte > 0x20 && hexByte < 0x7f) {
|
|
260
280
|
printableValues.push(String.fromCharCode(hexByte));
|
|
@@ -296,7 +316,7 @@ class NTTCP {
|
|
|
296
316
|
*/
|
|
297
317
|
checkErr() {
|
|
298
318
|
if (!this.connected || this.err) {
|
|
299
|
-
let err
|
|
319
|
+
let err;
|
|
300
320
|
if (this.savedErr) {
|
|
301
321
|
err = errors.getErr(errors.ERR_CONNECTION_LOSTCONTACT,
|
|
302
322
|
this.host, this.port, this.atts.connectionId, this.savedErr.message);
|
|
@@ -304,7 +324,7 @@ class NTTCP {
|
|
|
304
324
|
err = errors.getErr(errors.ERR_CONNECTION_EOF, this.host, this.port, this.atts.connectionId,);
|
|
305
325
|
}
|
|
306
326
|
/* Wrap around NJS-500 */
|
|
307
|
-
newErr = errors.getErr(errors.ERR_CONNECTION_CLOSED);
|
|
327
|
+
const newErr = errors.getErr(errors.ERR_CONNECTION_CLOSED);
|
|
308
328
|
newErr.message = newErr.message + "\n" + err.message;
|
|
309
329
|
throw (newErr);
|
|
310
330
|
}
|
|
@@ -318,21 +338,19 @@ class NTTCP {
|
|
|
318
338
|
send(buf) {
|
|
319
339
|
this.checkErr();
|
|
320
340
|
if (process.env.NODE_ORACLEDB_DEBUG_PACKETS)
|
|
321
|
-
this.printPacket(
|
|
341
|
+
this.printPacket(`Sending packet ${this.packetNum} on stream ${this.streamNum}`, buf);
|
|
322
342
|
const result = this.stream.write(buf, (err) => {
|
|
323
343
|
if (err) {
|
|
324
344
|
this.savedErr = err;
|
|
325
345
|
this.err = true;
|
|
326
|
-
|
|
327
|
-
this.waiter();
|
|
328
|
-
this.waiter = null;
|
|
329
|
-
}
|
|
346
|
+
this._notifyWaiters();
|
|
330
347
|
}
|
|
331
348
|
});
|
|
332
349
|
if (!result) {
|
|
333
350
|
this.needsDrain = true;
|
|
334
351
|
}
|
|
335
352
|
this.numPacketsSinceLastWait++;
|
|
353
|
+
this.packetNum++;
|
|
336
354
|
}
|
|
337
355
|
|
|
338
356
|
/**
|
|
@@ -352,7 +370,9 @@ class NTTCP {
|
|
|
352
370
|
async pauseWrite() {
|
|
353
371
|
this.checkErr();
|
|
354
372
|
if (this.needsDrain) {
|
|
355
|
-
await new Promise((resolve) =>
|
|
373
|
+
await new Promise((resolve) => {
|
|
374
|
+
this.drainWaiter = resolve;
|
|
375
|
+
});
|
|
356
376
|
this.checkErr();
|
|
357
377
|
} else {
|
|
358
378
|
await new Promise((resolve) => Timers.setImmediate(resolve));
|
|
@@ -394,15 +414,16 @@ class NTTCP {
|
|
|
394
414
|
const packet = {
|
|
395
415
|
buf: tempBuf.subarray(0, len),
|
|
396
416
|
type: tempBuf[4],
|
|
397
|
-
flags: tempBuf[5]
|
|
417
|
+
flags: tempBuf[5],
|
|
418
|
+
num : this.packetNum++
|
|
398
419
|
};
|
|
399
420
|
this.packets.push(packet);
|
|
400
|
-
if (this.
|
|
401
|
-
this.
|
|
402
|
-
this.
|
|
421
|
+
if (this.readWaiter) {
|
|
422
|
+
this.readWaiter();
|
|
423
|
+
this.readWaiter = null;
|
|
403
424
|
}
|
|
404
425
|
if (process.env.NODE_ORACLEDB_DEBUG_PACKETS)
|
|
405
|
-
this.printPacket(
|
|
426
|
+
this.printPacket(`Receiving packet ${packet.num} on stream ${this.streamNum}`, packet.buf);
|
|
406
427
|
|
|
407
428
|
// if the packet consumed all of the bytes (most common scenario), then
|
|
408
429
|
// simply clear the temporary buffer; otherwise, retain whatever bytes
|
|
@@ -436,7 +457,7 @@ class NTTCP {
|
|
|
436
457
|
if (this.packets.length === 0) {
|
|
437
458
|
this.checkErr();
|
|
438
459
|
await new Promise((resolve) => {
|
|
439
|
-
this.
|
|
460
|
+
this.readWaiter = resolve;
|
|
440
461
|
this.numPacketsSinceLastWait = 0;
|
|
441
462
|
});
|
|
442
463
|
this.checkErr();
|
|
@@ -451,7 +472,8 @@ class NTTCP {
|
|
|
451
472
|
async renegTLS() {
|
|
452
473
|
try {
|
|
453
474
|
this.checkErr();
|
|
454
|
-
|
|
475
|
+
this.doDNMatch = true;
|
|
476
|
+
const secureContext = tls.createSecureContext({
|
|
455
477
|
cert : this.atts.wallet,
|
|
456
478
|
key : this.atts.wallet,
|
|
457
479
|
passphrase: this.atts.walletPassword,
|
|
@@ -472,26 +494,25 @@ class NTTCP {
|
|
|
472
494
|
this.stream.on('error', (err) => {
|
|
473
495
|
this.savedErr = err;
|
|
474
496
|
this.err = true;
|
|
475
|
-
|
|
476
|
-
this.waiter();
|
|
477
|
-
this.waiter = null;
|
|
478
|
-
}
|
|
497
|
+
this._notifyWaiters();
|
|
479
498
|
});
|
|
480
499
|
|
|
481
500
|
this.stream.on('end', () => {
|
|
482
501
|
this.err = true;
|
|
483
|
-
|
|
484
|
-
this.waiter();
|
|
485
|
-
this.waiter = null;
|
|
486
|
-
}
|
|
502
|
+
this._notifyWaiters();
|
|
487
503
|
});
|
|
488
504
|
|
|
489
505
|
this.stream.on('close', () => {
|
|
490
506
|
this.connected = false;
|
|
507
|
+
this._notifyWaiters();
|
|
491
508
|
});
|
|
492
509
|
|
|
493
510
|
this.stream.on('drain', () => {
|
|
494
511
|
this.needsDrain = false;
|
|
512
|
+
if (this.drainWaiter) {
|
|
513
|
+
this.drainWaiter();
|
|
514
|
+
this.drainWaiter = null;
|
|
515
|
+
}
|
|
495
516
|
});
|
|
496
517
|
|
|
497
518
|
}
|
|
@@ -508,7 +529,7 @@ class NTTCP {
|
|
|
508
529
|
return (this.packets.length > 0);
|
|
509
530
|
case constants.REMOTEADDR: /* Remote Address */
|
|
510
531
|
{
|
|
511
|
-
|
|
532
|
+
const socket = this.secure ? this.connStream : this.stream;
|
|
512
533
|
return (socket.remoteAddress + ":" + socket.remotePort);
|
|
513
534
|
}
|
|
514
535
|
default:
|
|
@@ -516,6 +537,20 @@ class NTTCP {
|
|
|
516
537
|
}
|
|
517
538
|
}
|
|
518
539
|
|
|
540
|
+
/**
|
|
541
|
+
* Notify the waiters (drain and read) and reset them, if applicable.
|
|
542
|
+
*/
|
|
543
|
+
_notifyWaiters() {
|
|
544
|
+
if (this.drainWaiter) {
|
|
545
|
+
this.drainWaiter();
|
|
546
|
+
this.drainWaiter = null;
|
|
547
|
+
}
|
|
548
|
+
if (this.readWaiter) {
|
|
549
|
+
this.readWaiter();
|
|
550
|
+
this.readWaiter = null;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
519
554
|
}
|
|
520
555
|
|
|
521
556
|
module.exports = NTTCP;
|
|
@@ -176,7 +176,7 @@ class NVPair {
|
|
|
176
176
|
}
|
|
177
177
|
} else if (this.listType == LIST_COMMASEP) {
|
|
178
178
|
for (let i = 0; i < this.getListSize(); i++) {
|
|
179
|
-
|
|
179
|
+
const listElem = this.getListElement(i);
|
|
180
180
|
out = out + listElem.name;
|
|
181
181
|
if (i != this.getListSize() - 1)
|
|
182
182
|
out = out + ", ";
|
|
@@ -202,7 +202,7 @@ class NVPair {
|
|
|
202
202
|
} else if (this.listType == LIST_COMMASEP) {
|
|
203
203
|
out = out + " (";
|
|
204
204
|
for (let i = 0; i < this.getListSize(); i++) {
|
|
205
|
-
|
|
205
|
+
const listElem = this.getListElement(i);
|
|
206
206
|
out = out + listElem.name;
|
|
207
207
|
|
|
208
208
|
if (i != this.getListSize() - 1)
|
|
@@ -308,7 +308,7 @@ class NVTokens {
|
|
|
308
308
|
* function to trim leading and trailing spaces from a literal.
|
|
309
309
|
*/
|
|
310
310
|
_trimWhiteSpace(it) {
|
|
311
|
-
|
|
311
|
+
const length = it.length;
|
|
312
312
|
let start = 0;
|
|
313
313
|
let end = length;
|
|
314
314
|
|
|
@@ -337,7 +337,7 @@ class NVTokens {
|
|
|
337
337
|
this.tkType = new Array();
|
|
338
338
|
this.tkValue = new Array();
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
const len = nvString.length;
|
|
341
341
|
let eql_seen = false;
|
|
342
342
|
// convert NVString to character array for easier access
|
|
343
343
|
let input = new Array();
|
|
@@ -560,7 +560,7 @@ class NVTokens {
|
|
|
560
560
|
* @param nvString the nvString to parse
|
|
561
561
|
*/
|
|
562
562
|
function createNVPair(nvString) {
|
|
563
|
-
|
|
563
|
+
const nvt = new NVTokens();
|
|
564
564
|
nvt.parseTokens(nvString);
|
|
565
565
|
return readTopLevelNVPair(nvt);
|
|
566
566
|
}
|
|
@@ -579,7 +579,7 @@ function readTopLevelNVPair(nvt) {
|
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
let name = readNVLiteral(nvt);
|
|
582
|
-
|
|
582
|
+
const nvp = new NVPair(name);
|
|
583
583
|
|
|
584
584
|
if ((tk = nvt.getToken()) == TKN_COMMA) {
|
|
585
585
|
// read comma'ed names as one name
|
|
@@ -601,14 +601,14 @@ function readTopLevelNVPair(nvt) {
|
|
|
601
601
|
*/
|
|
602
602
|
function readNVPair(nvt) {
|
|
603
603
|
// Opening ( or , for NVPair
|
|
604
|
-
|
|
604
|
+
const tk = nvt.getToken();
|
|
605
605
|
nvt.eatToken();
|
|
606
606
|
if (!((tk == TKN_LPAREN) || (tk == TKN_COMMA))) {
|
|
607
607
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
-
|
|
611
|
-
|
|
610
|
+
const name = readNVLiteral(nvt);
|
|
611
|
+
const nvp = new NVPair(name);
|
|
612
612
|
|
|
613
613
|
return readRightHandSide(nvp, nvt);
|
|
614
614
|
}
|
|
@@ -628,7 +628,7 @@ function readRightHandSide(nvp, nvt) {
|
|
|
628
628
|
// otherwise read an NVList.
|
|
629
629
|
tk = nvt.getToken();
|
|
630
630
|
if (tk == TKN_LITERAL) {
|
|
631
|
-
|
|
631
|
+
const value = readNVLiteral(nvt);
|
|
632
632
|
nvp.setAtom = value;
|
|
633
633
|
} else {
|
|
634
634
|
// NVList is responsible for adding child NVPairs to this parent
|
|
@@ -663,7 +663,7 @@ function readRightHandSide(nvp, nvt) {
|
|
|
663
663
|
* function which returns the next literal from NVTokens.
|
|
664
664
|
*/
|
|
665
665
|
function readNVLiteral(nvt) {
|
|
666
|
-
|
|
666
|
+
const tk = nvt.getToken();
|
|
667
667
|
if (tk != TKN_LITERAL) {
|
|
668
668
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
669
669
|
}
|
|
@@ -677,12 +677,12 @@ function readNVLiteral(nvt) {
|
|
|
677
677
|
function readNVList(nvt, parent) {
|
|
678
678
|
// if next token is "(" or ",", then read an NVPair
|
|
679
679
|
// otherwise, assume epsilon
|
|
680
|
-
|
|
680
|
+
const tk = nvt.getToken();
|
|
681
681
|
if (!(tk == TKN_LPAREN || tk == TKN_COMMA)) {
|
|
682
682
|
return; // didn't read an nvpair
|
|
683
683
|
}
|
|
684
684
|
|
|
685
|
-
|
|
685
|
+
const child = readNVPair(nvt);
|
|
686
686
|
|
|
687
687
|
// read a good NVPair
|
|
688
688
|
parent.addListElement(child);
|
|
@@ -715,7 +715,7 @@ function findNVPairRecurse(nvp, name) {
|
|
|
715
715
|
|
|
716
716
|
/* Loop thru the list of children and searching each child for name. */
|
|
717
717
|
for (let i = 0; i < nvp.getListSize(); i++) {
|
|
718
|
-
|
|
718
|
+
const child = findNVPairRecurse(nvp.getListElement(i), name);
|
|
719
719
|
|
|
720
720
|
/* Did we find "name"? */
|
|
721
721
|
if (child !== null)
|
|
@@ -742,7 +742,7 @@ function findNVPair(nvp, name) {
|
|
|
742
742
|
|
|
743
743
|
/* Loop thru the list of children and searching each child for name. */
|
|
744
744
|
for (let i = 0; i < nvp.getListSize(); i++) {
|
|
745
|
-
|
|
745
|
+
const child = nvp.getListElement(i);
|
|
746
746
|
if (name.toUpperCase() == (child.name).toUpperCase())
|
|
747
747
|
return child;
|
|
748
748
|
}
|
|
@@ -764,7 +764,7 @@ function findValue(nvp, names) {
|
|
|
764
764
|
return null;
|
|
765
765
|
|
|
766
766
|
let output = nvp;
|
|
767
|
-
|
|
767
|
+
const sze = names.length;
|
|
768
768
|
|
|
769
769
|
for (let i = 1; i < sze; i++) {
|
|
770
770
|
output = findNVPair(output, names[i]);
|