oracledb 6.9.0 → 7.0.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/LICENSE.txt +1 -1
- package/NOTICE.txt +1 -1
- package/README.md +9 -9
- package/build/Release/oracledb-7.0.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-7.0.0-darwin-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-js-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-7.0.0-linux-arm64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-linux-x64.node +0 -0
- package/build/Release/oracledb-7.0.0-linux-x64.node-buildinfo.txt +1 -0
- package/build/Release/oracledb-7.0.0-win32-x64.node +0 -0
- package/build/Release/oracledb-7.0.0-win32-x64.node-buildinfo.txt +1 -0
- package/eslint.config.js +39 -0
- package/lib/aqDeqOptions.js +18 -1
- package/lib/aqQueue.js +10 -6
- package/lib/connection.js +418 -39
- package/lib/dbObject.js +25 -4
- package/lib/endUserSecurityContext.js +176 -0
- package/lib/errors.js +99 -8
- package/lib/impl/aqDeqOptions.js +10 -1
- package/lib/impl/connection.js +76 -2
- package/lib/impl/datahandlers/buffer.js +68 -5
- package/lib/impl/datahandlers/oson.js +7 -2
- package/lib/impl/datahandlers/vector.js +25 -5
- package/lib/impl/lob.js +9 -0
- package/lib/impl/parserHelpers.js +443 -0
- package/lib/impl/resultset.js +1 -1
- package/lib/impl/sodaDocument.js +5 -14
- package/lib/lob.js +27 -14
- package/lib/obfuscation.js +97 -0
- package/lib/oracledb.js +163 -49
- package/lib/parser.js +204 -0
- package/lib/pipeline.js +113 -0
- package/lib/pool.js +203 -147
- package/lib/poolStatistics.js +1 -1
- package/lib/resultset.js +42 -21
- package/lib/settings.js +1 -0
- package/lib/sodaCollection.js +12 -8
- package/lib/sodaDatabase.js +35 -8
- package/lib/sodaDocument.js +24 -6
- package/lib/sodaOperation.js +7 -6
- package/lib/thin/aq.js +475 -0
- package/lib/thin/connection.js +518 -54
- package/lib/thin/dbObject.js +7 -1
- package/lib/thin/lob.js +20 -1
- package/lib/thin/pool.js +42 -62
- package/lib/thin/protocol/capabilities.js +21 -4
- package/lib/thin/protocol/constants.js +143 -2
- package/lib/thin/protocol/encryptDecrypt.js +45 -10
- package/lib/thin/protocol/messages/aqArray.js +238 -0
- package/lib/thin/protocol/messages/aqBase.js +305 -0
- package/lib/thin/protocol/messages/aqDeq.js +164 -0
- package/lib/thin/protocol/messages/aqEnq.js +135 -0
- package/lib/thin/protocol/messages/auth.js +18 -28
- package/lib/thin/protocol/messages/base.js +245 -4
- package/lib/thin/protocol/messages/dataType.js +8 -3
- package/lib/thin/protocol/messages/directPathLoadStream.js +377 -0
- package/lib/thin/protocol/messages/directPathOp.js +65 -0
- package/lib/thin/protocol/messages/directPathPrepare.js +158 -0
- package/lib/thin/protocol/messages/endPipeline.js +56 -0
- package/lib/thin/protocol/messages/execute.js +9 -7
- package/lib/thin/protocol/messages/index.js +9 -1
- package/lib/thin/protocol/messages/protocol.js +2 -2
- package/lib/thin/protocol/messages/withData.js +10 -142
- package/lib/thin/protocol/packet.js +120 -28
- package/lib/thin/protocol/protocol.js +110 -25
- package/lib/thin/protocol/utils.js +1 -26
- package/lib/thin/resultSet.js +13 -19
- package/lib/thin/sqlnet/ezConnectResolver.js +2 -2
- package/lib/thin/sqlnet/networkSession.js +63 -41
- package/lib/thin/sqlnet/ntTcp.js +24 -0
- package/lib/thin/sqlnet/nvStrToNvPair.js +50 -25
- package/lib/thin/sqlnet/packet.js +25 -4
- package/lib/thin/sqlnet/paramParser.js +10 -7
- package/lib/thin/statementCache.js +2 -4
- package/lib/traceHandler.js +59 -2
- package/lib/transformer.js +8 -3
- package/lib/types.js +36 -22
- package/lib/util.js +6 -19
- package/lib/version.js +3 -3
- package/package/install.js +5 -5
- package/package/prunebinaries.js +1 -1
- package/package.json +1 -1
- package/plugins/configProviders/awsCommon.js +125 -0
- package/plugins/configProviders/awss3/index.js +138 -0
- package/plugins/configProviders/awssecretsmanager/index.js +147 -0
- package/plugins/configProviders/azure/index.js +7 -5
- package/plugins/token/extensionAzure/index.js +0 -1
- package/plugins/token/extensionOci/index.js +0 -1
- package/build/Release/oracledb-6.9.0-darwin-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-darwin-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-darwin-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-js-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-linux-arm64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-arm64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-linux-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-linux-x64.node-buildinfo.txt +0 -1
- package/build/Release/oracledb-6.9.0-win32-x64.node +0 -0
- package/build/Release/oracledb-6.9.0-win32-x64.node-buildinfo.txt +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -69,7 +69,7 @@ class Protocol {
|
|
|
69
69
|
async _decodeMessage(message) {
|
|
70
70
|
message.preProcess();
|
|
71
71
|
await this.readBuf.waitForPackets(true);
|
|
72
|
-
while (true) {
|
|
72
|
+
while (true) {
|
|
73
73
|
if (this.nsi.isBreak) {
|
|
74
74
|
await this.resetMessage();
|
|
75
75
|
delete this.readBuf.savedPackets;
|
|
@@ -89,7 +89,31 @@ class Protocol {
|
|
|
89
89
|
throw (err);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async _processPipelineMessage(messageObj, connImpl, continueOnError) {
|
|
95
|
+
let opProcessed = false;
|
|
96
|
+
const { message } = messageObj;
|
|
97
|
+
await this.readBuf.waitForPackets(true);
|
|
98
|
+
try {
|
|
99
|
+
message.preProcess();
|
|
100
|
+
message.decode(this.readBuf);
|
|
101
|
+
opProcessed = true;
|
|
102
|
+
this._checkAndRaiseException(message);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (!opProcessed && !this.connInProgress &&
|
|
105
|
+
err.code !== errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
106
|
+
this.readBuf.resetPackets();
|
|
107
|
+
}
|
|
108
|
+
if (messageObj.statement)
|
|
109
|
+
connImpl._returnStatement(messageObj.statement);
|
|
110
|
+
if (!continueOnError) {
|
|
111
|
+
err.opProcessed = opProcessed;
|
|
112
|
+
throw (err);
|
|
113
|
+
}
|
|
114
|
+
messageObj.pipelineResultImpl.error = err;
|
|
115
|
+
}
|
|
116
|
+
return opProcessed;
|
|
93
117
|
}
|
|
94
118
|
|
|
95
119
|
/**
|
|
@@ -112,6 +136,59 @@ class Protocol {
|
|
|
112
136
|
this.writeBuf.endRequest();
|
|
113
137
|
}
|
|
114
138
|
|
|
139
|
+
_raiseException(message) {
|
|
140
|
+
let err = new Error(message.errorInfo.message);
|
|
141
|
+
err.offset = message.errorInfo.pos;
|
|
142
|
+
err.errorNum = message.errorInfo.num;
|
|
143
|
+
err.isRecoverable = message.errorInfo.isRecoverable;
|
|
144
|
+
err = errors.transformErr(err);
|
|
145
|
+
if (err.code === errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
146
|
+
this.nsi.disconnect();
|
|
147
|
+
}
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_checkAndRaiseException(message) {
|
|
152
|
+
if (message.errorOccurred) {
|
|
153
|
+
this._raiseException(message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Called when all messages for the pipeline have been sent to the
|
|
158
|
+
* database. An end pipeline message is sent to the database and then
|
|
159
|
+
* the responses to all of the messages are processed.
|
|
160
|
+
*/
|
|
161
|
+
async endPipeline(messagesForPipeline, endMessage, connImpl,
|
|
162
|
+
continueOnError) {
|
|
163
|
+
await this._encodeMessage(endMessage);
|
|
164
|
+
|
|
165
|
+
// required for cleanup of response packets
|
|
166
|
+
let numResponsesToDiscard = messagesForPipeline.length + 1;
|
|
167
|
+
try {
|
|
168
|
+
for (const messageObj of messagesForPipeline) {
|
|
169
|
+
const opProcessed = await this._processPipelineMessage(
|
|
170
|
+
messageObj, connImpl, continueOnError);
|
|
171
|
+
if (opProcessed)
|
|
172
|
+
numResponsesToDiscard--;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Process the final message
|
|
176
|
+
await this.readBuf.waitForPackets(true);
|
|
177
|
+
endMessage.process(this.readBuf);
|
|
178
|
+
this._checkAndRaiseException(endMessage);
|
|
179
|
+
numResponsesToDiscard = 0;
|
|
180
|
+
|
|
181
|
+
} catch (err) {
|
|
182
|
+
|
|
183
|
+
// If an operation response was already consumed before failure, account
|
|
184
|
+
// for it before discarding the remaining pipeline responses.
|
|
185
|
+
if (err.opProcessed)
|
|
186
|
+
numResponsesToDiscard--;
|
|
187
|
+
await this.readBuf.discardPipelineResponses(numResponsesToDiscard);
|
|
188
|
+
throw (err);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
115
192
|
async _recoverFromError(caughtErr, message) {
|
|
116
193
|
/*
|
|
117
194
|
* We have NJS error(protocol related) detected during packet write/read
|
|
@@ -119,11 +196,16 @@ class Protocol {
|
|
|
119
196
|
* response as ORA-1013 from the server.
|
|
120
197
|
*/
|
|
121
198
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
199
|
+
if (message.isPipeline) {
|
|
200
|
+
// We just cleanup all pending response packets
|
|
201
|
+
this.readBuf.resetPackets();
|
|
202
|
+
} else {
|
|
203
|
+
this.breakMessage();
|
|
204
|
+
this._breakInProgress = false;
|
|
205
|
+
await this.resetMessage();
|
|
206
|
+
await this.readBuf.waitForPackets();
|
|
207
|
+
message.decode(this.readBuf);
|
|
208
|
+
}
|
|
127
209
|
} catch (err) { // Recovery failed
|
|
128
210
|
this.nsi.disconnect();
|
|
129
211
|
const newErr = errors.getErr(errors.ERR_CONNECTION_CLOSED);
|
|
@@ -134,6 +216,18 @@ class Protocol {
|
|
|
134
216
|
}
|
|
135
217
|
}
|
|
136
218
|
|
|
219
|
+
async _processCallStatus(message) {
|
|
220
|
+
if (message.flushOutBinds) {
|
|
221
|
+
await this.flushOutBindMessage(message);
|
|
222
|
+
}
|
|
223
|
+
this.txnInProgress = Boolean(message.callStatus &
|
|
224
|
+
constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
|
|
225
|
+
// processes the call status flags returned by the server.
|
|
226
|
+
if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
|
|
227
|
+
message.connection.statementCache.clearCursors();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
137
231
|
/**
|
|
138
232
|
*
|
|
139
233
|
* @param {object} message The RPC dynamic structure specific to the RPC
|
|
@@ -159,6 +253,11 @@ class Protocol {
|
|
|
159
253
|
if (traceEnabled) {
|
|
160
254
|
traceContext.operation = `oracledb.${message.constructor.name}`;
|
|
161
255
|
traceInstance.onBeginRoundTrip(traceContext);
|
|
256
|
+
if (traceContext.userContext?.traceParent) {
|
|
257
|
+
// The traceParent is set from instrumentation module.
|
|
258
|
+
message.connection.appContext('CLIENTCONTEXT',
|
|
259
|
+
[{ ora$opentelem$tracectx: traceContext.userContext.traceParent }]);
|
|
260
|
+
}
|
|
162
261
|
}
|
|
163
262
|
await this._encodeMessage(message);
|
|
164
263
|
if (message.messageType !== constants.TNS_MSG_TYPE_ONEWAY_FN) {
|
|
@@ -184,14 +283,7 @@ class Protocol {
|
|
|
184
283
|
traceInstance.onEndRoundTrip(traceContext);
|
|
185
284
|
}
|
|
186
285
|
}
|
|
187
|
-
|
|
188
|
-
await this.flushOutBindMessage(message);
|
|
189
|
-
}
|
|
190
|
-
this.txnInProgress = Boolean(message.callStatus & constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS);
|
|
191
|
-
// processes the call status flags returned by the server.
|
|
192
|
-
if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) {
|
|
193
|
-
message.connection.statementCache.clearCursors();
|
|
194
|
-
}
|
|
286
|
+
await this._processCallStatus(message);
|
|
195
287
|
|
|
196
288
|
if (message.errorOccurred) {
|
|
197
289
|
if (callTimeoutExpired) {
|
|
@@ -201,16 +293,9 @@ class Protocol {
|
|
|
201
293
|
message.errorOccurred = false;
|
|
202
294
|
return await this._processMessage(message);
|
|
203
295
|
}
|
|
204
|
-
|
|
205
|
-
err.offset = message.errorInfo.pos;
|
|
206
|
-
err.errorNum = message.errorInfo.num;
|
|
207
|
-
err.isRecoverable = message.errorInfo.isRecoverable;
|
|
208
|
-
err = errors.transformErr(err);
|
|
209
|
-
if (err.code === errors.ERR_CONNECTION_CLOSED_CODE) {
|
|
210
|
-
this.nsi.disconnect();
|
|
211
|
-
}
|
|
212
|
-
throw err;
|
|
296
|
+
this._raiseException(message);
|
|
213
297
|
}
|
|
298
|
+
await message.postProcess();
|
|
214
299
|
}
|
|
215
300
|
|
|
216
301
|
async flushOutBindMessage(message) {
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
|
|
29
29
|
const { Buffer } = require('buffer');
|
|
30
30
|
const constants = require('./constants');
|
|
31
|
-
const crypto = require('crypto');
|
|
32
31
|
|
|
33
32
|
class OutOfPacketsError extends Error { }
|
|
34
33
|
|
|
@@ -52,31 +51,7 @@ function encodeRowID(rowID) {
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
// obfuscate value
|
|
56
|
-
function setObfuscatedValue(value) {
|
|
57
|
-
const valueBytes = Buffer.from(value);
|
|
58
|
-
const obfuscatedBytes = crypto.randomBytes(valueBytes.length);
|
|
59
|
-
for (let i = 0; i < valueBytes.length; i++) {
|
|
60
|
-
valueBytes[i] = obfuscatedBytes[i] ^ valueBytes[i];
|
|
61
|
-
}
|
|
62
|
-
return {obfuscatedValue: obfuscatedBytes, value: valueBytes};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// returns the deobfuscated value, after removing the obfuscation
|
|
66
|
-
// and clear memory of temporary Buffers coming from Buffer pool
|
|
67
|
-
function getDeobfuscatedValue(valueBytes, obfuscatedBytes) {
|
|
68
|
-
const buf = Buffer.from(valueBytes);
|
|
69
|
-
for (let i = 0; i < valueBytes.length; i++) {
|
|
70
|
-
buf[i] = valueBytes[i] ^ obfuscatedBytes[i];
|
|
71
|
-
}
|
|
72
|
-
const retVal = buf.toString();
|
|
73
|
-
buf.fill(0);
|
|
74
|
-
return retVal;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
54
|
module.exports = {
|
|
78
55
|
encodeRowID,
|
|
79
|
-
|
|
80
|
-
OutOfPacketsError,
|
|
81
|
-
setObfuscatedValue
|
|
56
|
+
OutOfPacketsError
|
|
82
57
|
};
|
package/lib/thin/resultSet.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -94,26 +94,20 @@ class ThinResultSetImpl extends ResultSetImpl {
|
|
|
94
94
|
async getRows(numRows, options) {
|
|
95
95
|
options.fetchArraySize = numRows || this.options.fetchArraySize;
|
|
96
96
|
options.prefetchRows = this.options.prefetchRows;
|
|
97
|
-
if (this.statement.bufferRowCount - this.statement.bufferRowIndex >= options.fetchArraySize)
|
|
97
|
+
if (this.statement.bufferRowCount - this.statement.bufferRowIndex >= options.fetchArraySize)
|
|
98
98
|
return this._processRows(options.fetchArraySize);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
options.fetchArraySize = numRows || this.options.fetchArraySize;
|
|
107
|
-
if (prevBufferRowCount === this.statement.bufferRowCount) {
|
|
108
|
-
const numRowsFetched = this.statement.bufferRowCount - this.statement.bufferRowIndex;
|
|
109
|
-
this.statement.bufferRowCount = 0;
|
|
110
|
-
if (numRowsFetched > 0) {
|
|
111
|
-
return this._processRows(numRowsFetched);
|
|
112
|
-
}
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
}
|
|
99
|
+
|
|
100
|
+
// We fetch for the required number of rows
|
|
101
|
+
options.fetchArraySize = options.fetchArraySize - (this.statement.bufferRowCount - this.statement.bufferRowIndex);
|
|
102
|
+
const prevBufferRowCount = this.statement.bufferRowCount;
|
|
103
|
+
if (this.statement.moreRowsToFetch && options.fetchArraySize > 0)
|
|
104
|
+
await this._fetchMoreRows(options);
|
|
105
|
+
options.fetchArraySize = numRows || this.options.fetchArraySize;
|
|
116
106
|
const numRowsFetched = this.statement.bufferRowCount - this.statement.bufferRowIndex;
|
|
107
|
+
if (prevBufferRowCount === this.statement.bufferRowCount)
|
|
108
|
+
this.statement.bufferRowCount = 0;
|
|
109
|
+
|
|
110
|
+
// process the rows fetched
|
|
117
111
|
return this._processRows(numRowsFetched);
|
|
118
112
|
}
|
|
119
113
|
|
|
@@ -294,7 +294,7 @@ class EZConnectResolver {
|
|
|
294
294
|
if (serverDNMatch != null)
|
|
295
295
|
securityInfo.push(`(SSL_SERVER_DN_MATCH=${serverDNMatch})`);
|
|
296
296
|
if (serverCertDN != null)
|
|
297
|
-
securityInfo.push(`(SSL_SERVER_CERT_DN=${serverCertDN}
|
|
297
|
+
securityInfo.push(`(SSL_SERVER_CERT_DN=${serverCertDN})`);
|
|
298
298
|
if (walletDir != null)
|
|
299
299
|
securityInfo.push(`(MY_WALLET_DIRECTORY=${walletDir})`);
|
|
300
300
|
}
|
|
@@ -416,7 +416,7 @@ class EZConnectResolver {
|
|
|
416
416
|
// if it is an URL alias then add to URL props
|
|
417
417
|
this.urlProps.set(propertyName, value);
|
|
418
418
|
} else {
|
|
419
|
-
this.connectionProps.set(
|
|
419
|
+
this.connectionProps.set(key, value);
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -34,11 +34,27 @@ const { createNode } = require('./connStrategy.js');
|
|
|
34
34
|
const errors = require("../../errors.js");
|
|
35
35
|
const { findNVPairRecurse, createNVPair, findValue } = require("./nvStrToNvPair.js");
|
|
36
36
|
const { Buffer } = require('buffer');
|
|
37
|
-
const EzConnect = require("./ezConnectResolver.js");
|
|
38
|
-
const { NLParamParser, tnsnamesFilePath } = require("./paramParser.js");
|
|
39
|
-
const process = require('process');
|
|
40
37
|
const downHostInstance = require("./connStrategy.js").SOLE_INST_DHCACHE;
|
|
41
38
|
const {ANO} = require("./ANO.js");
|
|
39
|
+
const { resolveConnectStr } = require('../../impl/parserHelpers.js');
|
|
40
|
+
|
|
41
|
+
const MAX_REDIRECTS = 2;
|
|
42
|
+
|
|
43
|
+
const REDIRECT_SECURITY_KEYS = new Set([
|
|
44
|
+
'sslServerDNMatch',
|
|
45
|
+
'sslAllowWeakDNMatch',
|
|
46
|
+
'sslServerCertDN',
|
|
47
|
+
'walletLocation',
|
|
48
|
+
'walletPassword',
|
|
49
|
+
'walletContent'
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
function getRedirectParams(params) {
|
|
53
|
+
return Object.fromEntries(
|
|
54
|
+
Object.entries(params).filter(([key]) => !REDIRECT_SECURITY_KEYS.has(key))
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
/**
|
|
43
59
|
*
|
|
44
60
|
* @param {string} userConfig
|
|
@@ -68,36 +84,6 @@ async function getConnectionInfo(userConfig) {
|
|
|
68
84
|
* @param {String} connStr Connect string
|
|
69
85
|
* @returns AddressNode
|
|
70
86
|
*/
|
|
71
|
-
const nlParamParser = new NLParamParser;
|
|
72
|
-
async function resolveConnectStr(connectString, configDir) {
|
|
73
|
-
const connStr = connectString.trim();
|
|
74
|
-
let resolvedVal = connStr;
|
|
75
|
-
if ((connStr.indexOf(')') == -1) || (connStr.indexOf('(') != 0)) {
|
|
76
|
-
if ((connStr.indexOf(':') != -1) || (connStr.indexOf('/') != -1)) {
|
|
77
|
-
const ezcnObj = new EzConnect(connStr);
|
|
78
|
-
resolvedVal = ezcnObj.getResolvedUrl();
|
|
79
|
-
return resolvedVal;
|
|
80
|
-
} else {
|
|
81
|
-
//try tns alias
|
|
82
|
-
const namesFilePath = tnsnamesFilePath(configDir);
|
|
83
|
-
const p = await nlParamParser.initializeNlpa(namesFilePath);
|
|
84
|
-
resolvedVal = p.get(connStr.toUpperCase());
|
|
85
|
-
if (!resolvedVal)
|
|
86
|
-
errors.throwErr(errors.ERR_TNS_ENTRY_NOT_FOUND, connStr, configDir ? configDir + '/tnsnames.ora' : process.env.TNS_ADMIN + '/tnsnames.ora');
|
|
87
|
-
if (resolvedVal.rhsType == 1) {
|
|
88
|
-
const rString = resolvedVal.atom;
|
|
89
|
-
if ((rString.indexOf(':') != -1) || (rString.indexOf('/') != -1)) {
|
|
90
|
-
return new EzConnect(rString).getResolvedUrl();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
resolvedVal = resolvedVal.getListElement(0);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
return resolvedVal;
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
87
|
async function resolveAddress(connStr, userConfig) {
|
|
102
88
|
const connstr = await resolveConnectStr(connStr, userConfig.configDir);
|
|
103
89
|
return createNode(connstr, userConfig);
|
|
@@ -228,6 +214,8 @@ class NetworkSession {
|
|
|
228
214
|
let connectPkt = new Packet.ConnectPacket(this.cData, this.sAtts);
|
|
229
215
|
this._sendConnect(connectPkt);
|
|
230
216
|
|
|
217
|
+
let redirectCount = 0;
|
|
218
|
+
|
|
231
219
|
/* Read the response */
|
|
232
220
|
while (true) { // eslint-disable-line
|
|
233
221
|
const packet = await this._recvPacket();
|
|
@@ -257,6 +245,11 @@ class NetworkSession {
|
|
|
257
245
|
}
|
|
258
246
|
this._sendConnect(connectPkt);
|
|
259
247
|
} else if (packet.type === constants.NSPTRD) { /* REDIRECT */
|
|
248
|
+
if (redirectCount >= MAX_REDIRECTS) {
|
|
249
|
+
errors.throwErr(errors.ERR_TOO_MANY_REDIRECTS, MAX_REDIRECTS);
|
|
250
|
+
}
|
|
251
|
+
redirectCount++;
|
|
252
|
+
|
|
260
253
|
let adrLen, adrStr, redirConnData;
|
|
261
254
|
|
|
262
255
|
/* Read and connect to Redirect address */
|
|
@@ -277,8 +270,10 @@ class NetworkSession {
|
|
|
277
270
|
const redirAddressNode = await resolveAddress(adrStr, userConfig);
|
|
278
271
|
const host = address.hostname;
|
|
279
272
|
address = await redirAddressNode.execute();
|
|
280
|
-
|
|
281
|
-
|
|
273
|
+
/* Add on attributes from redirect connect String */
|
|
274
|
+
if (address.desc?.params) {
|
|
275
|
+
this.sAtts.setFrom(getRedirectParams(address.desc.params));
|
|
276
|
+
}
|
|
282
277
|
address.originHost = host;
|
|
283
278
|
this.redirectPkt = null;
|
|
284
279
|
this.ntAdapter.disconnect(constants.NSFIMM);
|
|
@@ -298,7 +293,6 @@ class NetworkSession {
|
|
|
298
293
|
|
|
299
294
|
/* Accepted */
|
|
300
295
|
|
|
301
|
-
this.connected = true;
|
|
302
296
|
this.cData = null;
|
|
303
297
|
this.sndDatapkt = new Packet.DataPacket(this.sAtts.largeSDU);
|
|
304
298
|
this.markerPkt = new Packet.MarkerPacket(this.sAtts.largeSDU);
|
|
@@ -319,6 +313,7 @@ class NetworkSession {
|
|
|
319
313
|
this.sndDatapkt.createPacket(constants.NSPDADAT); //Currently only used for disconnect
|
|
320
314
|
this.sndDatapkt.offset = this.sndDatapkt.dataPtr;
|
|
321
315
|
this.sndDatapkt.len = this.sndDatapkt.bufLen;
|
|
316
|
+
this.connected = true;
|
|
322
317
|
return (true);
|
|
323
318
|
}
|
|
324
319
|
|
|
@@ -349,7 +344,7 @@ class NetworkSession {
|
|
|
349
344
|
savedErr = err;
|
|
350
345
|
try {
|
|
351
346
|
address = await this.getAddress(addressNode, userConfig);
|
|
352
|
-
} catch
|
|
347
|
+
} catch {
|
|
353
348
|
break;
|
|
354
349
|
}
|
|
355
350
|
}
|
|
@@ -370,20 +365,39 @@ class NetworkSession {
|
|
|
370
365
|
const size = packet.buf.length;
|
|
371
366
|
const dataFlags = packet.buf.readUInt16BE(constants.NSPDAFLG);
|
|
372
367
|
if ((dataFlags & constants.NSPDAFCMP) != 0) { // compression enabled
|
|
368
|
+
if (!this.sAtts.networkCompressionEnabled) {
|
|
369
|
+
errors.throwErr(errors.ERR_INVALID_PACKET, "Compressed packet received without negotiation");
|
|
370
|
+
}
|
|
373
371
|
const packetHeader = packet.buf.subarray(0, constants.NSPDADAT);
|
|
374
372
|
const buffertoDeCompress = packet.buf.subarray(constants.NSPDADAT, size);
|
|
375
373
|
let deCompressedDataBuffer;
|
|
374
|
+
|
|
375
|
+
const maxPayload = this.sAtts.largeSDU
|
|
376
|
+
? Math.min(this.sAtts.sdu, constants.NSPABSSDULN)
|
|
377
|
+
: Math.min(this.sAtts.sdu, constants.NSPMXSDULN);
|
|
378
|
+
|
|
379
|
+
const inflateOptions = {
|
|
380
|
+
finishFlush: zlib.constants.Z_SYNC_FLUSH,
|
|
381
|
+
maxOutputLength: maxPayload
|
|
382
|
+
};
|
|
376
383
|
try {
|
|
377
384
|
if (this.sAtts.firstRecvCompressedPacket) {
|
|
378
|
-
deCompressedDataBuffer = zlib.inflateSync(buffertoDeCompress,
|
|
385
|
+
deCompressedDataBuffer = zlib.inflateSync(buffertoDeCompress, inflateOptions);
|
|
379
386
|
this.sAtts.firstRecvCompressedPacket = 0;
|
|
380
387
|
} else {
|
|
381
|
-
deCompressedDataBuffer = zlib.inflateRawSync(buffertoDeCompress,
|
|
388
|
+
deCompressedDataBuffer = zlib.inflateRawSync(buffertoDeCompress, inflateOptions);
|
|
382
389
|
}
|
|
383
390
|
} catch (err) {
|
|
391
|
+
if (err.code == 'ERR_BUFFER_TOO_LARGE') {
|
|
392
|
+
errors.throwErr(errors.ERR_INVALID_PACKET,
|
|
393
|
+
`: decompressed packet exceeds SDU ${maxPayload}`);
|
|
394
|
+
}
|
|
384
395
|
errors.throwErr(errors.ERR_DATA_COMPRESSION, err.message);
|
|
385
396
|
}
|
|
386
397
|
const resultLength = deCompressedDataBuffer.length;
|
|
398
|
+
if (resultLength > maxPayload) {
|
|
399
|
+
errors.throwErr(errors.ERR_INVALID_PACKET, `Decompressed size ${resultLength} exceeds SDU ${maxPayload}`);
|
|
400
|
+
}
|
|
387
401
|
//concatenate packet header with decompressed data
|
|
388
402
|
packet.buf = Buffer.concat([packetHeader, deCompressedDataBuffer]);
|
|
389
403
|
const length = resultLength + constants.NSPDADAT;
|
|
@@ -407,6 +421,7 @@ class NetworkSession {
|
|
|
407
421
|
if (this.sAtts.version >= constants.TNS_VERSION_MIN_END_OF_RESPONSE
|
|
408
422
|
&& (packet.flags & constants.TNS_ACCEPT_FLAG_HAS_END_OF_REQUEST)) {
|
|
409
423
|
this.endOfRequestSupport = true;
|
|
424
|
+
this.pipeliningSupport = true;
|
|
410
425
|
}
|
|
411
426
|
if (packet.flags & constants.TNS_ACCEPT_FLAG_FAST_AUTH) {
|
|
412
427
|
this.supportsFastAuth = true;
|
|
@@ -430,7 +445,7 @@ class NetworkSession {
|
|
|
430
445
|
* Control packets are consumed internally and discarded
|
|
431
446
|
*/
|
|
432
447
|
async _recvPacket() {
|
|
433
|
-
while (true) {
|
|
448
|
+
while (true) {
|
|
434
449
|
const packet = await this.ntAdapter.receive();
|
|
435
450
|
if (!packet)
|
|
436
451
|
break;
|
|
@@ -501,6 +516,9 @@ class NetworkSession {
|
|
|
501
516
|
this.isBreak = true;
|
|
502
517
|
this.markerPkt.prepare(constants.NSPMKTD1, constants.NIQIMARK);
|
|
503
518
|
this.sendPacket(this.markerPkt.buf);
|
|
519
|
+
if (this.pipelineEnabled) {
|
|
520
|
+
this.isBreak = false;
|
|
521
|
+
}
|
|
504
522
|
}
|
|
505
523
|
|
|
506
524
|
/**
|
|
@@ -513,6 +531,10 @@ class NetworkSession {
|
|
|
513
531
|
this.sendPacket(this.markerPkt.buf);
|
|
514
532
|
this.breakPosted = false;
|
|
515
533
|
}
|
|
534
|
+
if (this.pipelineEnabled) {
|
|
535
|
+
this.isBreak = this.isReset = false;
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
516
538
|
/* Send Reset */
|
|
517
539
|
this.markerPkt.prepare(constants.NSPMKTD1, constants.NIQRMARK);
|
|
518
540
|
this.sendPacket(this.markerPkt.buf);
|
package/lib/thin/sqlnet/ntTcp.js
CHANGED
|
@@ -389,6 +389,19 @@ class NTTCP {
|
|
|
389
389
|
this.numPacketsSinceLastWait = 0;
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Reject invalid packet and clean up
|
|
394
|
+
* @param {string} message Error message
|
|
395
|
+
* @returns {null} to clear tempBuf
|
|
396
|
+
*/
|
|
397
|
+
rejectInvalidPacket(message) {
|
|
398
|
+
this.savedErr = new Error(message);
|
|
399
|
+
this.err = true;
|
|
400
|
+
this.stream.destroy();
|
|
401
|
+
this._notifyWaiters();
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
|
|
392
405
|
/**
|
|
393
406
|
* Start Async reads
|
|
394
407
|
*/
|
|
@@ -414,6 +427,17 @@ class NTTCP {
|
|
|
414
427
|
len = tempBuf.readUInt16BE();
|
|
415
428
|
}
|
|
416
429
|
|
|
430
|
+
if (len < PACKET_HEADER_SIZE) {
|
|
431
|
+
tempBuf = this.rejectInvalidPacket(`Invalid packet length: ${len} (must be at least ${PACKET_HEADER_SIZE})`);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const maxPacket = this.largeSDU ? constants.NSPABSSDULN : constants.NSPMXSDULN;
|
|
436
|
+
if (len > maxPacket) {
|
|
437
|
+
tempBuf = this.rejectInvalidPacket(`Invalid packet length: ${len} (exceeds maximum ${maxPacket})`);
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
|
|
417
441
|
// not enough for a full packet so wait for more data to arrive
|
|
418
442
|
if (len > tempBuf.length)
|
|
419
443
|
break;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright (c) 2022,
|
|
1
|
+
// Copyright (c) 2022, 2026, Oracle and/or its affiliates.
|
|
2
2
|
|
|
3
3
|
//-----------------------------------------------------------------------------
|
|
4
4
|
//
|
|
@@ -28,6 +28,26 @@
|
|
|
28
28
|
|
|
29
29
|
const errors = require("../../errors.js");
|
|
30
30
|
|
|
31
|
+
// Maximum supported descriptor byte length.
|
|
32
|
+
const DEFAULT_MAX_DESCRIPTOR_LENGTH = 512 * 8;
|
|
33
|
+
|
|
34
|
+
// Maximum supported descriptor nesting depth before rejecting the parse.
|
|
35
|
+
const DEFAULT_MAX_DESCRIPTOR_DEPTH = 64;
|
|
36
|
+
|
|
37
|
+
function checkLength(nvString, maxLength) {
|
|
38
|
+
if (Buffer.byteLength(nvString, 'utf8') > maxLength) {
|
|
39
|
+
errors.throwErr(errors.ERR_CONNECT_DESCRIPTOR_LIMIT_EXCEEDED,
|
|
40
|
+
'byte length', maxLength);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function checkDepth(depth, maxDepth) {
|
|
45
|
+
if (depth > maxDepth) {
|
|
46
|
+
errors.throwErr(errors.ERR_CONNECT_DESCRIPTOR_LIMIT_EXCEEDED,
|
|
47
|
+
'nesting depth', maxDepth);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
31
51
|
|
|
32
52
|
/**
|
|
33
53
|
* Constant which implies that the VALUE has not been set to ATOM or LIST.
|
|
@@ -556,10 +576,13 @@ class NVTokens {
|
|
|
556
576
|
* Returns an NVPair which contains the broken-down form of nvString
|
|
557
577
|
* @param nvString the nvString to parse
|
|
558
578
|
*/
|
|
559
|
-
function createNVPair(nvString) {
|
|
579
|
+
function createNVPair(nvString, options = {}) {
|
|
580
|
+
const maxLength = options.maxLength ?? DEFAULT_MAX_DESCRIPTOR_LENGTH;
|
|
581
|
+
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DESCRIPTOR_DEPTH;
|
|
582
|
+
checkLength(nvString, maxLength);
|
|
560
583
|
const nvt = new NVTokens();
|
|
561
584
|
nvt.parseTokens(nvString);
|
|
562
|
-
return readTopLevelNVPair(nvt);
|
|
585
|
+
return readTopLevelNVPair(nvt, 1, maxDepth);
|
|
563
586
|
}
|
|
564
587
|
|
|
565
588
|
/*
|
|
@@ -567,7 +590,8 @@ function createNVPair(nvString) {
|
|
|
567
590
|
* NVPair: (name=value)
|
|
568
591
|
* value: atom | NVList
|
|
569
592
|
*/
|
|
570
|
-
function readTopLevelNVPair(nvt) {
|
|
593
|
+
function readTopLevelNVPair(nvt, depth, maxDepth) {
|
|
594
|
+
checkDepth(depth, maxDepth);
|
|
571
595
|
//check for opening (
|
|
572
596
|
let tk = nvt.getToken();
|
|
573
597
|
nvt.eatToken();
|
|
@@ -586,17 +610,18 @@ function readTopLevelNVPair(nvt) {
|
|
|
586
610
|
}
|
|
587
611
|
nvp.name = name;
|
|
588
612
|
|
|
589
|
-
return readRightHandSide(nvp, nvt);
|
|
613
|
+
return readRightHandSide(nvp, nvt, depth, maxDepth);
|
|
590
614
|
}
|
|
591
615
|
|
|
592
|
-
return readRightHandSide(nvp, nvt);
|
|
616
|
+
return readRightHandSide(nvp, nvt, depth, maxDepth);
|
|
593
617
|
}
|
|
594
618
|
/*
|
|
595
619
|
* function which returns the next NVPair from NVTokens.
|
|
596
620
|
* NVPair: (name=value) | (name, | ,name) | ,name,
|
|
597
621
|
* value: atom | NVList
|
|
598
622
|
*/
|
|
599
|
-
function readNVPair(nvt) {
|
|
623
|
+
function readNVPair(nvt, depth, maxDepth) {
|
|
624
|
+
checkDepth(depth, maxDepth);
|
|
600
625
|
// Opening ( or , for NVPair
|
|
601
626
|
const tk = nvt.getToken();
|
|
602
627
|
nvt.eatToken();
|
|
@@ -607,7 +632,7 @@ function readNVPair(nvt) {
|
|
|
607
632
|
const name = readNVLiteral(nvt);
|
|
608
633
|
const nvp = new NVPair(name);
|
|
609
634
|
|
|
610
|
-
return readRightHandSide(nvp, nvt);
|
|
635
|
+
return readRightHandSide(nvp, nvt, depth, maxDepth);
|
|
611
636
|
}
|
|
612
637
|
|
|
613
638
|
/*
|
|
@@ -615,7 +640,7 @@ function readNVPair(nvt) {
|
|
|
615
640
|
* NVPair: (name=value)
|
|
616
641
|
* value: atom | NVList
|
|
617
642
|
*/
|
|
618
|
-
function readRightHandSide(nvp, nvt) {
|
|
643
|
+
function readRightHandSide(nvp, nvt, depth, maxDepth) {
|
|
619
644
|
let tk = nvt.getToken();
|
|
620
645
|
switch (tk) {
|
|
621
646
|
case TKN_EQUAL:
|
|
@@ -630,7 +655,7 @@ function readRightHandSide(nvp, nvt) {
|
|
|
630
655
|
} else {
|
|
631
656
|
// NVList is responsible for adding child NVPairs to this parent
|
|
632
657
|
// NVPair.
|
|
633
|
-
readNVList(nvt, nvp);
|
|
658
|
+
readNVList(nvt, nvp, depth, maxDepth);
|
|
634
659
|
}
|
|
635
660
|
break;
|
|
636
661
|
|
|
@@ -671,24 +696,24 @@ function readNVLiteral(nvt) {
|
|
|
671
696
|
* function which adds a list of NVPairs to a parent NVPair.
|
|
672
697
|
* NVList: NVPair NVList | epsilon
|
|
673
698
|
*/
|
|
674
|
-
function readNVList(nvt, parent) {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
699
|
+
function readNVList(nvt, parent, depth, maxDepth) {
|
|
700
|
+
while (true) {
|
|
701
|
+
// if next token is "(" or ",", then read an NVPair
|
|
702
|
+
// otherwise, assume epsilon
|
|
703
|
+
const tk = nvt.getToken();
|
|
704
|
+
if (!(tk == TKN_LPAREN || tk == TKN_COMMA)) {
|
|
705
|
+
return; // didn't read an nvpair
|
|
706
|
+
}
|
|
681
707
|
|
|
682
|
-
|
|
708
|
+
const child = readNVPair(nvt, depth + 1, maxDepth);
|
|
683
709
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
710
|
+
// read a good NVPair
|
|
711
|
+
parent.addListElement(child);
|
|
712
|
+
if ((tk == TKN_COMMA) || (child.name == child.atom)) {
|
|
713
|
+
if (parent.getListType != LIST_COMMASEP) // if not already set
|
|
714
|
+
parent.setListType = LIST_COMMASEP; // set it
|
|
715
|
+
}
|
|
689
716
|
}
|
|
690
|
-
|
|
691
|
-
readNVList(nvt, parent); // next iteration of NVList()
|
|
692
717
|
}
|
|
693
718
|
|
|
694
719
|
/**
|