@fastify/reply-from 10.0.0 → 11.0.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/.gitattributes +2 -0
- package/.github/workflows/ci.yml +1 -1
- package/.taprc +1 -9
- package/README.md +114 -29
- package/index.js +55 -47
- package/lib/request.js +32 -12
- package/lib/utils.js +8 -0
- package/package.json +25 -22
- package/test/async-route-handler.test.js +1 -1
- package/test/base-get.test.js +1 -1
- package/test/base-querystring.test.js +1 -1
- package/test/build-url.test.js +9 -2
- package/test/core-with-path-in-base.test.js +1 -1
- package/test/custom-undici-instance.test.js +1 -1
- package/test/disable-request-logging.test.js +1 -1
- package/test/fastify-multipart-incompatibility.test.js +3 -3
- package/test/fix-GHSA-v2v2-hph8-q5xp.test.js +47 -0
- package/test/full-delete-http2.test.js +52 -0
- package/test/full-get-test.test.js +1 -1
- package/test/full-https-get.test.js +3 -3
- package/test/full-post-extended-content-type.test.js +1 -1
- package/test/full-post-http2.test.js +2 -0
- package/test/full-post-stream-core.test.js +1 -1
- package/test/full-post-stream.test.js +1 -1
- package/test/full-post.test.js +1 -1
- package/test/full-querystring-rewrite-option-complex.test.js +1 -1
- package/test/full-querystring-rewrite-option-function-request.test.js +58 -0
- package/test/full-querystring-rewrite-option-function.test.js +2 -2
- package/test/full-querystring-rewrite-option.test.js +1 -1
- package/test/full-querystring-rewrite-string.test.js +1 -1
- package/test/full-querystring-rewrite.test.js +1 -1
- package/test/full-querystring.test.js +1 -1
- package/test/full-rewrite-body-content-type.test.js +1 -1
- package/test/full-rewrite-body-http.test.js +1 -1
- package/test/full-rewrite-body-to-empty-string.test.js +1 -1
- package/test/full-rewrite-body-to-null.test.js +1 -1
- package/test/full-rewrite-body.test.js +1 -1
- package/test/get-upstream-http.test.js +1 -1
- package/test/get-upstream-type.test.js +1 -1
- package/test/get-upstream-undici.test.js +1 -1
- package/test/get-with-body.test.js +1 -1
- package/test/head-with-body.test.js +7 -1
- package/test/http-agents.test.js +2 -2
- package/test/http-global-agent.test.js +1 -1
- package/test/http-http2.test.js +2 -0
- package/test/http-retry.test.js +1 -1
- package/test/http-timeout.test.js +0 -2
- package/test/http2-http2.test.js +4 -2
- package/test/http2-https.test.js +2 -2
- package/test/http2-invalid-base.test.js +1 -1
- package/test/http2-timeout-disabled.test.js +85 -0
- package/test/http2-timeout.test.js +2 -0
- package/test/http2-unix-socket.test.js +1 -1
- package/test/https-agents.test.js +4 -4
- package/test/https-global-agent.test.js +3 -3
- package/test/method.test.js +70 -0
- package/test/modifyCoreObjects-false.test.js +1 -1
- package/test/no-body-opts-with-get.test.js +1 -1
- package/test/no-body-opts-with-head.test.js +1 -1
- package/test/no-stream-body-option.test.js +2 -2
- package/test/on-error.test.js +11 -15
- package/test/onResponse.test.js +4 -3
- package/test/padded-body.test.js +1 -1
- package/test/post-formbody.test.js +1 -1
- package/test/post-plain-text.test.js +1 -1
- package/test/post-with-custom-encoded-contenttype.test.js +2 -2
- package/test/post-with-octet-stream.test.js +2 -2
- package/test/retry-on-503.test.js +1 -1
- package/test/retry-with-a-custom-handler.test.js +186 -0
- package/test/rewrite-headers-type.test.js +1 -1
- package/test/rewrite-headers.test.js +1 -1
- package/test/rewrite-request-headers-type.test.js +1 -1
- package/test/rewrite-request-headers.test.js +1 -1
- package/test/transform-body.test.js +3 -3
- package/test/undici-agent.test.js +2 -2
- package/test/undici-body.test.js +1 -1
- package/test/undici-connect-timeout.test.js +10 -14
- package/test/undici-custom-dispatcher.test.js +73 -0
- package/test/undici-global-agent.test.js +1 -1
- package/test/undici-no-destroy.test.js +29 -0
- package/test/undici-options.test.js +1 -1
- package/test/undici-proxy-agent.test.js +81 -0
- package/test/undici-retry.test.js +1 -1
- package/test/undici-timeout-body-partial.test.js +15 -19
- package/test/undici-timeout-body.test.js +13 -17
- package/test/undici-timeout.test.js +11 -15
- package/test/undici-with-path-in-base.test.js +1 -1
- package/test/undici.test.js +1 -1
- package/test/unix-http-undici-from.test.js +3 -3
- package/test/unix-http-undici.test.js +3 -3
- package/test/unix-http.test.js +3 -3
- package/test/unix-https-undici.test.js +4 -4
- package/test/unix-https.test.js +4 -4
- package/types/index.d.ts +37 -19
- package/types/index.test-d.ts +37 -10
package/test/http2-http2.test.js
CHANGED
|
@@ -4,8 +4,8 @@ const h2url = require('h2url')
|
|
|
4
4
|
const t = require('tap')
|
|
5
5
|
const Fastify = require('fastify')
|
|
6
6
|
const From = require('..')
|
|
7
|
-
const fs = require('fs')
|
|
8
|
-
const path = require('path')
|
|
7
|
+
const fs = require('node:fs')
|
|
8
|
+
const path = require('node:path')
|
|
9
9
|
const certs = {
|
|
10
10
|
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
11
11
|
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
|
|
@@ -54,4 +54,6 @@ t.test('http2 -> http2', async (t) => {
|
|
|
54
54
|
t.equal(headers['x-my-header'], 'hello!')
|
|
55
55
|
t.match(headers['content-type'], /application\/json/)
|
|
56
56
|
t.same(JSON.parse(body), { hello: 'world' })
|
|
57
|
+
instance.close()
|
|
58
|
+
target.close()
|
|
57
59
|
})
|
package/test/http2-https.test.js
CHANGED
|
@@ -5,8 +5,8 @@ const t = require('tap')
|
|
|
5
5
|
const Fastify = require('fastify')
|
|
6
6
|
const From = require('..')
|
|
7
7
|
const got = require('got')
|
|
8
|
-
const fs = require('fs')
|
|
9
|
-
const path = require('path')
|
|
8
|
+
const fs = require('node:fs')
|
|
9
|
+
const path = require('node:path')
|
|
10
10
|
const certs = {
|
|
11
11
|
allowHTTP1: true, // fallback support for HTTP1
|
|
12
12
|
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
@@ -7,7 +7,7 @@ const From = require('../index')
|
|
|
7
7
|
test('http2 invalid base', async (t) => {
|
|
8
8
|
const instance = Fastify()
|
|
9
9
|
|
|
10
|
-
await t.rejects(instance.register(From, {
|
|
10
|
+
await t.rejects(async () => instance.register(From, {
|
|
11
11
|
http2: { requestTimeout: 100 }
|
|
12
12
|
}), new Error('Option base is required when http2 is true'))
|
|
13
13
|
})
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const From = require('..')
|
|
6
|
+
const got = require('got')
|
|
7
|
+
|
|
8
|
+
test('http2 request timeout disabled', async (t) => {
|
|
9
|
+
const target = Fastify({ http2: true })
|
|
10
|
+
t.teardown(target.close.bind(target))
|
|
11
|
+
|
|
12
|
+
target.get('/', () => {
|
|
13
|
+
t.pass('request arrives')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
await target.listen({ port: 0 })
|
|
17
|
+
|
|
18
|
+
const instance = Fastify()
|
|
19
|
+
t.teardown(instance.close.bind(instance))
|
|
20
|
+
|
|
21
|
+
instance.register(From, {
|
|
22
|
+
base: `http://localhost:${target.server.address().port}`,
|
|
23
|
+
http2: { requestTimeout: 0, sessionTimeout: 16000 }
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
instance.get('/', (request, reply) => {
|
|
27
|
+
reply.from(`http://localhost:${target.server.address().port}/`)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
await instance.listen({ port: 0 })
|
|
31
|
+
|
|
32
|
+
const result = await Promise.race([
|
|
33
|
+
got.get(`http://localhost:${instance.server.address().port}/`, {
|
|
34
|
+
retry: 0
|
|
35
|
+
}),
|
|
36
|
+
new Promise(resolve => setTimeout(resolve, 11000, 'passed'))
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
// if we wait 11000 ms without a timeout error, we assume disabling the timeout worked
|
|
40
|
+
// 10000 ms is the default timeout
|
|
41
|
+
t.equal(result, 'passed')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('http2 session timeout disabled', async (t) => {
|
|
45
|
+
const target = Fastify({ http2: true })
|
|
46
|
+
|
|
47
|
+
target.get('/', () => {
|
|
48
|
+
t.pass('request arrives')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
await target.listen({ port: 0 })
|
|
52
|
+
|
|
53
|
+
const instance = Fastify()
|
|
54
|
+
|
|
55
|
+
instance.register(From, {
|
|
56
|
+
sessionTimeout: 3000,
|
|
57
|
+
destroyAgent: true,
|
|
58
|
+
base: `http://localhost:${target.server.address().port}`,
|
|
59
|
+
http2: { requestTimeout: 0, sessionTimeout: 0 }
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
instance.get('/', (request, reply) => {
|
|
63
|
+
reply.from(`http://localhost:${target.server.address().port}/`)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
await instance.listen({ port: 0 })
|
|
67
|
+
|
|
68
|
+
const request = got.get(`http://localhost:${instance.server.address().port}/`, {
|
|
69
|
+
retry: 0
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const result = await Promise.race([
|
|
73
|
+
request,
|
|
74
|
+
new Promise(resolve => setTimeout(resolve, 4000, 'passed'))
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
// clean up right after the timeout, otherwise test will hang
|
|
78
|
+
request.cancel()
|
|
79
|
+
target.close()
|
|
80
|
+
instance.close()
|
|
81
|
+
|
|
82
|
+
// if we wait 4000 ms without a timeout error, we assume disabling the session timeout for reply-from worked
|
|
83
|
+
// because we pass 3000 ms as session timeout to the Fastify options itself
|
|
84
|
+
t.equal(result, 'passed')
|
|
85
|
+
})
|
|
@@ -122,4 +122,6 @@ test('http2 sse removes request and session timeout test', async (t) => {
|
|
|
122
122
|
|
|
123
123
|
const { statusCode } = await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
|
|
124
124
|
t.equal(statusCode, 200)
|
|
125
|
+
instance.close()
|
|
126
|
+
target.close()
|
|
125
127
|
})
|
|
@@ -9,7 +9,7 @@ test('throw an error if http2 is used with a Unix socket destination', async t =
|
|
|
9
9
|
|
|
10
10
|
const instance = Fastify()
|
|
11
11
|
|
|
12
|
-
await t.rejects(instance.register(From, {
|
|
12
|
+
await t.rejects(async () => instance.register(From, {
|
|
13
13
|
base: 'unix+http://localhost:1337',
|
|
14
14
|
http2: { requestTimeout: 100 }
|
|
15
15
|
}), new Error('Unix socket destination is not supported when http2 is true'))
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const http = require('http')
|
|
7
|
-
const https = require('https')
|
|
6
|
+
const http = require('node:http')
|
|
7
|
+
const https = require('node:https')
|
|
8
8
|
const get = require('simple-get').concat
|
|
9
9
|
|
|
10
|
-
const fs = require('fs')
|
|
11
|
-
const path = require('path')
|
|
10
|
+
const fs = require('node:fs')
|
|
11
|
+
const path = require('node:path')
|
|
12
12
|
const certs = {
|
|
13
13
|
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
14
14
|
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const https = require('https')
|
|
6
|
+
const https = require('node:https')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
8
|
|
|
9
|
-
const fs = require('fs')
|
|
10
|
-
const path = require('path')
|
|
9
|
+
const fs = require('node:fs')
|
|
10
|
+
const path = require('node:path')
|
|
11
11
|
const certs = {
|
|
12
12
|
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
13
13
|
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const t = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const From = require('..')
|
|
6
|
+
const http = require('node:http')
|
|
7
|
+
const get = require('simple-get').concat
|
|
8
|
+
|
|
9
|
+
const instance = Fastify()
|
|
10
|
+
|
|
11
|
+
t.plan(9)
|
|
12
|
+
t.teardown(instance.close.bind(instance))
|
|
13
|
+
|
|
14
|
+
const bodyString = JSON.stringify({ hello: 'world' })
|
|
15
|
+
|
|
16
|
+
const parsedLength = Buffer.byteLength(bodyString)
|
|
17
|
+
|
|
18
|
+
const target = http.createServer((req, res) => {
|
|
19
|
+
t.pass('request proxied')
|
|
20
|
+
t.equal(req.method, 'POST')
|
|
21
|
+
t.equal(req.headers['content-type'], 'application/json')
|
|
22
|
+
t.same(req.headers['content-length'], parsedLength)
|
|
23
|
+
let data = ''
|
|
24
|
+
req.setEncoding('utf8')
|
|
25
|
+
req.on('data', (d) => {
|
|
26
|
+
data += d
|
|
27
|
+
})
|
|
28
|
+
req.on('end', () => {
|
|
29
|
+
t.same(JSON.parse(data), { hello: 'world' })
|
|
30
|
+
res.statusCode = 200
|
|
31
|
+
res.setHeader('content-type', 'application/json')
|
|
32
|
+
res.end(JSON.stringify({ something: 'else' }))
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
instance.patch('/', (request, reply) => {
|
|
37
|
+
reply.from(`http://localhost:${target.address().port}`, { method: 'POST' })
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
t.teardown(target.close.bind(target))
|
|
41
|
+
|
|
42
|
+
target.listen({ port: 0 }, (err) => {
|
|
43
|
+
t.error(err)
|
|
44
|
+
|
|
45
|
+
instance.addContentTypeParser('application/json', function (req, payload, done) {
|
|
46
|
+
done(null, payload)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
instance.register(From, {
|
|
50
|
+
base: `http://localhost:${target.address().port}`,
|
|
51
|
+
undici: true
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
instance.listen({ port: 0 }, (err) => {
|
|
55
|
+
t.error(err)
|
|
56
|
+
|
|
57
|
+
get({
|
|
58
|
+
url: `http://localhost:${instance.server.address().port}`,
|
|
59
|
+
method: 'PATCH',
|
|
60
|
+
headers: {
|
|
61
|
+
'content-type': 'application/json'
|
|
62
|
+
},
|
|
63
|
+
body: bodyString
|
|
64
|
+
}, (err, res, data) => {
|
|
65
|
+
t.error(err)
|
|
66
|
+
const parsed = JSON.parse(data)
|
|
67
|
+
t.same(parsed, { something: 'else' })
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const http = require('http')
|
|
6
|
+
const http = require('node:http')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
|
-
const Readable = require('stream').Readable
|
|
8
|
+
const Readable = require('node:stream').Readable
|
|
9
9
|
|
|
10
10
|
const instance = Fastify()
|
|
11
11
|
instance.register(From)
|
package/test/on-error.test.js
CHANGED
|
@@ -8,21 +8,19 @@ const FakeTimers = require('@sinonjs/fake-timers')
|
|
|
8
8
|
|
|
9
9
|
const clock = FakeTimers.createClock()
|
|
10
10
|
|
|
11
|
-
t.
|
|
11
|
+
t.test('on-error', async (t) => {
|
|
12
|
+
const target = Fastify()
|
|
13
|
+
t.teardown(target.close.bind(target))
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
t.
|
|
15
|
+
target.get('/', (request, reply) => {
|
|
16
|
+
t.pass('request arrives')
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
t.end()
|
|
22
|
-
}, 1000)
|
|
23
|
-
})
|
|
18
|
+
clock.setTimeout(() => {
|
|
19
|
+
reply.status(200).send('hello world')
|
|
20
|
+
t.end()
|
|
21
|
+
}, 1000)
|
|
22
|
+
})
|
|
24
23
|
|
|
25
|
-
async function main () {
|
|
26
24
|
await target.listen({ port: 0 })
|
|
27
25
|
|
|
28
26
|
const instance = Fastify()
|
|
@@ -63,6 +61,4 @@ async function main () {
|
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
t.fail()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
main()
|
|
64
|
+
})
|
package/test/onResponse.test.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const http = require('http')
|
|
6
|
+
const http = require('node:http')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
8
|
|
|
9
9
|
const instance = Fastify()
|
|
10
10
|
instance.register(From)
|
|
11
11
|
|
|
12
|
-
t.plan(
|
|
12
|
+
t.plan(9)
|
|
13
13
|
t.teardown(instance.close.bind(instance))
|
|
14
14
|
|
|
15
15
|
const target = http.createServer((req, res) => {
|
|
@@ -22,8 +22,9 @@ const target = http.createServer((req, res) => {
|
|
|
22
22
|
instance.get('/', (request1, reply) => {
|
|
23
23
|
reply.from(`http://localhost:${target.address().port}`, {
|
|
24
24
|
onResponse: (request2, reply, res) => {
|
|
25
|
+
t.equal(res.statusCode, 200)
|
|
25
26
|
t.equal(request1.raw, request2.raw)
|
|
26
|
-
reply.send(res)
|
|
27
|
+
reply.send(res.stream)
|
|
27
28
|
}
|
|
28
29
|
})
|
|
29
30
|
})
|
package/test/padded-body.test.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const http = require('http')
|
|
6
|
+
const http = require('node:http')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
|
-
const { parse } = require('querystring')
|
|
8
|
+
const { parse } = require('node:querystring')
|
|
9
9
|
|
|
10
10
|
const instance = Fastify()
|
|
11
11
|
instance.register(From, {
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const test = require('tap').test
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('../index')
|
|
6
|
-
const http = require('http')
|
|
6
|
+
const http = require('node:http')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
|
-
const { parse } = require('querystring')
|
|
8
|
+
const { parse } = require('node:querystring')
|
|
9
9
|
|
|
10
10
|
test('with explicitly set content-type application/octet-stream', t => {
|
|
11
11
|
const instance = Fastify()
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const From = require('..')
|
|
6
|
+
const http = require('node:http')
|
|
7
|
+
const got = require('got')
|
|
8
|
+
|
|
9
|
+
function serverWithCustomError (stopAfter, statusCodeToFailOn, closeSocket) {
|
|
10
|
+
let requestCount = 0
|
|
11
|
+
return http.createServer((req, res) => {
|
|
12
|
+
if (requestCount++ < stopAfter) {
|
|
13
|
+
if (closeSocket) req.socket.end()
|
|
14
|
+
res.statusCode = statusCodeToFailOn
|
|
15
|
+
res.setHeader('Content-Type', 'text/plain')
|
|
16
|
+
return res.end('This Service is Unavailable')
|
|
17
|
+
} else {
|
|
18
|
+
res.statusCode = 205
|
|
19
|
+
res.setHeader('Content-Type', 'text/plain')
|
|
20
|
+
return res.end(`Hello World ${requestCount}!`)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function setupServer (t, fromOptions = {}, statusCodeToFailOn = 500, stopAfter = 4, closeSocket = false) {
|
|
26
|
+
const target = serverWithCustomError(stopAfter, statusCodeToFailOn, closeSocket)
|
|
27
|
+
|
|
28
|
+
await target.listen({ port: 0 })
|
|
29
|
+
t.teardown(target.close.bind(target))
|
|
30
|
+
|
|
31
|
+
const instance = Fastify()
|
|
32
|
+
instance.register(From, {
|
|
33
|
+
base: `http://localhost:${target.address().port}`
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
instance.get('/', (request, reply) => {
|
|
37
|
+
reply.from(`http://localhost:${target.address().port}`, fromOptions)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
t.teardown(instance.close.bind(instance))
|
|
41
|
+
await instance.listen({ port: 0 })
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
instance
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
test('a 500 status code with no custom handler should fail', async (t) => {
|
|
49
|
+
const { instance } = await setupServer(t)
|
|
50
|
+
|
|
51
|
+
let errorMessage
|
|
52
|
+
try {
|
|
53
|
+
await got.get(`http://localhost:${instance.server.address().port}`, { retry: 3 })
|
|
54
|
+
} catch (error) {
|
|
55
|
+
errorMessage = error.message
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
t.equal(errorMessage, 'Response code 500 (Internal Server Error)')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test("a server 500's with a custom handler and should revive", async (t) => {
|
|
62
|
+
const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay }) => {
|
|
63
|
+
const defaultDelay = getDefaultDelay()
|
|
64
|
+
if (defaultDelay) return defaultDelay
|
|
65
|
+
|
|
66
|
+
if (res && res.statusCode === 500 && req.method === 'GET') {
|
|
67
|
+
return 0.1
|
|
68
|
+
}
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { instance } = await setupServer(t, { retryDelay: customRetryLogic })
|
|
73
|
+
|
|
74
|
+
const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
|
|
75
|
+
|
|
76
|
+
t.equal(res.headers['content-type'], 'text/plain')
|
|
77
|
+
t.equal(res.statusCode, 205)
|
|
78
|
+
t.equal(res.body.toString(), 'Hello World 5!')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('custom retry does not invoke the default delay causing a 501', async (t) => {
|
|
82
|
+
// the key here is our retryDelay doesn't register the deefault handler and as a result it doesn't work
|
|
83
|
+
const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay }) => {
|
|
84
|
+
if (res && res.statusCode === 500 && req.method === 'GET') {
|
|
85
|
+
return 0
|
|
86
|
+
}
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const { instance } = await setupServer(t, { retryDelay: customRetryLogic }, 501)
|
|
91
|
+
|
|
92
|
+
let errorMessage
|
|
93
|
+
try {
|
|
94
|
+
await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
|
|
95
|
+
} catch (error) {
|
|
96
|
+
errorMessage = error.message
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
t.equal(errorMessage, 'Response code 501 (Not Implemented)')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('custom retry delay functions can invoke the default delay', async (t) => {
|
|
103
|
+
const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay }) => {
|
|
104
|
+
// registering the default retry logic for non 500 errors if it occurs
|
|
105
|
+
const defaultDelay = getDefaultDelay()
|
|
106
|
+
if (defaultDelay) return defaultDelay
|
|
107
|
+
|
|
108
|
+
if (res && res.statusCode === 500 && req.method === 'GET') {
|
|
109
|
+
return 0.1
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const { instance } = await setupServer(t, { retryDelay: customRetryLogic }, 500)
|
|
116
|
+
|
|
117
|
+
const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
|
|
118
|
+
|
|
119
|
+
t.equal(res.headers['content-type'], 'text/plain')
|
|
120
|
+
t.equal(res.statusCode, 205)
|
|
121
|
+
t.equal(res.body.toString(), 'Hello World 5!')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('custom retry delay function inspects the err paramater', async (t) => {
|
|
125
|
+
const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay }) => {
|
|
126
|
+
if (err && (err.code === 'UND_ERR_SOCKET' || err.code === 'ECONNRESET')) {
|
|
127
|
+
return 0.1
|
|
128
|
+
}
|
|
129
|
+
return null
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const { instance } = await setupServer(t, { retryDelay: customRetryLogic }, 500, 4, true)
|
|
133
|
+
|
|
134
|
+
const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
|
|
135
|
+
|
|
136
|
+
t.equal(res.headers['content-type'], 'text/plain')
|
|
137
|
+
t.equal(res.statusCode, 205)
|
|
138
|
+
t.equal(res.body.toString(), 'Hello World 5!')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('we can exceed our retryCount and introspect attempts independently', async (t) => {
|
|
142
|
+
const attemptCounter = []
|
|
143
|
+
|
|
144
|
+
const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay }) => {
|
|
145
|
+
attemptCounter.push(attempt)
|
|
146
|
+
|
|
147
|
+
if (err && (err.code === 'UND_ERR_SOCKET' || err.code === 'ECONNRESET')) {
|
|
148
|
+
return 0.1
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return null
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const { instance } = await setupServer(t, { retryDelay: customRetryLogic }, 500, 4, true)
|
|
155
|
+
|
|
156
|
+
const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
|
|
157
|
+
|
|
158
|
+
t.match(attemptCounter, [0, 1, 2, 3, 4])
|
|
159
|
+
t.equal(res.headers['content-type'], 'text/plain')
|
|
160
|
+
t.equal(res.statusCode, 205)
|
|
161
|
+
t.equal(res.body.toString(), 'Hello World 5!')
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
test('we handle our retries based on the retryCount', async (t) => {
|
|
165
|
+
const attemptCounter = []
|
|
166
|
+
const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay, retriesCount }) => {
|
|
167
|
+
if (retriesCount < attempt) {
|
|
168
|
+
return null
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (res && res.statusCode === 500 && req.method === 'GET') {
|
|
172
|
+
attemptCounter.push(attempt)
|
|
173
|
+
return 0.1
|
|
174
|
+
}
|
|
175
|
+
return null
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const { instance } = await setupServer(t, { retryDelay: customRetryLogic, retriesCount: 2 }, 500)
|
|
179
|
+
|
|
180
|
+
const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
|
|
181
|
+
|
|
182
|
+
t.match(attemptCounter, [0, 1])
|
|
183
|
+
t.equal(res.headers['content-type'], 'text/plain')
|
|
184
|
+
t.equal(res.statusCode, 205)
|
|
185
|
+
t.equal(res.body.toString(), 'Hello World 5!')
|
|
186
|
+
})
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const http = require('http')
|
|
6
|
+
const http = require('node:http')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
|
-
const Transform = require('stream').Transform
|
|
8
|
+
const Transform = require('node:stream').Transform
|
|
9
9
|
|
|
10
10
|
const instance = Fastify()
|
|
11
11
|
instance.register(From)
|
|
@@ -26,7 +26,7 @@ instance.get('/', (request, reply) => {
|
|
|
26
26
|
reply.from(`http://localhost:${target.address().port}`, {
|
|
27
27
|
onResponse: (request, reply, res) => {
|
|
28
28
|
reply.send(
|
|
29
|
-
res.pipe(
|
|
29
|
+
res.stream.pipe(
|
|
30
30
|
new Transform({
|
|
31
31
|
transform: function (chunk, enc, cb) {
|
|
32
32
|
this.push(chunk.toString().toUpperCase())
|