Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-1801434 add GUID to request in node.js driver #965

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5d74303
SNOW-1631790-Transport-Layer - Base HTTP client implemented
sfc-gh-fpawlowski Nov 17, 2024
4b2c001
SNOW-1631790-Transport-Layer - Base http client logging splitted into…
sfc-gh-fpawlowski Nov 17, 2024
df6f773
SNOW-1631790-Transport-Layer - Removed absent parameters from the doc…
sfc-gh-fpawlowski Nov 18, 2024
7725d96
SNOW-1631790-Transport-Layer - Improved readability by renaming varia…
sfc-gh-fpawlowski Nov 18, 2024
a858cb3
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver - Added guid to re…
sfc-gh-fpawlowski Nov 19, 2024
91628b1
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver - Guid logging imp…
sfc-gh-fpawlowski Nov 19, 2024
c79c2fc
SNOW-1631790-Transport-Layer - missing logs added for browser client
sfc-gh-fpawlowski Nov 19, 2024
45c1bbe
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: mock client adjus…
sfc-gh-fpawlowski Nov 19, 2024
e12d8ba
SNOW-1631790-Transport-Layer: Partial Identification of the HttpClien…
sfc-gh-fpawlowski Nov 22, 2024
b45999d
SNOW-1631790-Transport-Layer: Proxy description added to logs
sfc-gh-fpawlowski Nov 22, 2024
1d57d58
SNOW-1631790-Transport-Layer: Proxy redundant calls to getter eliminated
sfc-gh-fpawlowski Nov 22, 2024
b734f52
Merge branch 'master' into SNOW-1631790-Transport-Layer
sfc-gh-fpawlowski Nov 24, 2024
bcc9628
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Guid generated on…
sfc-gh-fpawlowski Nov 24, 2024
54d48e6
SNOW-1631790-Transport-Layer: Masking Tokens for '%' signs and parame…
sfc-gh-fpawlowski Nov 26, 2024
fc5531c
Merge branch 'master' into SNOW-1631790-Transport-Layer
sfc-gh-fpawlowski Nov 28, 2024
8e8998b
Merge branch 'master' into SNOW-1631790-Transport-Layer
sfc-gh-fpawlowski Nov 29, 2024
be0d198
Merge branch 'SNOW-1631790-Transport-Layer' into SNOW-1801434-Add-GUI…
sfc-gh-fpawlowski Dec 3, 2024
eb94b72
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: IncludeGuid extra…
sfc-gh-fpawlowski Dec 3, 2024
8d53d1a
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Added HttpClientW…
sfc-gh-fpawlowski Dec 4, 2024
cf39674
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Fixed tests for GUID
sfc-gh-fpawlowski Dec 4, 2024
6029097
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Formatting fix.
sfc-gh-fpawlowski Dec 4, 2024
adb13c4
Merge branch 'master' into SNOW-1631790-Transport-Layer
sfc-gh-fpawlowski Dec 4, 2024
69aee7b
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Tests with Interc…
sfc-gh-fpawlowski Dec 4, 2024
9674391
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Core instance inj…
sfc-gh-fpawlowski Dec 4, 2024
29a75a8
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: IncludeGuid added…
sfc-gh-fpawlowski Dec 4, 2024
8acb7aa
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Reverted extendin…
sfc-gh-fpawlowski Dec 4, 2024
691ede4
Merge branch 'SNOW-1631790-Transport-Layer' into SNOW-1801434-Add-GUI…
sfc-gh-fpawlowski Dec 5, 2024
fe9578b
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Removed unused co…
sfc-gh-fpawlowski Dec 5, 2024
895e356
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Fixed httpClient …
sfc-gh-fpawlowski Dec 5, 2024
d109f10
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Fixed httpClient …
sfc-gh-fpawlowski Dec 5, 2024
08cc997
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Removed old comments
sfc-gh-fpawlowski Dec 5, 2024
e9e96a2
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Add guid in async…
sfc-gh-fpawlowski Dec 5, 2024
e23851b
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Merged master
sfc-gh-fpawlowski Dec 5, 2024
31496c8
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: Rolled back to se…
sfc-gh-fpawlowski Dec 6, 2024
a8ddcfe
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: IncludeGuid chang…
sfc-gh-fpawlowski Dec 6, 2024
c05d219
Merge branch 'master' into SNOW-1801434-Add-GUID-to-request-in-NODE.j…
sfc-gh-fpawlowski Dec 6, 2024
9cf3a54
SNOW-1801434-Add-GUID-to-request-in-NODE.js-driver: ExcludeGuid setti…
sfc-gh-fpawlowski Dec 6, 2024
aec74ec
Merge branch 'master' into SNOW-1801434-Add-GUID-to-request-in-NODE.j…
sfc-gh-fpawlowski Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/configuration/client_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ function ConfigurationUtil(fsPromisesModule, processModule) {
}

async function searchForConfigInDefaultDirectories() {
Logger.getInstance().debug(`Searching for config in default directories: ${defaultDirectories}`);
Logger.getInstance().debug(`Searching for config in default directories: ${JSON.stringify(defaultDirectories)}`);
for (const directory of defaultDirectories) {
const configPath = await searchForConfigInDictionary(directory.dir, directory.dirDescription);
if (exists(configPath)) {
Expand Down
6 changes: 3 additions & 3 deletions lib/connection/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const Url = require('url');
const QueryString = require('querystring');
const QueryStatus = require('../constants/query_status');

const LoggingUtil = require('../logger/logging_utils');
const LoggingUtil = require('../logger/logging_util');
const Util = require('../util');
const Errors = require('../errors');
const ErrorCodes = Errors.codes;
Expand Down Expand Up @@ -153,7 +153,7 @@ function Connection(context) {

this.heartbeat = callback => {
Logger.getInstance().trace('Issuing heartbeat call');
const requestID = uuidv4();
const requestId = uuidv4();

services.sf.request(
{
Expand All @@ -163,7 +163,7 @@ function Connection(context) {
pathname: '/session/heartbeat',
search: QueryString.stringify(
{
requestId: requestID
requestId: requestId
})
}),
callback: Util.isFunction(callback) ? callback : function (err, body) {
Expand Down
2 changes: 2 additions & 0 deletions lib/constants/sf_params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
exports.paramsNames = {};
exports.paramsNames.SF_REQUEST_GUID = 'request_guid';
81 changes: 63 additions & 18 deletions lib/http/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
const zlib = require('zlib');
const Util = require('../util');
const Logger = require('../logger');
const ExecutionTimer = require('../logger/execution_timer');
const axios = require('axios');
const URL = require('node:url').URL;
const requestUtil = require('./request_util');

const DEFAULT_REQUEST_TIMEOUT = 360000;

Expand All @@ -18,6 +20,7 @@ const DEFAULT_REQUEST_TIMEOUT = 360000;
*/
function HttpClient(connectionConfig) {
// save the connection config
Logger.getInstance().trace('Initializing base HttpClient with connection config');
this._connectionConfig = connectionConfig;
}

Expand All @@ -29,42 +32,56 @@ function HttpClient(connectionConfig) {
* @returns {Object} an object representing the request that was issued.
*/
HttpClient.prototype.request = function (options) {
let request;
Logger.getInstance().trace('Request%s - preparing for sending.', requestUtil.describeRequestFromOptions(options));

let requestPromise;
const requestOptions = prepareRequestOptions.call(this, options);
let sendRequest = async function sendRequest() {
request = axios.request(requestOptions).then(response => {
Logger.getInstance().trace('Request%s - sending.', requestUtil.describeRequestFromOptions(requestOptions));
const timer = new ExecutionTimer().start();
requestPromise = axios.request(requestOptions).then(response => {
const httpResponseTime = timer.getDuration();
Logger.getInstance().debug('Request%s - response received after %s milliseconds with status %s.', requestUtil.describeRequestFromOptions(requestOptions), httpResponseTime, response.status);
sanitizeAxiosResponse(response);
if (Util.isFunction(options.callback)) {
Logger.getInstance().trace('Request%s - calling callback function.', requestUtil.describeRequestFromOptions(requestOptions));
return options.callback(null, normalizeResponse(response), response.data);
} else {
Logger.getInstance().trace(`Callback function was not provided for the call to ${options.url}`);
Logger.getInstance().trace('Request%s - callback function was not provided.', requestUtil.describeRequestFromOptions(requestOptions));
return null;
}
}).catch(err => {
const httpResponseTime = timer.getDuration();
Logger.getInstance().debug('Request%s - failed after %s milliseconds.', requestUtil.describeRequestFromOptions(requestOptions), httpResponseTime);
sanitizeAxiosError(err);
if (Util.isFunction(options.callback)) {
if (err.response) { // axios returns error for not 2xx responses - let's unwrap it
Logger.getInstance().trace('Request%s - calling callback function for error from response. Received code: ', requestUtil.describeRequestFromOptions(requestOptions), err.response.status);
options.callback(null, normalizeResponse(err.response), err.response.data);
} else {
Logger.getInstance().trace('Request%s - calling callback function for error without response.', requestUtil.describeRequestFromOptions(requestOptions));
options.callback(err, normalizeResponse(null), null);
}
return null;
} else {
Logger.getInstance().warn('Request%s - callback function was not provided. Error will be re-raised.', requestUtil.describeRequestFromOptions(requestOptions));
throw err;
}
});
};
sendRequest = sendRequest.bind(this);

Logger.getInstance().trace(`CALL ${requestOptions.method} with timeout ${requestOptions.timeout}: ${requestOptions.url}`);
Logger.getInstance().trace('Request%s - issued for the next tick.', requestUtil.describeRequestFromOptions(requestOptions));
process.nextTick(sendRequest);

// return an externalized request object that only contains
// methods we're comfortable exposing to the outside world
return {
abort: function () {
if (request) {
request.abort();
if (requestPromise) {
Logger.getInstance().trace('Request%s - aborting.', requestUtil.describeRequestFromOptions(requestOptions));
// TODO: This line won't work - promise has no method called abort
requestPromise.abort();
}
}
};
Expand All @@ -78,21 +95,38 @@ HttpClient.prototype.request = function (options) {
* @returns {Object} an object representing the request that was issued.
*/
HttpClient.prototype.requestAsync = async function (options) {
Logger.getInstance().trace('Request%s - preparing for async sending.', requestUtil.describeRequestFromOptions(options));
const timer = new ExecutionTimer();
try {
const requestOptions = prepareRequestOptions.call(this, options);

timer.start();
const response = await axios.request(requestOptions);
if (Util.isString(response['data']) &&
response['headers']['content-type'] === 'application/json') {
response['data'] = JSON.parse(response['data']);
}
const httpResponseTime = timer.getDuration();
Logger.getInstance().debug('Request%s - response received after %s milliseconds with status %s.', requestUtil.describeRequestFromOptions(requestOptions), httpResponseTime, response.status);
parseResponseData(response);
sanitizeAxiosResponse(response);
return response;
} catch (err) {
const httpResponseTime = timer.getDuration();
Logger.getInstance().debug('Request%s - failed after %s milliseconds. Error will be re-raised.', requestUtil.describeRequestFromOptions(options), httpResponseTime);
sanitizeAxiosError(err);
throw err;
}
};

function parseResponseData(response) {
Logger.getInstance().trace('Request%s - parsing response data.', requestUtil.describeRequestFromResponse(response));
parseIfJSONData(response);
}

function parseIfJSONData(response) {
if (Util.isString(response['data']) &&
response['headers']['content-type'] === 'application/json') {
response['data'] = JSON.parse(response['data']);
}
}

/**
* Issues an HTTP POST request.
*
Expand Down Expand Up @@ -184,6 +218,7 @@ HttpClient.prototype.getAgent = function () {
module.exports = HttpClient;

function sanitizeAxiosResponse(response) {
Logger.getInstance().trace('Request%s - sanitizing response data.', requestUtil.describeRequestFromResponse(response));
response.request = undefined;
if (response.config) {
response.config.data = undefined;
Expand All @@ -195,11 +230,13 @@ function sanitizeAxiosError(error) {
error.request = undefined;
error.config = undefined;
if (error.response) {
Logger.getInstance().trace('Request%s - sanitizing response error data.', requestUtil.describeRequestFromResponse(error.response));
sanitizeAxiosResponse(error.response);
}
}

function prepareRequestOptions(options) {
Logger.getInstance().trace('Request%s - constructing options.', requestUtil.describeRequestFromOptions(options));
const headers = normalizeHeaders(options.headers) || {};

const timeout = options.timeout ||
Expand All @@ -215,8 +252,11 @@ function prepareRequestOptions(options) {
if (!err) {
data = bufferCompressed;
headers['Content-Encoding'] = 'gzip';
Logger.getInstance().debug('Request%s - original buffer length: %d bytes. Compressed buffer length: %d bytes.', requestUtil.describeRequestFromOptions(options), bufferUncompressed.buffer.byteLength, bufferCompressed.buffer.byteLength);
} else {
Logger.getInstance().warn('Could not compress request data.');
// Logging 'err' variable value should not be done, since it may contain compressed customer's data.
// It can be added only for debugging purposes.
Logger.getInstance().warn('Request%s - could not compress request data.', requestUtil.describeRequestFromOptions(options));
}
});
}
Expand Down Expand Up @@ -254,6 +294,7 @@ function prepareRequestOptions(options) {
requestOptions.httpAgent = agent;
}

Logger.getInstance().trace('Request%s - options - timeout: %s, retryDelay: %s, responseType: %s', requestUtil.describeRequestFromOptions(options), requestOptions.timeout, requestOptions.retryDelay, requestOptions.responseType);
return requestOptions;
}

Expand All @@ -266,10 +307,9 @@ function prepareRequestOptions(options) {
* @returns {Object}
*/
function normalizeHeaders(headers) {
let ret = headers;

Logger.getInstance().trace('Normalizing headers');
if (Util.isObject(headers)) {
ret = {
const normalizedHeaders = {
'user-agent': Util.userAgent
};

Expand All @@ -288,15 +328,19 @@ function normalizeHeaders(headers) {
headerNameLowerCase = headerName.toLowerCase();
if ((headerNameLowerCase === 'accept') ||
(headerNameLowerCase === 'content-type')) {
ret[headerNameLowerCase] = headers[headerName];
normalizedHeaders[headerNameLowerCase] = headers[headerName];
} else {
ret[headerName] = headers[headerName];
normalizedHeaders[headerName] = headers[headerName];
}
}
}
Logger.getInstance().trace('Headers were normalized');
return normalizedHeaders;
} else {
Logger.getInstance().trace('Headers were not an object. Original value will be returned.');
return headers;
}

return ret;
}

/**
Expand All @@ -311,6 +355,7 @@ function normalizeHeaders(headers) {
function normalizeResponse(response) {
// if the response doesn't already have a getResponseHeader() method, add one
if (response && !response.getResponseHeader) {
Logger.getInstance().trace('Request%s - normalizing.', requestUtil.describeRequestFromResponse(response));
response.getResponseHeader = function (header) {
return response.headers && response.headers[
Util.isString(header) ? header.toLowerCase() : header];
Expand All @@ -323,4 +368,4 @@ function normalizeResponse(response) {
}

return response;
}
}
Loading