Skip to content

Commit 9002b83

Browse files
committed
feat: upgrade dnscache_httpclient and enable dnscache_fetch
style: formatting code fix: dns cache record
1 parent 918c21f commit 9002b83

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2034
-239
lines changed

app/extend/context.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const LOCALS_LIST = Symbol('Context#localsList');
1111
const COOKIES = Symbol('Context#cookies');
1212
const CONTEXT_LOGGERS = Symbol('Context#logger');
1313
const CONTEXT_HTTPCLIENT = Symbol('Context#httpclient');
14+
const CONTEXT_FETCH = Symbol('Context#fetch');
1415
const CONTEXT_ROUTER = Symbol('Context#router');
1516

1617
const proto = module.exports = {
@@ -49,6 +50,51 @@ const proto = module.exports = {
4950
return this.httpclient.curl(url, options);
5051
},
5152

53+
/**
54+
* Get a wrapper fetch instance with context
55+
*
56+
* @return {ContextFetch} the wrapper fetch instance
57+
*/
58+
get fetchClient() {
59+
if (!this.app.fetch) return null;
60+
if (!this[CONTEXT_FETCH]) {
61+
this[CONTEXT_FETCH] = new this.app.ContextFetch(this);
62+
}
63+
return this[CONTEXT_FETCH];
64+
},
65+
66+
/**
67+
* Shortcut for fetchClient.fetch
68+
*
69+
* @function Context#fetch
70+
* @param {String|URL} url - request url address.
71+
* @param {Object} [init] - fetch init options.
72+
* @return {Promise<Response>} see {@link ContextFetch#fetch}
73+
*/
74+
fetch(url, init) {
75+
const client = this.fetchClient;
76+
if (!client) {
77+
throw new Error('fetch is not available, please upgrade to Node.js >= 20 and install urllib4');
78+
}
79+
return client.fetch(url, init);
80+
},
81+
82+
/**
83+
* Shortcut for fetchClient.safeFetch with SSRF protection
84+
*
85+
* @function Context#safeFetch
86+
* @param {String|URL} url - request url address.
87+
* @param {Object} [init] - fetch init options.
88+
* @return {Promise<Response>} see {@link ContextFetch#safeFetch}
89+
*/
90+
safeFetch(url, init) {
91+
const client = this.fetchClient;
92+
if (!client) {
93+
throw new Error('safeFetch is not available, please upgrade to Node.js >= 20 and install urllib4');
94+
}
95+
return client.safeFetch(url, init);
96+
},
97+
5298
/**
5399
* Alias to {@link Application#router}
54100
*

config/config.default.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,14 @@ module.exports = appInfo => {
289289
/**
290290
* The option for httpclient
291291
* @member Config#httpclient
292-
* @property {Boolean} enableDNSCache - Enable DNS lookup from local cache or not, default is false.
293-
* @property {Boolean} dnsCacheLookupInterval - minimum interval of DNS query on the same hostname (default 10s).
292+
* @property {Boolean} enableDNSCache - Enable DNS lookup cache using dns.lookup (old behavior), default is false.
293+
* @property {Number} dnsCacheLookupInterval - DNS cache lookup interval in ms for old dns.lookup mode, default is 10000 ms.
294+
*
295+
* @property {Boolean} useDNSResolver - Enable DNS resolve cache using dns.resolve (new feature), default is false.
296+
* @property {Array<String>} dnsServers - Custom DNS nameservers for DNS resolver cache, e.g. ['8.8.8.8', '1.1.1.1']. If not set, use system default.
297+
*
298+
* @property {Number} dnsCacheMaxLength - DNS cache max size, default is 1000.
299+
* @property {Boolean} dnsAddressRotation - Enable address rotation for both lookup and resolve modes, default is true.
294300
*
295301
* @property {Number} request.timeout - httpclient request default timeout, default is 5000 ms.
296302
*
@@ -307,12 +313,21 @@ module.exports = appInfo => {
307313
* @property {Boolean} allowH2 - use urllib@4 HttpClient and enable H2, default is false. Only works on Node.js >= 18
308314
*/
309315
config.httpclient = {
316+
// Enable DNS cache mode using dns.lookup
310317
enableDNSCache: false,
311-
dnsCacheLookupInterval: 10000,
318+
dnsCacheLookupInterval: 10000, // will not work if useDNSResolver is true
319+
320+
// DNS resolver mode using dns.resolve (new feature)
321+
useDNSResolver: false, // will not work if enableDNSCache IS NOT true
322+
dnsServers: undefined, // Use system default if not set
323+
324+
// Common dns options
312325
dnsCacheMaxLength: 1000,
326+
dnsAddressRotation: true,
313327

314328
request: {
315329
timeout: 5000,
330+
reset: false, // only works when useHttpClientNext is true
316331
},
317332
httpAgent: {
318333
keepAlive: true,

index.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ declare module 'egg' {
8989
new(ctx: Context): EggContextHttpClient;
9090
}
9191

92+
export interface EggContextFetch {
93+
ctx: Context;
94+
app: Application;
95+
fetch(url: string | URL, init?: RequestInit): Promise<Response>;
96+
/**
97+
* safeFetch request helper with SSRF protection
98+
*/
99+
safeFetch(url: string | URL, init?: RequestInit): Promise<Response>;
100+
}
101+
interface EggContextFetchConstructor {
102+
new (ctx: Context): EggContextFetch;
103+
}
104+
92105
/**
93106
* BaseContextClass is a base class that can be extended,
94107
* it's instantiated in context level,

lib/core/context_fetch.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class ContextFetch {
2+
constructor(ctx) {
3+
this.ctx = ctx;
4+
this.app = ctx.app;
5+
}
6+
7+
/**
8+
* fetch request helper based on native fetch API or urllib4's FetchFactory
9+
* Keep the same api with {@link Application#fetch}.
10+
*
11+
* @param {String|URL} url - request url address.
12+
* @param {Object} [init] - fetch init options.
13+
* @return {Promise<Response>} fetch response
14+
*/
15+
async fetch(url, init) {
16+
init = init || {};
17+
init.ctx = this.ctx;
18+
return await this.app.fetch(url, init);
19+
}
20+
21+
/**
22+
* safeFetch request helper with SSRF protection
23+
* Keep the same api with {@link Application#safeFetch}.
24+
*
25+
* @param {String|URL} url - request url address.
26+
* @param {Object} [init] - fetch init options.
27+
* @return {Promise<Response>} fetch response
28+
*/
29+
async safeFetch(url, init) {
30+
init = init || {};
31+
init.ctx = this.ctx;
32+
return await this.app.safeFetch(url, init);
33+
}
34+
}
35+
36+
module.exports = ContextFetch;

0 commit comments

Comments
 (0)