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
+};