@fastify/reply-from 12.0.2 → 12.2.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/.github/workflows/ci.yml +6 -0
- package/CLAUDE.md +66 -0
- package/LICENSE +4 -1
- package/README.md +24 -0
- package/index.js +12 -1
- package/lib/request.js +16 -6
- package/lib/utils.js +1 -0
- package/package.json +6 -8
- package/test/async-route-handler.test.js +29 -32
- package/test/balanced-pool.test.js +48 -0
- package/test/base-get.test.js +27 -30
- package/test/base-path.test.js +27 -24
- package/test/base-querystring.test.js +27 -30
- package/test/build-url.test.js +17 -15
- package/test/core-with-path-in-base.test.js +30 -33
- package/test/custom-undici-instance.test.js +28 -36
- package/test/disable-request-logging.test.js +38 -52
- package/test/fastify-multipart-incompatibility.test.js +43 -49
- package/test/fix-GHSA-v2v2-hph8-q5xp.test.js +3 -2
- package/test/full-delete-http2.test.js +12 -11
- package/test/full-get-test.test.js +27 -30
- package/test/full-https-get.test.js +30 -30
- package/test/full-post-extended-content-type.test.js +40 -44
- package/test/full-post-http2.test.js +18 -13
- package/test/full-post-stream-core.test.js +39 -43
- package/test/full-post-stream.test.js +39 -43
- package/test/full-post.test.js +36 -38
- package/test/full-querystring-rewrite-option-complex.test.js +27 -31
- package/test/full-querystring-rewrite-option-function-request.test.js +30 -36
- package/test/full-querystring-rewrite-option-function.test.js +30 -33
- package/test/full-querystring-rewrite-option.test.js +28 -31
- package/test/full-querystring-rewrite-string.test.js +27 -30
- package/test/full-querystring-rewrite.test.js +27 -30
- package/test/full-querystring.test.js +27 -30
- package/test/full-rewrite-body-content-type.test.js +37 -41
- package/test/full-rewrite-body-http.test.js +39 -43
- package/test/full-rewrite-body-to-empty-string.test.js +37 -41
- package/test/full-rewrite-body-to-null.test.js +37 -41
- package/test/full-rewrite-body.test.js +39 -43
- package/test/get-upstream-cache.test.js +12 -11
- package/test/get-upstream-http.test.js +35 -41
- package/test/get-upstream-type.test.js +24 -27
- package/test/get-upstream-undici.test.js +23 -26
- package/test/host-header.test.js +22 -18
- package/test/http-agents.test.js +27 -30
- package/test/http-global-agent.test.js +20 -33
- package/test/http-http2.test.js +13 -18
- package/test/http-invalid-target.test.js +13 -17
- package/test/http-retry.test.js +22 -29
- package/test/http-timeout.test.js +87 -27
- package/test/http2-canceled-streams-cleanup.test.js +117 -0
- package/test/http2-http2.test.js +8 -8
- package/test/http2-https.test.js +29 -27
- package/test/http2-invalid-base.test.js +2 -2
- package/test/http2-invalid-target.test.js +13 -17
- package/test/http2-target-crash.test.js +16 -20
- package/test/http2-target-multi-crash.test.js +22 -27
- package/test/http2-timeout-disabled.test.js +20 -15
- package/test/http2-timeout.test.js +94 -43
- package/test/http2-unix-socket.test.js +2 -2
- package/test/https-agents.test.js +31 -30
- package/test/https-global-agent.test.js +22 -31
- package/test/method.test.js +37 -42
- package/test/modifyCoreObjects-false.test.js +27 -30
- package/test/no-body-opts-with-get.test.js +25 -31
- package/test/no-body-opts-with-head.test.js +28 -32
- package/test/no-stream-body-option.test.js +34 -36
- package/test/on-error.test.js +21 -23
- package/test/on-invalid-upstream-response.test.js +30 -37
- package/test/onResponse.test.js +25 -32
- package/test/padded-body.test.js +38 -43
- package/test/post-formbody.test.js +35 -40
- package/test/post-plain-text.test.js +35 -39
- package/test/post-with-custom-encoded-contenttype.test.js +37 -39
- package/test/post-with-octet-stream.test.js +18 -88
- package/test/retry-on-503.test.js +27 -26
- package/test/retry-with-a-custom-handler.test.js +33 -40
- package/test/rewrite-headers-type.test.js +24 -29
- package/test/rewrite-headers.test.js +31 -36
- package/test/rewrite-request-headers-type.test.js +25 -28
- package/test/rewrite-request-headers.test.js +26 -30
- package/test/transform-body.test.js +37 -43
- package/test/undici-agent.test.js +27 -31
- package/test/undici-body.test.js +37 -42
- package/test/undici-chaining.test.js +35 -42
- package/test/undici-connect-timeout.test.js +13 -13
- package/test/undici-custom-dispatcher.test.js +11 -11
- package/test/undici-global-agent.test.js +14 -33
- package/test/undici-no-destroy.test.js +2 -2
- package/test/undici-options.test.js +21 -24
- package/test/undici-proxy-agent.test.js +4 -3
- package/test/undici-retry.test.js +24 -31
- package/test/undici-timeout-body-partial.test.js +14 -16
- package/test/undici-timeout-body.test.js +17 -19
- package/test/undici-timeout.test.js +86 -23
- package/test/undici-with-path-in-base.test.js +28 -31
- package/test/undici.test.js +28 -31
- package/test/unexpected-error.test.js +13 -18
- package/test/unix-http-undici-from.test.js +22 -31
- package/test/unix-http-undici.test.js +32 -40
- package/test/unix-http.test.js +31 -39
- package/test/unix-https-undici.test.js +30 -35
- package/test/unix-https.test.js +35 -40
- package/types/index.d.ts +13 -5
- package/types/index.test-d.ts +6 -6
- package/test/get-with-body.test.js +0 -55
- package/test/head-with-body.test.js +0 -57
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { test } = require('
|
|
3
|
+
const { test } = require('node:test')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
|
+
const { request, Agent } = require('undici')
|
|
5
6
|
const From = require('..')
|
|
6
|
-
const got = require('got')
|
|
7
7
|
const FakeTimers = require('@sinonjs/fake-timers')
|
|
8
8
|
|
|
9
|
-
const clock = FakeTimers.createClock()
|
|
10
|
-
|
|
11
9
|
test('http request timeout', async (t) => {
|
|
10
|
+
const clock = FakeTimers.createClock()
|
|
12
11
|
const target = Fastify()
|
|
13
|
-
t.
|
|
12
|
+
t.after(() => target.close())
|
|
14
13
|
|
|
15
14
|
target.get('/', (_request, reply) => {
|
|
16
|
-
t.
|
|
15
|
+
t.assert.ok('request arrives')
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
setTimeout(() => {
|
|
19
18
|
reply.status(200).send('hello world')
|
|
20
|
-
t.end()
|
|
21
19
|
}, 200)
|
|
20
|
+
|
|
21
|
+
clock.tick(200)
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
await target.listen({ port: 0 })
|
|
25
25
|
|
|
26
26
|
const instance = Fastify()
|
|
27
|
-
t.
|
|
27
|
+
t.after(() => instance.close())
|
|
28
28
|
|
|
29
29
|
instance.register(From, { http: { requestOptions: { timeout: 100 } } })
|
|
30
30
|
|
|
@@ -34,30 +34,86 @@ test('http request timeout', async (t) => {
|
|
|
34
34
|
|
|
35
35
|
await instance.listen({ port: 0 })
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
t.equal(err.response.statusCode, 504)
|
|
41
|
-
t.match(err.response.headers['content-type'], /application\/json/)
|
|
42
|
-
t.same(JSON.parse(err.response.body), {
|
|
43
|
-
statusCode: 504,
|
|
44
|
-
code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
|
|
45
|
-
error: 'Gateway Timeout',
|
|
46
|
-
message: 'Gateway Timeout'
|
|
37
|
+
const result = await request(`http://localhost:${instance.server.address().port}/`, {
|
|
38
|
+
dispatcher: new Agent({
|
|
39
|
+
pipelining: 0
|
|
47
40
|
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
t.assert.strictEqual(result.statusCode, 504)
|
|
44
|
+
t.assert.match(result.headers['content-type'], /application\/json/)
|
|
45
|
+
t.assert.deepStrictEqual(await result.body.json(), {
|
|
46
|
+
statusCode: 504,
|
|
47
|
+
code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
|
|
48
|
+
error: 'Gateway Timeout',
|
|
49
|
+
message: 'Gateway Timeout'
|
|
50
|
+
})
|
|
51
|
+
clock.tick(200)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('http request with specific timeout', async (t) => {
|
|
55
|
+
const clock = FakeTimers.createClock()
|
|
56
|
+
const target = Fastify()
|
|
57
|
+
t.after(() => target.close())
|
|
58
|
+
|
|
59
|
+
target.get('/', (_request, reply) => {
|
|
60
|
+
t.assert.ok('request arrives')
|
|
61
|
+
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
reply.status(200).send('hello world')
|
|
64
|
+
}, 200)
|
|
65
|
+
|
|
48
66
|
clock.tick(200)
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
await target.listen({ port: 0 })
|
|
51
70
|
|
|
52
|
-
|
|
71
|
+
const instance = Fastify()
|
|
72
|
+
t.after(() => instance.close())
|
|
73
|
+
|
|
74
|
+
instance.register(From, { http: { requestOptions: { timeout: 100 } } })
|
|
75
|
+
|
|
76
|
+
instance.get('/success', (_request, reply) => {
|
|
77
|
+
reply.from(`http://localhost:${target.server.address().port}/`, {
|
|
78
|
+
timeout: 300
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
instance.get('/fail', (_request, reply) => {
|
|
82
|
+
reply.from(`http://localhost:${target.server.address().port}/`, {
|
|
83
|
+
timeout: 50
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
await instance.listen({ port: 0 })
|
|
88
|
+
const result = await request(`http://localhost:${instance.server.address().port}/success`, {
|
|
89
|
+
dispatcher: new Agent({
|
|
90
|
+
pipelining: 0
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
t.assert.strictEqual(result.statusCode, 200)
|
|
94
|
+
|
|
95
|
+
const result2 = await request(`http://localhost:${instance.server.address().port}/fail`, {
|
|
96
|
+
dispatcher: new Agent({
|
|
97
|
+
pipelining: 0
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
t.assert.strictEqual(result2.statusCode, 504)
|
|
102
|
+
t.assert.match(result2.headers['content-type'], /application\/json/)
|
|
103
|
+
t.assert.deepStrictEqual(await result2.body.json(), {
|
|
104
|
+
statusCode: 504,
|
|
105
|
+
code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
|
|
106
|
+
error: 'Gateway Timeout',
|
|
107
|
+
message: 'Gateway Timeout'
|
|
108
|
+
})
|
|
53
109
|
})
|
|
54
110
|
|
|
55
111
|
test('http sse removes timeout test', async (t) => {
|
|
56
112
|
const target = Fastify()
|
|
57
|
-
t.
|
|
113
|
+
t.after(() => target.close())
|
|
58
114
|
|
|
59
115
|
target.get('/', (_request, reply) => {
|
|
60
|
-
t.
|
|
116
|
+
t.assert.ok('request arrives')
|
|
61
117
|
|
|
62
118
|
reply.header('content-type', 'text/event-stream').status(200).send('hello world')
|
|
63
119
|
})
|
|
@@ -65,7 +121,7 @@ test('http sse removes timeout test', async (t) => {
|
|
|
65
121
|
await target.listen({ port: 0 })
|
|
66
122
|
|
|
67
123
|
const instance = Fastify()
|
|
68
|
-
t.
|
|
124
|
+
t.after(() => instance.close())
|
|
69
125
|
|
|
70
126
|
instance.register(From, { http: { requestOptions: { timeout: 100 } } })
|
|
71
127
|
|
|
@@ -75,6 +131,10 @@ test('http sse removes timeout test', async (t) => {
|
|
|
75
131
|
|
|
76
132
|
await instance.listen({ port: 0 })
|
|
77
133
|
|
|
78
|
-
const { statusCode } = await
|
|
79
|
-
|
|
134
|
+
const { statusCode } = await request(`http://localhost:${instance.server.address().port}/`, {
|
|
135
|
+
dispatcher: new Agent({
|
|
136
|
+
pipelining: 0
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
t.assert.strictEqual(statusCode, 200)
|
|
80
140
|
})
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const t = require('node:test')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const From = require('..')
|
|
6
|
+
const fs = require('node:fs')
|
|
7
|
+
const path = require('node:path')
|
|
8
|
+
const http2 = require('node:http2')
|
|
9
|
+
const { once } = require('events')
|
|
10
|
+
const certs = {
|
|
11
|
+
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
12
|
+
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
|
|
13
|
+
}
|
|
14
|
+
const { HTTP2_HEADER_STATUS, HTTP2_HEADER_PATH } = http2.constants
|
|
15
|
+
|
|
16
|
+
function makeRequest (client, counter) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
const controller = new AbortController()
|
|
19
|
+
const signal = controller.signal
|
|
20
|
+
const cancelRequestEarly = counter % 2 === 0 // cancel early every other request
|
|
21
|
+
let responseCounter = 0
|
|
22
|
+
|
|
23
|
+
const clientStream = client.request({ [HTTP2_HEADER_PATH]: '/' }, { signal })
|
|
24
|
+
|
|
25
|
+
clientStream.end()
|
|
26
|
+
|
|
27
|
+
clientStream.on('data', chunk => {
|
|
28
|
+
const s = chunk.toString()
|
|
29
|
+
// Sometimes we just get NGHTTP2_ENHANCE_YOUR_CALM internal server errors
|
|
30
|
+
if (s.startsWith('{"statusCode":500')) reject(new Error('got internal server error'))
|
|
31
|
+
else responseCounter++
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
clientStream.on('error', err => {
|
|
35
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
36
|
+
if (responseCounter === 0 && !cancelRequestEarly) {
|
|
37
|
+
// if we didn´t cancel early we should have received at least one response from the target
|
|
38
|
+
// if not, this indicated the stream resource leak
|
|
39
|
+
reject(new Error('no response'))
|
|
40
|
+
} else resolve()
|
|
41
|
+
} else reject(err instanceof Error ? err : new Error(JSON.stringify(err)))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
clientStream.on('end', () => { resolve() })
|
|
45
|
+
|
|
46
|
+
setTimeout(() => { controller.abort() }, cancelRequestEarly ? 20 : 200)
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const httpsOptions = {
|
|
51
|
+
...certs,
|
|
52
|
+
settings: {
|
|
53
|
+
maxConcurrentStreams: 10, // lower the default so we can reproduce the problem quicker
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
t.test('http2 -> http2', async (t) => {
|
|
58
|
+
const instance = Fastify({
|
|
59
|
+
http2: true,
|
|
60
|
+
https: httpsOptions
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
t.after(() => instance.close())
|
|
64
|
+
|
|
65
|
+
const target = http2.createSecureServer(httpsOptions)
|
|
66
|
+
|
|
67
|
+
target.on('stream', (stream, _headers, _flags) => {
|
|
68
|
+
let counter = 0
|
|
69
|
+
let headerSent = false
|
|
70
|
+
|
|
71
|
+
// deliberately delay sending the headers
|
|
72
|
+
const sendData = () => {
|
|
73
|
+
if (!headerSent) {
|
|
74
|
+
stream.respond({ [HTTP2_HEADER_STATUS]: 200, })
|
|
75
|
+
headerSent = true
|
|
76
|
+
}
|
|
77
|
+
stream.write(counter + '\n')
|
|
78
|
+
counter = counter + 1
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const intervalId = setInterval(sendData, 50)
|
|
82
|
+
|
|
83
|
+
// ignore write after end errors
|
|
84
|
+
stream.on('error', _err => { })
|
|
85
|
+
|
|
86
|
+
stream.on('close', () => { clearInterval(intervalId) })
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
instance.get('/', (_request, reply) => {
|
|
90
|
+
reply.from()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
t.after(() => target.close())
|
|
94
|
+
|
|
95
|
+
target.listen()
|
|
96
|
+
await once(target, 'listening')
|
|
97
|
+
|
|
98
|
+
instance.register(From, {
|
|
99
|
+
base: `https://localhost:${target.address().port}`,
|
|
100
|
+
http2: true,
|
|
101
|
+
rejectUnauthorized: false
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const url = await instance.listen({ port: 0 })
|
|
105
|
+
|
|
106
|
+
const client = http2.connect(url, {
|
|
107
|
+
rejectUnauthorized: false,
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// see https://github.com/fastify/fastify-reply-from/issues/424
|
|
111
|
+
// without the bug fix this will fail after about 15 requests
|
|
112
|
+
for (let i = 0; i < 30; i++) { await makeRequest(client, i) }
|
|
113
|
+
|
|
114
|
+
client.close()
|
|
115
|
+
instance.close()
|
|
116
|
+
target.close()
|
|
117
|
+
})
|
package/test/http2-http2.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const h2url = require('h2url')
|
|
4
|
-
const t = require('
|
|
4
|
+
const t = require('node:test')
|
|
5
5
|
const Fastify = require('fastify')
|
|
6
6
|
const From = require('..')
|
|
7
7
|
const fs = require('node:fs')
|
|
@@ -17,14 +17,14 @@ t.test('http2 -> http2', async (t) => {
|
|
|
17
17
|
https: certs
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
t.
|
|
20
|
+
t.after(() => instance.close())
|
|
21
21
|
|
|
22
22
|
const target = Fastify({
|
|
23
23
|
http2: true
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
target.get('/', (_request, reply) => {
|
|
27
|
-
t.
|
|
27
|
+
t.assert.ok('request proxied')
|
|
28
28
|
reply.code(404).header('x-my-header', 'hello!').send({
|
|
29
29
|
hello: 'world'
|
|
30
30
|
})
|
|
@@ -34,7 +34,7 @@ t.test('http2 -> http2', async (t) => {
|
|
|
34
34
|
reply.from()
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
t.
|
|
37
|
+
t.after(() => target.close())
|
|
38
38
|
|
|
39
39
|
await target.listen({ port: 0 })
|
|
40
40
|
|
|
@@ -50,10 +50,10 @@ t.test('http2 -> http2', async (t) => {
|
|
|
50
50
|
url: `https://localhost:${instance.server.address().port}`
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
t.
|
|
54
|
-
t.
|
|
55
|
-
t.match(headers['content-type'], /application\/json/)
|
|
56
|
-
t.
|
|
53
|
+
t.assert.strictEqual(headers[':status'], 404)
|
|
54
|
+
t.assert.strictEqual(headers['x-my-header'], 'hello!')
|
|
55
|
+
t.assert.match(headers['content-type'], /application\/json/)
|
|
56
|
+
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
|
|
57
57
|
instance.close()
|
|
58
58
|
target.close()
|
|
59
59
|
})
|
package/test/http2-https.test.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const h2url = require('h2url')
|
|
4
|
-
const t = require('
|
|
4
|
+
const t = require('node:test')
|
|
5
|
+
const assert = require('node:assert')
|
|
5
6
|
const Fastify = require('fastify')
|
|
7
|
+
const { request, Agent } = require('undici')
|
|
6
8
|
const From = require('..')
|
|
7
|
-
const got = require('got')
|
|
8
9
|
const fs = require('node:fs')
|
|
9
10
|
const path = require('node:path')
|
|
10
11
|
const certs = {
|
|
@@ -18,15 +19,12 @@ const instance = Fastify({
|
|
|
18
19
|
https: certs
|
|
19
20
|
})
|
|
20
21
|
|
|
21
|
-
t.plan(4)
|
|
22
|
-
t.teardown(instance.close.bind(instance))
|
|
23
|
-
|
|
24
22
|
const target = Fastify({
|
|
25
23
|
https: certs
|
|
26
24
|
})
|
|
27
25
|
|
|
28
26
|
target.get('/', (_request, reply) => {
|
|
29
|
-
|
|
27
|
+
assert.ok('request proxied')
|
|
30
28
|
reply.code(404).header('x-my-header', 'hello!').send({
|
|
31
29
|
hello: 'world'
|
|
32
30
|
})
|
|
@@ -36,9 +34,7 @@ instance.get('/', (_request, reply) => {
|
|
|
36
34
|
reply.from()
|
|
37
35
|
})
|
|
38
36
|
|
|
39
|
-
t
|
|
40
|
-
|
|
41
|
-
async function run () {
|
|
37
|
+
async function run (t) {
|
|
42
38
|
await target.listen({ port: 0 })
|
|
43
39
|
|
|
44
40
|
instance.register(From, {
|
|
@@ -48,33 +44,39 @@ async function run () {
|
|
|
48
44
|
|
|
49
45
|
await instance.listen({ port: 0 })
|
|
50
46
|
|
|
51
|
-
t.test('http2 -> https', async (t) => {
|
|
47
|
+
await t.test('http2 -> https', async (t) => {
|
|
48
|
+
t.plan(4)
|
|
52
49
|
const { headers, body } = await h2url.concat({
|
|
53
50
|
url: `https://localhost:${instance.server.address().port}`
|
|
54
51
|
})
|
|
55
52
|
|
|
56
|
-
t.
|
|
57
|
-
t.
|
|
58
|
-
t.match(headers['content-type'], /application\/json/)
|
|
59
|
-
t.
|
|
53
|
+
t.assert.strictEqual(headers[':status'], 404)
|
|
54
|
+
t.assert.strictEqual(headers['x-my-header'], 'hello!')
|
|
55
|
+
t.assert.match(headers['content-type'], /application\/json/)
|
|
56
|
+
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
|
|
60
57
|
})
|
|
61
58
|
|
|
62
|
-
t.test('https -> https', async (t) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
await t.test('https -> https', async (t) => {
|
|
60
|
+
t.plan(4)
|
|
61
|
+
const result = await request(`https://localhost:${instance.server.address().port}`, {
|
|
62
|
+
dispatcher: new Agent({
|
|
63
|
+
connect: {
|
|
66
64
|
rejectUnauthorized: false
|
|
67
65
|
}
|
|
68
66
|
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
t.fail()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
t.assert.strictEqual(result.statusCode, 404)
|
|
70
|
+
t.assert.strictEqual(result.headers['x-my-header'], 'hello!')
|
|
71
|
+
t.assert.match(result.headers['content-type'], /application\/json/)
|
|
72
|
+
t.assert.deepStrictEqual(await result.body.json(), { hello: 'world' })
|
|
77
73
|
})
|
|
78
74
|
}
|
|
79
75
|
|
|
80
|
-
|
|
76
|
+
t.test('http2 -> https', async (t) => {
|
|
77
|
+
t.plan(2)
|
|
78
|
+
t.after(() => instance.close())
|
|
79
|
+
t.after(() => target.close())
|
|
80
|
+
|
|
81
|
+
await run(t)
|
|
82
|
+
})
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { test } = require('
|
|
3
|
+
const { test } = require('node:test')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('../index')
|
|
6
6
|
|
|
7
7
|
test('http2 invalid base', async (t) => {
|
|
8
8
|
const instance = Fastify()
|
|
9
9
|
|
|
10
|
-
await t.rejects(async () => instance.register(From, {
|
|
10
|
+
await t.assert.rejects(async () => instance.register(From, {
|
|
11
11
|
http2: { requestTimeout: 100 }
|
|
12
12
|
}), new Error('Option base is required when http2 is true'))
|
|
13
13
|
})
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { test } = require('
|
|
3
|
+
const { test } = require('node:test')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
|
+
const { request } = require('undici')
|
|
5
6
|
const From = require('..')
|
|
6
|
-
const got = require('got')
|
|
7
7
|
|
|
8
8
|
test('http2 invalid target', async (t) => {
|
|
9
9
|
const instance = Fastify()
|
|
10
10
|
|
|
11
|
-
t.
|
|
11
|
+
t.after(() => instance.close())
|
|
12
12
|
|
|
13
13
|
instance.get('/', (_request, reply) => {
|
|
14
14
|
reply.from()
|
|
@@ -20,18 +20,14 @@ test('http2 invalid target', async (t) => {
|
|
|
20
20
|
|
|
21
21
|
await instance.listen({ port: 0 })
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
t.fail()
|
|
23
|
+
const result = await request(`http://localhost:${instance.server.address().port}`)
|
|
24
|
+
|
|
25
|
+
t.assert.strictEqual(result.statusCode, 503)
|
|
26
|
+
t.assert.match(result.headers['content-type'], /application\/json/)
|
|
27
|
+
t.assert.deepStrictEqual(await result.body.json(), {
|
|
28
|
+
statusCode: 503,
|
|
29
|
+
code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
|
|
30
|
+
error: 'Service Unavailable',
|
|
31
|
+
message: 'Service Unavailable'
|
|
32
|
+
})
|
|
37
33
|
})
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { test } = require('
|
|
3
|
+
const { test } = require('node:test')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
|
+
const { request } = require('undici')
|
|
5
6
|
const From = require('..')
|
|
6
|
-
const got = require('got')
|
|
7
7
|
|
|
8
8
|
test('http -> http2 crash', async (t) => {
|
|
9
9
|
const instance = Fastify()
|
|
10
10
|
|
|
11
|
-
t.
|
|
11
|
+
t.after(() => instance.close())
|
|
12
12
|
|
|
13
13
|
const target = Fastify({
|
|
14
14
|
http2: true
|
|
15
15
|
})
|
|
16
16
|
|
|
17
17
|
target.get('/', (_request, reply) => {
|
|
18
|
-
t.
|
|
18
|
+
t.assert.ok('request proxied')
|
|
19
19
|
reply.code(200).send({
|
|
20
20
|
hello: 'world'
|
|
21
21
|
})
|
|
@@ -25,7 +25,7 @@ test('http -> http2 crash', async (t) => {
|
|
|
25
25
|
reply.from()
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
-
t.
|
|
28
|
+
t.after(() => target.close())
|
|
29
29
|
|
|
30
30
|
await target.listen({ port: 0 })
|
|
31
31
|
|
|
@@ -36,19 +36,15 @@ test('http -> http2 crash', async (t) => {
|
|
|
36
36
|
|
|
37
37
|
await instance.listen({ port: 0 })
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
})
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
t.fail()
|
|
39
|
+
await target.close()
|
|
40
|
+
const result = await request(`http://localhost:${instance.server.address().port}`)
|
|
41
|
+
|
|
42
|
+
t.assert.strictEqual(result.statusCode, 503)
|
|
43
|
+
t.assert.match(result.headers['content-type'], /application\/json/)
|
|
44
|
+
t.assert.deepStrictEqual(await result.body.json(), {
|
|
45
|
+
statusCode: 503,
|
|
46
|
+
code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
|
|
47
|
+
error: 'Service Unavailable',
|
|
48
|
+
message: 'Service Unavailable'
|
|
49
|
+
})
|
|
54
50
|
})
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { test } = require('
|
|
3
|
+
const { test } = require('node:test')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
|
+
const { request } = require('undici')
|
|
5
6
|
const From = require('..')
|
|
6
|
-
const got = require('got')
|
|
7
7
|
|
|
8
8
|
test('http -> http2 crash multiple times', async (t) => {
|
|
9
9
|
const instance = Fastify()
|
|
10
10
|
|
|
11
|
-
t.
|
|
11
|
+
t.after(() => instance.close())
|
|
12
12
|
|
|
13
13
|
instance.get('/', (_request, reply) => {
|
|
14
14
|
reply.from()
|
|
@@ -23,29 +23,24 @@ test('http -> http2 crash multiple times', async (t) => {
|
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
await instance.listen({ port: 0 })
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
message: 'Service Unavailable'
|
|
45
|
-
})
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
t.fail()
|
|
26
|
+
let target = setupTarget()
|
|
27
|
+
await target.listen({ port: 3128 })
|
|
28
|
+
await request(`http://localhost:${instance.server.address().port}`)
|
|
29
|
+
await target.close()
|
|
30
|
+
target = setupTarget()
|
|
31
|
+
await target.listen({ port: 3128 })
|
|
32
|
+
await request(`http://localhost:${instance.server.address().port}`)
|
|
33
|
+
await target.close()
|
|
34
|
+
const result = await request(`http://localhost:${instance.server.address().port}`)
|
|
35
|
+
|
|
36
|
+
t.assert.strictEqual(result.statusCode, 503)
|
|
37
|
+
t.assert.match(result.headers['content-type'], /application\/json/)
|
|
38
|
+
t.assert.deepStrictEqual(await result.body.json(), {
|
|
39
|
+
statusCode: 503,
|
|
40
|
+
code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
|
|
41
|
+
error: 'Service Unavailable',
|
|
42
|
+
message: 'Service Unavailable'
|
|
43
|
+
})
|
|
49
44
|
|
|
50
45
|
function setupTarget () {
|
|
51
46
|
const target = Fastify({
|
|
@@ -53,7 +48,7 @@ test('http -> http2 crash multiple times', async (t) => {
|
|
|
53
48
|
})
|
|
54
49
|
|
|
55
50
|
target.get('/', (request, reply) => {
|
|
56
|
-
t.
|
|
51
|
+
t.assert.ok('request proxied')
|
|
57
52
|
reply.code(200).send({
|
|
58
53
|
hello: 'world'
|
|
59
54
|
})
|