fastify 4.10.0 → 4.10.2
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/docs/Guides/Ecosystem.md +2 -0
- package/fastify.js +1 -1
- package/lib/contentTypeParser.js +75 -6
- package/package.json +26 -24
- package/test/content-parser.test.js +214 -0
- package/test/custom-parser.test.js +3 -3
- package/test/server.test.js +2 -3
- package/test/types/logger.test-d.ts +1 -0
- package/types/logger.d.ts +1 -1
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -265,6 +265,8 @@ section.
|
|
|
265
265
|
- [`fastify-cockroachdb`](https://github.com/alex-ppg/fastify-cockroachdb)
|
|
266
266
|
Fastify plugin to connect to a CockroachDB PostgreSQL instance via the
|
|
267
267
|
Sequelize ORM.
|
|
268
|
+
- [`fastify-constraints`](https://github.com/nearform/fastify-constraints)
|
|
269
|
+
Fastify plugin to add constraints to multiple routes
|
|
268
270
|
- [`fastify-couchdb`](https://github.com/nigelhanlon/fastify-couchdb) Fastify
|
|
269
271
|
plugin to add CouchDB support via [nano](https://github.com/apache/nano).
|
|
270
272
|
- [`fastify-crud-generator`](https://github.com/beliven-it/fastify-crud-generator)
|
package/fastify.js
CHANGED
package/lib/contentTypeParser.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { AsyncResource } = require('async_hooks')
|
|
4
4
|
const lru = require('tiny-lru').lru
|
|
5
|
+
// TODO: find more perforamant solution
|
|
6
|
+
const { parse: parseContentType } = require('content-type')
|
|
5
7
|
|
|
6
8
|
const secureJson = require('secure-json-parse')
|
|
7
9
|
const {
|
|
@@ -33,7 +35,7 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning)
|
|
|
33
35
|
this.customParsers = new Map()
|
|
34
36
|
this.customParsers.set('application/json', new Parser(true, false, bodyLimit, this[kDefaultJsonParse]))
|
|
35
37
|
this.customParsers.set('text/plain', new Parser(true, false, bodyLimit, defaultPlainTextParser))
|
|
36
|
-
this.parserList = ['application/json', 'text/plain']
|
|
38
|
+
this.parserList = [new ParserListItem('application/json'), new ParserListItem('text/plain')]
|
|
37
39
|
this.parserRegExpList = []
|
|
38
40
|
this.cache = lru(100)
|
|
39
41
|
}
|
|
@@ -66,7 +68,7 @@ ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
|
|
|
66
68
|
this.customParsers.set('', parser)
|
|
67
69
|
} else {
|
|
68
70
|
if (contentTypeIsString) {
|
|
69
|
-
this.parserList.unshift(contentType)
|
|
71
|
+
this.parserList.unshift(new ParserListItem(contentType))
|
|
70
72
|
} else {
|
|
71
73
|
this.parserRegExpList.unshift(contentType)
|
|
72
74
|
}
|
|
@@ -97,11 +99,20 @@ ContentTypeParser.prototype.getParser = function (contentType) {
|
|
|
97
99
|
const parser = this.cache.get(contentType)
|
|
98
100
|
if (parser !== undefined) return parser
|
|
99
101
|
|
|
102
|
+
const parsed = safeParseContentType(contentType)
|
|
103
|
+
|
|
104
|
+
// dummyContentType always the same object
|
|
105
|
+
// we can use === for the comparsion and return early
|
|
106
|
+
if (parsed === dummyContentType) {
|
|
107
|
+
return this.customParsers.get('')
|
|
108
|
+
}
|
|
109
|
+
|
|
100
110
|
// eslint-disable-next-line no-var
|
|
101
111
|
for (var i = 0; i !== this.parserList.length; ++i) {
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
const parser = this.customParsers.get(
|
|
112
|
+
const parserListItem = this.parserList[i]
|
|
113
|
+
if (compareContentType(parsed, parserListItem)) {
|
|
114
|
+
const parser = this.customParsers.get(parserListItem.name)
|
|
115
|
+
// we set request content-type in cache to reduce parsing of MIME type
|
|
105
116
|
this.cache.set(contentType, parser)
|
|
106
117
|
return parser
|
|
107
118
|
}
|
|
@@ -110,8 +121,9 @@ ContentTypeParser.prototype.getParser = function (contentType) {
|
|
|
110
121
|
// eslint-disable-next-line no-var
|
|
111
122
|
for (var j = 0; j !== this.parserRegExpList.length; ++j) {
|
|
112
123
|
const parserRegExp = this.parserRegExpList[j]
|
|
113
|
-
if (
|
|
124
|
+
if (compareRegExpContentType(contentType, parsed.type, parserRegExp)) {
|
|
114
125
|
const parser = this.customParsers.get(parserRegExp.toString())
|
|
126
|
+
// we set request content-type in cache to reduce parsing of MIME type
|
|
115
127
|
this.cache.set(contentType, parser)
|
|
116
128
|
return parser
|
|
117
129
|
}
|
|
@@ -346,6 +358,63 @@ function removeAllContentTypeParsers () {
|
|
|
346
358
|
this[kContentTypeParser].removeAll()
|
|
347
359
|
}
|
|
348
360
|
|
|
361
|
+
// dummy here to prevent repeated object creation
|
|
362
|
+
const dummyContentType = { type: '', parameters: Object.create(null) }
|
|
363
|
+
|
|
364
|
+
function safeParseContentType (contentType) {
|
|
365
|
+
try {
|
|
366
|
+
return parseContentType(contentType)
|
|
367
|
+
} catch (err) {
|
|
368
|
+
return dummyContentType
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function compareContentType (contentType, parserListItem) {
|
|
373
|
+
if (parserListItem.isEssence) {
|
|
374
|
+
// we do essence check
|
|
375
|
+
return contentType.type.indexOf(parserListItem) !== -1
|
|
376
|
+
} else {
|
|
377
|
+
// when the content-type includes parameters
|
|
378
|
+
// we do a full-text search
|
|
379
|
+
// reject essence content-type before checking parameters
|
|
380
|
+
if (contentType.type.indexOf(parserListItem.type) === -1) return false
|
|
381
|
+
for (const key of parserListItem.parameterKeys) {
|
|
382
|
+
// reject when missing parameters
|
|
383
|
+
if (!(key in contentType.parameters)) return false
|
|
384
|
+
// reject when parameters do not match
|
|
385
|
+
if (contentType.parameters[key] !== parserListItem.parameters[key]) return false
|
|
386
|
+
}
|
|
387
|
+
return true
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
|
|
392
|
+
if (regexp.source.indexOf(';') === -1) {
|
|
393
|
+
// we do essence check
|
|
394
|
+
return regexp.test(essenceMIMEType)
|
|
395
|
+
} else {
|
|
396
|
+
// when the content-type includes parameters
|
|
397
|
+
// we do a full-text match
|
|
398
|
+
return regexp.test(contentType)
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function ParserListItem (contentType) {
|
|
403
|
+
this.name = contentType
|
|
404
|
+
// we pre-calculate all the needed information
|
|
405
|
+
// before content-type comparsion
|
|
406
|
+
const parsed = safeParseContentType(contentType)
|
|
407
|
+
this.type = parsed.type
|
|
408
|
+
this.parameters = parsed.parameters
|
|
409
|
+
this.parameterKeys = Object.keys(parsed.parameters)
|
|
410
|
+
this.isEssence = contentType.indexOf(';') === -1
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// used in ContentTypeParser.remove
|
|
414
|
+
ParserListItem.prototype.toString = function () {
|
|
415
|
+
return this.name
|
|
416
|
+
}
|
|
417
|
+
|
|
349
418
|
module.exports = ContentTypeParser
|
|
350
419
|
module.exports.helpers = {
|
|
351
420
|
buildContentTypeParser,
|
package/package.json
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "4.10.
|
|
3
|
+
"version": "4.10.2",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"types": "fastify.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"bench": "branchcmp -r 2 -g -s \"npm run benchmark\"",
|
|
10
|
+
"benchmark": "npx concurrently -k -s first \"node ./examples/benchmark/simple.js\" \"npx autocannon -c 100 -d 30 -p 10 localhost:3000/\"",
|
|
11
|
+
"coverage": "npm run unit -- --cov --coverage-report=html",
|
|
12
|
+
"coverage:ci": "npm run unit -- --cov --coverage-report=html --no-browser --no-check-coverage -R terse",
|
|
13
|
+
"coverage:ci-check-coverage": "nyc check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
|
|
14
|
+
"license-checker": "license-checker --production --onlyAllow=\"MIT;ISC;BSD-3-Clause;BSD-2-Clause\"",
|
|
15
|
+
"lint": "npm run lint:standard && npm run lint:typescript && npm run lint:markdown",
|
|
16
|
+
"lint:fix": "standard --fix",
|
|
17
|
+
"lint:markdown": "markdownlint-cli2",
|
|
18
|
+
"lint:standard": "standard | snazzy",
|
|
19
|
+
"lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
|
|
20
|
+
"prepublishOnly": "PREPUBLISH=true tap --no-check-coverage test/build/**.test.js",
|
|
21
|
+
"test": "npm run lint && npm run unit && npm run test:typescript",
|
|
22
|
+
"test:ci": "npm run unit -- -R terse --cov --coverage-report=lcovonly && npm run test:typescript",
|
|
23
|
+
"test:report": "npm run lint && npm run unit:report && npm run test:typescript",
|
|
24
|
+
"test:typescript": "tsc test/types/import.ts && tsd",
|
|
25
|
+
"test:watch": "npm run unit -- -w --no-coverage-report -R terse",
|
|
26
|
+
"unit": "tap",
|
|
27
|
+
"unit:junit": "tap-mocha-reporter xunit < out.tap > test/junit-testresults.xml",
|
|
28
|
+
"unit:report": "tap --cov --coverage-report=html --coverage-report=cobertura | tee out.tap"
|
|
29
|
+
},
|
|
8
30
|
"repository": {
|
|
9
31
|
"type": "git",
|
|
10
32
|
"url": "git+https://github.com/fastify/fastify.git"
|
|
@@ -105,7 +127,7 @@
|
|
|
105
127
|
"devDependencies": {
|
|
106
128
|
"@fastify/pre-commit": "^2.0.2",
|
|
107
129
|
"@sinclair/typebox": "^0.25.2",
|
|
108
|
-
"@sinonjs/fake-timers": "^
|
|
130
|
+
"@sinonjs/fake-timers": "^10.0.0",
|
|
109
131
|
"@types/node": "^18.7.18",
|
|
110
132
|
"@typescript-eslint/eslint-plugin": "^5.37.0",
|
|
111
133
|
"@typescript-eslint/parser": "^5.37.0",
|
|
@@ -154,6 +176,7 @@
|
|
|
154
176
|
"@fastify/fast-json-stringify-compiler": "^4.1.0",
|
|
155
177
|
"abstract-logging": "^2.0.1",
|
|
156
178
|
"avvio": "^8.2.0",
|
|
179
|
+
"content-type": "^1.0.4",
|
|
157
180
|
"find-my-way": "^7.3.0",
|
|
158
181
|
"light-my-request": "^5.6.1",
|
|
159
182
|
"pino": "^8.5.0",
|
|
@@ -176,26 +199,5 @@
|
|
|
176
199
|
},
|
|
177
200
|
"tsd": {
|
|
178
201
|
"directory": "test/types"
|
|
179
|
-
},
|
|
180
|
-
"scripts": {
|
|
181
|
-
"bench": "branchcmp -r 2 -g -s \"npm run benchmark\"",
|
|
182
|
-
"benchmark": "npx concurrently -k -s first \"node ./examples/benchmark/simple.js\" \"npx autocannon -c 100 -d 30 -p 10 localhost:3000/\"",
|
|
183
|
-
"coverage": "npm run unit -- --cov --coverage-report=html",
|
|
184
|
-
"coverage:ci": "npm run unit -- --cov --coverage-report=html --no-browser --no-check-coverage -R terse",
|
|
185
|
-
"coverage:ci-check-coverage": "nyc check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
|
|
186
|
-
"license-checker": "license-checker --production --onlyAllow=\"MIT;ISC;BSD-3-Clause;BSD-2-Clause\"",
|
|
187
|
-
"lint": "npm run lint:standard && npm run lint:typescript && npm run lint:markdown",
|
|
188
|
-
"lint:fix": "standard --fix",
|
|
189
|
-
"lint:markdown": "markdownlint-cli2",
|
|
190
|
-
"lint:standard": "standard | snazzy",
|
|
191
|
-
"lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
|
|
192
|
-
"test": "npm run lint && npm run unit && npm run test:typescript",
|
|
193
|
-
"test:ci": "npm run unit -- -R terse --cov --coverage-report=lcovonly && npm run test:typescript",
|
|
194
|
-
"test:report": "npm run lint && npm run unit:report && npm run test:typescript",
|
|
195
|
-
"test:typescript": "tsc test/types/import.ts && tsd",
|
|
196
|
-
"test:watch": "npm run unit -- -w --no-coverage-report -R terse",
|
|
197
|
-
"unit": "tap",
|
|
198
|
-
"unit:junit": "tap-mocha-reporter xunit < out.tap > test/junit-testresults.xml",
|
|
199
|
-
"unit:report": "tap --cov --coverage-report=html --coverage-report=cobertura | tee out.tap"
|
|
200
202
|
}
|
|
201
|
-
}
|
|
203
|
+
}
|
|
@@ -395,3 +395,217 @@ test('Safeguard against malicious content-type / 3', async t => {
|
|
|
395
395
|
|
|
396
396
|
t.same(response.statusCode, 415)
|
|
397
397
|
})
|
|
398
|
+
|
|
399
|
+
test('Safeguard against content-type spoofing - string', async t => {
|
|
400
|
+
t.plan(1)
|
|
401
|
+
|
|
402
|
+
const fastify = Fastify()
|
|
403
|
+
fastify.removeAllContentTypeParsers()
|
|
404
|
+
fastify.addContentTypeParser('text/plain', function (request, body, done) {
|
|
405
|
+
t.pass('should be called')
|
|
406
|
+
done(null, body)
|
|
407
|
+
})
|
|
408
|
+
fastify.addContentTypeParser('application/json', function (request, body, done) {
|
|
409
|
+
t.fail('shouldn\'t be called')
|
|
410
|
+
done(null, body)
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
fastify.post('/', async () => {
|
|
414
|
+
return 'ok'
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
await fastify.inject({
|
|
418
|
+
method: 'POST',
|
|
419
|
+
path: '/',
|
|
420
|
+
headers: {
|
|
421
|
+
'content-type': 'text/plain; content-type="application/json"'
|
|
422
|
+
},
|
|
423
|
+
body: ''
|
|
424
|
+
})
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
test('Safeguard against content-type spoofing - regexp', async t => {
|
|
428
|
+
t.plan(1)
|
|
429
|
+
|
|
430
|
+
const fastify = Fastify()
|
|
431
|
+
fastify.removeAllContentTypeParsers()
|
|
432
|
+
fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
|
|
433
|
+
t.pass('should be called')
|
|
434
|
+
done(null, body)
|
|
435
|
+
})
|
|
436
|
+
fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
|
|
437
|
+
t.fail('shouldn\'t be called')
|
|
438
|
+
done(null, body)
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
fastify.post('/', async () => {
|
|
442
|
+
return 'ok'
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
await fastify.inject({
|
|
446
|
+
method: 'POST',
|
|
447
|
+
path: '/',
|
|
448
|
+
headers: {
|
|
449
|
+
'content-type': 'text/plain; content-type="application/json"'
|
|
450
|
+
},
|
|
451
|
+
body: ''
|
|
452
|
+
})
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test('content-type match parameters - string 1', async t => {
|
|
456
|
+
t.plan(1)
|
|
457
|
+
|
|
458
|
+
const fastify = Fastify()
|
|
459
|
+
fastify.removeAllContentTypeParsers()
|
|
460
|
+
fastify.addContentTypeParser('text/plain; charset=utf8', function (request, body, done) {
|
|
461
|
+
t.fail('shouldn\'t be called')
|
|
462
|
+
done(null, body)
|
|
463
|
+
})
|
|
464
|
+
fastify.addContentTypeParser('application/json; charset=utf8', function (request, body, done) {
|
|
465
|
+
t.pass('should be called')
|
|
466
|
+
done(null, body)
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
fastify.post('/', async () => {
|
|
470
|
+
return 'ok'
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
await fastify.inject({
|
|
474
|
+
method: 'POST',
|
|
475
|
+
path: '/',
|
|
476
|
+
headers: {
|
|
477
|
+
'content-type': 'application/json; charset=utf8'
|
|
478
|
+
},
|
|
479
|
+
body: ''
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
test('content-type match parameters - string 2', async t => {
|
|
484
|
+
t.plan(1)
|
|
485
|
+
|
|
486
|
+
const fastify = Fastify()
|
|
487
|
+
fastify.removeAllContentTypeParsers()
|
|
488
|
+
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
|
|
489
|
+
t.pass('should be called')
|
|
490
|
+
done(null, body)
|
|
491
|
+
})
|
|
492
|
+
fastify.addContentTypeParser('text/plain; charset=utf8; foo=bar', function (request, body, done) {
|
|
493
|
+
t.fail('shouldn\'t be called')
|
|
494
|
+
done(null, body)
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
fastify.post('/', async () => {
|
|
498
|
+
return 'ok'
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
await fastify.inject({
|
|
502
|
+
method: 'POST',
|
|
503
|
+
path: '/',
|
|
504
|
+
headers: {
|
|
505
|
+
'content-type': 'application/json; foo=bar; charset=utf8'
|
|
506
|
+
},
|
|
507
|
+
body: ''
|
|
508
|
+
})
|
|
509
|
+
})
|
|
510
|
+
|
|
511
|
+
test('content-type match parameters - regexp', async t => {
|
|
512
|
+
t.plan(1)
|
|
513
|
+
|
|
514
|
+
const fastify = Fastify()
|
|
515
|
+
fastify.removeAllContentTypeParsers()
|
|
516
|
+
fastify.addContentTypeParser(/application\/json; charset=utf8/, function (request, body, done) {
|
|
517
|
+
t.pass('should be called')
|
|
518
|
+
done(null, body)
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
fastify.post('/', async () => {
|
|
522
|
+
return 'ok'
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
await fastify.inject({
|
|
526
|
+
method: 'POST',
|
|
527
|
+
path: '/',
|
|
528
|
+
headers: {
|
|
529
|
+
'content-type': 'application/json; charset=utf8'
|
|
530
|
+
},
|
|
531
|
+
body: ''
|
|
532
|
+
})
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
test('content-type fail when parameters not match - string 1', async t => {
|
|
536
|
+
t.plan(1)
|
|
537
|
+
|
|
538
|
+
const fastify = Fastify()
|
|
539
|
+
fastify.removeAllContentTypeParsers()
|
|
540
|
+
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
|
|
541
|
+
t.fail('shouldn\'t be called')
|
|
542
|
+
done(null, body)
|
|
543
|
+
})
|
|
544
|
+
|
|
545
|
+
fastify.post('/', async () => {
|
|
546
|
+
return 'ok'
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
const response = await fastify.inject({
|
|
550
|
+
method: 'POST',
|
|
551
|
+
path: '/',
|
|
552
|
+
headers: {
|
|
553
|
+
'content-type': 'application/json; charset=utf8'
|
|
554
|
+
},
|
|
555
|
+
body: ''
|
|
556
|
+
})
|
|
557
|
+
|
|
558
|
+
t.same(response.statusCode, 415)
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
test('content-type fail when parameters not match - string 2', async t => {
|
|
562
|
+
t.plan(1)
|
|
563
|
+
|
|
564
|
+
const fastify = Fastify()
|
|
565
|
+
fastify.removeAllContentTypeParsers()
|
|
566
|
+
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
|
|
567
|
+
t.fail('shouldn\'t be called')
|
|
568
|
+
done(null, body)
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
fastify.post('/', async () => {
|
|
572
|
+
return 'ok'
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
const response = await fastify.inject({
|
|
576
|
+
method: 'POST',
|
|
577
|
+
path: '/',
|
|
578
|
+
headers: {
|
|
579
|
+
'content-type': 'application/json; charset=utf8; foo=baz'
|
|
580
|
+
},
|
|
581
|
+
body: ''
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
t.same(response.statusCode, 415)
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
test('content-type fail when parameters not match - regexp', async t => {
|
|
588
|
+
t.plan(1)
|
|
589
|
+
|
|
590
|
+
const fastify = Fastify()
|
|
591
|
+
fastify.removeAllContentTypeParsers()
|
|
592
|
+
fastify.addContentTypeParser(/application\/json; charset=utf8; foo=bar/, function (request, body, done) {
|
|
593
|
+
t.fail('shouldn\'t be called')
|
|
594
|
+
done(null, body)
|
|
595
|
+
})
|
|
596
|
+
|
|
597
|
+
fastify.post('/', async () => {
|
|
598
|
+
return 'ok'
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
const response = await fastify.inject({
|
|
602
|
+
method: 'POST',
|
|
603
|
+
path: '/',
|
|
604
|
+
headers: {
|
|
605
|
+
'content-type': 'application/json; charset=utf8'
|
|
606
|
+
},
|
|
607
|
+
body: ''
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
t.same(response.statusCode, 415)
|
|
611
|
+
})
|
|
@@ -1053,7 +1053,7 @@ test('The charset should not interfere with the content type handling', t => {
|
|
|
1053
1053
|
url: getUrl(fastify),
|
|
1054
1054
|
body: '{"hello":"world"}',
|
|
1055
1055
|
headers: {
|
|
1056
|
-
'Content-Type': 'application/json charset=utf-8'
|
|
1056
|
+
'Content-Type': 'application/json; charset=utf-8'
|
|
1057
1057
|
}
|
|
1058
1058
|
}, (err, response, body) => {
|
|
1059
1059
|
t.error(err)
|
|
@@ -1236,7 +1236,7 @@ test('contentTypeParser should add a custom parser with RegExp value', t => {
|
|
|
1236
1236
|
url: getUrl(fastify),
|
|
1237
1237
|
body: '{"hello":"world"}',
|
|
1238
1238
|
headers: {
|
|
1239
|
-
'Content-Type': 'weird
|
|
1239
|
+
'Content-Type': 'weird/content-type+json'
|
|
1240
1240
|
}
|
|
1241
1241
|
}, (err, response, body) => {
|
|
1242
1242
|
t.error(err)
|
|
@@ -1266,7 +1266,7 @@ test('contentTypeParser should add multiple custom parsers with RegExp values',
|
|
|
1266
1266
|
done(null, 'xml')
|
|
1267
1267
|
})
|
|
1268
1268
|
|
|
1269
|
-
fastify.addContentTypeParser(/.*\+myExtension
|
|
1269
|
+
fastify.addContentTypeParser(/.*\+myExtension$/i, function (req, payload, done) {
|
|
1270
1270
|
let data = ''
|
|
1271
1271
|
payload.on('data', chunk => { data += chunk })
|
|
1272
1272
|
payload.on('end', () => {
|
package/test/server.test.js
CHANGED
|
@@ -36,19 +36,18 @@ test('listen should accept stringified number port', t => {
|
|
|
36
36
|
|
|
37
37
|
test('listen should reject string port', async (t) => {
|
|
38
38
|
t.plan(2)
|
|
39
|
-
|
|
40
39
|
const fastify = Fastify()
|
|
41
40
|
t.teardown(fastify.close.bind(fastify))
|
|
42
41
|
|
|
43
42
|
try {
|
|
44
43
|
await fastify.listen({ port: 'hello-world' })
|
|
45
44
|
} catch (error) {
|
|
46
|
-
t.
|
|
45
|
+
t.equal(error.code, 'ERR_SOCKET_BAD_PORT')
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
try {
|
|
50
49
|
await fastify.listen({ port: '1234hello' })
|
|
51
50
|
} catch (error) {
|
|
52
|
-
t.
|
|
51
|
+
t.equal(error.code, 'ERR_SOCKET_BAD_PORT')
|
|
53
52
|
}
|
|
54
53
|
})
|
|
@@ -183,6 +183,7 @@ expectDeprecated({} as FastifyLoggerInstance)
|
|
|
183
183
|
const childParent = fastify().log
|
|
184
184
|
// we test different option variant here
|
|
185
185
|
expectType<FastifyLoggerInstance>(childParent.child({}, { level: 'info' }))
|
|
186
|
+
expectType<FastifyLoggerInstance>(childParent.child({}, { level: 'silent' }))
|
|
186
187
|
expectType<FastifyLoggerInstance>(childParent.child({}, { redact: ['pass', 'pin'] }))
|
|
187
188
|
expectType<FastifyLoggerInstance>(childParent.child({}, { serializers: { key: () => {} } }))
|
|
188
189
|
expectType<FastifyLoggerInstance>(childParent.child({}, { level: 'info', redact: ['pass', 'pin'], serializers: { key: () => {} } }))
|