Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 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);
});
});
});