@fastify/reply-from 9.4.0 → 9.6.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/.gitattributes +2 -0
- package/README.md +78 -22
- package/index.js +40 -33
- package/lib/request.js +4 -4
- package/lib/utils.js +2 -0
- package/package.json +4 -2
- package/test/async-route-handler.test.js +1 -1
- package/test/base-get.test.js +1 -1
- package/test/base-querystring.test.js +1 -1
- package/test/core-with-path-in-base.test.js +1 -1
- package/test/custom-undici-instance.test.js +1 -1
- package/test/disable-request-logging.test.js +1 -1
- package/test/fastify-multipart-incompatibility.test.js +3 -3
- package/test/fix-GHSA-v2v2-hph8-q5xp.test.js +47 -0
- package/test/full-get-test.test.js +1 -1
- package/test/full-https-get.test.js +3 -3
- package/test/full-post-extended-content-type.test.js +1 -1
- package/test/full-post-stream-core.test.js +1 -1
- package/test/full-post-stream.test.js +1 -1
- package/test/full-post.test.js +1 -1
- package/test/full-querystring-rewrite-option-complex.test.js +1 -1
- package/test/full-querystring-rewrite-option-function.test.js +2 -2
- package/test/full-querystring-rewrite-option.test.js +1 -1
- package/test/full-querystring-rewrite-string.test.js +1 -1
- package/test/full-querystring-rewrite.test.js +1 -1
- package/test/full-querystring.test.js +1 -1
- package/test/full-rewrite-body-content-type.test.js +1 -1
- package/test/full-rewrite-body-http.test.js +1 -1
- package/test/full-rewrite-body-to-empty-string.test.js +1 -1
- package/test/full-rewrite-body-to-null.test.js +1 -1
- package/test/full-rewrite-body.test.js +1 -1
- package/test/get-upstream-http.test.js +1 -1
- package/test/get-upstream-type.test.js +1 -1
- package/test/get-upstream-undici.test.js +1 -1
- package/test/get-with-body.test.js +1 -1
- package/test/head-with-body.test.js +1 -1
- package/test/http-agents.test.js +2 -2
- package/test/http-global-agent.test.js +1 -1
- package/test/http-retry.test.js +1 -1
- package/test/http2-http2.test.js +2 -2
- package/test/http2-https.test.js +2 -2
- package/test/https-agents.test.js +4 -4
- package/test/https-global-agent.test.js +3 -3
- package/test/method.test.js +1 -1
- package/test/modifyCoreObjects-false.test.js +1 -1
- package/test/no-body-opts-with-get.test.js +1 -1
- package/test/no-body-opts-with-head.test.js +1 -1
- package/test/no-stream-body-option.test.js +2 -2
- package/test/onResponse.test.js +1 -1
- package/test/padded-body.test.js +1 -1
- package/test/post-formbody.test.js +1 -1
- package/test/post-plain-text.test.js +1 -1
- package/test/post-with-custom-encoded-contenttype.test.js +2 -2
- package/test/post-with-octet-stream.test.js +2 -2
- package/test/retry-on-503.test.js +1 -1
- package/test/retry-with-a-custom-handler.test.js +162 -0
- package/test/rewrite-headers-type.test.js +1 -1
- package/test/rewrite-headers.test.js +1 -1
- package/test/rewrite-request-headers-type.test.js +1 -1
- package/test/rewrite-request-headers.test.js +1 -1
- package/test/transform-body.test.js +2 -2
- package/test/undici-agent.test.js +1 -1
- package/test/undici-body.test.js +1 -1
- package/test/undici-connect-timeout.test.js +2 -2
- package/test/undici-global-agent.test.js +1 -1
- package/test/undici-options.test.js +1 -1
- package/test/undici-retry.test.js +1 -1
- package/test/undici-timeout-body-partial.test.js +1 -1
- package/test/undici-timeout-body.test.js +1 -1
- package/test/undici-with-path-in-base.test.js +1 -1
- package/test/undici.test.js +1 -1
- package/test/unix-http-undici-from.test.js +3 -3
- package/test/unix-http-undici.test.js +3 -3
- package/test/unix-http.test.js +3 -3
- package/test/unix-https-undici.test.js +4 -4
- package/test/unix-https.test.js +4 -4
- package/types/index.d.ts +24 -15
- package/types/index.test-d.ts +15 -6
package/.gitattributes
ADDED
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm i @fastify/reply-from
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Compatibility with @fastify/multipart
|
|
17
|
-
`@fastify/reply-from` and [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) should not be registered as sibling plugins nor should they be registered in plugins which have a parent-child relationship
|
|
17
|
+
`@fastify/reply-from` and [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) should not be registered as sibling plugins nor should they be registered in plugins which have a parent-child relationship.`<br>` The two plugins are incompatible, in the sense that the behavior of `@fastify/reply-from` might not be the expected one when the above-mentioned conditions are not respected.`<br>` This is due to the fact that `@fastify/multipart` consumes the multipart content by parsing it, hence this content is not forwarded to the target service by `@fastify/reply-from`.`<br>`
|
|
18
18
|
However, the two plugins may be used within the same fastify instance, at the condition that they belong to disjoint branches of the fastify plugins hierarchy tree.
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
@@ -74,7 +74,7 @@ socket server by using `querystring.escape(socketPath)` as the hostname. This i
|
|
|
74
74
|
for http2 nor undici. To illustrate:
|
|
75
75
|
|
|
76
76
|
```js
|
|
77
|
-
const socketPath = require('querystring').escape('/run/http-daemon.socket')
|
|
77
|
+
const socketPath = require('node:querystring').escape('/run/http-daemon.socket')
|
|
78
78
|
proxy.register(require('@fastify/reply-from'), {
|
|
79
79
|
base: 'unix+http://${socketPath}/'
|
|
80
80
|
});
|
|
@@ -115,7 +115,7 @@ proxy.register(require('@fastify/reply-from'), {
|
|
|
115
115
|
|
|
116
116
|
#### `http`
|
|
117
117
|
|
|
118
|
-
Set the `http` option to an Object to use
|
|
118
|
+
Set the `http` option to an Object to use
|
|
119
119
|
Node's [`http.request`](https://nodejs.org/api/http.html#http_http_request_options_callback)
|
|
120
120
|
will be used if you do not enable [`http2`](#http2). To customize the `request`,
|
|
121
121
|
you can pass in [`agentOptions`](https://nodejs.org/api/http.html#http_new_agent_options) and
|
|
@@ -136,6 +136,7 @@ proxy.register(require('@fastify/reply-from'), {
|
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
You can also pass custom HTTP agents. If you pass the agents, then the http.agentOptions will be ignored. To illustrate:
|
|
139
|
+
|
|
139
140
|
```js
|
|
140
141
|
proxy.register(require('@fastify/reply-from'), {
|
|
141
142
|
base: 'http://localhost:3001/',
|
|
@@ -192,27 +193,27 @@ The number of parsed URLs that will be cached. Default: `100`.
|
|
|
192
193
|
|
|
193
194
|
#### `disableCache`
|
|
194
195
|
|
|
195
|
-
This option will disable the URL caching.
|
|
196
|
+
This option will disable the URL caching.
|
|
196
197
|
This cache is dedicated to reduce the amount of URL object generation.
|
|
197
198
|
Generating URLs is a main bottleneck of this module, please disable this cache with caution.
|
|
198
199
|
|
|
199
200
|
#### `contentTypesToEncode`
|
|
200
201
|
|
|
201
|
-
An array of content types whose response body will be passed through `JSON.stringify()`.
|
|
202
|
+
An array of content types whose response body will be passed through `JSON.stringify()`.
|
|
202
203
|
This only applies when a custom [`body`](#body) is not passed in. Defaults to:
|
|
203
204
|
|
|
204
205
|
```js
|
|
205
|
-
[
|
|
206
|
+
[
|
|
206
207
|
'application/json'
|
|
207
208
|
]
|
|
208
209
|
```
|
|
209
210
|
|
|
210
211
|
#### `retryMethods`
|
|
211
212
|
|
|
212
|
-
On which methods should the connection be retried in case of socket hang up.
|
|
213
|
+
On which methods should the connection be retried in case of socket hang up.
|
|
213
214
|
**Be aware** that setting here not idempotent method may lead to unexpected results on target.
|
|
214
215
|
|
|
215
|
-
By default: `['GET', 'HEAD', 'OPTIONS', 'TRACE'
|
|
216
|
+
By default: `['GET', 'HEAD', 'OPTIONS', 'TRACE']`
|
|
216
217
|
|
|
217
218
|
This plugin will always retry on 503 errors, _unless_ `retryMethods` does not contain `GET`.
|
|
218
219
|
|
|
@@ -221,6 +222,7 @@ This plugin will always retry on 503 errors, _unless_ `retryMethods` does not co
|
|
|
221
222
|
Enables the possibility to explictly opt-in for global agents.
|
|
222
223
|
|
|
223
224
|
Usage for undici global agent:
|
|
225
|
+
|
|
224
226
|
```js
|
|
225
227
|
import { setGlobalDispatcher, ProxyAgent } from 'undici'
|
|
226
228
|
|
|
@@ -234,11 +236,12 @@ fastify.register(FastifyReplyFrom, {
|
|
|
234
236
|
```
|
|
235
237
|
|
|
236
238
|
Usage for http/https global agent:
|
|
239
|
+
|
|
237
240
|
```js
|
|
238
241
|
fastify.register(FastifyReplyFrom, {
|
|
239
242
|
base: 'http://localhost:3001/',
|
|
240
243
|
// http and https is allowed to use http.globalAgent or https.globalAgent
|
|
241
|
-
globalAgent: true,
|
|
244
|
+
globalAgent: true,
|
|
242
245
|
http: {
|
|
243
246
|
}
|
|
244
247
|
})
|
|
@@ -263,7 +266,59 @@ This option set the limit on how many times the plugin should retry the request,
|
|
|
263
266
|
|
|
264
267
|
By Default: 10
|
|
265
268
|
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
### `retryDelay`
|
|
272
|
+
|
|
273
|
+
- `handler`. Required
|
|
274
|
+
|
|
275
|
+
This plugin gives the client an option to pass their own retry callback to allow the client to define what retryDelay they would like on any retries
|
|
276
|
+
outside the scope of what is handled by default in fastify-reply-from. To see the default please refer to index.js `getDefaultDelay()`
|
|
277
|
+
If a `handler` is passed to the `retryDelay` object the onus is on the client to invoke the default retry logic in their callback otherwise default cases such as 500 will not be handled
|
|
278
|
+
|
|
279
|
+
- `err` is the error thrown by making a request using whichever agent is configured
|
|
280
|
+
- `req` is the raw request details sent to the underlying agent. __Note__: this object is not a Fastify request object, but instead the low-level request for the agent.
|
|
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
|
+
- `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
|
+
- `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
|
+
|
|
285
|
+
Given example
|
|
286
|
+
|
|
287
|
+
```js
|
|
288
|
+
const customRetryLogic = ({err, req, res, attempt, getDefaultRetry}) => {
|
|
289
|
+
//If this block is not included all non 500 errors will not be retried
|
|
290
|
+
const defaultDelay = getDefaultDelay();
|
|
291
|
+
if (defaultDelay) return defaultDelay();
|
|
292
|
+
|
|
293
|
+
//Custom retry logic
|
|
294
|
+
if (res && res.statusCode === 500 && req.method === 'GET') {
|
|
295
|
+
return 300
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (err && err.code == "UND_ERR_SOCKET"){
|
|
299
|
+
return 600
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return null
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.......
|
|
266
306
|
|
|
307
|
+
fastify.register(FastifyReplyFrom, {
|
|
308
|
+
base: 'http://localhost:3001/',
|
|
309
|
+
retryDelay: customRetryLogic
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Note the Typescript Equivalent
|
|
315
|
+
```
|
|
316
|
+
const customRetryLogic = ({req, res, err, getDefaultRetry}: RetryDetails) => {
|
|
317
|
+
...
|
|
318
|
+
}
|
|
319
|
+
...
|
|
320
|
+
|
|
321
|
+
```
|
|
267
322
|
---
|
|
268
323
|
|
|
269
324
|
### `reply.from(source, [opts])`
|
|
@@ -328,6 +383,7 @@ ContraintStrategies.
|
|
|
328
383
|
e.g.:
|
|
329
384
|
|
|
330
385
|
Route grpc-web/http1 and grpc/http2 to different routes with a ContentType-ConstraintStrategy:
|
|
386
|
+
|
|
331
387
|
```
|
|
332
388
|
const contentTypeMatchContraintStrategy = {
|
|
333
389
|
// strategy name for referencing in the route handler `constraints` options
|
|
@@ -341,17 +397,18 @@ const contentTypeMatchContraintStrategy = {
|
|
|
341
397
|
}
|
|
342
398
|
},
|
|
343
399
|
// function to get the value of the constraint from each incoming request
|
|
344
|
-
deriveConstraint: (req: any, ctx: any) => {
|
|
400
|
+
deriveConstraint: (req: any, ctx: any) => {
|
|
345
401
|
return req.headers['content-type']
|
|
346
402
|
},
|
|
347
403
|
// optional flag marking if handlers without constraints can match requests that have a value for this constraint
|
|
348
404
|
mustMatchWhenDerived: true
|
|
349
405
|
}
|
|
350
|
-
|
|
406
|
+
|
|
351
407
|
server.addConstraintStrategy(contentTypeMatchContraintStrategy);
|
|
352
408
|
```
|
|
353
409
|
|
|
354
410
|
and then 2 different upstreams with different register's:
|
|
411
|
+
|
|
355
412
|
```
|
|
356
413
|
// grpc-web / http1
|
|
357
414
|
server.register(fastifyHttpProxy, {
|
|
@@ -359,18 +416,17 @@ server.register(fastifyHttpProxy, {
|
|
|
359
416
|
// therefore we have to transport to the grpc-web-proxy via http1
|
|
360
417
|
http2: false,
|
|
361
418
|
upstream: 'http://grpc-web-proxy',
|
|
362
|
-
constraints: { "contentType": "application/grpc-web+proto" }
|
|
419
|
+
constraints: { "contentType": "application/grpc-web+proto" }
|
|
363
420
|
});
|
|
364
421
|
|
|
365
422
|
// grpc / http2
|
|
366
423
|
server.register(fastifyHttpProxy, {
|
|
367
424
|
http2: true,
|
|
368
425
|
upstream: 'http://grpc.server',
|
|
369
|
-
constraints: { "contentType": "application/grpc+proto" }
|
|
426
|
+
constraints: { "contentType": "application/grpc+proto" }
|
|
370
427
|
});
|
|
371
428
|
```
|
|
372
429
|
|
|
373
|
-
|
|
374
430
|
#### `queryString` or `queryString(search, reqUrl)`
|
|
375
431
|
|
|
376
432
|
Replaces the original querystring of the request with what is specified.
|
|
@@ -390,12 +446,12 @@ Setting this option to `null` will strip the body (and `content-type` header) en
|
|
|
390
446
|
|
|
391
447
|
#### `method`
|
|
392
448
|
|
|
393
|
-
Replaces the original request method with what is specified.
|
|
449
|
+
Replaces the original request method with what is specified.
|
|
394
450
|
|
|
395
451
|
#### `retriesCount`
|
|
396
452
|
|
|
397
|
-
How many times it will try to pick another connection on socket hangup (`ECONNRESET` error).
|
|
398
|
-
Useful when keeping the connection open (KeepAlive).
|
|
453
|
+
How many times it will try to pick another connection on socket hangup (`ECONNRESET` error).
|
|
454
|
+
Useful when keeping the connection open (KeepAlive).
|
|
399
455
|
This number should be a function of the number of connections and the number of instances of a target.
|
|
400
456
|
|
|
401
457
|
By default: 0 (disabled)
|
|
@@ -407,13 +463,13 @@ already overriding the [`body`](#body).
|
|
|
407
463
|
|
|
408
464
|
### Combining with [@fastify/formbody](https://github.com/fastify/fastify-formbody)
|
|
409
465
|
|
|
410
|
-
`formbody` expects the body to be returned as a string and not an object.
|
|
466
|
+
`formbody` expects the body to be returned as a string and not an object.
|
|
411
467
|
Use the [`contentTypesToEncode`](#contentTypesToEncode) option to pass in `['application/x-www-form-urlencoded']`
|
|
412
468
|
|
|
413
|
-
|
|
414
469
|
### HTTP & HTTP2 timeouts
|
|
415
470
|
|
|
416
471
|
This library has:
|
|
472
|
+
|
|
417
473
|
- `timeout` for `http` set by default. The default value is 10 seconds (`10000`).
|
|
418
474
|
- `requestTimeout` & `sessionTimeout` for `http2` set by default.
|
|
419
475
|
- The default value for `requestTimeout` is 10 seconds (`10000`).
|
|
@@ -426,10 +482,10 @@ will be returned to the client.
|
|
|
426
482
|
|
|
427
483
|
* [ ] support overriding the body with a stream
|
|
428
484
|
* [ ] forward the request id to the other peer might require some
|
|
429
|
-
|
|
430
|
-
|
|
485
|
+
refactoring because we have to make the `req.id` unique
|
|
486
|
+
(see [hyperid](https://npm.im/hyperid)).
|
|
431
487
|
* [ ] Support origin HTTP2 push
|
|
432
|
-
* [
|
|
488
|
+
* [X] benchmarks
|
|
433
489
|
|
|
434
490
|
## License
|
|
435
491
|
|
package/index.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
const fp = require('fastify-plugin')
|
|
4
4
|
const { lru } = require('tiny-lru')
|
|
5
5
|
const querystring = require('fast-querystring')
|
|
6
|
-
const
|
|
6
|
+
const fastContentTypeParse = require('fast-content-type-parse')
|
|
7
|
+
const Stream = require('node:stream')
|
|
7
8
|
const buildRequest = require('./lib/request')
|
|
8
9
|
const {
|
|
9
10
|
filterPseudoHeaders,
|
|
@@ -29,8 +30,7 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
29
30
|
])
|
|
30
31
|
|
|
31
32
|
const retryMethods = new Set(opts.retryMethods || [
|
|
32
|
-
'GET', 'HEAD', 'OPTIONS', 'TRACE'
|
|
33
|
-
])
|
|
33
|
+
'GET', 'HEAD', 'OPTIONS', 'TRACE'])
|
|
34
34
|
|
|
35
35
|
const cache = opts.disableCache ? undefined : lru(opts.cacheURLs || 100)
|
|
36
36
|
const base = opts.base
|
|
@@ -60,6 +60,7 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
60
60
|
const onError = opts.onError || onErrorDefault
|
|
61
61
|
const retriesCount = opts.retriesCount || 0
|
|
62
62
|
const maxRetriesOn503 = opts.maxRetriesOn503 || 10
|
|
63
|
+
const retryDelay = opts.retryDelay || undefined
|
|
63
64
|
|
|
64
65
|
if (!source) {
|
|
65
66
|
source = req.url
|
|
@@ -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
|
|
@@ -142,10 +141,32 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
142
141
|
const requestHeaders = rewriteRequestHeaders(this.request, headers)
|
|
143
142
|
const contentLength = requestHeaders['content-length']
|
|
144
143
|
let requestImpl
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
|
|
145
|
+
const getDefaultDelay = (req, res, err, retries) => {
|
|
146
|
+
if (retryMethods.has(method) && !contentLength) {
|
|
147
|
+
// Magic number, so why not 42? We might want to make this configurable.
|
|
148
|
+
let retryAfter = 42 * Math.random() * (retries + 1)
|
|
149
|
+
|
|
150
|
+
if (res && res.headers['retry-after']) {
|
|
151
|
+
retryAfter = res.headers['retry-after']
|
|
152
|
+
}
|
|
153
|
+
if (res && res.statusCode === 503 && req.method === 'GET') {
|
|
154
|
+
if (retriesCount === 0 && retries < maxRetriesOn503) {
|
|
155
|
+
return retryAfter
|
|
156
|
+
}
|
|
157
|
+
} else if (retriesCount > retries && err && err.code === retryOnError) {
|
|
158
|
+
return retryAfter
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (retryDelay) {
|
|
165
|
+
requestImpl = createRequestRetry(request, this, (req, res, err, retries) => {
|
|
166
|
+
return retryDelay({ err, req, res, attempt: retries, getDefaultDelay })
|
|
167
|
+
})
|
|
147
168
|
} else {
|
|
148
|
-
requestImpl = request
|
|
169
|
+
requestImpl = createRequestRetry(request, this, getDefaultDelay)
|
|
149
170
|
}
|
|
150
171
|
|
|
151
172
|
requestImpl({ method, url, qs, headers: requestHeaders, body }, (err, res) => {
|
|
@@ -200,7 +221,6 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
|
|
|
200
221
|
// actually destroy those sockets
|
|
201
222
|
setImmediate(next)
|
|
202
223
|
})
|
|
203
|
-
|
|
204
224
|
next()
|
|
205
225
|
}, {
|
|
206
226
|
fastify: '4.x',
|
|
@@ -251,28 +271,15 @@ function isFastifyMultipartRegistered (fastify) {
|
|
|
251
271
|
return (fastify.hasContentTypeParser('multipart') || fastify.hasContentTypeParser('multipart/form-data')) && fastify.hasRequestDecorator('multipart')
|
|
252
272
|
}
|
|
253
273
|
|
|
254
|
-
function createRequestRetry (requestImpl, reply,
|
|
274
|
+
function createRequestRetry (requestImpl, reply, retryHandler) {
|
|
255
275
|
function requestRetry (req, cb) {
|
|
256
276
|
let retries = 0
|
|
257
277
|
|
|
258
278
|
function run () {
|
|
259
279
|
requestImpl(req, function (err, res) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (res && res.headers['retry-after']) {
|
|
264
|
-
retryAfter = res.headers['retry-after']
|
|
265
|
-
}
|
|
266
|
-
if (!reply.sent) {
|
|
267
|
-
// always retry on 503 errors
|
|
268
|
-
if (res && res.statusCode === 503 && req.method === 'GET') {
|
|
269
|
-
if (retriesCount === 0 && retries < maxRetriesOn503) {
|
|
270
|
-
// we should stop at some point
|
|
271
|
-
return retry(retryAfter)
|
|
272
|
-
}
|
|
273
|
-
} else if (retriesCount > retries && err && err.code === retryOnError) {
|
|
274
|
-
return retry(retryAfter)
|
|
275
|
-
}
|
|
280
|
+
const retryDelay = retryHandler(req, res, err, retries)
|
|
281
|
+
if (!reply.sent && retryDelay) {
|
|
282
|
+
return retry(retryDelay)
|
|
276
283
|
}
|
|
277
284
|
cb(err, res)
|
|
278
285
|
})
|
package/lib/request.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
const http = require('http')
|
|
3
|
-
const https = require('https')
|
|
4
|
-
const querystring = require('querystring')
|
|
2
|
+
const http = require('node:http')
|
|
3
|
+
const https = require('node:https')
|
|
4
|
+
const querystring = require('node:querystring')
|
|
5
5
|
const eos = require('end-of-stream')
|
|
6
6
|
const pump = require('pump')
|
|
7
7
|
const undici = require('undici')
|
|
8
8
|
const { stripHttp1ConnectionHeaders } = require('./utils')
|
|
9
|
-
const http2 = require('http2')
|
|
9
|
+
const http2 = require('node:http2')
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
TimeoutError,
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastify/reply-from",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.6.0",
|
|
4
4
|
"description": "forward your HTTP request to another server, for fastify",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"type": "commonjs",
|
|
6
7
|
"types": "types/index.d.ts",
|
|
7
8
|
"scripts": {
|
|
8
9
|
"lint": "standard | snazzy",
|
|
@@ -47,11 +48,12 @@
|
|
|
47
48
|
"split2": "^4.1.0",
|
|
48
49
|
"standard": "^17.0.0",
|
|
49
50
|
"tap": "^16.2.0",
|
|
50
|
-
"tsd": "^0.
|
|
51
|
+
"tsd": "^0.30.1"
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
53
54
|
"@fastify/error": "^3.0.0",
|
|
54
55
|
"end-of-stream": "^1.4.4",
|
|
56
|
+
"fast-content-type-parse": "^1.1.0",
|
|
55
57
|
"fast-querystring": "^1.0.0",
|
|
56
58
|
"fastify-plugin": "^4.0.0",
|
|
57
59
|
"pump": "^3.0.0",
|
package/test/base-get.test.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const path = require('path')
|
|
3
|
+
const fs = require('node:fs')
|
|
4
|
+
const path = require('node:path')
|
|
5
5
|
const t = require('tap')
|
|
6
6
|
const Fastify = require('fastify')
|
|
7
7
|
const From = require('..')
|
|
8
8
|
const Multipart = require('@fastify/multipart')
|
|
9
|
-
const http = require('http')
|
|
9
|
+
const http = require('node:http')
|
|
10
10
|
const get = require('simple-get').concat
|
|
11
11
|
const FormData = require('form-data')
|
|
12
12
|
|
|
@@ -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
|
+
})
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const https = require('https')
|
|
6
|
+
const https = require('node:https')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
|
-
const fs = require('fs')
|
|
9
|
-
const path = require('path')
|
|
8
|
+
const fs = require('node:fs')
|
|
9
|
+
const path = require('node:path')
|
|
10
10
|
const certs = {
|
|
11
11
|
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
|
|
12
12
|
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
|
package/test/full-post.test.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const t = require('tap')
|
|
4
4
|
const Fastify = require('fastify')
|
|
5
5
|
const From = require('..')
|
|
6
|
-
const http = require('http')
|
|
6
|
+
const http = require('node:http')
|
|
7
7
|
const get = require('simple-get').concat
|
|
8
|
-
const querystring = require('querystring')
|
|
8
|
+
const querystring = require('node:querystring')
|
|
9
9
|
|
|
10
10
|
const instance = Fastify()
|
|
11
11
|
|