diff --git a/README.md b/README.md index 4a5af19a85..9ffde41ee7 100755 --- a/README.md +++ b/README.md @@ -482,6 +482,7 @@ These are the available config options for making requests. Only the `url` is re proxy: { protocol: 'https', host: '127.0.0.1', + // hostname: '127.0.0.1' // Takes precedence over 'host' if both are defined port: 9000, auth: { username: 'mikeymike', diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 35722b3106..9e56fdad6b 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -51,7 +51,7 @@ function dispatchBeforeRedirect(options) { * If the proxy or config afterRedirects functions are defined, call them with the options * * @param {http.ClientRequestArgs} options - * @param {AxiosProxyConfig} configProxy + * @param {AxiosProxyConfig} configProxy configuration from Axios options object * @param {string} location * * @returns {http.ClientRequestArgs} @@ -82,13 +82,14 @@ function setProxy(options, configProxy, location) { } options.headers.host = options.hostname + (options.port ? ':' + options.port : ''); - options.hostname = proxy.hostname; + const proxyHost = proxy.hostname || proxy.host; + options.hostname = proxyHost; // Replace 'host' since options is not a URL object - options.host = proxy.hostname; + options.host = proxyHost; options.port = proxy.port; options.path = location; if (proxy.protocol) { - options.protocol = proxy.protocol; + options.protocol = proxy.protocol.includes(':') ? proxy.protocol : `${proxy.protocol}:`; } } @@ -586,3 +587,5 @@ export default function httpAdapter(config) { } }); } + +export const __setProxy = setProxy; \ No newline at end of file diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index ed43446739..c92b0394bb 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -20,6 +20,7 @@ const isBlobSupported = typeof Blob !== 'undefined'; import {Throttle} from 'stream-throttle'; import devNull from 'dev-null'; import {AbortController} from 'abortcontroller-polyfill/dist/cjs-ponyfill.js'; +import {__setProxy} from "../../../lib/adapters/http.js"; const __filename = url.fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -1236,6 +1237,38 @@ describe('supports http with nodejs', function () { }); }); + context('different options for direct proxy configuration (without env variables)', () => { + const destination = 'www.example.com'; + + const testCases = [{ + description: 'hostname and trailing colon in protocol', + proxyConfig: { hostname: '127.0.0.1', protocol: 'http:', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination } + }, { + description: 'hostname and no trailing colon in protocol', + proxyConfig: { hostname: '127.0.0.1', protocol: 'http', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination } + }, { + description: 'both hostname and host -> hostname takes precedence', + proxyConfig: { hostname: '127.0.0.1', host: '0.0.0.0', protocol: 'http', port: 80 }, + expectedOptions: { host: '127.0.0.1', protocol: 'http:', port: 80, path: destination } + }, { + description: 'only host and https protocol', + proxyConfig: { host: '0.0.0.0', protocol: 'https', port: 80 }, + expectedOptions: { host: '0.0.0.0', protocol: 'https:', port: 80, path: destination } + }]; + + for (const test of testCases) { + it(test.description, () => { + const options = { headers: {}, beforeRedirects: {} }; + __setProxy(options, test.proxyConfig, destination); + for (const [key, expected] of Object.entries(test.expectedOptions)) { + assert.equal(options[key], expected); + } + }); + } + }); + it('should support cancel', function (done) { var source = axios.CancelToken.source(); server = http.createServer(function (req, res) {