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
|
@@ -71,6 +71,7 @@ class Protocol {
|
|
|
71
71
|
while (true) { // eslint-disable-line
|
|
72
72
|
if (this.nsi.isBreak) {
|
|
73
73
|
await this.resetMessage();
|
|
74
|
+
delete this.readBuf.savedBuffers;
|
|
74
75
|
await this.readBuf.waitForPackets();
|
|
75
76
|
}
|
|
76
77
|
try {
|
|
@@ -78,8 +79,10 @@ class Protocol {
|
|
|
78
79
|
break;
|
|
79
80
|
} catch (err) {
|
|
80
81
|
if (err instanceof utils.OutOfPacketsError) {
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
if (!this.nsi.isBreak) {
|
|
83
|
+
await this.readBuf.waitForPackets();
|
|
84
|
+
this.readBuf.restorePoint();
|
|
85
|
+
}
|
|
83
86
|
continue;
|
|
84
87
|
}
|
|
85
88
|
throw (err);
|
|
@@ -108,7 +111,7 @@ class Protocol {
|
|
|
108
111
|
this.writeBuf.endRequest();
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
async _recoverFromError(message) {
|
|
114
|
+
async _recoverFromError(caughtErr, message) {
|
|
112
115
|
/*
|
|
113
116
|
* We have NJS error(protocol related) detected during packet write/read
|
|
114
117
|
* operation. Issue a break and reset to clear channel . We receive the
|
|
@@ -121,10 +124,12 @@ class Protocol {
|
|
|
121
124
|
await this.readBuf.waitForPackets();
|
|
122
125
|
message.decode(this.readBuf);
|
|
123
126
|
} catch (err) { // Recovery failed
|
|
124
|
-
// TODO: throw different error indicating that reset failed, probably
|
|
125
|
-
// put inside resetMessage()
|
|
126
127
|
this.nsi.disconnect();
|
|
127
|
-
errors.
|
|
128
|
+
const newErr = errors.getErr(errors.ERR_CONNECTION_CLOSED);
|
|
129
|
+
caughtErr.message = newErr.message +
|
|
130
|
+
"\nError recovery failed: " + err.message +
|
|
131
|
+
"\nOriginal error: " + caughtErr.message;
|
|
132
|
+
throw caughtErr;
|
|
128
133
|
}
|
|
129
134
|
}
|
|
130
135
|
|
|
@@ -150,7 +155,7 @@ class Protocol {
|
|
|
150
155
|
} catch (err) {
|
|
151
156
|
if (!this.connInProgress &&
|
|
152
157
|
err.code !== errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
153
|
-
await this._recoverFromError(message);
|
|
158
|
+
await this._recoverFromError(err, message);
|
|
154
159
|
}
|
|
155
160
|
throw err;
|
|
156
161
|
} finally {
|
|
@@ -43,7 +43,7 @@ function _convertBase64(result, value, size, offset) {
|
|
|
43
43
|
function encodeRowID(rowID) {
|
|
44
44
|
let offset = 0;
|
|
45
45
|
if (rowID.rba !== 0 || rowID.partitionID !== 0 || rowID.blockNum !== 0 || rowID.slotNum != 0) {
|
|
46
|
-
|
|
46
|
+
const result = Buffer.alloc(constants.TNS_MAX_ROWID_LENGTH);
|
|
47
47
|
offset = _convertBase64(result, rowID.rba, 6, offset);
|
|
48
48
|
offset = _convertBase64(result, rowID.partitionID, 3, offset);
|
|
49
49
|
offset = _convertBase64(result, rowID.blockNum, 6, offset);
|
|
@@ -59,7 +59,7 @@ function setObfuscatedValue(value) {
|
|
|
59
59
|
const bytes = Buffer.from(value, 'utf8');
|
|
60
60
|
const len = Buffer.byteLength(value);
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const arr = [];
|
|
63
63
|
for (let i = 0; i < len; i++) {
|
|
64
64
|
arr.push(buf[i] ^ bytes[i]);
|
|
65
65
|
}
|
package/lib/thin/resultSet.js
CHANGED
|
@@ -68,10 +68,10 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
68
68
|
// Returns rows fetched to the common layer in array format
|
|
69
69
|
//---------------------------------------------------------------------------
|
|
70
70
|
_processRows(numRowsFetched) {
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
const rows = [];
|
|
72
|
+
const bufferRowIndex = this.statement.bufferRowIndex;
|
|
73
73
|
for (let row = bufferRowIndex; row < bufferRowIndex + numRowsFetched; row++) {
|
|
74
|
-
|
|
74
|
+
const rowObj = [];
|
|
75
75
|
for (let col = 0; col < this.statement.numQueryVars; col++) {
|
|
76
76
|
rowObj.push(this.statement.queryVars[col].values[row]);
|
|
77
77
|
}
|
|
@@ -99,13 +99,13 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
99
99
|
} else {
|
|
100
100
|
// We fetch for the required number of row
|
|
101
101
|
options.fetchArraySize = options.fetchArraySize - (this.statement.bufferRowCount - this.statement.bufferRowIndex);
|
|
102
|
-
|
|
102
|
+
const prevBufferRowCount = this.statement.bufferRowCount;
|
|
103
103
|
if (this.statement.moreRowsToFetch && options.fetchArraySize > 0) {
|
|
104
104
|
await this._fetchMoreRows(options);
|
|
105
105
|
}
|
|
106
106
|
options.fetchArraySize = numRows || this.options.fetchArraySize;
|
|
107
107
|
if (prevBufferRowCount === this.statement.bufferRowCount) {
|
|
108
|
-
|
|
108
|
+
const numRowsFetched = this.statement.bufferRowCount - this.statement.bufferRowIndex;
|
|
109
109
|
this.statement.bufferRowCount = 0;
|
|
110
110
|
if (numRowsFetched > 0) {
|
|
111
111
|
return this._processRows(numRowsFetched);
|
|
@@ -113,7 +113,7 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
113
113
|
return [];
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
const numRowsFetched = this.statement.bufferRowCount - this.statement.bufferRowIndex;
|
|
117
117
|
return this._processRows(numRowsFetched);
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
const { NavAddress, NavAddressList, NavDescription, NavDescriptionList } = require("./navNodes.js");
|
|
30
30
|
const { createNVPair } = require("./nvStrToNvPair.js");
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const errors = require("../../errors.js");
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* Class that holds all possible attributes under Description
|
|
@@ -55,6 +54,7 @@ class ConnectDescription {
|
|
|
55
54
|
class ConnStrategy {
|
|
56
55
|
constructor() {
|
|
57
56
|
this.nextOptToTry = 0;
|
|
57
|
+
this.reorderDescriptionList = 0;
|
|
58
58
|
this.retryCount = 0;
|
|
59
59
|
this.lastRetryCounter = 0;
|
|
60
60
|
this.lastRetryConnectDescription = 0;
|
|
@@ -96,9 +96,13 @@ class ConnStrategy {
|
|
|
96
96
|
this.retryCount = config.retryCount;
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
+
if (!this.reorderDescriptionList) {
|
|
100
|
+
this.descriptionList = SOLE_INST_DHCACHE.reorderDescriptionList(this.descriptionList);
|
|
101
|
+
this.reorderDescriptionList = true;
|
|
102
|
+
}
|
|
99
103
|
/* We try the address list at least once and upto (1 + retryCount) times */
|
|
100
104
|
for (let d = this.lastRetryConnectDescription; d < this.descriptionList.length; d++) {
|
|
101
|
-
|
|
105
|
+
const desc = this.descriptionList[d];
|
|
102
106
|
let cOpts = new Array();
|
|
103
107
|
cOpts = desc.getConnectOptions();
|
|
104
108
|
let delay = desc.delayInMillis;
|
|
@@ -109,8 +113,13 @@ class ConnStrategy {
|
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
for (let i = this.lastRetryCounter; i <= this.retryCount; ++i) {
|
|
116
|
+
//Conn options must be reordered only when all options are tried
|
|
117
|
+
// i.e for retry and before the first try.
|
|
118
|
+
if (this.nextOptToTry == 0) {
|
|
119
|
+
cOpts = SOLE_INST_DHCACHE.reorderAddresses(cOpts);
|
|
120
|
+
}
|
|
112
121
|
while (this.nextOptToTry < cOpts.length) {
|
|
113
|
-
|
|
122
|
+
const copt = cOpts[this.nextOptToTry];
|
|
114
123
|
this.lastRetryCounter = i;
|
|
115
124
|
this.lastRetryConnectDescription = d;
|
|
116
125
|
this.nextOptToTry++;
|
|
@@ -151,7 +160,7 @@ async function createNode(str) {
|
|
|
151
160
|
else
|
|
152
161
|
nvpair = str; //Already a NVPair
|
|
153
162
|
|
|
154
|
-
|
|
163
|
+
const arg = nvpair.name.toUpperCase();
|
|
155
164
|
let navobj = null;
|
|
156
165
|
switch (arg) {
|
|
157
166
|
case "ADDRESS":
|
|
@@ -166,10 +175,128 @@ async function createNode(str) {
|
|
|
166
175
|
case "DESCRIPTION_LIST":
|
|
167
176
|
navobj = new NavDescriptionList();
|
|
168
177
|
break;
|
|
178
|
+
default:
|
|
179
|
+
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_PARAMETERS,
|
|
180
|
+
`unknown top element ${arg}`);
|
|
169
181
|
}
|
|
170
182
|
navobj.initFromNVPair(nvpair);
|
|
171
|
-
|
|
183
|
+
const cs = new ConnStrategy();
|
|
172
184
|
await navobj.navigate(cs);
|
|
173
185
|
return cs;
|
|
174
186
|
}
|
|
175
|
-
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class DownHostsCache {
|
|
190
|
+
|
|
191
|
+
constructor() {
|
|
192
|
+
// Timeout for each item in the cache
|
|
193
|
+
this.DOWN_HOSTS_TIMEOUT = 600;
|
|
194
|
+
// Minimum amount of time between each refresh
|
|
195
|
+
this.MIN_TIME_BETWEEN_REFRESH = 60;
|
|
196
|
+
// DownHostsCache Map
|
|
197
|
+
this.downHostsCacheMap = new Map();
|
|
198
|
+
// Last Refresh Time
|
|
199
|
+
this.lastRefreshTime = 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Add an address to the cache
|
|
204
|
+
*
|
|
205
|
+
* @param connOption
|
|
206
|
+
* address to be cached
|
|
207
|
+
* @return Map with address as key and time of insertion as value
|
|
208
|
+
*/
|
|
209
|
+
markDownHost(addr) {
|
|
210
|
+
return this.downHostsCacheMap.set(addr, Date.now());
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Remove elements older than DownHostsTimeout
|
|
214
|
+
refreshCache() {
|
|
215
|
+
if (Date.now() - this.MIN_TIME_BETWEEN_REFRESH * 1000 > this.lastRefreshTime) {
|
|
216
|
+
this.downHostsCacheMap.forEach((value, key) => {
|
|
217
|
+
const entryTime = value;
|
|
218
|
+
if (entryTime != null && ((Date.now() - this.DOWN_HOSTS_TIMEOUT * 1000) > entryTime)) {
|
|
219
|
+
this.downHostsCacheMap.delete(key);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
this.lastRefreshTime = Date.now();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Reorder addresses such that cached elements
|
|
228
|
+
* occur at the end of the array.
|
|
229
|
+
*/
|
|
230
|
+
reorderAddresses(cOpts) {
|
|
231
|
+
this.refreshCache();
|
|
232
|
+
|
|
233
|
+
let topIdx = 0, btmIdx = cOpts.length - 1;
|
|
234
|
+
|
|
235
|
+
while (topIdx < btmIdx) {
|
|
236
|
+
|
|
237
|
+
// increment topIdx if the address is not cached
|
|
238
|
+
while (topIdx <= btmIdx
|
|
239
|
+
&& !this.isDownHostsCached(cOpts[topIdx]))
|
|
240
|
+
topIdx++;
|
|
241
|
+
|
|
242
|
+
// decrement btmIdx if address is cached
|
|
243
|
+
while (btmIdx >= topIdx
|
|
244
|
+
&& this.isDownHostsCached(cOpts[btmIdx]))
|
|
245
|
+
btmIdx--;
|
|
246
|
+
|
|
247
|
+
// swap cached with uncached
|
|
248
|
+
if (topIdx < btmIdx)
|
|
249
|
+
[cOpts[topIdx], cOpts[btmIdx]] = [cOpts[btmIdx], cOpts[topIdx]];
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
return cOpts;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Return if a desc is cached.
|
|
256
|
+
* A desc is cached if all the connection options(addresses)
|
|
257
|
+
* in that description are cached.
|
|
258
|
+
*/
|
|
259
|
+
isDownDescCached(desc) {
|
|
260
|
+
const cOpts = desc.getConnectOptions();
|
|
261
|
+
for (let i = 0; i < cOpts.length; i++) {
|
|
262
|
+
if (!this.isDownHostsCached(cOpts[i]))
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Reorder description list such that description with all connection options in downcache
|
|
269
|
+
* is pushed to the end of the description list
|
|
270
|
+
*/
|
|
271
|
+
reorderDescriptionList(descs) {
|
|
272
|
+
this.refreshCache();
|
|
273
|
+
|
|
274
|
+
let topIdx = 0, btmIdx = descs.length - 1;
|
|
275
|
+
|
|
276
|
+
while (topIdx < btmIdx) {
|
|
277
|
+
|
|
278
|
+
// increment topIdx if the desc is not cached
|
|
279
|
+
while (topIdx <= btmIdx
|
|
280
|
+
&& !this.isDownDescCached(descs[topIdx]))
|
|
281
|
+
topIdx++;
|
|
282
|
+
|
|
283
|
+
// decrement btmIdx if desc is cached
|
|
284
|
+
while (btmIdx >= topIdx
|
|
285
|
+
&& this.isDownDescCached(descs[btmIdx]))
|
|
286
|
+
btmIdx--;
|
|
287
|
+
|
|
288
|
+
// swap cached with uncached
|
|
289
|
+
if (topIdx < btmIdx) {
|
|
290
|
+
[descs[topIdx], descs[btmIdx]] = [descs[btmIdx], descs[topIdx]];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return descs;
|
|
294
|
+
}
|
|
295
|
+
// Return if a host is cached
|
|
296
|
+
isDownHostsCached(copt) {
|
|
297
|
+
return this.downHostsCacheMap.has(copt.host);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Single instance
|
|
301
|
+
const SOLE_INST_DHCACHE = new DownHostsCache();
|
|
302
|
+
module.exports = { createNode, SOLE_INST_DHCACHE };
|
|
@@ -107,6 +107,8 @@ module.exports = {
|
|
|
107
107
|
NSGRAW : 0x1000, // I/O is direct to/from transport
|
|
108
108
|
TNS_VERSION_DESIRED : 319,
|
|
109
109
|
TNS_VERSION_MINIMUM : 300,
|
|
110
|
+
TNS_VERSION_MIN_UUID : 319,
|
|
111
|
+
TNS_UUID_OFFSET : 45,
|
|
110
112
|
|
|
111
113
|
/* Accept Packet */
|
|
112
114
|
NSPACVSN : 8, // connection version
|
|
@@ -39,8 +39,7 @@ Test Case in oracle_private/ezconnectTest.js
|
|
|
39
39
|
const HOSTNAMES_PATTERN = new RegExp("((?=(?<hostnames>(((\\[[A-z0-9:]+\\])|([A-z0-9][A-z0-9._-]+))[,]?)+)))\\k<hostnames>(:(?<port>\\d+)?)?", 'g');
|
|
40
40
|
|
|
41
41
|
// The EZConnect pattern without the extended settings part.
|
|
42
|
-
const EZ_URL_PATTERN = new RegExp("^((?<protocol>
|
|
43
|
-
+ "(//)?"
|
|
42
|
+
const EZ_URL_PATTERN = new RegExp("^(((?<protocol>[A-z0-9]+):)?//)?"
|
|
44
43
|
+ "(?<hostinfo>(" + HOSTNAMES_PATTERN.source + "(?=([,]|[;]|[/]|[:]|$))([,]|[;])?)+)"
|
|
45
44
|
+ "(/(?<servicename>[A-z0-9][A-z0-9,-.]+)?)"
|
|
46
45
|
+ "?(:(?<servermode>dedicated|shared|pooled))"
|
|
@@ -72,7 +71,7 @@ const DESCRIPTION_PARAMS = ["ENABLE", "FAILOVER", "LOAD_BALANCE",
|
|
|
72
71
|
class EZConnectResolver {
|
|
73
72
|
constructor(url) {
|
|
74
73
|
this.URL_PROPS_ALIAS = this.initializeUrlAlias();
|
|
75
|
-
|
|
74
|
+
const jdbcUrlPrefix = url.indexOf('@');
|
|
76
75
|
if (jdbcUrlPrefix != -1) {
|
|
77
76
|
this.url = url.substring(jdbcUrlPrefix + 1);
|
|
78
77
|
this.urlPrefix = url.substring(0, jdbcUrlPrefix + 1);
|
|
@@ -126,7 +125,7 @@ class EZConnectResolver {
|
|
|
126
125
|
// URL is in the following format
|
|
127
126
|
// [protocol://]host1[,host13][:port1][,host2:port2][/service_name][:server][/instance_name]
|
|
128
127
|
|
|
129
|
-
|
|
128
|
+
const urlWithoutWhiteSpaces = url.replace(/\s/g, "");
|
|
130
129
|
let bool = 0;
|
|
131
130
|
let protocol = null, hostInfo = null, serviceName = null, serverMode = null, instanceName = null;
|
|
132
131
|
for (const match of urlWithoutWhiteSpaces.matchAll(EZ_URL_PATTERN)) {
|
|
@@ -145,15 +144,16 @@ class EZConnectResolver {
|
|
|
145
144
|
if (protocol == null) {
|
|
146
145
|
if (!(url.includes("//")))
|
|
147
146
|
protocol = 'TCP';
|
|
147
|
+
} else if (protocol.toLowerCase() != 'tcp' && protocol.toLowerCase() != 'tcps') {
|
|
148
|
+
errors.throwErr(errors.ERR_INVALID_EZCONNECT_SYNTAX, 'Unsupported protocol in thin mode', protocol);
|
|
148
149
|
}
|
|
149
|
-
|
|
150
150
|
// Try to get the proxy information from URL properties
|
|
151
151
|
const proxyHost = this.urlProps.get("HTTPS_PROXY");
|
|
152
152
|
const proxyPort = this.urlProps.get("HTTPS_PROXY_PORT");
|
|
153
153
|
const addressInfo =
|
|
154
154
|
await this.buildAddressList(hostInfo, protocol, proxyHost, proxyPort);
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
const connectionIdPrefix =
|
|
157
157
|
this.urlProps.get("CONNECTION_ID_PREFIX");
|
|
158
158
|
// Build the available information in TNS format.
|
|
159
159
|
const parts = [];
|
|
@@ -214,26 +214,30 @@ class EZConnectResolver {
|
|
|
214
214
|
proxyHost, proxyPort) {
|
|
215
215
|
let shost = '';
|
|
216
216
|
let ipcnt = 0;
|
|
217
|
-
|
|
217
|
+
const builder = new Array();
|
|
218
218
|
let proxyInfo = '';
|
|
219
|
-
if (proxyHost != null
|
|
220
|
-
|
|
219
|
+
if (proxyHost != null) {
|
|
220
|
+
if (proxyPort != null) {
|
|
221
|
+
proxyInfo = `(HTTPS_PROXY=${proxyHost})(HTTPS_PROXY_PORT=${proxyPort})`;
|
|
222
|
+
} else {
|
|
223
|
+
proxyInfo = `(HTTPS_PROXY=${proxyHost})`;
|
|
224
|
+
}
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
if (protocol == null) protocol = 'TCP';
|
|
224
228
|
let naddr = 0;
|
|
225
229
|
// ; groups the user into a ADDRESS_LIST
|
|
226
|
-
|
|
227
|
-
for (
|
|
230
|
+
const addressLists = hostInfo.split(";");
|
|
231
|
+
for (const addressList in addressLists) {
|
|
228
232
|
let addressNodeCount = 0;
|
|
229
|
-
|
|
233
|
+
const addressListBuilder = new Array();
|
|
230
234
|
for (const match of addressLists[addressList].matchAll(HOSTNAMES_PATTERN)) {
|
|
231
|
-
|
|
235
|
+
const hostnames = (match.groups.hostnames).split(',');
|
|
232
236
|
let port = match.groups.port;
|
|
233
237
|
if (port == null) {
|
|
234
238
|
port = '1521' + '';
|
|
235
239
|
}
|
|
236
|
-
for (
|
|
240
|
+
for (const hname in hostnames) {
|
|
237
241
|
addressListBuilder.push(this.getAddrStr(hostnames[hname], port, protocol, proxyInfo));
|
|
238
242
|
shost = hostnames[hname];
|
|
239
243
|
addressNodeCount++;
|
|
@@ -296,7 +300,7 @@ class EZConnectResolver {
|
|
|
296
300
|
buildDescriptionParams() {
|
|
297
301
|
if (this.urlProps.size === 0)
|
|
298
302
|
return '';
|
|
299
|
-
|
|
303
|
+
const builder = new Array();
|
|
300
304
|
this.urlProps.forEach(function(v, k) {
|
|
301
305
|
if (DESCRIPTION_PARAMS.includes(k)) // Add only if it is a DESCRIPTION node parameter
|
|
302
306
|
builder.push(`(${k}=${v})`);
|
|
@@ -314,10 +318,11 @@ class EZConnectResolver {
|
|
|
314
318
|
if (protocol != null && protocol.toLowerCase() == "tcps") {
|
|
315
319
|
// In EZConnect format if the DN match is not specified the enable it
|
|
316
320
|
// by default for TCPS protocol.
|
|
317
|
-
const serverDNMatch = this.urlProps.get("SSL_SERVER_DN_MATCH")
|
|
321
|
+
const serverDNMatch = this.urlProps.get("SSL_SERVER_DN_MATCH");
|
|
318
322
|
const serverCertDN = this.urlProps.get("SSL_SERVER_CERT_DN");
|
|
319
323
|
const walletDir = this.urlProps.get("MY_WALLET_DIRECTORY");
|
|
320
|
-
|
|
324
|
+
if (serverDNMatch != null)
|
|
325
|
+
securityInfo.push(`(SSL_SERVER_DN_MATCH=${serverDNMatch})`);
|
|
321
326
|
if (serverCertDN != null)
|
|
322
327
|
securityInfo.push(`(SSL_SERVER_CERT_DN=${serverCertDN}})`);
|
|
323
328
|
if (walletDir != null)
|
|
@@ -338,8 +343,8 @@ class EZConnectResolver {
|
|
|
338
343
|
* @return the parsed URL which does not contain the extended settings part.
|
|
339
344
|
*/
|
|
340
345
|
parseExtendedSettings(urlStr) {
|
|
341
|
-
|
|
342
|
-
|
|
346
|
+
const urlBytes = Array.from(urlStr.trim());
|
|
347
|
+
const extendedSettingsIndex = this.findExtendedSettingPosition(urlBytes);
|
|
343
348
|
|
|
344
349
|
if (extendedSettingsIndex == -1) {
|
|
345
350
|
return urlStr; // No extended settings configuration found
|
|
@@ -356,7 +361,7 @@ class EZConnectResolver {
|
|
|
356
361
|
parseExtendedProperties(urlChars, extIndex) {
|
|
357
362
|
let key = null;
|
|
358
363
|
let value = null;
|
|
359
|
-
|
|
364
|
+
const token = new Array(urlChars.length);
|
|
360
365
|
let tokenIndx = 0;
|
|
361
366
|
let indices = '';
|
|
362
367
|
for (let i = extIndex; i < urlChars.length; i++) {
|
|
@@ -417,7 +422,7 @@ class EZConnectResolver {
|
|
|
417
422
|
parseQuotedString(startIndex, urlChars, tokenIndex, token) {
|
|
418
423
|
let i = startIndex + 1; // look for closing '"' from the next index
|
|
419
424
|
while (i < urlChars.length) {
|
|
420
|
-
|
|
425
|
+
const curChar = urlChars[i];
|
|
421
426
|
if (curChar == EXT_DOUBLE_QT) {
|
|
422
427
|
// Got the " which ends the quoted block, so break the loop
|
|
423
428
|
// Return the new indices, caller would resume from this new indices.
|
|
@@ -435,8 +440,8 @@ class EZConnectResolver {
|
|
|
435
440
|
* @param value
|
|
436
441
|
*/
|
|
437
442
|
addParam(key, value) {
|
|
438
|
-
|
|
439
|
-
|
|
443
|
+
const aliasKeyName = key.toLowerCase();
|
|
444
|
+
const propertyName = this.URL_PROPS_ALIAS.get(aliasKeyName);
|
|
440
445
|
if (propertyName != null) {
|
|
441
446
|
// if it is an URL alias then add to URL props
|
|
442
447
|
this.urlProps.set(propertyName, value);
|
|
@@ -461,7 +466,7 @@ class EZConnectResolver {
|
|
|
461
466
|
* @return url alias map
|
|
462
467
|
*/
|
|
463
468
|
initializeUrlAlias() {
|
|
464
|
-
|
|
469
|
+
const aliasMap = new Map();
|
|
465
470
|
aliasMap.set("enable", "ENABLE");
|
|
466
471
|
aliasMap.set("failover", "FAILOVER");
|
|
467
472
|
aliasMap.set("load_balance", "LOAD_BALANCE");
|
|
@@ -32,6 +32,7 @@ const os = require("os");
|
|
|
32
32
|
const net = require('net');
|
|
33
33
|
const dns = require('dns');
|
|
34
34
|
const dnsPromises = dns.promises;
|
|
35
|
+
const cInfo = require("../util.js").CLIENT_INFO;
|
|
35
36
|
|
|
36
37
|
const SchemaObjectFactoryInterface = {
|
|
37
38
|
ADDR:0,
|
|
@@ -57,7 +58,7 @@ class Address {
|
|
|
57
58
|
* (ie, "(ADDRESS=(DESCRIPTION=...)) and ")
|
|
58
59
|
*/
|
|
59
60
|
initFromString(s) {
|
|
60
|
-
|
|
61
|
+
const nvp = createNVPair(s);
|
|
61
62
|
this.initFromNVPair(nvp);
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -69,11 +70,11 @@ class Address {
|
|
|
69
70
|
initFromNVPair(nvp) {
|
|
70
71
|
if (nvp == null || !(nvp.name.toUpperCase() == "ADDRESS"))
|
|
71
72
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
const protnvp = findNVPairRecurse(nvp, 'protocol');
|
|
74
|
+
const portnvp = findNVPairRecurse(nvp, 'port');
|
|
75
|
+
const hostnvp = findNVPairRecurse(nvp, 'host');
|
|
76
|
+
const httpsProxyNVP = findNVPairRecurse(nvp, 'https_proxy');
|
|
77
|
+
const httpsProxyPortNVP = findNVPairRecurse(nvp, 'https_proxy_port');
|
|
77
78
|
|
|
78
79
|
if (portnvp)
|
|
79
80
|
this.port = portnvp.atom;
|
|
@@ -120,7 +121,7 @@ class AddressList {
|
|
|
120
121
|
* (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
121
122
|
*/
|
|
122
123
|
initFromString(s) {
|
|
123
|
-
|
|
124
|
+
const nvp = createNVPair(s);
|
|
124
125
|
this.initFromNVPair(nvp);
|
|
125
126
|
}
|
|
126
127
|
|
|
@@ -133,7 +134,7 @@ class AddressList {
|
|
|
133
134
|
/* for each child of "ADDRESS_LIST", create child or set SR/LB/FO */
|
|
134
135
|
this.children = [];
|
|
135
136
|
let childnv, child;
|
|
136
|
-
|
|
137
|
+
const listsize = nvp.getListSize();
|
|
137
138
|
if (listsize == 0) /* atom can not be valid */
|
|
138
139
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
139
140
|
|
|
@@ -215,7 +216,7 @@ class Description {
|
|
|
215
216
|
* Error thrown if invalid syntax (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
216
217
|
*/
|
|
217
218
|
initFromString(s) {
|
|
218
|
-
|
|
219
|
+
const nvp = createNVPair(s);
|
|
219
220
|
this.initFromNVPair(nvp);
|
|
220
221
|
}
|
|
221
222
|
|
|
@@ -226,7 +227,7 @@ class Description {
|
|
|
226
227
|
*/
|
|
227
228
|
//errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
228
229
|
initFromNVPair(nvp) {
|
|
229
|
-
|
|
230
|
+
const listsize = nvp.getListSize();
|
|
230
231
|
let childnv, child;
|
|
231
232
|
if (listsize == 0) // atom can not be valid
|
|
232
233
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
@@ -255,7 +256,7 @@ class Description {
|
|
|
255
256
|
this.children.push(child);
|
|
256
257
|
} else if (childnv.name.toUpperCase() == "CONNECT_DATA") {
|
|
257
258
|
let tmpnv;
|
|
258
|
-
|
|
259
|
+
const listsize = childnv.getListSize();
|
|
259
260
|
for (let i = 0; i < listsize; i++) {
|
|
260
261
|
tmpnv = childnv.getListElement(i);
|
|
261
262
|
if (tmpnv.name.toUpperCase() == "CONNECTION_ID_PREFIX") {
|
|
@@ -293,7 +294,7 @@ class Description {
|
|
|
293
294
|
if (childnv.atom > 0)
|
|
294
295
|
this.params.expireTime = childnv.atom;
|
|
295
296
|
} else if (childnv.name.toUpperCase() == "SECURITY") {
|
|
296
|
-
|
|
297
|
+
const listsize = childnv.getListSize();
|
|
297
298
|
let tmpnv;
|
|
298
299
|
for (let i = 0; i < listsize; i++) {
|
|
299
300
|
tmpnv = childnv.getListElement(i);
|
|
@@ -303,6 +304,10 @@ class Description {
|
|
|
303
304
|
this.params.sslServerDNMatch = (tmpnv.atom.toLowerCase() == "yes"
|
|
304
305
|
|| tmpnv.atom.toLowerCase() == "on"
|
|
305
306
|
|| tmpnv.atom.toLowerCase() == "true");
|
|
307
|
+
} else if (tmpnv.name.toUpperCase() == "SSL_ALLOW_WEAK_DN_MATCH") {
|
|
308
|
+
this.params.sslAllowWeakDNMatch = (tmpnv.atom.toLowerCase() == "yes"
|
|
309
|
+
|| tmpnv.atom.toLowerCase() == "on"
|
|
310
|
+
|| tmpnv.atom.toLowerCase() == "true");
|
|
306
311
|
} else if ((tmpnv.name.toUpperCase() == "WALLET_LOCATION") || (tmpnv.name.toUpperCase() == "MY_WALLET_DIRECTORY")) {
|
|
307
312
|
this.params.walletLocation = tmpnv.atom;
|
|
308
313
|
}
|
|
@@ -359,7 +364,7 @@ class DescriptionList {
|
|
|
359
364
|
* (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
360
365
|
*/
|
|
361
366
|
initFromString(s) {
|
|
362
|
-
|
|
367
|
+
const nvp = createNVPair(s);
|
|
363
368
|
this.initFromNVPair(nvp);
|
|
364
369
|
}
|
|
365
370
|
|
|
@@ -369,7 +374,7 @@ class DescriptionList {
|
|
|
369
374
|
* (ie, "(ADDRESS=(DESCRIPTION=...))")
|
|
370
375
|
*/
|
|
371
376
|
initFromNVPair(nvp) {
|
|
372
|
-
|
|
377
|
+
const listsize = nvp.getListSize();
|
|
373
378
|
let child, childnv;
|
|
374
379
|
if (listsize == 0) /* atom can not be valid */
|
|
375
380
|
errors.throwErr(errors.ERR_INVALID_CONNECT_STRING_SYNTAX);
|
|
@@ -443,7 +448,6 @@ const NavSchemaObject = {
|
|
|
443
448
|
LB: "(LOAD_BALANCE=yes)",
|
|
444
449
|
NFO: "(FAILOVER=false)",
|
|
445
450
|
CD: "(CONNECT_DATA=",
|
|
446
|
-
CID: `(CID=(PROGRAM=nodejs)(HOST=${os.hostname()})(USER=${os.userInfo().username}))`,
|
|
447
451
|
CONID: "(CONNECTION_ID="
|
|
448
452
|
};
|
|
449
453
|
const options = {
|
|
@@ -482,8 +486,8 @@ class NavAddress extends Address {
|
|
|
482
486
|
if (!net.isIP(this.host)) {
|
|
483
487
|
try {
|
|
484
488
|
addresses = await dnsPromises.lookup(this.host, options);
|
|
485
|
-
for (
|
|
486
|
-
|
|
489
|
+
for (const addr in addresses) {
|
|
490
|
+
const co = new ConnOption();
|
|
487
491
|
co.hostname = this.host;
|
|
488
492
|
co.port = this.port;
|
|
489
493
|
co.protocol = this.prot;
|
|
@@ -503,7 +507,7 @@ class NavAddress extends Address {
|
|
|
503
507
|
// do nothing
|
|
504
508
|
}
|
|
505
509
|
} else {
|
|
506
|
-
|
|
510
|
+
const co = new ConnOption();
|
|
507
511
|
co.hostname = this.host;
|
|
508
512
|
co.port = this.port;
|
|
509
513
|
co.protocol = this.prot;
|
|
@@ -530,7 +534,7 @@ class NavAddress extends Address {
|
|
|
530
534
|
* Address. Constructing a string is mainly needed when source route is ON.
|
|
531
535
|
*/
|
|
532
536
|
addToString(cs) {
|
|
533
|
-
|
|
537
|
+
const NVString = this.toString();
|
|
534
538
|
let cOpts = new Array();
|
|
535
539
|
cOpts = cs.getcurrentDescription().getConnectOptions();
|
|
536
540
|
for (let i = 0;i < cOpts.length; i++) {
|
|
@@ -589,7 +593,7 @@ class NavAddressList extends AddressList {
|
|
|
589
593
|
|
|
590
594
|
}
|
|
591
595
|
addToString(cs) {
|
|
592
|
-
|
|
596
|
+
const NVString = this.toString();
|
|
593
597
|
let cOpts = new Array();
|
|
594
598
|
cOpts = cs.getcurrentDescription().getConnectOptions();
|
|
595
599
|
for (let i = 0;i < cOpts.length; i++) {
|
|
@@ -631,7 +635,7 @@ class NavAddressList extends AddressList {
|
|
|
631
635
|
|
|
632
636
|
closeNVPair(cs) {
|
|
633
637
|
let cOpts = new Array();
|
|
634
|
-
|
|
638
|
+
const childS = this.getChildrenSize();
|
|
635
639
|
if (cs.getcurrentDescription() != null) {
|
|
636
640
|
cOpts = cs.getcurrentDescription().getConnectOptions();
|
|
637
641
|
let numChildren = 0;
|
|
@@ -682,7 +686,7 @@ class NavDescription extends Description {
|
|
|
682
686
|
async navigate(cs) {
|
|
683
687
|
cs.sBuf.length = 0; //reset
|
|
684
688
|
cs.sBuf.push("(DESCRIPTION=");
|
|
685
|
-
|
|
689
|
+
const desc = cs.newConnectionDescription(); //connectiondescription
|
|
686
690
|
if (this.retryCount != null) {
|
|
687
691
|
cs.retryCount = this.getIntValue(this.retryCount, cs.retryCount);
|
|
688
692
|
desc.retryCount = cs.retryCount;
|
|
@@ -711,7 +715,7 @@ class NavDescription extends Description {
|
|
|
711
715
|
if ('enable' in this.params) {
|
|
712
716
|
cs.sBuf.push("(ENABLE=" + this.params.enable + ")");
|
|
713
717
|
}
|
|
714
|
-
if (('sslServerCertDN' in this.params) || ('sslServerDNMatch' in this.params) || ('walletLocation' in this.params)) {
|
|
718
|
+
if (('sslServerCertDN' in this.params) || ('sslServerDNMatch' in this.params) || ('walletLocation' in this.params) || ('sslAllowWeakDNMatch' in this.params)) {
|
|
715
719
|
cs.sBuf.push("(SECURITY=");
|
|
716
720
|
if ('sslServerCertDN' in this.params) {
|
|
717
721
|
cs.sBuf.push("(SSL_SERVER_CERT_DN=" + this.params.sslServerCertDN + ")");
|
|
@@ -719,6 +723,9 @@ class NavDescription extends Description {
|
|
|
719
723
|
if ('sslServerDNMatch' in this.params) {
|
|
720
724
|
cs.sBuf.push("(SSL_SERVER_DN_MATCH=" + this.params.sslServerDNMatch + ")");
|
|
721
725
|
}
|
|
726
|
+
if ('sslAllowWeakDNMatch' in this.params) {
|
|
727
|
+
cs.sBuf.push("(SSL_ALLOW_WEAK_DN_MATCH=" + this.params.sslAllowWeakDNMatch + ")");
|
|
728
|
+
}
|
|
722
729
|
if ('walletLocation' in this.params) {
|
|
723
730
|
cs.sBuf.push("(WALLET_LOCATION=" + this.params.walletLocation + ")");
|
|
724
731
|
}
|
|
@@ -770,10 +777,10 @@ class NavDescription extends Description {
|
|
|
770
777
|
if (this.connectData == null) {
|
|
771
778
|
this.connectData = "(SERVICE_NAME=)";
|
|
772
779
|
}
|
|
773
|
-
|
|
780
|
+
const cid = `(CID=(PROGRAM=${cInfo.program})(HOST=${cInfo.hostName})(USER=${cInfo.userName}))`;
|
|
774
781
|
cOpts[i].CNdata.push(NavSchemaObject.CD);
|
|
775
782
|
cOpts[i].CNdata.push(this.connectData);
|
|
776
|
-
cOpts[i].CNdata.push(
|
|
783
|
+
cOpts[i].CNdata.push(cid);
|
|
777
784
|
cOpts[i].CNdata.push(")");
|
|
778
785
|
|
|
779
786
|
if (this.SID != null) {
|
|
@@ -834,10 +841,10 @@ class NavDescriptionList extends DescriptionList {
|
|
|
834
841
|
*/
|
|
835
842
|
static setActiveChildren(children, failover, loadBalance) {
|
|
836
843
|
let randNumber;
|
|
837
|
-
|
|
844
|
+
const listSize = children.length;
|
|
838
845
|
let tmpChildren = new Array();
|
|
839
|
-
|
|
840
|
-
|
|
846
|
+
const rand = Math.floor(Math.random() * 10);
|
|
847
|
+
const arr = new Array(listSize).fill(false);
|
|
841
848
|
|
|
842
849
|
if (failover) {
|
|
843
850
|
if (loadBalance) {
|