@fastify/reply-from 7.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.
Files changed (88) hide show
  1. package/.github/dependabot.yml +13 -0
  2. package/.github/stale.yml +21 -0
  3. package/.github/workflows/ci.yml +60 -0
  4. package/.taprc +5 -0
  5. package/LICENSE +21 -0
  6. package/README.md +335 -0
  7. package/example.js +36 -0
  8. package/index.d.ts +99 -0
  9. package/index.js +262 -0
  10. package/lib/request.js +288 -0
  11. package/lib/utils.js +81 -0
  12. package/package.json +70 -0
  13. package/test/async-route-handler.js +50 -0
  14. package/test/base-get.js +48 -0
  15. package/test/base-path.js +38 -0
  16. package/test/base-querystring.js +48 -0
  17. package/test/build-url.js +69 -0
  18. package/test/core-with-path-in-base.js +50 -0
  19. package/test/custom-undici-instance.js +77 -0
  20. package/test/fastify-multipart-incompatibility.js +90 -0
  21. package/test/fixtures/fastify.cert +19 -0
  22. package/test/fixtures/fastify.key +27 -0
  23. package/test/fixtures/file.txt +1 -0
  24. package/test/full-get.js +45 -0
  25. package/test/full-https-get.js +55 -0
  26. package/test/full-post-extended-content-type.js +59 -0
  27. package/test/full-post-http2.js +49 -0
  28. package/test/full-post-stream-core.js +66 -0
  29. package/test/full-post-stream.js +64 -0
  30. package/test/full-post.js +56 -0
  31. package/test/full-querystring-rewrite-option-complex.js +48 -0
  32. package/test/full-querystring-rewrite-option-function.js +51 -0
  33. package/test/full-querystring-rewrite-option.js +48 -0
  34. package/test/full-querystring-rewrite-string.js +46 -0
  35. package/test/full-querystring-rewrite.js +46 -0
  36. package/test/full-querystring.js +46 -0
  37. package/test/full-rewrite-body-content-type.js +59 -0
  38. package/test/full-rewrite-body-http.js +63 -0
  39. package/test/full-rewrite-body-to-empty-string.js +61 -0
  40. package/test/full-rewrite-body-to-null.js +61 -0
  41. package/test/full-rewrite-body.js +61 -0
  42. package/test/get-upstream-http.js +70 -0
  43. package/test/get-upstream-undici.js +45 -0
  44. package/test/get-with-body.js +55 -0
  45. package/test/head-with-body.js +57 -0
  46. package/test/host-header.js +67 -0
  47. package/test/http-agents.js +55 -0
  48. package/test/http-http2.js +50 -0
  49. package/test/http-invalid-target.js +35 -0
  50. package/test/http-retry.js +109 -0
  51. package/test/http-timeout.js +56 -0
  52. package/test/http2-http2.js +57 -0
  53. package/test/http2-https.js +80 -0
  54. package/test/http2-invalid-target.js +36 -0
  55. package/test/http2-target-crash.js +53 -0
  56. package/test/http2-target-multi-crash.js +60 -0
  57. package/test/http2-timeout.js +92 -0
  58. package/test/https-agents.js +67 -0
  59. package/test/index.test-d.ts +136 -0
  60. package/test/modifyCoreObjects-false.js +48 -0
  61. package/test/no-body-opts-with-get.js +49 -0
  62. package/test/no-body-opts-with-head.js +51 -0
  63. package/test/no-stream-body-option.js +58 -0
  64. package/test/on-error.js +62 -0
  65. package/test/onResponse.js +48 -0
  66. package/test/padded-body.js +64 -0
  67. package/test/post-formbody.js +59 -0
  68. package/test/post-plain-text.js +56 -0
  69. package/test/post-with-custom-encoded-contenttype.js +65 -0
  70. package/test/retry-on-503.js +101 -0
  71. package/test/rewrite-headers.js +52 -0
  72. package/test/rewrite-request-headers.js +47 -0
  73. package/test/transform-body.js +61 -0
  74. package/test/undici-agent.js +77 -0
  75. package/test/undici-body.js +70 -0
  76. package/test/undici-options.js +73 -0
  77. package/test/undici-retry.js +109 -0
  78. package/test/undici-timeout-body-partial.js +60 -0
  79. package/test/undici-timeout-body.js +63 -0
  80. package/test/undici-timeout.js +61 -0
  81. package/test/undici-with-path-in-base.js +50 -0
  82. package/test/undici.js +50 -0
  83. package/test/unexpected-error.js +46 -0
  84. package/test/unix-http-undici-from.js +51 -0
  85. package/test/unix-http-undici.js +62 -0
  86. package/test/unix-http.js +65 -0
  87. package/test/unix-https-undici.js +71 -0
  88. package/test/unix-https.js +71 -0
@@ -0,0 +1,101 @@
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 got = require('got')
8
+
9
+ function createTargetServer (withRetryAfterHeader, stopAfter = 1) {
10
+ let requestCount = 0
11
+ return http.createServer((req, res) => {
12
+ if (requestCount++ < stopAfter) {
13
+ res.statusCode = 503
14
+ res.setHeader('Content-Type', 'text/plain')
15
+ if (withRetryAfterHeader) {
16
+ res.setHeader('Retry-After', 100)
17
+ }
18
+ return res.end('This Service is Unavailable')
19
+ }
20
+ res.statusCode = 205
21
+ res.setHeader('Content-Type', 'text/plain')
22
+ return res.end(`Hello World ${requestCount}!`)
23
+ })
24
+ }
25
+
26
+ test('Should retry on 503 HTTP error', async function (t) {
27
+ t.plan(3)
28
+ const target = createTargetServer()
29
+ await target.listen(0)
30
+ t.teardown(target.close.bind(target))
31
+
32
+ const instance = Fastify()
33
+
34
+ instance.register(From, {
35
+ base: `http://localhost:${target.address().port}`
36
+ })
37
+
38
+ instance.get('/', (request, reply) => {
39
+ reply.from()
40
+ })
41
+
42
+ t.teardown(instance.close.bind(instance))
43
+ await instance.listen(0)
44
+
45
+ const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 0 })
46
+ t.equal(res.headers['content-type'], 'text/plain')
47
+ t.equal(res.statusCode, 205)
48
+ t.equal(res.body.toString(), 'Hello World 2!')
49
+ })
50
+
51
+ test('Should retry on 503 HTTP error with Retry-After response header', async function (t) {
52
+ t.plan(3)
53
+ const target = createTargetServer(true)
54
+ await target.listen(0)
55
+ t.teardown(target.close.bind(target))
56
+
57
+ const instance = Fastify()
58
+
59
+ instance.register(From, {
60
+ base: `http://localhost:${target.address().port}`
61
+ })
62
+
63
+ instance.get('/', (request, reply) => {
64
+ reply.from()
65
+ })
66
+
67
+ t.teardown(instance.close.bind(instance))
68
+ await instance.listen(0)
69
+
70
+ const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 0 })
71
+ t.equal(res.headers['content-type'], 'text/plain')
72
+ t.equal(res.statusCode, 205)
73
+ t.equal(res.body.toString(), 'Hello World 2!')
74
+ })
75
+
76
+ test('Should abort if server is always returning 503', async function (t) {
77
+ t.plan(2)
78
+ const target = createTargetServer(true, Number.MAX_SAFE_INTEGER)
79
+ await target.listen(0)
80
+ t.teardown(target.close.bind(target))
81
+
82
+ const instance = Fastify()
83
+
84
+ instance.register(From, {
85
+ base: `http://localhost:${target.address().port}`
86
+ })
87
+
88
+ instance.get('/', (request, reply) => {
89
+ reply.from()
90
+ })
91
+
92
+ t.teardown(instance.close.bind(instance))
93
+ await instance.listen(0)
94
+ try {
95
+ await got.get(`http://localhost:${instance.server.address().port}`, { retry: 0 })
96
+ t.fail()
97
+ } catch (err) {
98
+ t.equal(err.response.statusCode, 503)
99
+ t.equal(err.response.body.toString(), 'This Service is Unavailable')
100
+ }
101
+ })
@@ -0,0 +1,52 @@
1
+ 'use strict'
2
+
3
+ const t = 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
+ const instance = Fastify()
10
+ instance.register(From)
11
+
12
+ t.plan(10)
13
+ t.teardown(instance.close.bind(instance))
14
+
15
+ const target = http.createServer((req, res) => {
16
+ t.pass('request proxied')
17
+ t.equal(req.method, 'GET')
18
+ res.statusCode = 205
19
+ res.setHeader('Content-Type', 'text/plain')
20
+ res.setHeader('x-my-header', 'hello!')
21
+ res.end('hello world')
22
+ })
23
+
24
+ instance.get('/', (request, reply) => {
25
+ reply.from(`http://localhost:${target.address().port}`, {
26
+ rewriteHeaders: (headers, req) => {
27
+ t.pass('rewriteHeaders called')
28
+ return {
29
+ 'content-type': headers['content-type'],
30
+ 'x-another-header': 'so headers!'
31
+ }
32
+ }
33
+ })
34
+ })
35
+
36
+ t.teardown(target.close.bind(target))
37
+
38
+ instance.listen(0, (err) => {
39
+ t.error(err)
40
+
41
+ target.listen(0, (err) => {
42
+ t.error(err)
43
+
44
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
45
+ t.error(err)
46
+ t.equal(res.headers['content-type'], 'text/plain')
47
+ t.equal(res.headers['x-another-header'], 'so headers!')
48
+ t.notOk(res.headers['x-my-header'])
49
+ t.equal(res.statusCode, 205)
50
+ })
51
+ })
52
+ })
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const t = 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
+ const instance = Fastify()
10
+ instance.register(From)
11
+
12
+ t.plan(9)
13
+ t.teardown(instance.close.bind(instance))
14
+
15
+ const target = http.createServer((req, res) => {
16
+ t.pass('request proxied')
17
+ t.equal(req.method, 'GET')
18
+ res.statusCode = 205
19
+ res.setHeader('Content-Type', 'text/plain')
20
+ res.end(req.headers.host)
21
+ })
22
+
23
+ instance.get('/', (request, reply) => {
24
+ reply.from(`http://localhost:${target.address().port}`, {
25
+ rewriteRequestHeaders: (originalReq, headers) => {
26
+ t.pass('rewriteRequestHeaders called')
27
+ return Object.assign(headers, { host: 'host-override' })
28
+ }
29
+ })
30
+ })
31
+
32
+ t.teardown(target.close.bind(target))
33
+
34
+ instance.listen(0, (err) => {
35
+ t.error(err)
36
+
37
+ target.listen(0, (err) => {
38
+ t.error(err)
39
+
40
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
41
+ t.error(err)
42
+ t.equal(res.headers['content-type'], 'text/plain')
43
+ t.equal(res.statusCode, 205)
44
+ t.equal(data.toString(), 'host-override')
45
+ })
46
+ })
47
+ })
@@ -0,0 +1,61 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const http = require('http')
7
+ const get = require('simple-get').concat
8
+ const Transform = require('stream').Transform
9
+
10
+ const instance = Fastify()
11
+ instance.register(From)
12
+
13
+ t.plan(9)
14
+ t.teardown(instance.close.bind(instance))
15
+
16
+ const target = http.createServer((req, res) => {
17
+ t.pass('request proxied')
18
+ t.equal(req.method, 'GET')
19
+ res.statusCode = 205
20
+ res.setHeader('Content-Type', 'text/plain')
21
+ res.setHeader('x-my-header', 'hello!')
22
+ res.end('hello world')
23
+ })
24
+
25
+ instance.get('/', (request, reply) => {
26
+ reply.from(`http://localhost:${target.address().port}`, {
27
+ onResponse: (request, reply, res) => {
28
+ reply.send(
29
+ res.pipe(
30
+ new Transform({
31
+ transform: function (chunk, enc, cb) {
32
+ this.push(chunk.toString().toUpperCase())
33
+ cb()
34
+ }
35
+ })
36
+ )
37
+ )
38
+ }
39
+ })
40
+ })
41
+
42
+ t.teardown(target.close.bind(target))
43
+
44
+ instance.listen(0, err => {
45
+ t.error(err)
46
+
47
+ target.listen(0, err => {
48
+ t.error(err)
49
+
50
+ get(
51
+ `http://localhost:${instance.server.address().port}`,
52
+ (err, res, data) => {
53
+ t.error(err)
54
+ t.equal(res.headers['content-type'], 'text/plain')
55
+ t.equal(res.headers['x-my-header'], 'hello!')
56
+ t.equal(res.statusCode, 205)
57
+ t.equal(data.toString(), 'HELLO WORLD')
58
+ }
59
+ )
60
+ })
61
+ })
@@ -0,0 +1,77 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const proxyquire = require('proxyquire')
6
+ const http = require('http')
7
+ const get = require('simple-get').concat
8
+ const undici = require('undici')
9
+ const { getUndiciOptions } = require('../lib/request')
10
+
11
+ t.plan(10)
12
+
13
+ const instance = Fastify()
14
+ t.teardown(instance.close.bind(instance))
15
+
16
+ const target = http.createServer((req, res) => {
17
+ res.statusCode = 200
18
+ res.end('hello world')
19
+ })
20
+
21
+ instance.get('/', (request, reply) => {
22
+ reply.from()
23
+ })
24
+
25
+ t.teardown(target.close.bind(target))
26
+
27
+ target.listen(0, err => {
28
+ t.error(err)
29
+ let poolCreation = 0
30
+
31
+ const From = proxyquire('..', {
32
+ './lib/request.js': proxyquire('../lib/request.js', {
33
+ undici: proxyquire('undici', {
34
+ './lib/agent': proxyquire('undici/lib/agent.js', {
35
+ './pool': class Pool extends undici.Pool {
36
+ constructor (url, options) {
37
+ super(url, options)
38
+ poolCreation++
39
+ }
40
+ }
41
+ })
42
+ })
43
+ })
44
+ })
45
+
46
+ instance.register(From, {
47
+ base: `http://localhost:${target.address().port}`,
48
+ undici: buildUndiciOptions()
49
+ })
50
+
51
+ instance.listen(0, err => {
52
+ t.error(err)
53
+
54
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
55
+ t.error(err)
56
+ t.equal(res.statusCode, 200)
57
+ t.equal(data.toString(), 'hello world')
58
+ t.equal(poolCreation, 1)
59
+
60
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
61
+ t.error(err)
62
+ t.equal(res.statusCode, 200)
63
+ t.equal(data.toString(), 'hello world')
64
+ t.equal(poolCreation, 1)
65
+ })
66
+ })
67
+ })
68
+ })
69
+
70
+ function buildUndiciOptions () {
71
+ return getUndiciOptions({
72
+ connections: 42,
73
+ pipelining: 24,
74
+ keepAliveTimeout: 4242,
75
+ strictContentLength: false
76
+ })
77
+ }
@@ -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('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.post('/', (request, reply) => {
37
+ reply.from(`http://localhost:${target.address().port}`)
38
+ })
39
+
40
+ t.teardown(target.close.bind(target))
41
+
42
+ target.listen(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(0, (err) => {
55
+ t.error(err)
56
+
57
+ get({
58
+ url: `http://localhost:${instance.server.address().port}`,
59
+ method: 'POST',
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
+ })
@@ -0,0 +1,73 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const proxyquire = require('proxyquire')
6
+ const http = require('http')
7
+ const get = require('simple-get').concat
8
+ const undici = require('undici')
9
+ const { getUndiciOptions } = require('../lib/request')
10
+
11
+ const instance = Fastify()
12
+
13
+ t.plan(6)
14
+ t.teardown(instance.close.bind(instance))
15
+
16
+ const target = http.createServer((req, res) => {
17
+ res.statusCode = 200
18
+ res.end('hello world')
19
+ })
20
+
21
+ instance.get('/', (request, reply) => {
22
+ reply.from()
23
+ })
24
+
25
+ t.teardown(target.close.bind(target))
26
+
27
+ target.listen(0, err => {
28
+ t.error(err)
29
+
30
+ const From = proxyquire('..', {
31
+ './lib/request.js': proxyquire('../lib/request.js', {
32
+ undici: undiciProxy
33
+ })
34
+ })
35
+
36
+ instance.register(From, {
37
+ base: `http://localhost:${target.address().port}`,
38
+ undici: buildUndiciOptions()
39
+ })
40
+
41
+ instance.listen(0, err => {
42
+ t.error(err)
43
+
44
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
45
+ t.error(err)
46
+ t.equal(res.statusCode, 200)
47
+ t.equal(data.toString(), 'hello world')
48
+ })
49
+ })
50
+ })
51
+
52
+ function undiciProxy () {}
53
+ undiciProxy.Agent = class Agent extends undici.Agent {
54
+ constructor (opts) {
55
+ super(opts)
56
+ t.strictSame(opts, buildUndiciOptions())
57
+ }
58
+ }
59
+ undiciProxy.Pool = class Pool extends undici.Pool {
60
+ constructor (url, options) {
61
+ super(url, options)
62
+ t.hasStrict(options, buildUndiciOptions())
63
+ }
64
+ }
65
+
66
+ function buildUndiciOptions () {
67
+ return getUndiciOptions({
68
+ connections: 42,
69
+ pipelining: 24,
70
+ keepAliveTimeout: 4242,
71
+ strictContentLength: false
72
+ })
73
+ }
@@ -0,0 +1,109 @@
1
+ 'use strict'
2
+
3
+ const Fastify = require('fastify')
4
+ const From = require('..')
5
+ const got = require('got')
6
+ const { test } = require('tap')
7
+
8
+ let retryNum = 1
9
+
10
+ const target = require('http').createServer(function (req, res) {
11
+ if (retryNum % 2 !== 0) {
12
+ req.socket.destroy()
13
+ } else {
14
+ res.statusCode = 200
15
+ res.setHeader('Content-Type', 'text/plain')
16
+ res.end('hello world')
17
+ }
18
+
19
+ retryNum += 1
20
+ })
21
+
22
+ test('Will retry', async function (t) {
23
+ t.teardown(() => { retryNum = 1 })
24
+
25
+ await target.listen(0)
26
+ t.teardown(target.close.bind(target))
27
+
28
+ const instance = Fastify()
29
+
30
+ instance.register(From, { undici: true })
31
+
32
+ instance.get('/', (request, reply) => {
33
+ reply.from(`http://localhost:${target.address().port}/`, {
34
+ retriesCount: 1,
35
+ onError: (reply, { error }) => {
36
+ t.equal(error.code, 'UND_ERR_SOCKET')
37
+ reply.send(error)
38
+ }
39
+ })
40
+ })
41
+
42
+ await instance.listen(0)
43
+ t.teardown(instance.close.bind(instance))
44
+
45
+ const { statusCode } = await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
46
+ t.equal(statusCode, 200)
47
+ })
48
+
49
+ test('will not retry', async function (t) {
50
+ t.teardown(() => { retryNum = 1 })
51
+
52
+ await target.listen(0)
53
+ t.teardown(target.close.bind(target))
54
+
55
+ const instance = Fastify()
56
+
57
+ instance.register(From, { undici: true })
58
+
59
+ instance.get('/', (request, reply) => {
60
+ reply.from(`http://localhost:${target.address().port}/`, {
61
+ retriesCount: 0,
62
+ onError: (reply, { error }) => {
63
+ t.equal(error.code, 'UND_ERR_SOCKET')
64
+ reply.send(error)
65
+ }
66
+ })
67
+ })
68
+
69
+ await instance.listen(0)
70
+ t.teardown(instance.close.bind(instance))
71
+
72
+ try {
73
+ await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
74
+ t.fail()
75
+ } catch (err) {
76
+ t.equal(err.response.statusCode, 500)
77
+ }
78
+ })
79
+
80
+ test('will not retry unsupported method', async function (t) {
81
+ t.teardown(() => { retryNum = 1 })
82
+
83
+ await target.listen(0)
84
+ t.teardown(target.close.bind(target))
85
+
86
+ const instance = Fastify()
87
+
88
+ instance.register(From, { undici: true, retryMethods: ['DELETE'] })
89
+
90
+ instance.get('/', (request, reply) => {
91
+ reply.from(`http://localhost:${target.address().port}/`, {
92
+ retriesCount: 1,
93
+ onError: (reply, { error }) => {
94
+ t.equal(error.code, 'UND_ERR_SOCKET')
95
+ reply.send(error)
96
+ }
97
+ })
98
+ })
99
+
100
+ await instance.listen(0)
101
+ t.teardown(instance.close.bind(instance))
102
+
103
+ try {
104
+ await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
105
+ t.fail()
106
+ } catch (err) {
107
+ t.equal(err.response.statusCode, 500)
108
+ }
109
+ })
@@ -0,0 +1,60 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const http = require('http')
5
+ const Fastify = require('fastify')
6
+ const From = require('..')
7
+ const got = require('got')
8
+ const FakeTimers = require('@sinonjs/fake-timers')
9
+
10
+ const clock = FakeTimers.createClock()
11
+
12
+ t.autoend(false)
13
+
14
+ const target = http.createServer((req, res) => {
15
+ t.pass('request proxied')
16
+ req.on('data', () => undefined)
17
+ req.on('end', () => {
18
+ res.writeHead(200)
19
+ res.flushHeaders()
20
+ res.write('test')
21
+ clock.setTimeout(() => {
22
+ res.end()
23
+ t.end()
24
+ }, 1000)
25
+ })
26
+ })
27
+
28
+ async function main () {
29
+ await target.listen(0)
30
+
31
+ const instance = Fastify()
32
+ t.teardown(instance.close.bind(instance))
33
+ t.teardown(target.close.bind(target))
34
+
35
+ instance.register(From, {
36
+ base: `http://localhost:${target.address().port}`,
37
+ undici: {
38
+ bodyTimeout: 100
39
+ }
40
+ })
41
+
42
+ instance.get('/', (request, reply) => {
43
+ reply.from()
44
+ })
45
+
46
+ await instance.listen(0)
47
+
48
+ try {
49
+ await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
50
+ } catch (err) {
51
+ t.equal(err.code, 'ECONNRESET')
52
+ t.equal(err.response.statusCode, 200)
53
+ clock.tick(1000)
54
+ return
55
+ }
56
+
57
+ t.fail()
58
+ }
59
+
60
+ main()