From de74edb50f198b010517ac52e4b0fa18395c2075 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 6 Oct 2023 22:49:48 +0530 Subject: [PATCH] feat: interpolation of proxy vars --- .../ResponsePane/QueryResult/index.js | 2 +- .../src/runner/interpolate-string.js | 55 +++++++++++++++++++ .../src/runner/run-single-request.js | 20 +++++-- .../bruno-cli/src/utils/axios-instance.js | 4 +- .../src/ipc/network/axios-instance.js | 4 +- .../bruno-electron/src/ipc/network/index.js | 47 +++++++++++----- .../src/ipc/network/interpolate-string.js | 55 +++++++++++++++++++ 7 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 packages/bruno-cli/src/runner/interpolate-string.js create mode 100644 packages/bruno-electron/src/ipc/network/interpolate-string.js diff --git a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js index 5729e0b2d..999eb16fc 100644 --- a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js +++ b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js @@ -87,7 +87,7 @@ const QueryResult = ({ item, collection, data, width, disableRunEventListener, h }; const activeResult = useMemo(() => { - if (tab === 'preview' && mode.includes('html')) { + if (tab === 'preview' && mode.includes('html') && item.requestSent && item.requestSent.url) { // Add the Base tag to the head so content loads properly. This also needs the correct CSP settings const webViewSrc = data.replace('', ``); return ( diff --git a/packages/bruno-cli/src/runner/interpolate-string.js b/packages/bruno-cli/src/runner/interpolate-string.js new file mode 100644 index 000000000..33701dd0b --- /dev/null +++ b/packages/bruno-cli/src/runner/interpolate-string.js @@ -0,0 +1,55 @@ +const Handlebars = require('handlebars'); +const { forOwn, cloneDeep } = require('lodash'); + +const interpolateEnvVars = (str, processEnvVars) => { + if (!str || !str.length || typeof str !== 'string') { + return str; + } + + const template = Handlebars.compile(str, { noEscape: true }); + + return template({ + process: { + env: { + ...processEnvVars + } + } + }); +}; + +const interpolateString = (str, { envVars, collectionVariables, processEnvVars }) => { + if (!str || !str.length || typeof str !== 'string') { + return str; + } + + processEnvVars = processEnvVars || {}; + collectionVariables = collectionVariables || {}; + + // we clone envVars because we don't want to modify the original object + envVars = envVars ? cloneDeep(envVars) : {}; + + // envVars can inturn have values as {{process.env.VAR_NAME}} + // so we need to interpolate envVars first with processEnvVars + forOwn(envVars, (value, key) => { + envVars[key] = interpolateEnvVars(value, processEnvVars); + }); + + const template = Handlebars.compile(str, { noEscape: true }); + + // collectionVariables take precedence over envVars + const combinedVars = { + ...envVars, + ...collectionVariables, + process: { + env: { + ...processEnvVars + } + } + }; + + return template(combinedVars); +}; + +module.exports = { + interpolateString +}; diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 7497a53c4..1bdc77999 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -6,6 +6,7 @@ const { forOwn, each, extend, get } = require('lodash'); const FormData = require('form-data'); const prepareRequest = require('./prepare-request'); const interpolateVars = require('./interpolate-vars'); +const { interpolateString } = require('./interpolate-string'); const { ScriptRuntime, TestRuntime, VarsRuntime, AssertRuntime } = require('@usebruno/js'); const { stripExtension } = require('../utils/filesystem'); const { getOptions } = require('../utils/bru'); @@ -92,16 +93,23 @@ const runSingleRequest = async function ( // set proxy if enabled const proxyEnabled = get(brunoConfig, 'proxy.enabled', false); if (proxyEnabled) { - const proxyProtocol = get(brunoConfig, 'proxy.protocol'); - const proxyHostname = get(brunoConfig, 'proxy.hostname'); - const proxyPort = get(brunoConfig, 'proxy.port'); + let proxy; + const interpolationOptions = { + envVars: envVariables, + collectionVariables, + processEnvVars + }; + + const proxyProtocol = interpolateString(get(brunoConfig, 'proxy.protocol'), interpolationOptions); + const proxyHostname = interpolateString(get(brunoConfig, 'proxy.hostname'), interpolationOptions); + const proxyPort = interpolateString(get(brunoConfig, 'proxy.port'), interpolationOptions); const proxyAuthEnabled = get(brunoConfig, 'proxy.auth.enabled', false); - let proxy; + interpolateString; if (proxyAuthEnabled) { - const proxyAuthUsername = get(brunoConfig, 'proxy.auth.username'); - const proxyAuthPassword = get(brunoConfig, 'proxy.auth.password'); + const proxyAuthUsername = interpolateString(get(brunoConfig, 'proxy.auth.username'), interpolationOptions); + const proxyAuthPassword = interpolateString(get(brunoConfig, 'proxy.auth.password'), interpolationOptions); proxy = `${proxyProtocol}://${proxyAuthUsername}:${proxyAuthPassword}@${proxyHostname}:${proxyPort}`; } else { diff --git a/packages/bruno-cli/src/utils/axios-instance.js b/packages/bruno-cli/src/utils/axios-instance.js index f4810becd..286ffc0f5 100644 --- a/packages/bruno-cli/src/utils/axios-instance.js +++ b/packages/bruno-cli/src/utils/axios-instance.js @@ -26,7 +26,9 @@ function makeAxiosInstance() { if (error.response) { const end = Date.now(); const start = error.config.headers['request-start-time']; - error.response.headers['request-duration'] = end - start; + if (error.response) { + error.response.headers['request-duration'] = end - start; + } } return Promise.reject(error); } diff --git a/packages/bruno-electron/src/ipc/network/axios-instance.js b/packages/bruno-electron/src/ipc/network/axios-instance.js index f4abd839a..90ca1afea 100644 --- a/packages/bruno-electron/src/ipc/network/axios-instance.js +++ b/packages/bruno-electron/src/ipc/network/axios-instance.js @@ -25,7 +25,9 @@ function makeAxiosInstance() { (error) => { const end = Date.now(); const start = error.config.headers['request-start-time']; - error.response.headers['request-duration'] = end - start; + if (error.response) { + error.response.headers['request-duration'] = end - start; + } return Promise.reject(error); } ); diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 9ba07b5e2..43d06d6c4 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -12,6 +12,7 @@ const prepareGqlIntrospectionRequest = require('./prepare-gql-introspection-requ const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token'); const { uuid } = require('../../utils/common'); const interpolateVars = require('./interpolate-vars'); +const { interpolateString } = require('./interpolate-string'); const { sortFolder, getAllRequestsInFolderRecursively } = require('./helper'); const { getPreferences } = require('../../store/preferences'); const { getProcessEnvVars } = require('../../store/process-env'); @@ -219,16 +220,22 @@ const registerNetworkIpc = (mainWindow) => { const brunoConfig = getBrunoConfig(collectionUid); const proxyEnabled = get(brunoConfig, 'proxy.enabled', false); if (proxyEnabled) { - const proxyProtocol = get(brunoConfig, 'proxy.protocol'); - const proxyHostname = get(brunoConfig, 'proxy.hostname'); - const proxyPort = get(brunoConfig, 'proxy.port'); - const proxyAuthEnabled = get(brunoConfig, 'proxy.auth.enabled', false); - let proxy; + const interpolationOptions = { + envVars, + collectionVariables, + processEnvVars + }; + + const proxyProtocol = interpolateString(get(brunoConfig, 'proxy.protocol'), interpolationOptions); + const proxyHostname = interpolateString(get(brunoConfig, 'proxy.hostname'), interpolationOptions); + const proxyPort = interpolateString(get(brunoConfig, 'proxy.port'), interpolationOptions); + const proxyAuthEnabled = get(brunoConfig, 'proxy.auth.enabled', false); + if (proxyAuthEnabled) { - const proxyAuthUsername = get(brunoConfig, 'proxy.auth.username'); - const proxyAuthPassword = get(brunoConfig, 'proxy.auth.password'); + const proxyAuthUsername = interpolateString(get(brunoConfig, 'proxy.auth.username'), interpolationOptions); + const proxyAuthPassword = interpolateString(get(brunoConfig, 'proxy.auth.password'), interpolationOptions); proxy = `${proxyProtocol}://${proxyAuthUsername}:${proxyAuthPassword}@${proxyHostname}:${proxyPort}`; } else { @@ -648,16 +655,28 @@ const registerNetworkIpc = (mainWindow) => { const brunoConfig = getBrunoConfig(collectionUid); const proxyEnabled = get(brunoConfig, 'proxy.enabled', false); if (proxyEnabled) { - const proxyProtocol = get(brunoConfig, 'proxy.protocol'); - const proxyHostname = get(brunoConfig, 'proxy.hostname'); - const proxyPort = get(brunoConfig, 'proxy.port'); + let proxy; + const interpolationOptions = { + envVars, + collectionVariables, + processEnvVars + }; + + const proxyProtocol = interpolateString(get(brunoConfig, 'proxy.protocol'), interpolationOptions); + const proxyHostname = interpolateString(get(brunoConfig, 'proxy.hostname'), interpolationOptions); + const proxyPort = interpolateString(get(brunoConfig, 'proxy.port'), interpolationOptions); const proxyAuthEnabled = get(brunoConfig, 'proxy.auth.enabled', false); - let proxy; - if (proxyAuthEnabled) { - const proxyAuthUsername = get(brunoConfig, 'proxy.auth.username'); - const proxyAuthPassword = get(brunoConfig, 'proxy.auth.password'); + const proxyAuthUsername = interpolateString( + get(brunoConfig, 'proxy.auth.username'), + interpolationOptions + ); + + const proxyAuthPassword = interpolateString( + get(brunoConfig, 'proxy.auth.password'), + interpolationOptions + ); proxy = `${proxyProtocol}://${proxyAuthUsername}:${proxyAuthPassword}@${proxyHostname}:${proxyPort}`; } else { diff --git a/packages/bruno-electron/src/ipc/network/interpolate-string.js b/packages/bruno-electron/src/ipc/network/interpolate-string.js new file mode 100644 index 000000000..33701dd0b --- /dev/null +++ b/packages/bruno-electron/src/ipc/network/interpolate-string.js @@ -0,0 +1,55 @@ +const Handlebars = require('handlebars'); +const { forOwn, cloneDeep } = require('lodash'); + +const interpolateEnvVars = (str, processEnvVars) => { + if (!str || !str.length || typeof str !== 'string') { + return str; + } + + const template = Handlebars.compile(str, { noEscape: true }); + + return template({ + process: { + env: { + ...processEnvVars + } + } + }); +}; + +const interpolateString = (str, { envVars, collectionVariables, processEnvVars }) => { + if (!str || !str.length || typeof str !== 'string') { + return str; + } + + processEnvVars = processEnvVars || {}; + collectionVariables = collectionVariables || {}; + + // we clone envVars because we don't want to modify the original object + envVars = envVars ? cloneDeep(envVars) : {}; + + // envVars can inturn have values as {{process.env.VAR_NAME}} + // so we need to interpolate envVars first with processEnvVars + forOwn(envVars, (value, key) => { + envVars[key] = interpolateEnvVars(value, processEnvVars); + }); + + const template = Handlebars.compile(str, { noEscape: true }); + + // collectionVariables take precedence over envVars + const combinedVars = { + ...envVars, + ...collectionVariables, + process: { + env: { + ...processEnvVars + } + } + }; + + return template(combinedVars); +}; + +module.exports = { + interpolateString +};