@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,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
+
9
+ const instance = Fastify()
10
+ instance.register(From, {
11
+ http: true
12
+ })
13
+
14
+ t.plan(9)
15
+ t.teardown(instance.close.bind(instance))
16
+
17
+ const target = http.createServer((req, res) => {
18
+ t.pass('request proxied')
19
+ t.equal(req.method, 'POST')
20
+ t.equal(req.headers['content-type'], 'application/json')
21
+ t.equal(req.headers['content-length'], '2')
22
+ let data = ''
23
+ req.setEncoding('utf8')
24
+ req.on('data', (d) => {
25
+ data += d
26
+ })
27
+ req.on('end', () => {
28
+ t.same(JSON.parse(data), '')
29
+ res.statusCode = 200
30
+ res.setHeader('content-type', 'application/json')
31
+ res.end(JSON.stringify({ hello: 'fastify' }))
32
+ })
33
+ })
34
+
35
+ instance.post('/', (request, reply) => {
36
+ reply.from(`http://localhost:${target.address().port}`, {
37
+ body: ''
38
+ })
39
+ })
40
+
41
+ t.teardown(target.close.bind(target))
42
+
43
+ instance.listen(0, (err) => {
44
+ t.error(err)
45
+
46
+ target.listen(0, (err) => {
47
+ t.error(err)
48
+
49
+ get({
50
+ url: `http://localhost:${instance.server.address().port}`,
51
+ method: 'POST',
52
+ json: true,
53
+ body: {
54
+ hello: 'world'
55
+ }
56
+ }, (err, res, data) => {
57
+ t.error(err)
58
+ t.same(data, { hello: 'fastify' })
59
+ })
60
+ })
61
+ })
@@ -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
+
9
+ const instance = Fastify()
10
+ instance.register(From, {
11
+ http: true
12
+ })
13
+
14
+ t.plan(9)
15
+ t.teardown(instance.close.bind(instance))
16
+
17
+ const target = http.createServer((req, res) => {
18
+ t.pass('request proxied')
19
+ t.equal(req.method, 'POST')
20
+ t.notOk('content-type' in req.headers)
21
+ t.equal(req.headers['content-length'], '0')
22
+ let data = ''
23
+ req.setEncoding('utf8')
24
+ req.on('data', (d) => {
25
+ data += d
26
+ })
27
+ req.on('end', () => {
28
+ t.equal(data.length, 0)
29
+ res.statusCode = 200
30
+ res.setHeader('content-type', 'application/json')
31
+ res.end(JSON.stringify({ hello: 'fastify' }))
32
+ })
33
+ })
34
+
35
+ instance.post('/', (request, reply) => {
36
+ reply.from(`http://localhost:${target.address().port}`, {
37
+ body: null
38
+ })
39
+ })
40
+
41
+ t.teardown(target.close.bind(target))
42
+
43
+ instance.listen(0, (err) => {
44
+ t.error(err)
45
+
46
+ target.listen(0, (err) => {
47
+ t.error(err)
48
+
49
+ get({
50
+ url: `http://localhost:${instance.server.address().port}`,
51
+ method: 'POST',
52
+ json: true,
53
+ body: {
54
+ hello: 'world'
55
+ }
56
+ }, (err, res, data) => {
57
+ t.error(err)
58
+ t.same(data, { hello: 'fastify' })
59
+ })
60
+ })
61
+ })
@@ -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
+
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, 'POST')
18
+ t.equal(req.headers['content-type'], 'application/json')
19
+ t.equal(req.headers['content-length'], '20')
20
+ let data = ''
21
+ req.setEncoding('utf8')
22
+ req.on('data', (d) => {
23
+ data += d
24
+ })
25
+ req.on('end', () => {
26
+ t.same(JSON.parse(data), { something: 'else' })
27
+ res.statusCode = 200
28
+ res.setHeader('content-type', 'application/json')
29
+ res.end(JSON.stringify({ hello: 'fastify' }))
30
+ })
31
+ })
32
+
33
+ instance.post('/', (request, reply) => {
34
+ reply.from(`http://localhost:${target.address().port}`, {
35
+ body: {
36
+ something: 'else'
37
+ }
38
+ })
39
+ })
40
+
41
+ t.teardown(target.close.bind(target))
42
+
43
+ instance.listen(0, (err) => {
44
+ t.error(err)
45
+
46
+ target.listen(0, (err) => {
47
+ t.error(err)
48
+
49
+ get({
50
+ url: `http://localhost:${instance.server.address().port}`,
51
+ method: 'POST',
52
+ json: true,
53
+ body: {
54
+ hello: 'world'
55
+ }
56
+ }, (err, res, data) => {
57
+ t.error(err)
58
+ t.same(data, { hello: 'fastify' })
59
+ })
60
+ })
61
+ })
@@ -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
+ const instanceWithoutBase = Fastify()
11
+ instance.register(From, {
12
+ base: 'http://localhost',
13
+ http: true,
14
+ disableCache: true
15
+ })
16
+
17
+ instanceWithoutBase.register(From, {
18
+ http: true,
19
+ disableCache: true
20
+ })
21
+
22
+ t.plan(13)
23
+ t.teardown(instance.close.bind(instance))
24
+ t.teardown(instanceWithoutBase.close.bind(instanceWithoutBase))
25
+
26
+ const target = http.createServer((req, res) => {
27
+ t.pass('request proxied')
28
+ t.equal(req.method, 'GET')
29
+ res.end(req.headers.host)
30
+ })
31
+
32
+ instance.get('/test', (request, reply) => {
33
+ reply.from('/test', {
34
+ getUpstream: (req, base) => {
35
+ t.pass('getUpstream called')
36
+ return `${base}:${target.address().port}`
37
+ }
38
+ })
39
+ })
40
+
41
+ instanceWithoutBase.get('/test2', (request, reply) => {
42
+ reply.from('/test2', {
43
+ getUpstream: () => {
44
+ t.pass('getUpstream called')
45
+ return `http://localhost:${target.address().port}`
46
+ }
47
+ })
48
+ })
49
+
50
+ t.teardown(target.close.bind(target))
51
+
52
+ instance.listen(0, (err) => {
53
+ t.error(err)
54
+ instanceWithoutBase.listen(0, (err) => {
55
+ t.error(err)
56
+ target.listen(0, (err) => {
57
+ t.error(err)
58
+
59
+ get(`http://localhost:${instance.server.address().port}/test`, (err, res) => {
60
+ t.error(err)
61
+ t.equal(res.statusCode, 200)
62
+ })
63
+
64
+ get(`http://localhost:${instanceWithoutBase.server.address().port}/test2`, (err, res) => {
65
+ t.error(err)
66
+ t.equal(res.statusCode, 200)
67
+ })
68
+ })
69
+ })
70
+ })
@@ -0,0 +1,45 @@
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
+ disableCache: true
12
+ })
13
+
14
+ t.plan(7)
15
+ t.teardown(instance.close.bind(instance))
16
+
17
+ const target = http.createServer((req, res) => {
18
+ t.pass('request proxied')
19
+ t.equal(req.method, 'GET')
20
+ res.end(req.headers.host)
21
+ })
22
+
23
+ instance.get('/test', (request, reply) => {
24
+ reply.from('/test', {
25
+ getUpstream: () => {
26
+ t.pass('getUpstream called')
27
+ return `http://localhost:${target.address().port}`
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}/test`, (err, res) => {
41
+ t.error(err)
42
+ t.equal(res.statusCode, 200)
43
+ })
44
+ })
45
+ })
@@ -0,0 +1,55 @@
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.body, undefined)
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
+ // Use node core HTTP, Undici requires spec compliance
37
+ http: {}
38
+ })
39
+
40
+ instance.listen(0, (err) => {
41
+ t.error(err)
42
+
43
+ get({
44
+ url: `http://localhost:${instance.server.address().port}`,
45
+ method: 'GET',
46
+ body: 'this is get body'
47
+ }, (err, res, data) => {
48
+ t.error(err)
49
+ t.equal(res.headers['content-type'], 'text/plain')
50
+ t.equal(res.headers['x-my-header'], 'hello!')
51
+ t.equal(res.statusCode, 205)
52
+ t.equal(data.toString(), 'hello world')
53
+ })
54
+ })
55
+ })
@@ -0,0 +1,57 @@
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(13)
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, 'HEAD')
17
+ t.equal(req.url, '/')
18
+ t.equal(req.headers['content-length'], '16')
19
+ t.equal(req.body, undefined)
20
+ res.statusCode = 205
21
+ res.setHeader('Content-Type', 'text/plain')
22
+ res.setHeader('x-my-header', 'hello!')
23
+ res.end('hello world')
24
+ })
25
+
26
+ instance.head('/', (request, reply) => {
27
+ t.pass('head received')
28
+ reply.from()
29
+ })
30
+
31
+ t.teardown(target.close.bind(target))
32
+
33
+ target.listen(0, (err) => {
34
+ t.error(err)
35
+
36
+ instance.register(From, {
37
+ base: `http://localhost:${target.address().port}`,
38
+ // Use node core HTTP, Undici requires spec compliance
39
+ http: {}
40
+ })
41
+
42
+ instance.listen(0, (err) => {
43
+ t.error(err)
44
+
45
+ get({
46
+ url: `http://localhost:${instance.server.address().port}`,
47
+ method: 'HEAD',
48
+ body: 'this is get body'
49
+ }, (err, res, data) => {
50
+ t.error(err)
51
+ t.equal(res.headers['content-type'], 'text/plain')
52
+ t.equal(res.headers['x-my-header'], 'hello!')
53
+ t.equal(res.statusCode, 205)
54
+ t.equal(data.toString(), '')
55
+ })
56
+ })
57
+ })
@@ -0,0 +1,67 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const nock = require('nock')
7
+ const got = require('got')
8
+
9
+ test('hostname', async (t) => {
10
+ const instance = Fastify()
11
+ t.teardown(instance.close.bind(instance))
12
+
13
+ nock('http://httpbin.org')
14
+ .get('/ip')
15
+ .reply(200, function (uri, requestBody) {
16
+ t.equal(this.req.headers.host, 'httpbin.org')
17
+ return { origin: '127.0.0.1' }
18
+ })
19
+
20
+ instance.get('*', (request, reply) => {
21
+ reply.from()
22
+ })
23
+
24
+ instance.register(From, {
25
+ base: 'http://httpbin.org',
26
+ http: {} // force the use of Node.js core
27
+ })
28
+
29
+ await instance.listen(0)
30
+
31
+ const res = await got.get(`http://localhost:${instance.server.address().port}/ip`, {
32
+ retry: 0
33
+ })
34
+ t.equal(res.statusCode, 200)
35
+ t.equal(res.headers['content-type'], 'application/json')
36
+ t.equal(typeof JSON.parse(res.body).origin, 'string')
37
+ })
38
+
39
+ test('hostname and port', async (t) => {
40
+ const instance = Fastify()
41
+ t.teardown(instance.close.bind(instance))
42
+
43
+ nock('http://httpbin.org:8080')
44
+ .get('/ip')
45
+ .reply(200, function (uri, requestBody) {
46
+ t.equal(this.req.headers.host, 'httpbin.org:8080')
47
+ return { origin: '127.0.0.1' }
48
+ })
49
+
50
+ instance.register(From, {
51
+ base: 'http://httpbin.org:8080',
52
+ http: true
53
+ })
54
+
55
+ instance.get('*', (request, reply) => {
56
+ reply.from()
57
+ })
58
+
59
+ await instance.listen(0)
60
+
61
+ const res = await got.get(`http://localhost:${instance.server.address().port}/ip`, {
62
+ retry: 0
63
+ })
64
+ t.equal(res.statusCode, 200)
65
+ t.equal(res.headers['content-type'], 'application/json')
66
+ t.equal(typeof JSON.parse(res.body).origin, 'string')
67
+ })
@@ -0,0 +1,55 @@
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 https = require('https')
8
+ const get = require('simple-get').concat
9
+
10
+ const instance = Fastify()
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
+ t.equal(req.url, '/')
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
+ http: {
37
+ agents: {
38
+ 'http:': new http.Agent({}),
39
+ 'https:': new https.Agent({})
40
+ }
41
+ }
42
+ })
43
+
44
+ instance.listen(0, (err) => {
45
+ t.error(err)
46
+
47
+ get(`http://localhost:${instance.server.address().port}`, (err, res, data) => {
48
+ t.error(err)
49
+ t.equal(res.headers['content-type'], 'text/plain')
50
+ t.equal(res.headers['x-my-header'], 'hello!')
51
+ t.equal(res.statusCode, 205)
52
+ t.equal(data.toString(), 'hello world')
53
+ })
54
+ })
55
+ })
@@ -0,0 +1,50 @@
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('http -> http2', async (t) => {
9
+ const instance = Fastify()
10
+
11
+ t.teardown(instance.close.bind(instance))
12
+
13
+ const target = Fastify({
14
+ http2: true
15
+ })
16
+
17
+ target.get('/', (request, reply) => {
18
+ t.pass('request proxied')
19
+ reply.code(404).header('x-my-header', 'hello!').send({
20
+ hello: 'world'
21
+ })
22
+ })
23
+
24
+ instance.get('/', (request, reply) => {
25
+ reply.from()
26
+ })
27
+
28
+ t.teardown(target.close.bind(target))
29
+
30
+ await target.listen(0)
31
+
32
+ instance.register(From, {
33
+ base: `http://localhost:${target.server.address().port}`,
34
+ http2: true
35
+ })
36
+
37
+ await instance.listen(0)
38
+
39
+ try {
40
+ await got(`http://localhost:${instance.server.address().port}`)
41
+ } catch (err) {
42
+ t.equal(err.response.statusCode, 404)
43
+ t.equal(err.response.headers['x-my-header'], 'hello!')
44
+ t.match(err.response.headers['content-type'], /application\/json/)
45
+ t.same(JSON.parse(err.response.body), { hello: 'world' })
46
+ return
47
+ }
48
+
49
+ t.fail()
50
+ })
@@ -0,0 +1,35 @@
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('http invalid target', async (t) => {
9
+ const instance = Fastify()
10
+
11
+ t.teardown(instance.close.bind(instance))
12
+
13
+ instance.get('/', (request, reply) => {
14
+ reply.from()
15
+ })
16
+ instance.register(From, {
17
+ base: 'http://abc.xyz1'
18
+ })
19
+
20
+ await instance.listen(0)
21
+
22
+ try {
23
+ await got(`http://localhost:${instance.server.address().port}`)
24
+ } catch (err) {
25
+ t.equal(err.response.statusCode, 503)
26
+ t.match(err.response.headers['content-type'], /application\/json/)
27
+ t.same(JSON.parse(err.response.body), {
28
+ statusCode: 503,
29
+ error: 'Service Unavailable',
30
+ message: 'Service Unavailable'
31
+ })
32
+ return
33
+ }
34
+ t.fail()
35
+ })