@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,63 @@
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.flushHeaders()
19
+ clock.setTimeout(() => {
20
+ res.end()
21
+ t.end()
22
+ }, 1000)
23
+ })
24
+ })
25
+
26
+ async function main () {
27
+ await target.listen(0)
28
+
29
+ const instance = Fastify()
30
+ t.teardown(instance.close.bind(instance))
31
+ t.teardown(target.close.bind(target))
32
+
33
+ instance.register(From, {
34
+ base: `http://localhost:${target.address().port}`,
35
+ undici: {
36
+ bodyTimeout: 100
37
+ }
38
+ })
39
+
40
+ instance.get('/', (request, reply) => {
41
+ reply.from()
42
+ })
43
+
44
+ await instance.listen(0)
45
+
46
+ try {
47
+ await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
48
+ } catch (err) {
49
+ t.equal(err.response.statusCode, 500)
50
+ t.same(JSON.parse(err.response.body), {
51
+ statusCode: 500,
52
+ code: 'UND_ERR_BODY_TIMEOUT',
53
+ error: 'Internal Server Error',
54
+ message: 'Body Timeout Error'
55
+ })
56
+ clock.tick(1000)
57
+ return
58
+ }
59
+
60
+ t.fail()
61
+ }
62
+
63
+ main()
@@ -0,0 +1,61 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const got = require('got')
7
+ const FakeTimers = require('@sinonjs/fake-timers')
8
+
9
+ const clock = FakeTimers.createClock()
10
+
11
+ t.autoend(false)
12
+
13
+ const target = Fastify()
14
+ t.teardown(target.close.bind(target))
15
+
16
+ target.get('/', (request, reply) => {
17
+ t.pass('request arrives')
18
+
19
+ clock.setTimeout(() => {
20
+ reply.status(200).send('hello world')
21
+ t.end()
22
+ }, 1000)
23
+ })
24
+
25
+ async function main () {
26
+ await target.listen(0)
27
+
28
+ const instance = Fastify()
29
+ t.teardown(instance.close.bind(instance))
30
+
31
+ instance.register(From, {
32
+ base: `http://localhost:${target.server.address().port}`,
33
+ undici: {
34
+ headersTimeout: 100
35
+ }
36
+ })
37
+
38
+ instance.get('/', (request, reply) => {
39
+ reply.from()
40
+ })
41
+
42
+ await instance.listen(0)
43
+
44
+ try {
45
+ await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
46
+ } catch (err) {
47
+ t.equal(err.response.statusCode, 504)
48
+ t.match(err.response.headers['content-type'], /application\/json/)
49
+ t.same(JSON.parse(err.response.body), {
50
+ statusCode: 504,
51
+ error: 'Gateway Timeout',
52
+ message: 'Gateway Timeout'
53
+ })
54
+ clock.tick(1000)
55
+ return
56
+ }
57
+
58
+ t.fail()
59
+ }
60
+
61
+ main()
@@ -0,0 +1,50 @@
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(11)
12
+ t.teardown(instance.close.bind(instance))
13
+
14
+ const target = http.createServer((req, res) => {
15
+ t.pass('request proxied')
16
+ t.equal(req.method, 'GET')
17
+ t.equal(req.url, '/hello')
18
+ t.equal(req.headers.connection, 'keep-alive')
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('/hello')
27
+ })
28
+
29
+ t.teardown(target.close.bind(target))
30
+
31
+ target.listen(0, (err) => {
32
+ t.error(err)
33
+
34
+ instance.register(From, {
35
+ base: `http://localhost:${target.address().port}/hello`,
36
+ undici: true
37
+ })
38
+
39
+ instance.listen(0, (err) => {
40
+ t.error(err)
41
+
42
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
43
+ t.error(err)
44
+ t.equal(res.headers['content-type'], 'text/plain')
45
+ t.equal(res.headers['x-my-header'], 'hello!')
46
+ t.equal(res.statusCode, 205)
47
+ t.equal(data.toString(), 'hello world')
48
+ })
49
+ })
50
+ })
package/test/undici.js ADDED
@@ -0,0 +1,50 @@
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(11)
12
+ t.teardown(instance.close.bind(instance))
13
+
14
+ const target = http.createServer((req, res) => {
15
+ t.pass('request proxied')
16
+ t.equal(req.method, 'GET')
17
+ t.equal(req.url, '/')
18
+ t.equal(req.headers.connection, 'keep-alive')
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()
27
+ })
28
+
29
+ t.teardown(target.close.bind(target))
30
+
31
+ target.listen(0, (err) => {
32
+ t.error(err)
33
+
34
+ instance.register(From, {
35
+ base: `http://localhost:${target.address().port}`,
36
+ undici: true
37
+ })
38
+
39
+ instance.listen(0, (err) => {
40
+ t.error(err)
41
+
42
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
43
+ t.error(err)
44
+ t.equal(res.headers['content-type'], 'text/plain')
45
+ t.equal(res.headers['x-my-header'], 'hello!')
46
+ t.equal(res.statusCode, 205)
47
+ t.equal(data.toString(), 'hello world')
48
+ })
49
+ })
50
+ })
@@ -0,0 +1,46 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const got = require('got')
6
+ const proxyquire = require('proxyquire')
7
+
8
+ // Stub request to throw error 'foo'
9
+ const From = proxyquire('..', {
10
+ './lib/request': function () {
11
+ return {
12
+ request: (opts, callback) => { callback(new Error('foo')) },
13
+ close: () => {}
14
+ }
15
+ }
16
+ })
17
+
18
+ test('unexpected error renders 500', async (t) => {
19
+ const instance = Fastify()
20
+
21
+ t.teardown(instance.close.bind(instance))
22
+
23
+ instance.get('/', (request, reply) => {
24
+ reply.code(201)
25
+ reply.from()
26
+ })
27
+ instance.register(From, {
28
+ base: 'http://localhost'
29
+ })
30
+
31
+ await instance.listen(0)
32
+
33
+ try {
34
+ await got(`http://localhost:${instance.server.address().port}`)
35
+ } catch (err) {
36
+ t.equal(err.response.statusCode, 500)
37
+ t.match(err.response.headers['content-type'], /application\/json/)
38
+ t.same(JSON.parse(err.response.body), {
39
+ statusCode: 500,
40
+ error: 'Internal Server Error',
41
+ message: 'foo'
42
+ })
43
+ return
44
+ }
45
+ t.fail()
46
+ })
@@ -0,0 +1,51 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const fs = require('fs')
7
+ const querystring = require('querystring')
8
+ const http = require('http')
9
+ const get = require('simple-get').concat
10
+
11
+ if (process.platform === 'win32') {
12
+ t.pass()
13
+ process.exit(0)
14
+ }
15
+
16
+ const instance = Fastify()
17
+ instance.register(From)
18
+
19
+ t.plan(4)
20
+ t.teardown(instance.close.bind(instance))
21
+
22
+ const socketPath = `${__filename}.socket`
23
+
24
+ try {
25
+ fs.unlinkSync(socketPath)
26
+ } catch (_) {
27
+ }
28
+
29
+ const target = http.createServer((req, res) => {
30
+ t.fail('no response')
31
+ res.end()
32
+ })
33
+
34
+ instance.get('/', (request, reply) => {
35
+ reply.from(`unix+http://${querystring.escape(socketPath)}/hello`)
36
+ })
37
+
38
+ t.teardown(target.close.bind(target))
39
+
40
+ instance.listen(0, (err) => {
41
+ t.error(err)
42
+
43
+ target.listen(socketPath, (err) => {
44
+ t.error(err)
45
+
46
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
47
+ t.error(err)
48
+ t.equal(res.statusCode, 500)
49
+ })
50
+ })
51
+ })
@@ -0,0 +1,62 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const fs = require('fs')
7
+ const querystring = require('querystring')
8
+ const http = require('http')
9
+ const get = require('simple-get').concat
10
+
11
+ if (process.platform === 'win32') {
12
+ t.pass()
13
+ process.exit(0)
14
+ }
15
+
16
+ const socketPath = `${__filename}.socket`
17
+ const upstream = `unix+http://${querystring.escape(socketPath)}/`
18
+
19
+ const instance = Fastify()
20
+ instance.register(From, {
21
+ base: upstream
22
+ })
23
+
24
+ t.plan(10)
25
+ t.teardown(instance.close.bind(instance))
26
+
27
+ try {
28
+ fs.unlinkSync(socketPath)
29
+ } catch (_) {
30
+ }
31
+
32
+ const target = http.createServer((req, res) => {
33
+ t.pass('request proxied')
34
+ t.equal(req.method, 'GET')
35
+ t.equal(req.url, '/hello')
36
+ res.statusCode = 205
37
+ res.setHeader('Content-Type', 'text/plain')
38
+ res.setHeader('x-my-header', 'hello!')
39
+ res.end('hello world')
40
+ })
41
+
42
+ instance.get('/', (request, reply) => {
43
+ reply.from('hello')
44
+ })
45
+
46
+ t.teardown(target.close.bind(target))
47
+
48
+ instance.listen(0, (err) => {
49
+ t.error(err)
50
+
51
+ target.listen(socketPath, (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.headers['content-type'], 'text/plain')
57
+ t.equal(res.headers['x-my-header'], 'hello!')
58
+ t.equal(res.statusCode, 205)
59
+ t.equal(data.toString(), 'hello world')
60
+ })
61
+ })
62
+ })
@@ -0,0 +1,65 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const fs = require('fs')
7
+ const querystring = require('querystring')
8
+ const http = require('http')
9
+ const get = require('simple-get').concat
10
+
11
+ if (process.platform === 'win32') {
12
+ t.pass()
13
+ process.exit(0)
14
+ }
15
+
16
+ const socketPath = `${__filename}.socket`
17
+ const upstream = `unix+http://${querystring.escape(socketPath)}/`
18
+
19
+ const instance = Fastify()
20
+ instance.register(From, {
21
+ // Use node core http, unix sockets are not
22
+ // supported yet.
23
+ http: true,
24
+ base: upstream
25
+ })
26
+
27
+ t.plan(10)
28
+ t.teardown(instance.close.bind(instance))
29
+
30
+ try {
31
+ fs.unlinkSync(socketPath)
32
+ } catch (_) {
33
+ }
34
+
35
+ const target = http.createServer((req, res) => {
36
+ t.pass('request proxied')
37
+ t.equal(req.method, 'GET')
38
+ t.equal(req.url, '/hello')
39
+ res.statusCode = 205
40
+ res.setHeader('Content-Type', 'text/plain')
41
+ res.setHeader('x-my-header', 'hello!')
42
+ res.end('hello world')
43
+ })
44
+
45
+ instance.get('/', (request, reply) => {
46
+ reply.from('hello')
47
+ })
48
+
49
+ t.teardown(target.close.bind(target))
50
+
51
+ instance.listen(0, (err) => {
52
+ t.error(err)
53
+
54
+ target.listen(socketPath, (err) => {
55
+ t.error(err)
56
+
57
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
58
+ t.error(err)
59
+ t.equal(res.headers['content-type'], 'text/plain')
60
+ t.equal(res.headers['x-my-header'], 'hello!')
61
+ t.equal(res.statusCode, 205)
62
+ t.equal(data.toString(), 'hello world')
63
+ })
64
+ })
65
+ })
@@ -0,0 +1,71 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const https = require('https')
7
+ const get = require('simple-get').concat
8
+ const fs = require('fs')
9
+ const querystring = require('querystring')
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
+ if (process.platform === 'win32') {
17
+ t.pass()
18
+ process.exit(0)
19
+ }
20
+
21
+ const socketPath = `${__filename}.socket`
22
+
23
+ try {
24
+ fs.unlinkSync(socketPath)
25
+ } catch (_) {
26
+ }
27
+
28
+ const instance = Fastify({
29
+ https: certs
30
+ })
31
+ instance.register(From, {
32
+ base: `unix+https://${querystring.escape(socketPath)}`
33
+ })
34
+
35
+ t.plan(10)
36
+ t.teardown(instance.close.bind(instance))
37
+
38
+ const target = https.createServer(certs, (req, res) => {
39
+ t.pass('request proxied')
40
+ t.equal(req.method, 'GET')
41
+ t.equal(req.url, '/hello')
42
+ res.statusCode = 205
43
+ res.setHeader('Content-Type', 'text/plain')
44
+ res.setHeader('x-my-header', 'hello!')
45
+ res.end('hello world')
46
+ })
47
+
48
+ instance.get('/', (request, reply) => {
49
+ reply.from('hello')
50
+ })
51
+
52
+ t.teardown(target.close.bind(target))
53
+
54
+ instance.listen(0, (err) => {
55
+ t.error(err)
56
+
57
+ target.listen(socketPath, (err) => {
58
+ t.error(err)
59
+
60
+ get({
61
+ url: `https://localhost:${instance.server.address().port}`,
62
+ rejectUnauthorized: false
63
+ }, (err, res, data) => {
64
+ t.error(err)
65
+ t.equal(res.headers['content-type'], 'text/plain')
66
+ t.equal(res.headers['x-my-header'], 'hello!')
67
+ t.equal(res.statusCode, 205)
68
+ t.equal(data.toString(), 'hello world')
69
+ })
70
+ })
71
+ })
@@ -0,0 +1,71 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const https = require('https')
7
+ const get = require('simple-get').concat
8
+ const fs = require('fs')
9
+ const querystring = require('querystring')
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
+ if (process.platform === 'win32') {
17
+ t.pass()
18
+ process.exit(0)
19
+ }
20
+
21
+ const instance = Fastify({
22
+ https: certs
23
+ })
24
+ instance.register(From, {
25
+ http: true
26
+ })
27
+
28
+ t.plan(10)
29
+ t.teardown(instance.close.bind(instance))
30
+
31
+ const socketPath = `${__filename}.socket`
32
+
33
+ try {
34
+ fs.unlinkSync(socketPath)
35
+ } catch (_) {
36
+ }
37
+
38
+ const target = https.createServer(certs, (req, res) => {
39
+ t.pass('request proxied')
40
+ t.equal(req.method, 'GET')
41
+ t.equal(req.url, '/hello')
42
+ res.statusCode = 205
43
+ res.setHeader('Content-Type', 'text/plain')
44
+ res.setHeader('x-my-header', 'hello!')
45
+ res.end('hello world')
46
+ })
47
+
48
+ instance.get('/', (request, reply) => {
49
+ reply.from(`unix+https://${querystring.escape(socketPath)}/hello`)
50
+ })
51
+
52
+ t.teardown(target.close.bind(target))
53
+
54
+ instance.listen(0, (err) => {
55
+ t.error(err)
56
+
57
+ target.listen(socketPath, (err) => {
58
+ t.error(err)
59
+
60
+ get({
61
+ url: `https://localhost:${instance.server.address().port}`,
62
+ rejectUnauthorized: false
63
+ }, (err, res, data) => {
64
+ t.error(err)
65
+ t.equal(res.headers['content-type'], 'text/plain')
66
+ t.equal(res.headers['x-my-header'], 'hello!')
67
+ t.equal(res.statusCode, 205)
68
+ t.equal(data.toString(), 'hello world')
69
+ })
70
+ })
71
+ })