@fastify/reply-from 9.5.0 → 9.7.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/README.md +1 -0
- package/index.js +9 -10
- package/package.json +2 -1
- package/test/fix-GHSA-v2v2-hph8-q5xp.test.js +47 -0
- package/test/retry-with-a-custom-handler.test.js +24 -0
package/README.md
CHANGED
|
@@ -281,6 +281,7 @@ If a `handler` is passed to the `retryDelay` object the onus is on the client to
|
|
|
281
281
|
- `res` is the raw response returned by the underlying agent (if available) __Note__: this object is not a Fastify response, but instead the low-level response from the agent. This property may be null if no response was obtained at all, like from a connection reset or timeout.
|
|
282
282
|
- `attempt` in the object callback refers to the current retriesAttempt number. You are given the freedom to use this in concert with the retryCount property set to handle retries
|
|
283
283
|
- `getDefaultRetry` refers to the default retry handler. If this callback returns not null and you wish to handle those case of errors simply invoke it as done below.
|
|
284
|
+
- `retriesCount` refers to the retriesCount property a client passes to reply-from. Note if the client does not explicitly set this value it will default to 0. The objective value here is to avoid hard-coding and seeing the retriesCount set. It is your perogative to ensure that you ensure the value here is as you wish (and not `0` if not intended to be as a result of a lack of not setting it).
|
|
284
285
|
|
|
285
286
|
Given example
|
|
286
287
|
|
package/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const fp = require('fastify-plugin')
|
|
4
4
|
const { lru } = require('tiny-lru')
|
|
5
5
|
const querystring = require('fast-querystring')
|
|
6
|
+
const fastContentTypeParse = require('fast-content-type-parse')
|
|
6
7
|
const Stream = require('node:stream')
|
|
7
8
|
const buildRequest = require('./lib/request')
|
|
8
9
|
const {
|
|
@@ -107,15 +108,13 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
107
108
|
body = this.request.body
|
|
108
109
|
} else {
|
|
109
110
|
// Per RFC 7231 §3.1.1.5 if this header is not present we MAY assume application/octet-stream
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
: lowerCaseContentType
|
|
118
|
-
const shouldEncodeJSON = contentTypesToEncode.has(plainContentType)
|
|
111
|
+
let contentType = 'application/octet-stream'
|
|
112
|
+
if (req.headers['content-type']) {
|
|
113
|
+
const plainContentType = fastContentTypeParse.parse(req.headers['content-type'])
|
|
114
|
+
contentType = plainContentType.type
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const shouldEncodeJSON = contentTypesToEncode.has(contentType)
|
|
119
118
|
// transparently support JSON encoding
|
|
120
119
|
body = shouldEncodeJSON ? JSON.stringify(this.request.body) : this.request.body
|
|
121
120
|
// update origin request headers after encoding
|
|
@@ -164,7 +163,7 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
164
163
|
|
|
165
164
|
if (retryDelay) {
|
|
166
165
|
requestImpl = createRequestRetry(request, this, (req, res, err, retries) => {
|
|
167
|
-
return retryDelay({ err, req, res, attempt: retries, getDefaultDelay })
|
|
166
|
+
return retryDelay({ err, req, res, attempt: retries, getDefaultDelay, retriesCount })
|
|
168
167
|
})
|
|
169
168
|
} else {
|
|
170
169
|
requestImpl = createRequestRetry(request, this, getDefaultDelay)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastify/reply-from",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.7.0",
|
|
4
4
|
"description": "forward your HTTP request to another server, for fastify",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@fastify/error": "^3.0.0",
|
|
55
55
|
"end-of-stream": "^1.4.4",
|
|
56
|
+
"fast-content-type-parse": "^1.1.0",
|
|
56
57
|
"fast-querystring": "^1.0.0",
|
|
57
58
|
"fastify-plugin": "^4.0.0",
|
|
58
59
|
"pump": "^3.0.0",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const t = require('tap')
|
|
4
|
+
const fastify = require('fastify')
|
|
5
|
+
const get = require('simple-get').concat
|
|
6
|
+
const From = require('..')
|
|
7
|
+
|
|
8
|
+
const upstream = fastify()
|
|
9
|
+
t.teardown(upstream.close.bind(upstream))
|
|
10
|
+
t.plan(4)
|
|
11
|
+
|
|
12
|
+
upstream.post('/test', async (request, reply) => {
|
|
13
|
+
if (typeof request.body === 'object') {
|
|
14
|
+
return 'not ok'
|
|
15
|
+
}
|
|
16
|
+
return 'ok'
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
upstream.listen({ port: 0 }, function (err) {
|
|
20
|
+
t.error(err)
|
|
21
|
+
|
|
22
|
+
const app = fastify()
|
|
23
|
+
app.register(From)
|
|
24
|
+
t.teardown(app.close.bind(app))
|
|
25
|
+
|
|
26
|
+
app.post('/test', (request, reply) => {
|
|
27
|
+
if (request.body.method === 'invalid_method') {
|
|
28
|
+
return reply.code(400).send({ message: 'payload contains invalid method' })
|
|
29
|
+
}
|
|
30
|
+
reply.from(`http://127.0.0.1:${upstream.server.address().port}/test`)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
app.listen({ port: 0 }, function (err) {
|
|
34
|
+
t.error(err)
|
|
35
|
+
|
|
36
|
+
get({
|
|
37
|
+
url: `http://127.0.0.1:${app.server.address().port}/test`,
|
|
38
|
+
headers: { 'content-type': 'application/json ; charset=utf-8' },
|
|
39
|
+
// eslint-disable-next-line no-useless-escape
|
|
40
|
+
body: '"{\\\"method\\\":\\\"invalid_method\\\"}"',
|
|
41
|
+
method: 'POST'
|
|
42
|
+
}, (err, res, data) => {
|
|
43
|
+
t.error(err)
|
|
44
|
+
t.equal(data.toString(), 'ok')
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -160,3 +160,27 @@ test('we can exceed our retryCount and introspect attempts independently', async
|
|
|
160
160
|
t.equal(res.statusCode, 205)
|
|
161
161
|
t.equal(res.body.toString(), 'Hello World 5!')
|
|
162
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
|
+
})
|