@fastify/reply-from 8.3.1 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -2
- package/index.js +5 -2
- package/lib/request.js +14 -2
- package/package.json +4 -4
- package/test/http-global-agent.js +57 -0
- package/test/https-global-agent.js +69 -0
- package/test/undici-global-agent.js +66 -0
- package/types/index.d.ts +1 -0
- package/types/index.test-d.ts +1 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @fastify/reply-from
|
|
2
2
|
|
|
3
|
-
[](https://github.com/fastify/fastify-reply-from/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/@fastify/reply-from)
|
|
5
5
|
[](https://standardjs.com/)
|
|
6
6
|
|
|
@@ -166,7 +166,7 @@ proxy.register(require('@fastify/reply-from'), {
|
|
|
166
166
|
sessionOptions: { // HTTP/2 session connect options, pass in any options from https://nodejs.org/api/http2.html#http2_http2_connect_authority_options_listener
|
|
167
167
|
rejectUnauthorized: true
|
|
168
168
|
},
|
|
169
|
-
|
|
169
|
+
requestOptions: { // HTTP/2 request options, pass in any options from https://nodejs.org/api/http2.html#clienthttp2sessionrequestheaders-options
|
|
170
170
|
endStream: true
|
|
171
171
|
}
|
|
172
172
|
}
|
|
@@ -216,6 +216,34 @@ By default: `['GET', 'HEAD', 'OPTIONS', 'TRACE' ]`
|
|
|
216
216
|
|
|
217
217
|
This plugin will always retry on 503 errors, _unless_ `retryMethods` does not contain `GET`.
|
|
218
218
|
|
|
219
|
+
#### `globalAgent`
|
|
220
|
+
|
|
221
|
+
Enables the possibility to explictly opt-in for global agents.
|
|
222
|
+
|
|
223
|
+
Usage for undici global agent:
|
|
224
|
+
```js
|
|
225
|
+
import { setGlobalDispatcher, ProxyAgent } from 'undici'
|
|
226
|
+
|
|
227
|
+
const proxyAgent = new ProxyAgent('my.proxy.server')
|
|
228
|
+
setGlobalDispatcher(proxyAgent)
|
|
229
|
+
|
|
230
|
+
fastify.register(FastifyReplyFrom, {
|
|
231
|
+
base: 'http://localhost:3001/',
|
|
232
|
+
globalAgent: true
|
|
233
|
+
})
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Usage for http/https global agent:
|
|
237
|
+
```js
|
|
238
|
+
fastify.register(FastifyReplyFrom, {
|
|
239
|
+
base: 'http://localhost:3001/',
|
|
240
|
+
// http and https is allowed to use http.globalAgent or https.globalAgent
|
|
241
|
+
globalAgent: true,
|
|
242
|
+
http: {
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
```
|
|
246
|
+
|
|
219
247
|
---
|
|
220
248
|
|
|
221
249
|
#### `maxRetriesOn503`
|
package/index.js
CHANGED
|
@@ -37,7 +37,8 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
37
37
|
http: opts.http,
|
|
38
38
|
http2: opts.http2,
|
|
39
39
|
base,
|
|
40
|
-
undici: opts.undici
|
|
40
|
+
undici: opts.undici,
|
|
41
|
+
globalAgent: opts.globalAgent
|
|
41
42
|
})
|
|
42
43
|
if (requestBuilt instanceof Error) {
|
|
43
44
|
next(requestBuilt)
|
|
@@ -240,7 +241,9 @@ function onErrorDefault (reply, { error }) {
|
|
|
240
241
|
}
|
|
241
242
|
|
|
242
243
|
function isFastifyMultipartRegistered (fastify) {
|
|
243
|
-
|
|
244
|
+
// TODO: remove fastify.hasContentTypeParser('multipart') in next major
|
|
245
|
+
// It is used to be compatible with @fastify/multipart@<=7.3.0
|
|
246
|
+
return (fastify.hasContentTypeParser('multipart') || fastify.hasContentTypeParser('multipart/form-data')) && fastify.hasRequestDecorator('multipart')
|
|
244
247
|
}
|
|
245
248
|
|
|
246
249
|
function createRequestRetry (requestImpl, reply, retriesCount, retryOnError, maxRetriesOn503) {
|
package/lib/request.js
CHANGED
|
@@ -41,6 +41,7 @@ function buildRequest (opts) {
|
|
|
41
41
|
const httpOpts = getHttpOpts(opts)
|
|
42
42
|
const baseUrl = opts.base && new URL(opts.base).origin
|
|
43
43
|
const undiciOpts = opts.undici || {}
|
|
44
|
+
const globalAgent = opts.globalAgent
|
|
44
45
|
let http2Client
|
|
45
46
|
let undiciAgent
|
|
46
47
|
let undiciInstance
|
|
@@ -51,11 +52,16 @@ function buildRequest (opts) {
|
|
|
51
52
|
if (opts.base.startsWith('unix+')) {
|
|
52
53
|
return new Error('Unix socket destination is not supported when http2 is true')
|
|
53
54
|
}
|
|
54
|
-
} else {
|
|
55
|
+
} else if (!globalAgent) {
|
|
55
56
|
agents = httpOpts.agents || {
|
|
56
57
|
'http:': new http.Agent(httpOpts.agentOptions),
|
|
57
58
|
'https:': new https.Agent(httpOpts.agentOptions)
|
|
58
59
|
}
|
|
60
|
+
} else {
|
|
61
|
+
agents = {
|
|
62
|
+
'http:': http.globalAgent,
|
|
63
|
+
'https:': https.globalAgent
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
if (isHttp2) {
|
|
@@ -68,8 +74,10 @@ function buildRequest (opts) {
|
|
|
68
74
|
undiciInstance = new undici.Pool(protocol + '://localhost', undiciOpts)
|
|
69
75
|
} else if (isUndiciInstance(opts.undici)) {
|
|
70
76
|
undiciInstance = opts.undici
|
|
71
|
-
} else {
|
|
77
|
+
} else if (!globalAgent) {
|
|
72
78
|
undiciAgent = new undici.Agent(getUndiciOptions(opts.undici))
|
|
79
|
+
} else {
|
|
80
|
+
undiciAgent = undici.getGlobalDispatcher()
|
|
73
81
|
}
|
|
74
82
|
return { request: handleUndici, close, retryOnError: 'UND_ERR_SOCKET' }
|
|
75
83
|
} else {
|
|
@@ -77,6 +85,10 @@ function buildRequest (opts) {
|
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
function close () {
|
|
88
|
+
if (globalAgent) {
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
|
|
80
92
|
if (hasUndiciOptions) {
|
|
81
93
|
undiciAgent && undiciAgent.destroy()
|
|
82
94
|
undiciInstance && undiciInstance.destroy()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastify/reply-from",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.0",
|
|
4
4
|
"description": "forward your HTTP request to another server, for fastify",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/fastify/fastify-reply-from#readme",
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@fastify/formbody": "^7.0
|
|
32
|
-
"@fastify/multipart": "^7.
|
|
31
|
+
"@fastify/formbody": "^7.4.0",
|
|
32
|
+
"@fastify/multipart": "^7.4.0",
|
|
33
33
|
"@fastify/pre-commit": "^2.0.2",
|
|
34
34
|
"@sinonjs/fake-timers": "^10.0.0",
|
|
35
35
|
"@types/node": "^18.0.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"split2": "^4.1.0",
|
|
47
47
|
"standard": "^17.0.0",
|
|
48
48
|
"tap": "^16.2.0",
|
|
49
|
-
"tsd": "^0.
|
|
49
|
+
"tsd": "^0.25.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@fastify/error": "^3.0.0",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const From = require('..')
|
|
6
|
+
const http = require('http')
|
|
7
|
+
const get = require('simple-get').concat
|
|
8
|
+
|
|
9
|
+
test('http global agent is used, but not destroyed', async (t) => {
|
|
10
|
+
http.globalAgent.destroy = () => {
|
|
11
|
+
t.fail()
|
|
12
|
+
}
|
|
13
|
+
const instance = Fastify()
|
|
14
|
+
t.teardown(instance.close.bind(instance))
|
|
15
|
+
instance.get('/', (request, reply) => {
|
|
16
|
+
reply.from()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const target = http.createServer((req, res) => {
|
|
20
|
+
t.pass('request proxied')
|
|
21
|
+
t.equal(req.method, 'GET')
|
|
22
|
+
t.equal(req.url, '/')
|
|
23
|
+
res.statusCode = 200
|
|
24
|
+
res.end()
|
|
25
|
+
})
|
|
26
|
+
t.teardown(target.close.bind(target))
|
|
27
|
+
|
|
28
|
+
const executionFlow = () => new Promise((resolve) => {
|
|
29
|
+
target.listen({ port: 0 }, (err) => {
|
|
30
|
+
t.error(err)
|
|
31
|
+
|
|
32
|
+
instance.register(From, {
|
|
33
|
+
base: `http://localhost:${target.address().port}`,
|
|
34
|
+
globalAgent: true,
|
|
35
|
+
http: {
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
instance.listen({ port: 0 }, (err) => {
|
|
40
|
+
t.error(err)
|
|
41
|
+
|
|
42
|
+
get(
|
|
43
|
+
`http://localhost:${instance.server.address().port}`,
|
|
44
|
+
(err, res) => {
|
|
45
|
+
t.error(err)
|
|
46
|
+
t.equal(res.statusCode, 200)
|
|
47
|
+
resolve()
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
await executionFlow()
|
|
55
|
+
|
|
56
|
+
target.close()
|
|
57
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const From = require('..')
|
|
6
|
+
const https = require('https')
|
|
7
|
+
const get = require('simple-get').concat
|
|
8
|
+
|
|
9
|
+
const fs = require('fs')
|
|
10
|
+
const path = require('path')
|
|
11
|
+
const certs = {
|
|
12
|
+
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
13
|
+
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
test('https global agent is used, but not destroyed', async (t) => {
|
|
17
|
+
https.globalAgent.destroy = () => {
|
|
18
|
+
t.fail()
|
|
19
|
+
}
|
|
20
|
+
const instance = Fastify({
|
|
21
|
+
https: certs
|
|
22
|
+
})
|
|
23
|
+
t.teardown(instance.close.bind(instance))
|
|
24
|
+
instance.get('/', (request, reply) => {
|
|
25
|
+
reply.from()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const target = https.createServer(certs, (req, res) => {
|
|
29
|
+
t.pass('request proxied')
|
|
30
|
+
t.equal(req.method, 'GET')
|
|
31
|
+
t.equal(req.url, '/')
|
|
32
|
+
res.statusCode = 200
|
|
33
|
+
res.end()
|
|
34
|
+
})
|
|
35
|
+
t.teardown(target.close.bind(target))
|
|
36
|
+
|
|
37
|
+
const executionFlow = () => new Promise((resolve) => {
|
|
38
|
+
target.listen({ port: 0 }, (err) => {
|
|
39
|
+
t.error(err)
|
|
40
|
+
|
|
41
|
+
instance.register(From, {
|
|
42
|
+
base: `https://localhost:${target.address().port}`,
|
|
43
|
+
globalAgent: true,
|
|
44
|
+
http: {
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
instance.listen({ port: 0 }, (err) => {
|
|
49
|
+
t.error(err)
|
|
50
|
+
|
|
51
|
+
get(
|
|
52
|
+
{
|
|
53
|
+
url: `https://localhost:${instance.server.address().port}`,
|
|
54
|
+
rejectUnauthorized: false
|
|
55
|
+
},
|
|
56
|
+
(err, res) => {
|
|
57
|
+
t.error(err)
|
|
58
|
+
t.equal(res.statusCode, 200)
|
|
59
|
+
resolve()
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
await executionFlow()
|
|
67
|
+
|
|
68
|
+
target.close()
|
|
69
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const http = require('http')
|
|
6
|
+
const get = require('simple-get').concat
|
|
7
|
+
const undici = require('undici')
|
|
8
|
+
const From = require('..')
|
|
9
|
+
|
|
10
|
+
test('undici global agent is used, but not destroyed', async (t) => {
|
|
11
|
+
const mockAgent = new undici.Agent()
|
|
12
|
+
mockAgent.destroy = () => {
|
|
13
|
+
t.fail()
|
|
14
|
+
}
|
|
15
|
+
undici.setGlobalDispatcher(mockAgent)
|
|
16
|
+
const instance = Fastify()
|
|
17
|
+
|
|
18
|
+
t.teardown(instance.close.bind(instance))
|
|
19
|
+
|
|
20
|
+
const target = http.createServer((req, res) => {
|
|
21
|
+
res.statusCode = 200
|
|
22
|
+
res.end()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
instance.get('/', (request, reply) => {
|
|
26
|
+
reply.from()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
t.teardown(target.close.bind(target))
|
|
30
|
+
|
|
31
|
+
const executionFlow = () => new Promise((resolve) => {
|
|
32
|
+
target.listen({ port: 0 }, (err) => {
|
|
33
|
+
t.error(err)
|
|
34
|
+
|
|
35
|
+
instance.register(From, {
|
|
36
|
+
base: `http://localhost:${target.address().port}`,
|
|
37
|
+
globalAgent: true
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
instance.listen({ port: 0 }, (err) => {
|
|
41
|
+
t.error(err)
|
|
42
|
+
|
|
43
|
+
get(
|
|
44
|
+
`http://localhost:${instance.server.address().port}`,
|
|
45
|
+
(err, res) => {
|
|
46
|
+
t.error(err)
|
|
47
|
+
t.equal(res.statusCode, 200)
|
|
48
|
+
|
|
49
|
+
get(
|
|
50
|
+
`http://localhost:${instance.server.address().port}`,
|
|
51
|
+
(err, res) => {
|
|
52
|
+
t.error(err)
|
|
53
|
+
t.equal(res.statusCode, 200)
|
|
54
|
+
resolve()
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
await executionFlow()
|
|
64
|
+
|
|
65
|
+
target.close()
|
|
66
|
+
})
|
package/types/index.d.ts
CHANGED