Skip to content

Commit

Permalink
feat(dns): added support for a custom lookup function; (axios#5339)
Browse files Browse the repository at this point in the history
  • Loading branch information
DigitalBrainJS authored and WillianAgostini committed Jul 24, 2023
1 parent 4db4530 commit 1bb6f32
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -514,4 +514,4 @@
- [Marco Weber](https://github.com/mrcwbr)
- [Luca Pizzini](https://github.com/lpizzinidev)
- [Willian Agostini](https://github.com/WillianAgostini)
- [Huyen Nguyen](https://github.com/huyenltnguyen)
- [Huyen Nguyen](https://github.com/huyenltnguyen)
3 changes: 3 additions & 0 deletions index.d.cts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ declare namespace axios {
FormData?: new (...args: any[]) => object;
};
formSerializer?: FormSerializerOptions;
family?: 4 | 6 | undefined;
lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: string, family: number) => void) => void) |
((hostname: string, options: object) => Promise<[address: string, family: number] | string>);
}

// Alias
Expand Down
5 changes: 4 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ export interface AxiosRequestConfig<D = any> {
maxBodyLength?: number;
maxRedirects?: number;
maxRate?: number | [MaxUploadRate, MaxDownloadRate];
beforeRedirect?: (options: Record<string, any>, responseDetails: {headers: Record<string, string>}) => void;
beforeRedirect?: (options: Record<string, any>, responseDetails: { headers: Record<string, string> }) => void;
socketPath?: string | null;
transport?: any;
httpAgent?: any;
Expand All @@ -344,6 +344,9 @@ export interface AxiosRequestConfig<D = any> {
FormData?: new (...args: any[]) => object;
};
formSerializer?: FormSerializerOptions;
family?: 4 | 6 | undefined;
lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: string, family: number) => void) => void) |
((hostname: string, options: object) => Promise<[address: string, family: number] | string>);
}

// Alias
Expand Down
16 changes: 15 additions & 1 deletion lib/adapters/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import EventEmitter from 'events';
import formDataToStream from "../helpers/formDataToStream.js";
import readBlob from "../helpers/readBlob.js";
import ZlibHeaderTransformStream from '../helpers/ZlibHeaderTransformStream.js';
import callbackify from "../helpers/callbackify.js";

const zlibOptions = {
flush: zlib.constants.Z_SYNC_FLUSH,
Expand Down Expand Up @@ -146,13 +147,24 @@ const wrapAsync = (asyncExecutor) => {
/*eslint consistent-return:0*/
export default isHttpAdapterSupported && function httpAdapter(config) {
return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
let {data} = config;
let {data, lookup, family} = config;
const {responseType, responseEncoding} = config;
const method = config.method.toUpperCase();
let isDone;
let rejected = false;
let req;

if (lookup && utils.isAsyncFn(lookup)) {
lookup = callbackify(lookup, (entry) => {
if(utils.isString(entry)) {
entry = [entry, entry.indexOf('.') < 0 ? 6 : 4]
} else if (!utils.isArray(entry)) {
throw new TypeError('lookup async function must return an array [ip: string, family: number]]')
}
return entry;
})
}

// temporary internal emitter until the AxiosRequest class will be implemented
const emitter = new EventEmitter();

Expand Down Expand Up @@ -378,6 +390,8 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
agents: { http: config.httpAgent, https: config.httpsAgent },
auth,
protocol,
family,
lookup,
beforeRedirect: dispatchBeforeRedirect,
beforeRedirects: {}
};
Expand Down
16 changes: 16 additions & 0 deletions lib/helpers/callbackify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import utils from "../utils.js";

const callbackify = (fn, reducer) => {
return utils.isAsyncFn(fn) ? function (...args) {
const cb = args.pop();
fn.apply(this, args).then((value) => {
try {
reducer ? cb(null, ...reducer(value)) : cb(null, value);
} catch (err) {
cb(err);
}
}, cb);
} : fn;
}

export default callbackify;
16 changes: 15 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,15 @@ const toJSONObject = (obj) => {
return visit(obj, 0);
}

const [isPlainFunction, isAsyncFn, isGeneratorFn, isAsyncGeneratorFn] = (
(...fns) => fns.map(
({constructor})=> (thing) => thing && typeof thing === 'function' && thing.constructor === constructor
)
)(()=> {}, async()=>{}, function*(){}, async function*(){});

const isThenable = (thing) =>
thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch);

export default {
isArray,
isArrayBuffer,
Expand Down Expand Up @@ -711,5 +720,10 @@ export default {
ALPHABET,
generateString,
isSpecCompliantForm,
toJSONObject
toJSONObject,
isAsyncFn,
isGeneratorFn,
isAsyncGeneratorFn,
isPlainFunction,
isThenable
};
14 changes: 14 additions & 0 deletions test/module/typings/esm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,3 +627,17 @@ for (const [header, value] of headers) {
}
});
}

// lookup
axios.get('/user', {
lookup: (hostname: string, opt: object, cb: (err: Error | null, address: string, family: number) => void) => {
cb(null, '127.0.0.1', 4);
}
});

// lookup async
axios.get('/user', {
lookup: (hostname: string, opt: object) => {
return ['127.0.0.1', 4];
}
});
61 changes: 61 additions & 0 deletions test/unit/adapters/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ var noop = ()=> {};

const LOCAL_SERVER_URL = 'http://localhost:4444';

const SERVER_HANDLER_STREAM_ECHO = (req, res) => req.pipe(res);

function startHTTPServer(options) {

const {handler, useBuffering = false, rate = undefined, port = 4444} = typeof options === 'function' ? {
Expand Down Expand Up @@ -2117,4 +2119,63 @@ describe('supports http with nodejs', function () {

assert.strictEqual(data, '/?foo');
});

describe('DNS', function() {
it('should support custom DNS lookup function', async function () {
server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO);

const payload = 'test';

let isCalled = false;

const {data} = await axios.post(`http://fake-name.axios:4444`, payload,{
lookup: (hostname, opt, cb) => {
isCalled = true;
cb(null, '127.0.0.1', 4);
}
});

assert.ok(isCalled);

assert.strictEqual(data, payload);
});

it('should support custom DNS lookup function (async)', async function () {
server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO);

const payload = 'test';

let isCalled = false;

const {data} = await axios.post(`http://fake-name.axios:4444`, payload,{
lookup: async (hostname, opt) => {
isCalled = true;
return ['127.0.0.1', 4];
}
});

assert.ok(isCalled);

assert.strictEqual(data, payload);
});

it('should support custom DNS lookup function that returns only IP address (async)', async function () {
server = await startHTTPServer(SERVER_HANDLER_STREAM_ECHO);

const payload = 'test';

let isCalled = false;

const {data} = await axios.post(`http://fake-name.axios:4444`, payload,{
lookup: async (hostname, opt) => {
isCalled = true;
return '127.0.0.1';
}
});

assert.ok(isCalled);

assert.strictEqual(data, payload);
});
});
});

0 comments on commit 1bb6f32

Please sign in to comment.