mirror of
https://github.com/tenrok/axios.git
synced 2026-06-20 20:00:40 +03:00
feat(dns): added support for a custom lookup function; (#5339)
This commit is contained in:
@@ -403,6 +403,9 @@ declare namespace axios {
|
|||||||
FormData?: new (...args: any[]) => object;
|
FormData?: new (...args: any[]) => object;
|
||||||
};
|
};
|
||||||
formSerializer?: FormSerializerOptions;
|
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
|
// Alias
|
||||||
|
|||||||
Vendored
+4
-1
@@ -329,7 +329,7 @@ export interface AxiosRequestConfig<D = any> {
|
|||||||
maxBodyLength?: number;
|
maxBodyLength?: number;
|
||||||
maxRedirects?: number;
|
maxRedirects?: number;
|
||||||
maxRate?: number | [MaxUploadRate, MaxDownloadRate];
|
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;
|
socketPath?: string | null;
|
||||||
transport?: any;
|
transport?: any;
|
||||||
httpAgent?: any;
|
httpAgent?: any;
|
||||||
@@ -344,6 +344,9 @@ export interface AxiosRequestConfig<D = any> {
|
|||||||
FormData?: new (...args: any[]) => object;
|
FormData?: new (...args: any[]) => object;
|
||||||
};
|
};
|
||||||
formSerializer?: FormSerializerOptions;
|
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
|
// Alias
|
||||||
|
|||||||
+15
-1
@@ -23,6 +23,7 @@ import EventEmitter from 'events';
|
|||||||
import formDataToStream from "../helpers/formDataToStream.js";
|
import formDataToStream from "../helpers/formDataToStream.js";
|
||||||
import readBlob from "../helpers/readBlob.js";
|
import readBlob from "../helpers/readBlob.js";
|
||||||
import ZlibHeaderTransformStream from '../helpers/ZlibHeaderTransformStream.js';
|
import ZlibHeaderTransformStream from '../helpers/ZlibHeaderTransformStream.js';
|
||||||
|
import callbackify from "../helpers/callbackify.js";
|
||||||
|
|
||||||
const zlibOptions = {
|
const zlibOptions = {
|
||||||
flush: zlib.constants.Z_SYNC_FLUSH,
|
flush: zlib.constants.Z_SYNC_FLUSH,
|
||||||
@@ -146,13 +147,24 @@ const wrapAsync = (asyncExecutor) => {
|
|||||||
/*eslint consistent-return:0*/
|
/*eslint consistent-return:0*/
|
||||||
export default isHttpAdapterSupported && function httpAdapter(config) {
|
export default isHttpAdapterSupported && function httpAdapter(config) {
|
||||||
return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
|
return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
|
||||||
let {data} = config;
|
let {data, lookup, family} = config;
|
||||||
const {responseType, responseEncoding} = config;
|
const {responseType, responseEncoding} = config;
|
||||||
const method = config.method.toUpperCase();
|
const method = config.method.toUpperCase();
|
||||||
let isDone;
|
let isDone;
|
||||||
let rejected = false;
|
let rejected = false;
|
||||||
let req;
|
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
|
// temporary internal emitter until the AxiosRequest class will be implemented
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
|
|
||||||
@@ -378,6 +390,8 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
|
|||||||
agents: { http: config.httpAgent, https: config.httpsAgent },
|
agents: { http: config.httpAgent, https: config.httpsAgent },
|
||||||
auth,
|
auth,
|
||||||
protocol,
|
protocol,
|
||||||
|
family,
|
||||||
|
lookup,
|
||||||
beforeRedirect: dispatchBeforeRedirect,
|
beforeRedirect: dispatchBeforeRedirect,
|
||||||
beforeRedirects: {}
|
beforeRedirects: {}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
+15
-1
@@ -662,6 +662,15 @@ const toJSONObject = (obj) => {
|
|||||||
return visit(obj, 0);
|
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 {
|
export default {
|
||||||
isArray,
|
isArray,
|
||||||
isArrayBuffer,
|
isArrayBuffer,
|
||||||
@@ -711,5 +720,10 @@ export default {
|
|||||||
ALPHABET,
|
ALPHABET,
|
||||||
generateString,
|
generateString,
|
||||||
isSpecCompliantForm,
|
isSpecCompliantForm,
|
||||||
toJSONObject
|
toJSONObject,
|
||||||
|
isAsyncFn,
|
||||||
|
isGeneratorFn,
|
||||||
|
isAsyncGeneratorFn,
|
||||||
|
isPlainFunction,
|
||||||
|
isThenable
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ var noop = ()=> {};
|
|||||||
|
|
||||||
const LOCAL_SERVER_URL = 'http://localhost:4444';
|
const LOCAL_SERVER_URL = 'http://localhost:4444';
|
||||||
|
|
||||||
|
const SERVER_HANDLER_STREAM_ECHO = (req, res) => req.pipe(res);
|
||||||
|
|
||||||
function startHTTPServer(options) {
|
function startHTTPServer(options) {
|
||||||
|
|
||||||
const {handler, useBuffering = false, rate = undefined, port = 4444} = typeof options === 'function' ? {
|
const {handler, useBuffering = false, rate = undefined, port = 4444} = typeof options === 'function' ? {
|
||||||
@@ -2117,4 +2119,63 @@ describe('supports http with nodejs', function () {
|
|||||||
|
|
||||||
assert.strictEqual(data, '/?foo');
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user