Aktueller Stand
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// This file is autogenerated by build/build-validation.js, do not edit
|
||||
/* istanbul ignore file */
|
||||
/* c8 ignore start */
|
||||
"use strict";
|
||||
module.exports = validate10;
|
||||
module.exports.default = validate10;
|
||||
const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"type":"boolean","default":false},"jsonShorthand":{"type":"boolean","default":true},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"enum":[false]},{"type":"string"}],"default":"request-id"},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":true},"versioning":{"type":"object","additionalProperties":true,"required":["storage","deriveVersion"],"properties":{"storage":{},"deriveVersion":{}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
|
||||
const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"default":false},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"type":"boolean"},{"type":"string"}],"default":false},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":false},"routerOptions":{"type":"object","additionalProperties":true,"properties":{"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"maxParamLength":{"type":"integer","default":100},"allowUnsafeRegex":{"type":"boolean","default":false},"useSemicolonDelimiter":{"type":"boolean","default":false}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
|
||||
const func2 = Object.prototype.hasOwnProperty;
|
||||
const pattern0 = new RegExp("idle", "u");
|
||||
|
||||
@@ -42,9 +42,6 @@ data.ignoreDuplicateSlashes = false;
|
||||
if(data.disableRequestLogging === undefined){
|
||||
data.disableRequestLogging = false;
|
||||
}
|
||||
if(data.jsonShorthand === undefined){
|
||||
data.jsonShorthand = true;
|
||||
}
|
||||
if(data.maxParamLength === undefined){
|
||||
data.maxParamLength = 100;
|
||||
}
|
||||
@@ -58,7 +55,7 @@ if(data.pluginTimeout === undefined){
|
||||
data.pluginTimeout = 10000;
|
||||
}
|
||||
if(data.requestIdHeader === undefined){
|
||||
data.requestIdHeader = "request-id";
|
||||
data.requestIdHeader = false;
|
||||
}
|
||||
if(data.requestIdLogLabel === undefined){
|
||||
data.requestIdLogLabel = "reqId";
|
||||
@@ -70,7 +67,7 @@ if(data.exposeHeadRoutes === undefined){
|
||||
data.exposeHeadRoutes = true;
|
||||
}
|
||||
if(data.useSemicolonDelimiter === undefined){
|
||||
data.useSemicolonDelimiter = true;
|
||||
data.useSemicolonDelimiter = false;
|
||||
}
|
||||
const _errs1 = errors;
|
||||
for(const key0 in data){
|
||||
@@ -688,163 +685,122 @@ data["ignoreDuplicateSlashes"] = coerced14;
|
||||
}
|
||||
var valid0 = _errs43 === errors;
|
||||
if(valid0){
|
||||
let data13 = data.disableRequestLogging;
|
||||
let data13 = data.maxParamLength;
|
||||
const _errs45 = errors;
|
||||
if(typeof data13 !== "boolean"){
|
||||
if(!(((typeof data13 == "number") && (!(data13 % 1) && !isNaN(data13))) && (isFinite(data13)))){
|
||||
let dataType15 = typeof data13;
|
||||
let coerced15 = undefined;
|
||||
if(!(coerced15 !== undefined)){
|
||||
if(data13 === "false" || data13 === 0 || data13 === null){
|
||||
coerced15 = false;
|
||||
}
|
||||
else if(data13 === "true" || data13 === 1){
|
||||
coerced15 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/disableRequestLogging",schemaPath:"#/properties/disableRequestLogging/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced15 !== undefined){
|
||||
data13 = coerced15;
|
||||
if(data !== undefined){
|
||||
data["disableRequestLogging"] = coerced15;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs45 === errors;
|
||||
if(valid0){
|
||||
let data14 = data.jsonShorthand;
|
||||
const _errs47 = errors;
|
||||
if(typeof data14 !== "boolean"){
|
||||
let coerced16 = undefined;
|
||||
if(!(coerced16 !== undefined)){
|
||||
if(data14 === "false" || data14 === 0 || data14 === null){
|
||||
coerced16 = false;
|
||||
}
|
||||
else if(data14 === "true" || data14 === 1){
|
||||
coerced16 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/jsonShorthand",schemaPath:"#/properties/jsonShorthand/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced16 !== undefined){
|
||||
data14 = coerced16;
|
||||
if(data !== undefined){
|
||||
data["jsonShorthand"] = coerced16;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs47 === errors;
|
||||
if(valid0){
|
||||
let data15 = data.maxParamLength;
|
||||
const _errs49 = errors;
|
||||
if(!(((typeof data15 == "number") && (!(data15 % 1) && !isNaN(data15))) && (isFinite(data15)))){
|
||||
let dataType17 = typeof data15;
|
||||
let coerced17 = undefined;
|
||||
if(!(coerced17 !== undefined)){
|
||||
if(dataType17 === "boolean" || data15 === null
|
||||
|| (dataType17 === "string" && data15 && data15 == +data15 && !(data15 % 1))){
|
||||
coerced17 = +data15;
|
||||
if(dataType15 === "boolean" || data13 === null
|
||||
|| (dataType15 === "string" && data13 && data13 == +data13 && !(data13 % 1))){
|
||||
coerced15 = +data13;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/maxParamLength",schemaPath:"#/properties/maxParamLength/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced17 !== undefined){
|
||||
data15 = coerced17;
|
||||
if(coerced15 !== undefined){
|
||||
data13 = coerced15;
|
||||
if(data !== undefined){
|
||||
data["maxParamLength"] = coerced17;
|
||||
data["maxParamLength"] = coerced15;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs49 === errors;
|
||||
var valid0 = _errs45 === errors;
|
||||
if(valid0){
|
||||
let data16 = data.onProtoPoisoning;
|
||||
const _errs51 = errors;
|
||||
if(typeof data16 !== "string"){
|
||||
let dataType18 = typeof data16;
|
||||
let coerced18 = undefined;
|
||||
if(!(coerced18 !== undefined)){
|
||||
if(dataType18 == "number" || dataType18 == "boolean"){
|
||||
coerced18 = "" + data16;
|
||||
let data14 = data.onProtoPoisoning;
|
||||
const _errs47 = errors;
|
||||
if(typeof data14 !== "string"){
|
||||
let dataType16 = typeof data14;
|
||||
let coerced16 = undefined;
|
||||
if(!(coerced16 !== undefined)){
|
||||
if(dataType16 == "number" || dataType16 == "boolean"){
|
||||
coerced16 = "" + data14;
|
||||
}
|
||||
else if(data16 === null){
|
||||
coerced18 = "";
|
||||
else if(data14 === null){
|
||||
coerced16 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/onProtoPoisoning",schemaPath:"#/properties/onProtoPoisoning/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced18 !== undefined){
|
||||
data16 = coerced18;
|
||||
if(coerced16 !== undefined){
|
||||
data14 = coerced16;
|
||||
if(data !== undefined){
|
||||
data["onProtoPoisoning"] = coerced18;
|
||||
data["onProtoPoisoning"] = coerced16;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs51 === errors;
|
||||
var valid0 = _errs47 === errors;
|
||||
if(valid0){
|
||||
let data17 = data.onConstructorPoisoning;
|
||||
const _errs53 = errors;
|
||||
if(typeof data17 !== "string"){
|
||||
let dataType19 = typeof data17;
|
||||
let coerced19 = undefined;
|
||||
if(!(coerced19 !== undefined)){
|
||||
if(dataType19 == "number" || dataType19 == "boolean"){
|
||||
coerced19 = "" + data17;
|
||||
let data15 = data.onConstructorPoisoning;
|
||||
const _errs49 = errors;
|
||||
if(typeof data15 !== "string"){
|
||||
let dataType17 = typeof data15;
|
||||
let coerced17 = undefined;
|
||||
if(!(coerced17 !== undefined)){
|
||||
if(dataType17 == "number" || dataType17 == "boolean"){
|
||||
coerced17 = "" + data15;
|
||||
}
|
||||
else if(data17 === null){
|
||||
coerced19 = "";
|
||||
else if(data15 === null){
|
||||
coerced17 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/onConstructorPoisoning",schemaPath:"#/properties/onConstructorPoisoning/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced19 !== undefined){
|
||||
data17 = coerced19;
|
||||
if(coerced17 !== undefined){
|
||||
data15 = coerced17;
|
||||
if(data !== undefined){
|
||||
data["onConstructorPoisoning"] = coerced19;
|
||||
data["onConstructorPoisoning"] = coerced17;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs53 === errors;
|
||||
var valid0 = _errs49 === errors;
|
||||
if(valid0){
|
||||
let data18 = data.pluginTimeout;
|
||||
const _errs55 = errors;
|
||||
if(!(((typeof data18 == "number") && (!(data18 % 1) && !isNaN(data18))) && (isFinite(data18)))){
|
||||
let dataType20 = typeof data18;
|
||||
let coerced20 = undefined;
|
||||
if(!(coerced20 !== undefined)){
|
||||
if(dataType20 === "boolean" || data18 === null
|
||||
|| (dataType20 === "string" && data18 && data18 == +data18 && !(data18 % 1))){
|
||||
coerced20 = +data18;
|
||||
let data16 = data.pluginTimeout;
|
||||
const _errs51 = errors;
|
||||
if(!(((typeof data16 == "number") && (!(data16 % 1) && !isNaN(data16))) && (isFinite(data16)))){
|
||||
let dataType18 = typeof data16;
|
||||
let coerced18 = undefined;
|
||||
if(!(coerced18 !== undefined)){
|
||||
if(dataType18 === "boolean" || data16 === null
|
||||
|| (dataType18 === "string" && data16 && data16 == +data16 && !(data16 % 1))){
|
||||
coerced18 = +data16;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/pluginTimeout",schemaPath:"#/properties/pluginTimeout/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced20 !== undefined){
|
||||
data18 = coerced20;
|
||||
if(coerced18 !== undefined){
|
||||
data16 = coerced18;
|
||||
if(data !== undefined){
|
||||
data["pluginTimeout"] = coerced20;
|
||||
data["pluginTimeout"] = coerced18;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs55 === errors;
|
||||
var valid0 = _errs51 === errors;
|
||||
if(valid0){
|
||||
let data19 = data.requestIdHeader;
|
||||
const _errs57 = errors;
|
||||
const _errs58 = errors;
|
||||
let data17 = data.requestIdHeader;
|
||||
const _errs53 = errors;
|
||||
const _errs54 = errors;
|
||||
let valid6 = false;
|
||||
const _errs59 = errors;
|
||||
if(!(data19 === false)){
|
||||
const err12 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/0/enum",keyword:"enum",params:{allowedValues: schema11.properties.requestIdHeader.anyOf[0].enum},message:"must be equal to one of the allowed values"};
|
||||
const _errs55 = errors;
|
||||
if(typeof data17 !== "boolean"){
|
||||
let coerced19 = undefined;
|
||||
if(!(coerced19 !== undefined)){
|
||||
if(data17 === "false" || data17 === 0 || data17 === null){
|
||||
coerced19 = false;
|
||||
}
|
||||
else if(data17 === "true" || data17 === 1){
|
||||
coerced19 = true;
|
||||
}
|
||||
else {
|
||||
const err12 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/0/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};
|
||||
if(vErrors === null){
|
||||
vErrors = [err12];
|
||||
}
|
||||
@@ -853,19 +809,27 @@ vErrors.push(err12);
|
||||
}
|
||||
errors++;
|
||||
}
|
||||
var _valid3 = _errs59 === errors;
|
||||
}
|
||||
if(coerced19 !== undefined){
|
||||
data17 = coerced19;
|
||||
if(data !== undefined){
|
||||
data["requestIdHeader"] = coerced19;
|
||||
}
|
||||
}
|
||||
}
|
||||
var _valid3 = _errs55 === errors;
|
||||
valid6 = valid6 || _valid3;
|
||||
if(!valid6){
|
||||
const _errs60 = errors;
|
||||
if(typeof data19 !== "string"){
|
||||
let dataType21 = typeof data19;
|
||||
let coerced21 = undefined;
|
||||
if(!(coerced21 !== undefined)){
|
||||
if(dataType21 == "number" || dataType21 == "boolean"){
|
||||
coerced21 = "" + data19;
|
||||
const _errs57 = errors;
|
||||
if(typeof data17 !== "string"){
|
||||
let dataType20 = typeof data17;
|
||||
let coerced20 = undefined;
|
||||
if(!(coerced20 !== undefined)){
|
||||
if(dataType20 == "number" || dataType20 == "boolean"){
|
||||
coerced20 = "" + data17;
|
||||
}
|
||||
else if(data19 === null){
|
||||
coerced21 = "";
|
||||
else if(data17 === null){
|
||||
coerced20 = "";
|
||||
}
|
||||
else {
|
||||
const err13 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/1/type",keyword:"type",params:{type: "string"},message:"must be string"};
|
||||
@@ -878,14 +842,14 @@ vErrors.push(err13);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if(coerced21 !== undefined){
|
||||
data19 = coerced21;
|
||||
if(coerced20 !== undefined){
|
||||
data17 = coerced20;
|
||||
if(data !== undefined){
|
||||
data["requestIdHeader"] = coerced21;
|
||||
data["requestIdHeader"] = coerced20;
|
||||
}
|
||||
}
|
||||
}
|
||||
var _valid3 = _errs60 === errors;
|
||||
var _valid3 = _errs57 === errors;
|
||||
valid6 = valid6 || _valid3;
|
||||
}
|
||||
if(!valid6){
|
||||
@@ -901,95 +865,140 @@ validate10.errors = vErrors;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
errors = _errs58;
|
||||
errors = _errs54;
|
||||
if(vErrors !== null){
|
||||
if(_errs58){
|
||||
vErrors.length = _errs58;
|
||||
if(_errs54){
|
||||
vErrors.length = _errs54;
|
||||
}
|
||||
else {
|
||||
vErrors = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs57 === errors;
|
||||
var valid0 = _errs53 === errors;
|
||||
if(valid0){
|
||||
let data20 = data.requestIdLogLabel;
|
||||
const _errs62 = errors;
|
||||
if(typeof data20 !== "string"){
|
||||
let dataType22 = typeof data20;
|
||||
let coerced22 = undefined;
|
||||
if(!(coerced22 !== undefined)){
|
||||
if(dataType22 == "number" || dataType22 == "boolean"){
|
||||
coerced22 = "" + data20;
|
||||
let data18 = data.requestIdLogLabel;
|
||||
const _errs59 = errors;
|
||||
if(typeof data18 !== "string"){
|
||||
let dataType21 = typeof data18;
|
||||
let coerced21 = undefined;
|
||||
if(!(coerced21 !== undefined)){
|
||||
if(dataType21 == "number" || dataType21 == "boolean"){
|
||||
coerced21 = "" + data18;
|
||||
}
|
||||
else if(data20 === null){
|
||||
coerced22 = "";
|
||||
else if(data18 === null){
|
||||
coerced21 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/requestIdLogLabel",schemaPath:"#/properties/requestIdLogLabel/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced22 !== undefined){
|
||||
data20 = coerced22;
|
||||
if(coerced21 !== undefined){
|
||||
data18 = coerced21;
|
||||
if(data !== undefined){
|
||||
data["requestIdLogLabel"] = coerced22;
|
||||
data["requestIdLogLabel"] = coerced21;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs62 === errors;
|
||||
var valid0 = _errs59 === errors;
|
||||
if(valid0){
|
||||
let data21 = data.http2SessionTimeout;
|
||||
const _errs64 = errors;
|
||||
if(!(((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21))) && (isFinite(data21)))){
|
||||
let dataType23 = typeof data21;
|
||||
let coerced23 = undefined;
|
||||
if(!(coerced23 !== undefined)){
|
||||
if(dataType23 === "boolean" || data21 === null
|
||||
|| (dataType23 === "string" && data21 && data21 == +data21 && !(data21 % 1))){
|
||||
coerced23 = +data21;
|
||||
let data19 = data.http2SessionTimeout;
|
||||
const _errs61 = errors;
|
||||
if(!(((typeof data19 == "number") && (!(data19 % 1) && !isNaN(data19))) && (isFinite(data19)))){
|
||||
let dataType22 = typeof data19;
|
||||
let coerced22 = undefined;
|
||||
if(!(coerced22 !== undefined)){
|
||||
if(dataType22 === "boolean" || data19 === null
|
||||
|| (dataType22 === "string" && data19 && data19 == +data19 && !(data19 % 1))){
|
||||
coerced22 = +data19;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/http2SessionTimeout",schemaPath:"#/properties/http2SessionTimeout/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced23 !== undefined){
|
||||
data21 = coerced23;
|
||||
if(coerced22 !== undefined){
|
||||
data19 = coerced22;
|
||||
if(data !== undefined){
|
||||
data["http2SessionTimeout"] = coerced23;
|
||||
data["http2SessionTimeout"] = coerced22;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs64 === errors;
|
||||
var valid0 = _errs61 === errors;
|
||||
if(valid0){
|
||||
let data22 = data.exposeHeadRoutes;
|
||||
const _errs66 = errors;
|
||||
if(typeof data22 !== "boolean"){
|
||||
let coerced24 = undefined;
|
||||
if(!(coerced24 !== undefined)){
|
||||
if(data22 === "false" || data22 === 0 || data22 === null){
|
||||
coerced24 = false;
|
||||
let data20 = data.exposeHeadRoutes;
|
||||
const _errs63 = errors;
|
||||
if(typeof data20 !== "boolean"){
|
||||
let coerced23 = undefined;
|
||||
if(!(coerced23 !== undefined)){
|
||||
if(data20 === "false" || data20 === 0 || data20 === null){
|
||||
coerced23 = false;
|
||||
}
|
||||
else if(data22 === "true" || data22 === 1){
|
||||
coerced24 = true;
|
||||
else if(data20 === "true" || data20 === 1){
|
||||
coerced23 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/exposeHeadRoutes",schemaPath:"#/properties/exposeHeadRoutes/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced24 !== undefined){
|
||||
data22 = coerced24;
|
||||
if(coerced23 !== undefined){
|
||||
data20 = coerced23;
|
||||
if(data !== undefined){
|
||||
data["exposeHeadRoutes"] = coerced24;
|
||||
data["exposeHeadRoutes"] = coerced23;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs66 === errors;
|
||||
var valid0 = _errs63 === errors;
|
||||
if(valid0){
|
||||
let data23 = data.useSemicolonDelimiter;
|
||||
const _errs68 = errors;
|
||||
let data21 = data.useSemicolonDelimiter;
|
||||
const _errs65 = errors;
|
||||
if(typeof data21 !== "boolean"){
|
||||
let coerced24 = undefined;
|
||||
if(!(coerced24 !== undefined)){
|
||||
if(data21 === "false" || data21 === 0 || data21 === null){
|
||||
coerced24 = false;
|
||||
}
|
||||
else if(data21 === "true" || data21 === 1){
|
||||
coerced24 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/useSemicolonDelimiter",schemaPath:"#/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced24 !== undefined){
|
||||
data21 = coerced24;
|
||||
if(data !== undefined){
|
||||
data["useSemicolonDelimiter"] = coerced24;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs65 === errors;
|
||||
if(valid0){
|
||||
if(data.routerOptions !== undefined){
|
||||
let data22 = data.routerOptions;
|
||||
const _errs67 = errors;
|
||||
if(errors === _errs67){
|
||||
if(data22 && typeof data22 == "object" && !Array.isArray(data22)){
|
||||
if(data22.ignoreTrailingSlash === undefined){
|
||||
data22.ignoreTrailingSlash = false;
|
||||
}
|
||||
if(data22.ignoreDuplicateSlashes === undefined){
|
||||
data22.ignoreDuplicateSlashes = false;
|
||||
}
|
||||
if(data22.maxParamLength === undefined){
|
||||
data22.maxParamLength = 100;
|
||||
}
|
||||
if(data22.allowUnsafeRegex === undefined){
|
||||
data22.allowUnsafeRegex = false;
|
||||
}
|
||||
if(data22.useSemicolonDelimiter === undefined){
|
||||
data22.useSemicolonDelimiter = false;
|
||||
}
|
||||
let data23 = data22.ignoreTrailingSlash;
|
||||
const _errs70 = errors;
|
||||
if(typeof data23 !== "boolean"){
|
||||
let coerced25 = undefined;
|
||||
if(!(coerced25 !== undefined)){
|
||||
@@ -1000,78 +1009,170 @@ else if(data23 === "true" || data23 === 1){
|
||||
coerced25 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/useSemicolonDelimiter",schemaPath:"#/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/ignoreTrailingSlash",schemaPath:"#/properties/routerOptions/properties/ignoreTrailingSlash/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced25 !== undefined){
|
||||
data23 = coerced25;
|
||||
if(data !== undefined){
|
||||
data["useSemicolonDelimiter"] = coerced25;
|
||||
if(data22 !== undefined){
|
||||
data22["ignoreTrailingSlash"] = coerced25;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs68 === errors;
|
||||
if(valid0){
|
||||
if(data.versioning !== undefined){
|
||||
let data24 = data.versioning;
|
||||
const _errs70 = errors;
|
||||
if(errors === _errs70){
|
||||
if(data24 && typeof data24 == "object" && !Array.isArray(data24)){
|
||||
let missing1;
|
||||
if(((data24.storage === undefined) && (missing1 = "storage")) || ((data24.deriveVersion === undefined) && (missing1 = "deriveVersion"))){
|
||||
validate10.errors = [{instancePath:instancePath+"/versioning",schemaPath:"#/properties/versioning/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];
|
||||
var valid7 = _errs70 === errors;
|
||||
if(valid7){
|
||||
let data24 = data22.ignoreDuplicateSlashes;
|
||||
const _errs72 = errors;
|
||||
if(typeof data24 !== "boolean"){
|
||||
let coerced26 = undefined;
|
||||
if(!(coerced26 !== undefined)){
|
||||
if(data24 === "false" || data24 === 0 || data24 === null){
|
||||
coerced26 = false;
|
||||
}
|
||||
else if(data24 === "true" || data24 === 1){
|
||||
coerced26 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/ignoreDuplicateSlashes",schemaPath:"#/properties/routerOptions/properties/ignoreDuplicateSlashes/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced26 !== undefined){
|
||||
data24 = coerced26;
|
||||
if(data22 !== undefined){
|
||||
data22["ignoreDuplicateSlashes"] = coerced26;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs72 === errors;
|
||||
if(valid7){
|
||||
let data25 = data22.maxParamLength;
|
||||
const _errs74 = errors;
|
||||
if(!(((typeof data25 == "number") && (!(data25 % 1) && !isNaN(data25))) && (isFinite(data25)))){
|
||||
let dataType27 = typeof data25;
|
||||
let coerced27 = undefined;
|
||||
if(!(coerced27 !== undefined)){
|
||||
if(dataType27 === "boolean" || data25 === null
|
||||
|| (dataType27 === "string" && data25 && data25 == +data25 && !(data25 % 1))){
|
||||
coerced27 = +data25;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/maxParamLength",schemaPath:"#/properties/routerOptions/properties/maxParamLength/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced27 !== undefined){
|
||||
data25 = coerced27;
|
||||
if(data22 !== undefined){
|
||||
data22["maxParamLength"] = coerced27;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs74 === errors;
|
||||
if(valid7){
|
||||
let data26 = data22.allowUnsafeRegex;
|
||||
const _errs76 = errors;
|
||||
if(typeof data26 !== "boolean"){
|
||||
let coerced28 = undefined;
|
||||
if(!(coerced28 !== undefined)){
|
||||
if(data26 === "false" || data26 === 0 || data26 === null){
|
||||
coerced28 = false;
|
||||
}
|
||||
else if(data26 === "true" || data26 === 1){
|
||||
coerced28 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/allowUnsafeRegex",schemaPath:"#/properties/routerOptions/properties/allowUnsafeRegex/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced28 !== undefined){
|
||||
data26 = coerced28;
|
||||
if(data22 !== undefined){
|
||||
data22["allowUnsafeRegex"] = coerced28;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs76 === errors;
|
||||
if(valid7){
|
||||
let data27 = data22.useSemicolonDelimiter;
|
||||
const _errs78 = errors;
|
||||
if(typeof data27 !== "boolean"){
|
||||
let coerced29 = undefined;
|
||||
if(!(coerced29 !== undefined)){
|
||||
if(data27 === "false" || data27 === 0 || data27 === null){
|
||||
coerced29 = false;
|
||||
}
|
||||
else if(data27 === "true" || data27 === 1){
|
||||
coerced29 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/useSemicolonDelimiter",schemaPath:"#/properties/routerOptions/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced29 !== undefined){
|
||||
data27 = coerced29;
|
||||
if(data22 !== undefined){
|
||||
data22["useSemicolonDelimiter"] = coerced29;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs78 === errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/versioning",schemaPath:"#/properties/versioning/type",keyword:"type",params:{type: "object"},message:"must be object"}];
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions",schemaPath:"#/properties/routerOptions/type",keyword:"type",params:{type: "object"},message:"must be object"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var valid0 = _errs70 === errors;
|
||||
var valid0 = _errs67 === errors;
|
||||
}
|
||||
else {
|
||||
var valid0 = true;
|
||||
}
|
||||
if(valid0){
|
||||
if(data.constraints !== undefined){
|
||||
let data25 = data.constraints;
|
||||
const _errs73 = errors;
|
||||
if(errors === _errs73){
|
||||
if(data25 && typeof data25 == "object" && !Array.isArray(data25)){
|
||||
for(const key2 in data25){
|
||||
let data26 = data25[key2];
|
||||
const _errs76 = errors;
|
||||
if(errors === _errs76){
|
||||
if(data26 && typeof data26 == "object" && !Array.isArray(data26)){
|
||||
let missing2;
|
||||
if(((((data26.name === undefined) && (missing2 = "name")) || ((data26.storage === undefined) && (missing2 = "storage"))) || ((data26.validate === undefined) && (missing2 = "validate"))) || ((data26.deriveConstraint === undefined) && (missing2 = "deriveConstraint"))){
|
||||
validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/required",keyword:"required",params:{missingProperty: missing2},message:"must have required property '"+missing2+"'"}];
|
||||
let data28 = data.constraints;
|
||||
const _errs80 = errors;
|
||||
if(errors === _errs80){
|
||||
if(data28 && typeof data28 == "object" && !Array.isArray(data28)){
|
||||
for(const key2 in data28){
|
||||
let data29 = data28[key2];
|
||||
const _errs83 = errors;
|
||||
if(errors === _errs83){
|
||||
if(data29 && typeof data29 == "object" && !Array.isArray(data29)){
|
||||
let missing1;
|
||||
if(((((data29.name === undefined) && (missing1 = "name")) || ((data29.storage === undefined) && (missing1 = "storage"))) || ((data29.validate === undefined) && (missing1 = "validate"))) || ((data29.deriveConstraint === undefined) && (missing1 = "deriveConstraint"))){
|
||||
validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(data26.name !== undefined){
|
||||
let data27 = data26.name;
|
||||
if(typeof data27 !== "string"){
|
||||
let dataType26 = typeof data27;
|
||||
let coerced26 = undefined;
|
||||
if(!(coerced26 !== undefined)){
|
||||
if(dataType26 == "number" || dataType26 == "boolean"){
|
||||
coerced26 = "" + data27;
|
||||
if(data29.name !== undefined){
|
||||
let data30 = data29.name;
|
||||
if(typeof data30 !== "string"){
|
||||
let dataType30 = typeof data30;
|
||||
let coerced30 = undefined;
|
||||
if(!(coerced30 !== undefined)){
|
||||
if(dataType30 == "number" || dataType30 == "boolean"){
|
||||
coerced30 = "" + data30;
|
||||
}
|
||||
else if(data27 === null){
|
||||
coerced26 = "";
|
||||
else if(data30 === null){
|
||||
coerced30 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1")+"/name",schemaPath:"#/properties/constraints/additionalProperties/properties/name/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced26 !== undefined){
|
||||
data27 = coerced26;
|
||||
if(data26 !== undefined){
|
||||
data26["name"] = coerced26;
|
||||
if(coerced30 !== undefined){
|
||||
data30 = coerced30;
|
||||
if(data29 !== undefined){
|
||||
data29["name"] = coerced30;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1083,8 +1184,8 @@ validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var valid7 = _errs76 === errors;
|
||||
if(!valid7){
|
||||
var valid8 = _errs83 === errors;
|
||||
if(!valid8){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1094,7 +1195,7 @@ validate10.errors = [{instancePath:instancePath+"/constraints",schemaPath:"#/pro
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var valid0 = _errs73 === errors;
|
||||
var valid0 = _errs80 === errors;
|
||||
}
|
||||
else {
|
||||
var valid0 = true;
|
||||
@@ -1123,8 +1224,6 @@ var valid0 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}];
|
||||
return false;
|
||||
@@ -1135,4 +1234,5 @@ return errors === 0;
|
||||
}
|
||||
|
||||
|
||||
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"jsonShorthand":true,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":"request-id","requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":true}
|
||||
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false,"allowErrorHandlerOverride":true,"routerOptions":{"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"allowUnsafeRegex":false,"useSemicolonDelimiter":false}}
|
||||
/* c8 ignore stop */
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
const { AsyncResource } = require('node:async_hooks')
|
||||
const { FifoMap: Fifo } = require('toad-cache')
|
||||
const { safeParse: safeParseContentType, defaultContentType } = require('fast-content-type-parse')
|
||||
const secureJson = require('secure-json-parse')
|
||||
const { parse: secureJsonParse } = require('secure-json-parse')
|
||||
const {
|
||||
kDefaultJsonParse,
|
||||
kContentTypeParser,
|
||||
@@ -25,8 +24,10 @@ const {
|
||||
FST_ERR_CTP_INVALID_MEDIA_TYPE,
|
||||
FST_ERR_CTP_INVALID_CONTENT_LENGTH,
|
||||
FST_ERR_CTP_EMPTY_JSON_BODY,
|
||||
FST_ERR_CTP_INSTANCE_ALREADY_STARTED
|
||||
FST_ERR_CTP_INSTANCE_ALREADY_STARTED,
|
||||
FST_ERR_CTP_INVALID_JSON_BODY
|
||||
} = require('./errors')
|
||||
const { FSTSEC001 } = require('./warnings')
|
||||
|
||||
function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning) {
|
||||
this[kDefaultJsonParse] = getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning)
|
||||
@@ -34,7 +35,7 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning)
|
||||
this.customParsers = new Map()
|
||||
this.customParsers.set('application/json', new Parser(true, false, bodyLimit, this[kDefaultJsonParse]))
|
||||
this.customParsers.set('text/plain', new Parser(true, false, bodyLimit, defaultPlainTextParser))
|
||||
this.parserList = [new ParserListItem('application/json'), new ParserListItem('text/plain')]
|
||||
this.parserList = ['application/json', 'text/plain']
|
||||
this.parserRegExpList = []
|
||||
this.cache = new Fifo(100)
|
||||
}
|
||||
@@ -42,9 +43,16 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning)
|
||||
ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
|
||||
const contentTypeIsString = typeof contentType === 'string'
|
||||
|
||||
if (!contentTypeIsString && !(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
if (contentTypeIsString && contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
|
||||
if (typeof parserFn !== 'function') throw new FST_ERR_CTP_INVALID_HANDLER()
|
||||
if (contentTypeIsString) {
|
||||
contentType = contentType.trim().toLowerCase()
|
||||
if (contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
|
||||
} else if (!(contentType instanceof RegExp)) {
|
||||
throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
}
|
||||
|
||||
if (typeof parserFn !== 'function') {
|
||||
throw new FST_ERR_CTP_INVALID_HANDLER()
|
||||
}
|
||||
|
||||
if (this.existingParser(contentType)) {
|
||||
throw new FST_ERR_CTP_ALREADY_PRESENT(contentType)
|
||||
@@ -63,21 +71,29 @@ ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
|
||||
parserFn
|
||||
)
|
||||
|
||||
if (contentTypeIsString && contentType === '*') {
|
||||
if (contentType === '*') {
|
||||
this.customParsers.set('', parser)
|
||||
} else {
|
||||
if (contentTypeIsString) {
|
||||
this.parserList.unshift(new ParserListItem(contentType))
|
||||
this.parserList.unshift(contentType)
|
||||
this.customParsers.set(contentType, parser)
|
||||
} else {
|
||||
contentType.isEssence = contentType.source.indexOf(';') === -1
|
||||
validateRegExp(contentType)
|
||||
this.parserRegExpList.unshift(contentType)
|
||||
this.customParsers.set(contentType.toString(), parser)
|
||||
}
|
||||
this.customParsers.set(contentType.toString(), parser)
|
||||
}
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.hasParser = function (contentType) {
|
||||
return this.customParsers.has(typeof contentType === 'string' ? contentType : contentType.toString())
|
||||
if (typeof contentType === 'string') {
|
||||
contentType = contentType.trim().toLowerCase()
|
||||
} else {
|
||||
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
contentType = contentType.toString()
|
||||
}
|
||||
|
||||
return this.customParsers.has(contentType)
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.existingParser = function (contentType) {
|
||||
@@ -92,38 +108,33 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.getParser = function (contentType) {
|
||||
if (this.hasParser(contentType)) {
|
||||
return this.customParsers.get(contentType)
|
||||
}
|
||||
|
||||
const parser = this.cache.get(contentType)
|
||||
let parser = this.customParsers.get(contentType)
|
||||
if (parser !== undefined) return parser
|
||||
parser = this.cache.get(contentType)
|
||||
if (parser !== undefined) return parser
|
||||
|
||||
const parsed = safeParseContentType(contentType)
|
||||
|
||||
// dummyContentType always the same object
|
||||
// we can use === for the comparison and return early
|
||||
if (parsed === defaultContentType) {
|
||||
return this.customParsers.get('')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i !== this.parserList.length; ++i) {
|
||||
const caseInsensitiveContentType = contentType.toLowerCase()
|
||||
for (let i = 0; i !== this.parserList.length; ++i) {
|
||||
const parserListItem = this.parserList[i]
|
||||
if (compareContentType(parsed, parserListItem)) {
|
||||
const parser = this.customParsers.get(parserListItem.name)
|
||||
// we set request content-type in cache to reduce parsing of MIME type
|
||||
if (
|
||||
caseInsensitiveContentType.slice(0, parserListItem.length) === parserListItem &&
|
||||
(
|
||||
caseInsensitiveContentType.length === parserListItem.length ||
|
||||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 59 /* `;` */ ||
|
||||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 32 /* ` ` */ ||
|
||||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 9 /* `\t` */
|
||||
)
|
||||
) {
|
||||
parser = this.customParsers.get(parserListItem)
|
||||
this.cache.set(contentType, parser)
|
||||
return parser
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var j = 0; j !== this.parserRegExpList.length; ++j) {
|
||||
for (let j = 0; j !== this.parserRegExpList.length; ++j) {
|
||||
const parserRegExp = this.parserRegExpList[j]
|
||||
if (compareRegExpContentType(contentType, parsed.type, parserRegExp)) {
|
||||
const parser = this.customParsers.get(parserRegExp.toString())
|
||||
// we set request content-type in cache to reduce parsing of MIME type
|
||||
if (parserRegExp.test(contentType)) {
|
||||
parser = this.customParsers.get(parserRegExp.toString())
|
||||
this.cache.set(contentType, parser)
|
||||
return parser
|
||||
}
|
||||
@@ -140,13 +151,19 @@ ContentTypeParser.prototype.removeAll = function () {
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.remove = function (contentType) {
|
||||
if (!(typeof contentType === 'string' || contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
let parsers
|
||||
|
||||
const removed = this.customParsers.delete(contentType.toString())
|
||||
if (typeof contentType === 'string') {
|
||||
contentType = contentType.trim().toLowerCase()
|
||||
parsers = this.parserList
|
||||
} else {
|
||||
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
contentType = contentType.toString()
|
||||
parsers = this.parserRegExpList
|
||||
}
|
||||
|
||||
const parsers = typeof contentType === 'string' ? this.parserList : this.parserRegExpList
|
||||
|
||||
const idx = parsers.findIndex(ct => ct.toString() === contentType.toString())
|
||||
const removed = this.customParsers.delete(contentType)
|
||||
const idx = parsers.findIndex(ct => ct.toString() === contentType)
|
||||
|
||||
if (idx > -1) {
|
||||
parsers.splice(idx, 1)
|
||||
@@ -159,17 +176,18 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
||||
const parser = this.getParser(contentType)
|
||||
|
||||
if (parser === undefined) {
|
||||
if (request.is404) {
|
||||
if (request.is404 === true) {
|
||||
handler(request, reply)
|
||||
} else {
|
||||
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined))
|
||||
return
|
||||
}
|
||||
|
||||
// Early return to avoid allocating an AsyncResource if it's not needed
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined))
|
||||
return
|
||||
}
|
||||
|
||||
const resource = new AsyncResource('content-type-parser:run', request)
|
||||
const done = resource.bind(onDone)
|
||||
|
||||
if (parser.asString === true || parser.asBuffer === true) {
|
||||
rawBody(
|
||||
@@ -179,50 +197,44 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
||||
parser,
|
||||
done
|
||||
)
|
||||
} else {
|
||||
const result = parser.fn(request, request[kRequestPayloadStream], done)
|
||||
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(body => done(null, body), done)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
function done (error, body) {
|
||||
// We cannot use resource.bind() because it is broken in node v12 and v14
|
||||
resource.runInAsyncScope(() => {
|
||||
resource.emitDestroy()
|
||||
if (error) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(error)
|
||||
} else {
|
||||
request.body = body
|
||||
handler(request, reply)
|
||||
}
|
||||
})
|
||||
const result = parser.fn(request, request[kRequestPayloadStream], done)
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(body => { done(null, body) }, done)
|
||||
}
|
||||
|
||||
function onDone (error, body) {
|
||||
resource.emitDestroy()
|
||||
if (error != null) {
|
||||
// We must close the connection as the client may
|
||||
// send more data
|
||||
reply.header('connection', 'close')
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(error)
|
||||
return
|
||||
}
|
||||
request.body = body
|
||||
handler(request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function rawBody (request, reply, options, parser, done) {
|
||||
const asString = parser.asString
|
||||
const asString = parser.asString === true
|
||||
const limit = options.limit === null ? parser.bodyLimit : options.limit
|
||||
const contentLength = request.headers['content-length'] === undefined
|
||||
? NaN
|
||||
: Number(request.headers['content-length'])
|
||||
const contentLength = Number(request.headers['content-length'])
|
||||
|
||||
if (contentLength > limit) {
|
||||
// We must close the connection as the client is going
|
||||
// to send this data anyway
|
||||
reply.header('connection', 'close')
|
||||
reply.send(new FST_ERR_CTP_BODY_TOO_LARGE())
|
||||
done(new FST_ERR_CTP_BODY_TOO_LARGE(), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
let receivedLength = 0
|
||||
let body = asString === true ? '' : []
|
||||
|
||||
let body = asString ? '' : []
|
||||
const payload = request[kRequestPayloadStream] || request.raw
|
||||
|
||||
if (asString === true) {
|
||||
if (asString) {
|
||||
payload.setEncoding('utf8')
|
||||
}
|
||||
|
||||
@@ -232,7 +244,7 @@ function rawBody (request, reply, options, parser, done) {
|
||||
payload.resume()
|
||||
|
||||
function onData (chunk) {
|
||||
receivedLength += chunk.length
|
||||
receivedLength += asString ? Buffer.byteLength(chunk) : chunk.length
|
||||
const { receivedEncodedLength = 0 } = payload
|
||||
// The resulting body length must not exceed bodyLimit (see "zip bomb").
|
||||
// The case when encoded length is larger than received length is rather theoretical,
|
||||
@@ -241,11 +253,11 @@ function rawBody (request, reply, options, parser, done) {
|
||||
payload.removeListener('data', onData)
|
||||
payload.removeListener('end', onEnd)
|
||||
payload.removeListener('error', onEnd)
|
||||
reply.send(new FST_ERR_CTP_BODY_TOO_LARGE())
|
||||
done(new FST_ERR_CTP_BODY_TOO_LARGE(), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (asString === true) {
|
||||
if (asString) {
|
||||
body += chunk
|
||||
} else {
|
||||
body.push(chunk)
|
||||
@@ -257,51 +269,45 @@ function rawBody (request, reply, options, parser, done) {
|
||||
payload.removeListener('end', onEnd)
|
||||
payload.removeListener('error', onEnd)
|
||||
|
||||
if (err !== undefined) {
|
||||
if (err != null) {
|
||||
if (!(typeof err.statusCode === 'number' && err.statusCode >= 400)) {
|
||||
err.statusCode = 400
|
||||
}
|
||||
reply[kReplyIsError] = true
|
||||
reply.code(err.statusCode).send(err)
|
||||
done(err, undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (asString === true) {
|
||||
receivedLength = Buffer.byteLength(body)
|
||||
}
|
||||
|
||||
if (!Number.isNaN(contentLength) && (payload.receivedEncodedLength || receivedLength) !== contentLength) {
|
||||
reply.header('connection', 'close')
|
||||
reply.send(new FST_ERR_CTP_INVALID_CONTENT_LENGTH())
|
||||
done(new FST_ERR_CTP_INVALID_CONTENT_LENGTH(), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (asString === false) {
|
||||
if (!asString) {
|
||||
body = Buffer.concat(body)
|
||||
}
|
||||
|
||||
const result = parser.fn(request, body, done)
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(body => done(null, body), done)
|
||||
result.then(body => { done(null, body) }, done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaultJsonParser (onProtoPoisoning, onConstructorPoisoning) {
|
||||
const parseOptions = { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning }
|
||||
|
||||
return defaultJsonParser
|
||||
|
||||
function defaultJsonParser (req, body, done) {
|
||||
if (body === '' || body == null || (Buffer.isBuffer(body) && body.length === 0)) {
|
||||
return done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
|
||||
if (body.length === 0) {
|
||||
done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
|
||||
return
|
||||
}
|
||||
let json
|
||||
try {
|
||||
json = secureJson.parse(body, { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning })
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
return done(err, undefined)
|
||||
done(null, secureJsonParse(body, parseOptions))
|
||||
} catch {
|
||||
done(new FST_ERR_CTP_INVALID_JSON_BODY(), undefined)
|
||||
}
|
||||
done(null, json)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,60 +379,15 @@ function removeAllContentTypeParsers () {
|
||||
this[kContentTypeParser].removeAll()
|
||||
}
|
||||
|
||||
function compareContentType (contentType, parserListItem) {
|
||||
if (parserListItem.isEssence) {
|
||||
// we do essence check
|
||||
return contentType.type.indexOf(parserListItem) !== -1
|
||||
} else {
|
||||
// when the content-type includes parameters
|
||||
// we do a full-text search
|
||||
// reject essence content-type before checking parameters
|
||||
if (contentType.type.indexOf(parserListItem.type) === -1) return false
|
||||
for (const key of parserListItem.parameterKeys) {
|
||||
// reject when missing parameters
|
||||
if (!(key in contentType.parameters)) return false
|
||||
// reject when parameters do not match
|
||||
if (contentType.parameters[key] !== parserListItem.parameters[key]) return false
|
||||
}
|
||||
return true
|
||||
function validateRegExp (regexp) {
|
||||
// RegExp should either start with ^ or include ;?
|
||||
// It can ensure the user is properly detect the essence
|
||||
// MIME types.
|
||||
if (regexp.source[0] !== '^' && regexp.source.includes(';?') === false) {
|
||||
FSTSEC001(regexp.source)
|
||||
}
|
||||
}
|
||||
|
||||
function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
|
||||
if (regexp.isEssence) {
|
||||
// we do essence check
|
||||
return regexp.test(essenceMIMEType)
|
||||
} else {
|
||||
// when the content-type includes parameters
|
||||
// we do a full-text match
|
||||
return regexp.test(contentType)
|
||||
}
|
||||
}
|
||||
|
||||
function ParserListItem (contentType) {
|
||||
this.name = contentType
|
||||
// we pre-calculate all the needed information
|
||||
// before content-type comparison
|
||||
const parsed = safeParseContentType(contentType)
|
||||
this.isEssence = contentType.indexOf(';') === -1
|
||||
// we should not allow empty string for parser list item
|
||||
// because it would become a match-all handler
|
||||
if (this.isEssence === false && parsed.type === '') {
|
||||
// handle semicolon or empty string
|
||||
const tmp = contentType.split(';', 1)[0]
|
||||
this.type = tmp === '' ? contentType : tmp
|
||||
} else {
|
||||
this.type = parsed.type
|
||||
}
|
||||
this.parameters = parsed.parameters
|
||||
this.parameterKeys = Object.keys(parsed.parameters)
|
||||
}
|
||||
|
||||
// used in ContentTypeParser.remove
|
||||
ParserListItem.prototype.toString = function () {
|
||||
return this.name
|
||||
}
|
||||
|
||||
module.exports = ContentTypeParser
|
||||
module.exports.helpers = {
|
||||
buildContentTypeParser,
|
||||
26
backend/node_modules/fastify/lib/context.js
generated
vendored
26
backend/node_modules/fastify/lib/context.js
generated
vendored
@@ -14,8 +14,7 @@ const {
|
||||
kContentTypeParser,
|
||||
kRouteByFastify,
|
||||
kRequestCacheValidateFns,
|
||||
kReplyCacheSerializeFns,
|
||||
kPublicRouteContext
|
||||
kReplyCacheSerializeFns
|
||||
} = require('./symbols.js')
|
||||
|
||||
// Object that holds the context of every request
|
||||
@@ -79,35 +78,14 @@ function Context ({
|
||||
this.validatorCompiler = validatorCompiler || null
|
||||
this.serializerCompiler = serializerCompiler || null
|
||||
|
||||
// Route + Userland configurations for the route
|
||||
this[kPublicRouteContext] = getPublicRouteContext(this)
|
||||
|
||||
this.server = server
|
||||
}
|
||||
|
||||
function getPublicRouteContext (context) {
|
||||
return Object.create(null, {
|
||||
schema: {
|
||||
enumerable: true,
|
||||
get () {
|
||||
return context.schema
|
||||
}
|
||||
},
|
||||
config: {
|
||||
enumerable: true,
|
||||
get () {
|
||||
return context.config
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function defaultSchemaErrorFormatter (errors, dataVar) {
|
||||
let text = ''
|
||||
const separator = ', '
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i !== errors.length; ++i) {
|
||||
for (let i = 0; i !== errors.length; ++i) {
|
||||
const e = errors[i]
|
||||
text += dataVar + (e.instancePath || '') + ' ' + e.message + separator
|
||||
}
|
||||
|
||||
33
backend/node_modules/fastify/lib/decorate.js
generated
vendored
33
backend/node_modules/fastify/lib/decorate.js
generated
vendored
@@ -1,7 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
/* eslint no-prototype-builtins: 0 */
|
||||
|
||||
const {
|
||||
kReply,
|
||||
kRequest,
|
||||
@@ -13,13 +11,13 @@ const {
|
||||
FST_ERR_DEC_ALREADY_PRESENT,
|
||||
FST_ERR_DEC_MISSING_DEPENDENCY,
|
||||
FST_ERR_DEC_AFTER_START,
|
||||
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE
|
||||
FST_ERR_DEC_REFERENCE_TYPE,
|
||||
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE,
|
||||
FST_ERR_DEC_UNDECLARED
|
||||
} = require('./errors')
|
||||
|
||||
const { FSTDEP006 } = require('./warnings')
|
||||
|
||||
function decorate (instance, name, fn, dependencies) {
|
||||
if (Object.prototype.hasOwnProperty.call(instance, name)) {
|
||||
if (Object.hasOwn(instance, name)) {
|
||||
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
|
||||
}
|
||||
|
||||
@@ -35,9 +33,21 @@ function decorate (instance, name, fn, dependencies) {
|
||||
}
|
||||
}
|
||||
|
||||
function getInstanceDecorator (name) {
|
||||
if (!checkExistence(this, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'instance')
|
||||
}
|
||||
|
||||
if (typeof this[name] === 'function') {
|
||||
return this[name].bind(this)
|
||||
}
|
||||
|
||||
return this[name]
|
||||
}
|
||||
|
||||
function decorateConstructor (konstructor, name, fn, dependencies) {
|
||||
const instance = konstructor.prototype
|
||||
if (Object.prototype.hasOwnProperty.call(instance, name) || hasKey(konstructor, name)) {
|
||||
if (Object.hasOwn(instance, name) || hasKey(konstructor, name)) {
|
||||
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
|
||||
}
|
||||
|
||||
@@ -58,7 +68,7 @@ function decorateConstructor (konstructor, name, fn, dependencies) {
|
||||
|
||||
function checkReferenceType (name, fn) {
|
||||
if (typeof fn === 'object' && fn && !(typeof fn.getter === 'function' || typeof fn.setter === 'function')) {
|
||||
FSTDEP006(name)
|
||||
throw new FST_ERR_DEC_REFERENCE_TYPE(name, typeof fn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,8 +112,7 @@ function checkDependencies (instance, name, deps) {
|
||||
throw new FST_ERR_DEC_DEPENDENCY_INVALID_TYPE(name)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i !== deps.length; ++i) {
|
||||
for (let i = 0; i !== deps.length; ++i) {
|
||||
if (!checkExistence(instance, deps[i])) {
|
||||
throw new FST_ERR_DEC_MISSING_DEPENDENCY(deps[i])
|
||||
}
|
||||
@@ -137,5 +146,7 @@ module.exports = {
|
||||
existReply: checkReplyExistence,
|
||||
dependencies: checkDependencies,
|
||||
decorateReply,
|
||||
decorateRequest
|
||||
decorateRequest,
|
||||
getInstanceDecorator,
|
||||
hasKey
|
||||
}
|
||||
|
||||
23
backend/node_modules/fastify/lib/error-handler.js
generated
vendored
23
backend/node_modules/fastify/lib/error-handler.js
generated
vendored
@@ -1,12 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const statusCodes = require('node:http').STATUS_CODES
|
||||
const wrapThenable = require('./wrapThenable')
|
||||
const wrapThenable = require('./wrap-thenable.js')
|
||||
const { setErrorStatusCode } = require('./error-status.js')
|
||||
const {
|
||||
kReplyHeaders,
|
||||
kReplyNextErrorHandler,
|
||||
kReplyIsRunningOnErrorHook,
|
||||
kReplyHasStatusCode,
|
||||
kRouteContext,
|
||||
kDisableRequestLogging
|
||||
} = require('./symbols.js')
|
||||
@@ -39,7 +39,7 @@ function handleError (reply, error, cb) {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
reply.log.warn(
|
||||
{ req: reply.request, res: reply, err: error },
|
||||
error && error.message
|
||||
error?.message
|
||||
)
|
||||
}
|
||||
reply.raw.writeHead(reply.raw.statusCode)
|
||||
@@ -81,22 +81,19 @@ function handleError (reply, error, cb) {
|
||||
|
||||
function defaultErrorHandler (error, request, reply) {
|
||||
setErrorHeaders(error, reply)
|
||||
if (!reply[kReplyHasStatusCode] || reply.statusCode === 200) {
|
||||
const statusCode = error.statusCode || error.status
|
||||
reply.code(statusCode >= 400 ? statusCode : 500)
|
||||
}
|
||||
setErrorStatusCode(reply, error)
|
||||
if (reply.statusCode < 500) {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
reply.log.info(
|
||||
{ res: reply, err: error },
|
||||
error && error.message
|
||||
error?.message
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
reply.log.error(
|
||||
{ req: request, res: reply, err: error },
|
||||
error && error.message
|
||||
error?.message
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -110,18 +107,20 @@ function fallbackErrorHandler (error, reply, cb) {
|
||||
let payload
|
||||
try {
|
||||
const serializerFn = getSchemaSerializer(reply[kRouteContext], statusCode, reply[kReplyHeaders]['content-type'])
|
||||
payload = (serializerFn === false)
|
||||
? serializeError({
|
||||
if (serializerFn === false) {
|
||||
payload = serializeError({
|
||||
error: statusCodes[statusCode + ''],
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
statusCode
|
||||
})
|
||||
: serializerFn(Object.create(error, {
|
||||
} else {
|
||||
payload = serializerFn(Object.create(error, {
|
||||
error: { value: statusCodes[statusCode + ''] },
|
||||
message: { value: error.message },
|
||||
statusCode: { value: statusCode }
|
||||
}))
|
||||
}
|
||||
} catch (err) {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
// error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
|
||||
|
||||
3
backend/node_modules/fastify/lib/error-serializer.js
generated
vendored
3
backend/node_modules/fastify/lib/error-serializer.js
generated
vendored
@@ -1,5 +1,5 @@
|
||||
// This file is autogenerated by build/build-error-serializer.js, do not edit
|
||||
/* istanbul ignore file */
|
||||
/* c8 ignore start */
|
||||
|
||||
'use strict'
|
||||
|
||||
@@ -117,3 +117,4 @@ let addComma = false
|
||||
return main
|
||||
|
||||
}(validator, serializer)
|
||||
/* c8 ignore stop */
|
||||
|
||||
14
backend/node_modules/fastify/lib/error-status.js
generated
vendored
Normal file
14
backend/node_modules/fastify/lib/error-status.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
kReplyHasStatusCode
|
||||
} = require('./symbols')
|
||||
|
||||
function setErrorStatusCode (reply, err) {
|
||||
if (!reply[kReplyHasStatusCode] || reply.statusCode === 200) {
|
||||
const statusCode = err && (err.statusCode || err.status)
|
||||
reply.code(statusCode >= 400 ? statusCode : 500)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { setErrorStatusCode }
|
||||
72
backend/node_modules/fastify/lib/errors.js
generated
vendored
72
backend/node_modules/fastify/lib/errors.js
generated
vendored
@@ -47,12 +47,6 @@ const codes = {
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_VERSION_CONSTRAINT_NOT_STR: createError(
|
||||
'FST_ERR_VERSION_CONSTRAINT_NOT_STR',
|
||||
'Version constraint should be a string.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_VALIDATION: createError(
|
||||
'FST_ERR_VALIDATION',
|
||||
'%s',
|
||||
@@ -70,6 +64,12 @@ const codes = {
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_ERROR_HANDLER_ALREADY_SET: createError(
|
||||
'FST_ERR_ERROR_HANDLER_ALREADY_SET',
|
||||
"Error Handler already set in this scope. Set 'allowErrorHandlerOverride: true' to allow overriding.",
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
/**
|
||||
* ContentTypeParser
|
||||
@@ -124,6 +124,11 @@ const codes = {
|
||||
"Body cannot be empty when content-type is set to 'application/json'",
|
||||
400
|
||||
),
|
||||
FST_ERR_CTP_INVALID_JSON_BODY: createError(
|
||||
'FST_ERR_CTP_INVALID_JSON_BODY',
|
||||
"Body is not valid JSON but content-type is set to 'application/json'",
|
||||
400
|
||||
),
|
||||
FST_ERR_CTP_INSTANCE_ALREADY_STARTED: createError(
|
||||
'FST_ERR_CTP_INSTANCE_ALREADY_STARTED',
|
||||
'Cannot call "%s" when fastify instance is already started!',
|
||||
@@ -151,6 +156,14 @@ const codes = {
|
||||
'FST_ERR_DEC_AFTER_START',
|
||||
"The decorator '%s' has been added after start!"
|
||||
),
|
||||
FST_ERR_DEC_REFERENCE_TYPE: createError(
|
||||
'FST_ERR_DEC_REFERENCE_TYPE',
|
||||
"The decorator '%s' of type '%s' is a reference type. Use the { getter, setter } interface instead."
|
||||
),
|
||||
FST_ERR_DEC_UNDECLARED: createError(
|
||||
'FST_ERR_DEC_UNDECLARED',
|
||||
"No decorator '%s' has been declared on %s."
|
||||
),
|
||||
|
||||
/**
|
||||
* hooks
|
||||
@@ -191,7 +204,7 @@ const codes = {
|
||||
|
||||
FST_ERR_HOOK_TIMEOUT: createError(
|
||||
'FST_ERR_HOOK_TIMEOUT',
|
||||
"A callback for '%s' hook timed out. You may have forgotten to call 'done' function or to resolve a Promise"
|
||||
"A callback for '%s' hook%s timed out. You may have forgotten to call 'done' function or to resolve a Promise"
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -209,6 +222,27 @@ const codes = {
|
||||
TypeError
|
||||
),
|
||||
|
||||
FST_ERR_LOG_INVALID_LOGGER_INSTANCE: createError(
|
||||
'FST_ERR_LOG_INVALID_LOGGER_INSTANCE',
|
||||
'loggerInstance only accepts a logger instance.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
FST_ERR_LOG_INVALID_LOGGER_CONFIG: createError(
|
||||
'FST_ERR_LOG_INVALID_LOGGER_CONFIG',
|
||||
'logger options only accepts a configuration object.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED: createError(
|
||||
'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED',
|
||||
'You cannot provide both logger and loggerInstance. Please provide only one.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
/**
|
||||
* reply
|
||||
*/
|
||||
@@ -222,6 +256,10 @@ const codes = {
|
||||
'FST_ERR_REP_RESPONSE_BODY_CONSUMED',
|
||||
'Response.body is already consumed.'
|
||||
),
|
||||
FST_ERR_REP_READABLE_STREAM_LOCKED: createError(
|
||||
'FST_ERR_REP_READABLE_STREAM_LOCKED',
|
||||
'ReadableStream was locked. You should call releaseLock() method on reader before sending.'
|
||||
),
|
||||
FST_ERR_REP_ALREADY_SENT: createError(
|
||||
'FST_ERR_REP_ALREADY_SENT',
|
||||
'Reply was already sent, did you forget to "return reply" in "%s" (%s)?'
|
||||
@@ -301,14 +339,6 @@ const codes = {
|
||||
'response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }'
|
||||
),
|
||||
|
||||
/**
|
||||
* http2
|
||||
*/
|
||||
FST_ERR_HTTP2_INVALID_VERSION: createError(
|
||||
'FST_ERR_HTTP2_INVALID_VERSION',
|
||||
'HTTP2 is available only from node >= 8.8.1'
|
||||
),
|
||||
|
||||
/**
|
||||
* initialConfig
|
||||
*/
|
||||
@@ -339,12 +369,6 @@ const codes = {
|
||||
'Unexpected error from async constraint',
|
||||
500
|
||||
),
|
||||
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE: createError(
|
||||
'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE',
|
||||
'The defaultRoute type should be a function',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_INVALID_URL: createError(
|
||||
'FST_ERR_INVALID_URL',
|
||||
"URL must be a string. Received '%s'",
|
||||
@@ -429,6 +453,12 @@ const codes = {
|
||||
'FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE',
|
||||
"The decorator '%s'%s is not present in %s"
|
||||
),
|
||||
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER: createError(
|
||||
'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER',
|
||||
'The %s plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
/**
|
||||
* Avvio Errors
|
||||
|
||||
@@ -18,8 +18,8 @@ const { buildErrorHandler } = require('./error-handler.js')
|
||||
const {
|
||||
FST_ERR_NOT_FOUND
|
||||
} = require('./errors')
|
||||
const { createChildLogger } = require('./logger')
|
||||
const { getGenReqId } = require('./reqIdGenFactory.js')
|
||||
const { createChildLogger } = require('./logger-factory')
|
||||
const { getGenReqId } = require('./req-id-gen-factory.js')
|
||||
|
||||
/**
|
||||
* Each fastify instance have a:
|
||||
@@ -49,7 +49,8 @@ function fourOhFour (options) {
|
||||
function basic404 (request, reply) {
|
||||
const { url, method } = request.raw
|
||||
const message = `Route ${method}:${url} not found`
|
||||
if (!disableRequestLogging) {
|
||||
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(request.raw) : disableRequestLogging
|
||||
if (!resolvedDisableRequestLogging) {
|
||||
request.log.info(message)
|
||||
}
|
||||
reply.code(404).send({
|
||||
@@ -150,7 +151,9 @@ function fourOhFour (options) {
|
||||
.map(h => h.bind(this))
|
||||
context[hook] = toSet.length ? toSet : null
|
||||
}
|
||||
context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
|
||||
context.errorHandler = opts.errorHandler
|
||||
? buildErrorHandler(this[kErrorHandler], opts.errorHandler)
|
||||
: this[kErrorHandler]
|
||||
})
|
||||
|
||||
if (this[kFourOhFourContext] !== null && prefix === '/') {
|
||||
187
backend/node_modules/fastify/lib/handle-request.js
generated
vendored
Normal file
187
backend/node_modules/fastify/lib/handle-request.js
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
'use strict'
|
||||
|
||||
const diagnostics = require('node:diagnostics_channel')
|
||||
const { validate: validateSchema } = require('./validation')
|
||||
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
||||
const wrapThenable = require('./wrap-thenable')
|
||||
const { setErrorStatusCode } = require('./error-status')
|
||||
const {
|
||||
kReplyIsError,
|
||||
kRouteContext,
|
||||
kFourOhFourContext,
|
||||
kSupportedHTTPMethods
|
||||
} = require('./symbols')
|
||||
|
||||
const channels = diagnostics.tracingChannel('fastify.request.handler')
|
||||
|
||||
function handleRequest (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const method = request.method
|
||||
|
||||
if (this[kSupportedHTTPMethods].bodyless.has(method)) {
|
||||
handler(request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
if (this[kSupportedHTTPMethods].bodywith.has(method)) {
|
||||
const headers = request.headers
|
||||
const contentType = headers['content-type']
|
||||
|
||||
if (contentType === undefined) {
|
||||
const contentLength = headers['content-length']
|
||||
const transferEncoding = headers['transfer-encoding']
|
||||
const isEmptyBody = transferEncoding === undefined &&
|
||||
(contentLength === undefined || contentLength === '0')
|
||||
|
||||
if (isEmptyBody) {
|
||||
// Request has no body to parse
|
||||
handler(request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
request[kRouteContext].contentTypeParser.run('', handler, request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
request[kRouteContext].contentTypeParser.run(contentType, handler, request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
// Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
|
||||
handler(request, reply)
|
||||
}
|
||||
|
||||
function handler (request, reply) {
|
||||
try {
|
||||
if (request[kRouteContext].preValidation !== null) {
|
||||
preValidationHookRunner(
|
||||
request[kRouteContext].preValidation,
|
||||
request,
|
||||
reply,
|
||||
preValidationCallback
|
||||
)
|
||||
} else {
|
||||
preValidationCallback(null, request, reply)
|
||||
}
|
||||
} catch (err) {
|
||||
preValidationCallback(err, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preValidationCallback (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const validationErr = validateSchema(reply[kRouteContext], request)
|
||||
const isAsync = (validationErr && typeof validationErr.then === 'function') || false
|
||||
|
||||
if (isAsync) {
|
||||
const cb = validationCompleted.bind(null, request, reply)
|
||||
validationErr.then(cb, cb)
|
||||
} else {
|
||||
validationCompleted(request, reply, validationErr)
|
||||
}
|
||||
}
|
||||
|
||||
function validationCompleted (request, reply, validationErr) {
|
||||
if (validationErr) {
|
||||
if (reply[kRouteContext].attachValidation === false) {
|
||||
reply.send(validationErr)
|
||||
return
|
||||
}
|
||||
|
||||
reply.request.validationError = validationErr
|
||||
}
|
||||
|
||||
// preHandler hook
|
||||
if (request[kRouteContext].preHandler !== null) {
|
||||
preHandlerHookRunner(
|
||||
request[kRouteContext].preHandler,
|
||||
request,
|
||||
reply,
|
||||
preHandlerCallback
|
||||
)
|
||||
} else {
|
||||
preHandlerCallback(null, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preHandlerCallback (err, request, reply) {
|
||||
if (reply.sent) return
|
||||
|
||||
const context = request[kRouteContext]
|
||||
|
||||
if (!channels.hasSubscribers || context[kFourOhFourContext] === null) {
|
||||
preHandlerCallbackInner(err, request, reply)
|
||||
} else {
|
||||
const store = {
|
||||
request,
|
||||
reply,
|
||||
async: false,
|
||||
route: {
|
||||
url: context.config.url,
|
||||
method: context.config.method
|
||||
}
|
||||
}
|
||||
channels.start.runStores(store, preHandlerCallbackInner, undefined, err, request, reply, store)
|
||||
}
|
||||
}
|
||||
|
||||
function preHandlerCallbackInner (err, request, reply, store) {
|
||||
const context = request[kRouteContext]
|
||||
|
||||
try {
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
if (store) {
|
||||
store.error = err
|
||||
// Set status code before publishing so subscribers see the correct value
|
||||
setErrorStatusCode(reply, err)
|
||||
channels.error.publish(store)
|
||||
}
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
let result
|
||||
|
||||
try {
|
||||
result = context.handler(request, reply)
|
||||
} catch (err) {
|
||||
if (store) {
|
||||
store.error = err
|
||||
// Set status code before publishing so subscribers see the correct value
|
||||
setErrorStatusCode(reply, err)
|
||||
channels.error.publish(store)
|
||||
}
|
||||
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
if (result !== undefined) {
|
||||
if (result !== null && typeof result.then === 'function') {
|
||||
wrapThenable(result, reply, store)
|
||||
} else {
|
||||
reply.send(result)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (store) channels.end.publish(store)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = handleRequest
|
||||
module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }
|
||||
156
backend/node_modules/fastify/lib/handleRequest.js
generated
vendored
156
backend/node_modules/fastify/lib/handleRequest.js
generated
vendored
@@ -1,156 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { validate: validateSchema } = require('./validation')
|
||||
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
||||
const wrapThenable = require('./wrapThenable')
|
||||
const {
|
||||
kReplyIsError,
|
||||
kRouteContext
|
||||
} = require('./symbols')
|
||||
|
||||
function handleRequest (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const method = request.raw.method
|
||||
const headers = request.headers
|
||||
const context = request[kRouteContext]
|
||||
|
||||
if (method === 'GET' || method === 'HEAD') {
|
||||
handler(request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
const contentType = headers['content-type']
|
||||
|
||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH' ||
|
||||
method === 'PROPFIND' || method === 'PROPPATCH' || method === 'LOCK' || method === 'COPY' || method === 'MOVE' ||
|
||||
method === 'MKCOL' || method === 'REPORT' || method === 'MKCALENDAR') {
|
||||
if (contentType === undefined) {
|
||||
if (
|
||||
headers['transfer-encoding'] === undefined &&
|
||||
(headers['content-length'] === '0' || headers['content-length'] === undefined)
|
||||
) { // Request has no body to parse
|
||||
handler(request, reply)
|
||||
} else {
|
||||
context.contentTypeParser.run('', handler, request, reply)
|
||||
}
|
||||
} else {
|
||||
context.contentTypeParser.run(contentType, handler, request, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (method === 'OPTIONS' || method === 'DELETE') {
|
||||
if (
|
||||
contentType !== undefined &&
|
||||
(
|
||||
headers['transfer-encoding'] !== undefined ||
|
||||
headers['content-length'] !== undefined
|
||||
)
|
||||
) {
|
||||
context.contentTypeParser.run(contentType, handler, request, reply)
|
||||
} else {
|
||||
handler(request, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
|
||||
handler(request, reply)
|
||||
}
|
||||
|
||||
function handler (request, reply) {
|
||||
try {
|
||||
if (request[kRouteContext].preValidation !== null) {
|
||||
preValidationHookRunner(
|
||||
request[kRouteContext].preValidation,
|
||||
request,
|
||||
reply,
|
||||
preValidationCallback
|
||||
)
|
||||
} else {
|
||||
preValidationCallback(null, request, reply)
|
||||
}
|
||||
} catch (err) {
|
||||
preValidationCallback(err, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preValidationCallback (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const validationErr = validateSchema(reply[kRouteContext], request)
|
||||
const isAsync = (validationErr && typeof validationErr.then === 'function') || false
|
||||
|
||||
if (isAsync) {
|
||||
const cb = validationCompleted.bind(null, request, reply)
|
||||
validationErr.then(cb, cb)
|
||||
} else {
|
||||
validationCompleted(request, reply, validationErr)
|
||||
}
|
||||
}
|
||||
|
||||
function validationCompleted (request, reply, validationErr) {
|
||||
if (validationErr) {
|
||||
if (reply[kRouteContext].attachValidation === false) {
|
||||
reply.send(validationErr)
|
||||
return
|
||||
}
|
||||
|
||||
reply.request.validationError = validationErr
|
||||
}
|
||||
|
||||
// preHandler hook
|
||||
if (request[kRouteContext].preHandler !== null) {
|
||||
preHandlerHookRunner(
|
||||
request[kRouteContext].preHandler,
|
||||
request,
|
||||
reply,
|
||||
preHandlerCallback
|
||||
)
|
||||
} else {
|
||||
preHandlerCallback(null, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preHandlerCallback (err, request, reply) {
|
||||
if (reply.sent) return
|
||||
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
let result
|
||||
|
||||
try {
|
||||
result = request[kRouteContext].handler(request, reply)
|
||||
} catch (err) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
if (result !== undefined) {
|
||||
if (result !== null && typeof result.then === 'function') {
|
||||
wrapThenable(result, reply)
|
||||
} else {
|
||||
reply.send(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = handleRequest
|
||||
module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }
|
||||
@@ -3,15 +3,27 @@ function headRouteOnSendHandler (req, reply, payload, done) {
|
||||
// If payload is undefined
|
||||
if (payload === undefined) {
|
||||
reply.header('content-length', '0')
|
||||
return done(null, null)
|
||||
done(null, null)
|
||||
return
|
||||
}
|
||||
|
||||
// node:stream
|
||||
if (typeof payload.resume === 'function') {
|
||||
payload.on('error', (err) => {
|
||||
reply.log.error({ err }, 'Error on Stream found for HEAD route')
|
||||
})
|
||||
payload.resume()
|
||||
return done(null, null)
|
||||
done(null, null)
|
||||
return
|
||||
}
|
||||
|
||||
// node:stream/web
|
||||
if (typeof payload.getReader === 'function') {
|
||||
payload.cancel('Stream cancelled by HEAD route').catch((err) => {
|
||||
reply.log.error({ err }, 'Error on Stream found for HEAD route')
|
||||
})
|
||||
done(null, null)
|
||||
return
|
||||
}
|
||||
|
||||
const size = '' + Buffer.byteLength(payload)
|
||||
@@ -23,7 +35,9 @@ function headRouteOnSendHandler (req, reply, payload, done) {
|
||||
|
||||
function parseHeadOnSendHandlers (onSendHandlers) {
|
||||
if (onSendHandlers == null) return headRouteOnSendHandler
|
||||
return Array.isArray(onSendHandlers) ? [...onSendHandlers, headRouteOnSendHandler] : [onSendHandlers, headRouteOnSendHandler]
|
||||
return Array.isArray(onSendHandlers)
|
||||
? [...onSendHandlers, headRouteOnSendHandler]
|
||||
: [onSendHandlers, headRouteOnSendHandler]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
5
backend/node_modules/fastify/lib/hooks.js
generated
vendored
5
backend/node_modules/fastify/lib/hooks.js
generated
vendored
@@ -98,9 +98,12 @@ function hookRunnerApplication (hookName, boot, server, cb) {
|
||||
next()
|
||||
|
||||
function exit (err) {
|
||||
const hookFnName = hooks[i - 1]?.name
|
||||
const hookFnFragment = hookFnName ? ` "${hookFnName}"` : ''
|
||||
|
||||
if (err) {
|
||||
if (err.code === 'AVV_ERR_READY_TIMEOUT') {
|
||||
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName))
|
||||
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName, hookFnFragment))
|
||||
} else {
|
||||
err = AVVIO_ERRORS_MAP[err.code] != null
|
||||
? appendStackTrace(err, new AVVIO_ERRORS_MAP[err.code](err.message))
|
||||
|
||||
24
backend/node_modules/fastify/lib/httpMethods.js
generated
vendored
24
backend/node_modules/fastify/lib/httpMethods.js
generated
vendored
@@ -1,24 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
supportedMethods: [
|
||||
'DELETE',
|
||||
'GET',
|
||||
'HEAD',
|
||||
'PATCH',
|
||||
'POST',
|
||||
'PUT',
|
||||
'OPTIONS',
|
||||
'PROPFIND',
|
||||
'PROPPATCH',
|
||||
'MKCOL',
|
||||
'COPY',
|
||||
'MOVE',
|
||||
'LOCK',
|
||||
'UNLOCK',
|
||||
'TRACE',
|
||||
'SEARCH',
|
||||
'REPORT',
|
||||
'MKCALENDAR'
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const validate = require('./configValidator')
|
||||
const validate = require('./config-validator')
|
||||
const deepClone = require('rfdc')({ circles: true, proto: false })
|
||||
const { FST_ERR_INIT_OPTS_INVALID } = require('./errors')
|
||||
|
||||
@@ -1,105 +1,48 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Code imported from `pino-http`
|
||||
* Repo: https://github.com/pinojs/pino-http
|
||||
* License: MIT (https://raw.githubusercontent.com/pinojs/pino-http/master/LICENSE)
|
||||
*/
|
||||
|
||||
const nullLogger = require('abstract-logging')
|
||||
const pino = require('pino')
|
||||
const { serializersSym } = pino.symbols
|
||||
const {
|
||||
FST_ERR_LOG_INVALID_DESTINATION,
|
||||
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED,
|
||||
FST_ERR_LOG_INVALID_LOGGER_CONFIG,
|
||||
FST_ERR_LOG_INVALID_LOGGER_INSTANCE,
|
||||
FST_ERR_LOG_INVALID_LOGGER
|
||||
} = require('./errors')
|
||||
|
||||
function createPinoLogger (opts) {
|
||||
if (opts.stream && opts.file) {
|
||||
throw new FST_ERR_LOG_INVALID_DESTINATION()
|
||||
} else if (opts.file) {
|
||||
// we do not have stream
|
||||
opts.stream = pino.destination(opts.file)
|
||||
delete opts.file
|
||||
/**
|
||||
* Utility for creating a child logger with the appropriate bindings, logger factory
|
||||
* and validation.
|
||||
* @param {object} context
|
||||
* @param {import('../fastify').FastifyBaseLogger} logger
|
||||
* @param {import('../fastify').RawRequestDefaultExpression<any>} req
|
||||
* @param {string} reqId
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions?} loggerOpts
|
||||
*
|
||||
* @returns {object} New logger instance, inheriting all parent bindings,
|
||||
* with child bindings added.
|
||||
*/
|
||||
function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
||||
const loggerBindings = {
|
||||
[context.requestIdLogLabel]: reqId
|
||||
}
|
||||
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
||||
|
||||
// Optimization: bypass validation if the factory is our own default factory
|
||||
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
||||
validateLogger(child, true) // throw if the child is not a valid logger
|
||||
}
|
||||
|
||||
const prevLogger = opts.logger
|
||||
const prevGenReqId = opts.genReqId
|
||||
let logger = null
|
||||
|
||||
if (prevLogger) {
|
||||
opts.logger = undefined
|
||||
opts.genReqId = undefined
|
||||
// we need to tap into pino internals because in v5 it supports
|
||||
// adding serializers in child loggers
|
||||
if (prevLogger[serializersSym]) {
|
||||
opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
|
||||
}
|
||||
logger = prevLogger.child({}, opts)
|
||||
opts.logger = prevLogger
|
||||
opts.genReqId = prevGenReqId
|
||||
} else {
|
||||
logger = pino(opts, opts.stream)
|
||||
}
|
||||
|
||||
return logger
|
||||
return child
|
||||
}
|
||||
|
||||
const serializers = {
|
||||
req: function asReqValue (req) {
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
version: req.headers && req.headers['accept-version'],
|
||||
hostname: req.hostname,
|
||||
remoteAddress: req.ip,
|
||||
remotePort: req.socket ? req.socket.remotePort : undefined
|
||||
}
|
||||
},
|
||||
err: pino.stdSerializers.err,
|
||||
res: function asResValue (reply) {
|
||||
return {
|
||||
statusCode: reply.statusCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function now () {
|
||||
const ts = process.hrtime()
|
||||
return (ts[0] * 1e3) + (ts[1] / 1e6)
|
||||
}
|
||||
|
||||
function createLogger (options) {
|
||||
if (!options.logger) {
|
||||
const logger = nullLogger
|
||||
logger.child = () => logger
|
||||
return { logger, hasLogger: false }
|
||||
}
|
||||
|
||||
if (validateLogger(options.logger)) {
|
||||
const logger = createPinoLogger({
|
||||
logger: options.logger,
|
||||
serializers: Object.assign({}, serializers, options.logger.serializers)
|
||||
})
|
||||
return { logger, hasLogger: true }
|
||||
}
|
||||
|
||||
const localLoggerOptions = {}
|
||||
if (Object.prototype.toString.call(options.logger) === '[object Object]') {
|
||||
Reflect.ownKeys(options.logger).forEach(prop => {
|
||||
Object.defineProperty(localLoggerOptions, prop, {
|
||||
value: options.logger[prop],
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})
|
||||
})
|
||||
}
|
||||
localLoggerOptions.level = localLoggerOptions.level || 'info'
|
||||
localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
|
||||
options.logger = localLoggerOptions
|
||||
const logger = createPinoLogger(options.logger)
|
||||
return { logger, hasLogger: true }
|
||||
/** Default factory to create child logger instance
|
||||
*
|
||||
* @param {import('../fastify.js').FastifyBaseLogger} logger
|
||||
* @param {import('../types/logger.js').Bindings} bindings
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions} opts
|
||||
*
|
||||
* @returns {import('../types/logger.js').FastifyBaseLogger}
|
||||
*/
|
||||
function defaultChildLoggerFactory (logger, bindings, opts) {
|
||||
return logger.child(bindings, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,42 +72,65 @@ function validateLogger (logger, strict) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility for creating a child logger with the appropriate bindings, logger factory
|
||||
* and validation.
|
||||
* @param {object} context
|
||||
* @param {import('../fastify').FastifyBaseLogger} logger
|
||||
* @param {import('../fastify').RawRequestDefaultExpression<any>} req
|
||||
* @param {string} reqId
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions?} loggerOpts
|
||||
*/
|
||||
function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
||||
const loggerBindings = {
|
||||
[context.requestIdLogLabel]: reqId
|
||||
}
|
||||
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
||||
|
||||
// Optimization: bypass validation if the factory is our own default factory
|
||||
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
||||
validateLogger(child, true) // throw if the child is not a valid logger
|
||||
function createLogger (options) {
|
||||
if (options.logger && options.loggerInstance) {
|
||||
throw new FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
|
||||
}
|
||||
|
||||
return child
|
||||
if (!options.loggerInstance && !options.logger) {
|
||||
const nullLogger = require('abstract-logging')
|
||||
const logger = nullLogger
|
||||
logger.child = () => logger
|
||||
return { logger, hasLogger: false }
|
||||
}
|
||||
|
||||
const { createPinoLogger, serializers } = require('./logger-pino.js')
|
||||
|
||||
// check if the logger instance has all required properties
|
||||
if (validateLogger(options.loggerInstance)) {
|
||||
const logger = createPinoLogger({
|
||||
logger: options.loggerInstance,
|
||||
serializers: Object.assign({}, serializers, options.loggerInstance.serializers)
|
||||
})
|
||||
return { logger, hasLogger: true }
|
||||
}
|
||||
|
||||
// if a logger instance is passed to logger, throw an exception
|
||||
if (validateLogger(options.logger)) {
|
||||
throw FST_ERR_LOG_INVALID_LOGGER_CONFIG()
|
||||
}
|
||||
|
||||
if (options.loggerInstance) {
|
||||
throw FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
|
||||
}
|
||||
|
||||
const localLoggerOptions = {}
|
||||
if (Object.prototype.toString.call(options.logger) === '[object Object]') {
|
||||
Reflect.ownKeys(options.logger).forEach(prop => {
|
||||
Object.defineProperty(localLoggerOptions, prop, {
|
||||
value: options.logger[prop],
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})
|
||||
})
|
||||
}
|
||||
localLoggerOptions.level = localLoggerOptions.level || 'info'
|
||||
localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
|
||||
options.logger = localLoggerOptions
|
||||
const logger = createPinoLogger(options.logger)
|
||||
return { logger, hasLogger: true }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('../fastify.js').FastifyBaseLogger} logger
|
||||
* @param {import('../types/logger.js').Bindings} bindings
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions} opts
|
||||
*/
|
||||
function defaultChildLoggerFactory (logger, bindings, opts) {
|
||||
return logger.child(bindings, opts)
|
||||
function now () {
|
||||
const ts = process.hrtime()
|
||||
return (ts[0] * 1e3) + (ts[1] / 1e6)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createLogger,
|
||||
createChildLogger,
|
||||
defaultChildLoggerFactory,
|
||||
serializers,
|
||||
createLogger,
|
||||
validateLogger,
|
||||
now
|
||||
}
|
||||
68
backend/node_modules/fastify/lib/logger-pino.js
generated
vendored
Normal file
68
backend/node_modules/fastify/lib/logger-pino.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Code imported from `pino-http`
|
||||
* Repo: https://github.com/pinojs/pino-http
|
||||
* License: MIT (https://raw.githubusercontent.com/pinojs/pino-http/master/LICENSE)
|
||||
*/
|
||||
|
||||
const pino = require('pino')
|
||||
const { serializersSym } = pino.symbols
|
||||
const {
|
||||
FST_ERR_LOG_INVALID_DESTINATION
|
||||
} = require('./errors')
|
||||
|
||||
function createPinoLogger (opts) {
|
||||
if (opts.stream && opts.file) {
|
||||
throw new FST_ERR_LOG_INVALID_DESTINATION()
|
||||
} else if (opts.file) {
|
||||
// we do not have stream
|
||||
opts.stream = pino.destination(opts.file)
|
||||
delete opts.file
|
||||
}
|
||||
|
||||
const prevLogger = opts.logger
|
||||
const prevGenReqId = opts.genReqId
|
||||
let logger = null
|
||||
|
||||
if (prevLogger) {
|
||||
opts.logger = undefined
|
||||
opts.genReqId = undefined
|
||||
// we need to tap into pino internals because in v5 it supports
|
||||
// adding serializers in child loggers
|
||||
if (prevLogger[serializersSym]) {
|
||||
opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
|
||||
}
|
||||
logger = prevLogger.child({}, opts)
|
||||
opts.logger = prevLogger
|
||||
opts.genReqId = prevGenReqId
|
||||
} else {
|
||||
logger = pino(opts, opts.stream)
|
||||
}
|
||||
|
||||
return logger
|
||||
}
|
||||
|
||||
const serializers = {
|
||||
req: function asReqValue (req) {
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
version: req.headers && req.headers['accept-version'],
|
||||
host: req.host,
|
||||
remoteAddress: req.ip,
|
||||
remotePort: req.socket ? req.socket.remotePort : undefined
|
||||
}
|
||||
},
|
||||
err: pino.stdSerializers.err,
|
||||
res: function asResValue (reply) {
|
||||
return {
|
||||
statusCode: reply.statusCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
serializers,
|
||||
createPinoLogger
|
||||
}
|
||||
@@ -12,15 +12,16 @@ const {
|
||||
kReply,
|
||||
kRequest,
|
||||
kFourOhFour,
|
||||
kPluginNameChain
|
||||
kPluginNameChain,
|
||||
kErrorHandlerAlreadySet
|
||||
} = require('./symbols.js')
|
||||
|
||||
const Reply = require('./reply')
|
||||
const Request = require('./request')
|
||||
const SchemaController = require('./schema-controller')
|
||||
const ContentTypeParser = require('./contentTypeParser')
|
||||
const ContentTypeParser = require('./content-type-parser.js')
|
||||
const { buildHooks } = require('./hooks')
|
||||
const pluginUtils = require('./pluginUtils')
|
||||
const pluginUtils = require('./plugin-utils.js')
|
||||
|
||||
// Function that runs the encapsulation magic.
|
||||
// Everything that need to be encapsulated must be handled in this function.
|
||||
@@ -57,6 +58,7 @@ module.exports = function override (old, fn, opts) {
|
||||
// Track the plugin chain since the root instance.
|
||||
// When an non-encapsulated plugin is added, the chain will be updated.
|
||||
instance[kPluginNameChain] = [fnName]
|
||||
instance[kErrorHandlerAlreadySet] = false
|
||||
|
||||
if (instance[kLogSerializers] || opts.logSerializers) {
|
||||
instance[kLogSerializers] = Object.assign(Object.create(instance[kLogSerializers]), opts.logSerializers)
|
||||
@@ -66,7 +68,7 @@ module.exports = function override (old, fn, opts) {
|
||||
instance[kFourOhFour].arrange404(instance)
|
||||
}
|
||||
|
||||
for (const hook of instance[kHooks].onRegister) hook.call(this, instance, opts)
|
||||
for (const hook of instance[kHooks].onRegister) hook.call(old, instance, opts)
|
||||
|
||||
return instance
|
||||
}
|
||||
@@ -6,12 +6,14 @@ const kRegisteredPlugins = Symbol.for('registered-plugin')
|
||||
const {
|
||||
kTestInternals
|
||||
} = require('./symbols.js')
|
||||
const { exist, existReply, existRequest } = require('./decorate')
|
||||
const { exist, existReply, existRequest } = require('./decorate.js')
|
||||
const {
|
||||
FST_ERR_PLUGIN_VERSION_MISMATCH,
|
||||
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
|
||||
} = require('./errors')
|
||||
const { FSTWRN002 } = require('./warnings.js')
|
||||
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
|
||||
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
|
||||
} = require('./errors.js')
|
||||
|
||||
const rcRegex = /-(?:rc|pre|alpha).+$/u
|
||||
|
||||
function getMeta (fn) {
|
||||
return fn[Symbol.for('plugin-meta')]
|
||||
@@ -48,7 +50,7 @@ function getPluginName (func) {
|
||||
|
||||
function getFuncPreview (func) {
|
||||
// takes the first two lines of the function if nothing else works
|
||||
return func.toString().split('\n').slice(0, 2).map(s => s.trim()).join(' -- ')
|
||||
return func.toString().split('\n', 2).map(s => s.trim()).join(' -- ')
|
||||
}
|
||||
|
||||
function getDisplayName (fn) {
|
||||
@@ -106,11 +108,11 @@ function _checkDecorators (that, instance, decorators, name) {
|
||||
|
||||
function checkVersion (fn) {
|
||||
const meta = getMeta(fn)
|
||||
if (!meta) return
|
||||
if (meta?.fastify == null) return
|
||||
|
||||
const requiredVersion = meta.fastify
|
||||
|
||||
const fastifyRc = /-rc.+$/.test(this.version)
|
||||
const fastifyRc = rcRegex.test(this.version)
|
||||
if (fastifyRc === true && semver.gt(this.version, semver.coerce(requiredVersion)) === true) {
|
||||
// A Fastify release candidate phase is taking place. In order to reduce
|
||||
// the effort needed to test plugins with the RC, we allow plugins targeting
|
||||
@@ -138,7 +140,7 @@ function registerPluginName (fn) {
|
||||
|
||||
function checkPluginHealthiness (fn, pluginName) {
|
||||
if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
|
||||
FSTWRN002(pluginName || 'anonymous')
|
||||
throw new FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER(pluginName)
|
||||
}
|
||||
}
|
||||
|
||||
23
backend/node_modules/fastify/lib/promise.js
generated
vendored
Normal file
23
backend/node_modules/fastify/lib/promise.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
const { kTestInternals } = require('./symbols')
|
||||
|
||||
function withResolvers () {
|
||||
let res, rej
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
res = resolve
|
||||
rej = reject
|
||||
})
|
||||
return { promise, resolve: res, reject: rej }
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// TODO(20.x): remove when node@20 is not supported
|
||||
withResolvers: typeof Promise.withResolvers === 'function'
|
||||
? Promise.withResolvers.bind(Promise) // Promise.withResolvers must bind to itself
|
||||
/* c8 ignore next */
|
||||
: withResolvers, // Tested using the kTestInternals
|
||||
[kTestInternals]: {
|
||||
withResolvers
|
||||
}
|
||||
}
|
||||
223
backend/node_modules/fastify/lib/reply.js
generated
vendored
223
backend/node_modules/fastify/lib/reply.js
generated
vendored
@@ -1,11 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const eos = require('node:stream').finished
|
||||
const Readable = require('node:stream').Readable
|
||||
|
||||
const {
|
||||
kFourOhFourContext,
|
||||
kPublicRouteContext,
|
||||
kReplyErrorHandlerCalled,
|
||||
kReplyHijacked,
|
||||
kReplyStartTime,
|
||||
@@ -32,8 +30,8 @@ const {
|
||||
preSerializationHookRunner
|
||||
} = require('./hooks')
|
||||
|
||||
const internals = require('./handleRequest')[Symbol.for('internals')]
|
||||
const loggerUtils = require('./logger')
|
||||
const internals = require('./handle-request.js')[Symbol.for('internals')]
|
||||
const loggerUtils = require('./logger-factory')
|
||||
const now = loggerUtils.now
|
||||
const { handleError } = require('./error-handler')
|
||||
const { getSchemaSerializer } = require('./schemas')
|
||||
@@ -46,16 +44,17 @@ const CONTENT_TYPE = {
|
||||
const {
|
||||
FST_ERR_REP_INVALID_PAYLOAD_TYPE,
|
||||
FST_ERR_REP_RESPONSE_BODY_CONSUMED,
|
||||
FST_ERR_REP_READABLE_STREAM_LOCKED,
|
||||
FST_ERR_REP_ALREADY_SENT,
|
||||
FST_ERR_REP_SENT_VALUE,
|
||||
FST_ERR_SEND_INSIDE_ONERR,
|
||||
FST_ERR_BAD_STATUS_CODE,
|
||||
FST_ERR_BAD_TRAILER_NAME,
|
||||
FST_ERR_BAD_TRAILER_VALUE,
|
||||
FST_ERR_MISSING_SERIALIZATION_FN,
|
||||
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN
|
||||
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN,
|
||||
FST_ERR_DEC_UNDECLARED
|
||||
} = require('./errors')
|
||||
const { FSTDEP010, FSTDEP013, FSTDEP019, FSTDEP020, FSTDEP021 } = require('./warnings')
|
||||
const decorators = require('./decorate')
|
||||
|
||||
const toString = Object.prototype.toString
|
||||
|
||||
@@ -80,14 +79,6 @@ Object.defineProperties(Reply.prototype, {
|
||||
return this.request[kRouteContext]
|
||||
}
|
||||
},
|
||||
// TODO: remove once v5 is done
|
||||
// Is temporary to avoid constant conflicts between `next` and `main`
|
||||
context: {
|
||||
get () {
|
||||
FSTDEP019()
|
||||
return this.request[kRouteContext]
|
||||
}
|
||||
},
|
||||
elapsedTime: {
|
||||
get () {
|
||||
if (this[kReplyStartTime] === undefined) {
|
||||
@@ -106,20 +97,6 @@ Object.defineProperties(Reply.prototype, {
|
||||
get () {
|
||||
// We are checking whether reply was hijacked or the response has ended.
|
||||
return (this[kReplyHijacked] || this.raw.writableEnded) === true
|
||||
},
|
||||
set (value) {
|
||||
FSTDEP010()
|
||||
|
||||
if (value !== true) {
|
||||
throw new FST_ERR_REP_SENT_VALUE()
|
||||
}
|
||||
|
||||
// We throw only if sent was overwritten from Fastify
|
||||
if (this.sent && this[kReplyHijacked]) {
|
||||
throw new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method)
|
||||
}
|
||||
|
||||
this[kReplyHijacked] = true
|
||||
}
|
||||
},
|
||||
statusCode: {
|
||||
@@ -130,29 +107,34 @@ Object.defineProperties(Reply.prototype, {
|
||||
this.code(value)
|
||||
}
|
||||
},
|
||||
[kPublicRouteContext]: {
|
||||
routeOptions: {
|
||||
get () {
|
||||
return this.request[kPublicRouteContext]
|
||||
return this.request.routeOptions
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reply.prototype.writeEarlyHints = function (hints, callback) {
|
||||
this.raw.writeEarlyHints(hints, callback)
|
||||
return this
|
||||
}
|
||||
|
||||
Reply.prototype.hijack = function () {
|
||||
this[kReplyHijacked] = true
|
||||
return this
|
||||
}
|
||||
|
||||
Reply.prototype.send = function (payload) {
|
||||
if (this[kReplyIsRunningOnErrorHook] === true) {
|
||||
if (this[kReplyIsRunningOnErrorHook]) {
|
||||
throw new FST_ERR_SEND_INSIDE_ONERR()
|
||||
}
|
||||
|
||||
if (this.sent) {
|
||||
if (this.sent === true) {
|
||||
this.log.warn({ err: new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method) })
|
||||
return this
|
||||
}
|
||||
|
||||
if (payload instanceof Error || this[kReplyIsError] === true) {
|
||||
if (this[kReplyIsError] || payload instanceof Error) {
|
||||
this[kReplyIsError] = false
|
||||
onErrorHook(this, payload, onSendHook)
|
||||
return this
|
||||
@@ -179,16 +161,18 @@ Reply.prototype.send = function (payload) {
|
||||
return this
|
||||
}
|
||||
|
||||
if (payload?.buffer instanceof ArrayBuffer) {
|
||||
if (hasContentType === false) {
|
||||
if (payload.buffer instanceof ArrayBuffer) {
|
||||
if (!hasContentType) {
|
||||
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.OCTET
|
||||
}
|
||||
const payloadToSend = Buffer.isBuffer(payload) ? payload : Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)
|
||||
const payloadToSend = Buffer.isBuffer(payload)
|
||||
? payload
|
||||
: Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)
|
||||
onSendHook(this, payloadToSend)
|
||||
return this
|
||||
}
|
||||
|
||||
if (hasContentType === false && typeof payload === 'string') {
|
||||
if (!hasContentType && typeof payload === 'string') {
|
||||
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.PLAIN
|
||||
onSendHook(this, payload)
|
||||
return this
|
||||
@@ -199,26 +183,24 @@ Reply.prototype.send = function (payload) {
|
||||
if (typeof payload !== 'string') {
|
||||
preSerializationHook(this, payload)
|
||||
return this
|
||||
} else {
|
||||
payload = this[kReplySerializer](payload)
|
||||
}
|
||||
payload = this[kReplySerializer](payload)
|
||||
|
||||
// The indexOf below also matches custom json mimetypes such as 'application/hal+json' or 'application/ld+json'
|
||||
} else if (hasContentType === false || contentType.indexOf('json') > -1) {
|
||||
if (hasContentType === false) {
|
||||
// The indexOf below also matches custom json mimetypes such as 'application/hal+json' or 'application/ld+json'
|
||||
} else if (!hasContentType || contentType.indexOf('json') !== -1) {
|
||||
if (!hasContentType) {
|
||||
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.JSON
|
||||
} else {
|
||||
} else if (contentType.indexOf('charset') === -1) {
|
||||
// If user doesn't set charset, we will set charset to utf-8
|
||||
if (contentType.indexOf('charset') === -1) {
|
||||
const customContentType = contentType.trim()
|
||||
if (customContentType.endsWith(';')) {
|
||||
// custom content-type is ended with ';'
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType} charset=utf-8`
|
||||
} else {
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType}; charset=utf-8`
|
||||
}
|
||||
const customContentType = contentType.trim()
|
||||
if (customContentType.endsWith(';')) {
|
||||
// custom content-type is ended with ';'
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType} charset=utf-8`
|
||||
} else {
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType}; charset=utf-8`
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof payload !== 'string') {
|
||||
preSerializationHook(this, payload)
|
||||
return this
|
||||
@@ -232,12 +214,8 @@ Reply.prototype.send = function (payload) {
|
||||
|
||||
Reply.prototype.getHeader = function (key) {
|
||||
key = key.toLowerCase()
|
||||
const res = this.raw
|
||||
let value = this[kReplyHeaders][key]
|
||||
if (value === undefined && res.hasHeader(key)) {
|
||||
value = res.getHeader(key)
|
||||
}
|
||||
return value
|
||||
const value = this[kReplyHeaders][key]
|
||||
return value !== undefined ? value : this.raw.getHeader(key)
|
||||
}
|
||||
|
||||
Reply.prototype.getHeaders = function () {
|
||||
@@ -283,8 +261,7 @@ Reply.prototype.header = function (key, value = '') {
|
||||
|
||||
Reply.prototype.headers = function (headers) {
|
||||
const keys = Object.keys(headers)
|
||||
/* eslint-disable no-var */
|
||||
for (var i = 0; i !== keys.length; ++i) {
|
||||
for (let i = 0; i !== keys.length; ++i) {
|
||||
const key = keys[i]
|
||||
this.header(key, headers[key])
|
||||
}
|
||||
@@ -333,12 +310,12 @@ Reply.prototype.removeTrailer = function (key) {
|
||||
}
|
||||
|
||||
Reply.prototype.code = function (code) {
|
||||
const intValue = Number(code)
|
||||
if (isNaN(intValue) || intValue < 100 || intValue > 599) {
|
||||
const statusCode = +code
|
||||
if (!(statusCode >= 100 && statusCode <= 599)) {
|
||||
throw new FST_ERR_BAD_STATUS_CODE(code || String(code))
|
||||
}
|
||||
|
||||
this.raw.statusCode = intValue
|
||||
this.raw.statusCode = statusCode
|
||||
this[kReplyHasStatusCode] = true
|
||||
return this
|
||||
}
|
||||
@@ -371,13 +348,13 @@ Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null
|
||||
}
|
||||
|
||||
const serializerCompiler = this[kRouteContext].serializerCompiler ||
|
||||
this.server[kSchemaController].serializerCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom serializerCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupSerializer(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].serializerCompiler
|
||||
)
|
||||
this.server[kSchemaController].serializerCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom serializerCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupSerializer(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].serializerCompiler
|
||||
)
|
||||
|
||||
const serializeFn = serializerCompiler({
|
||||
schema,
|
||||
@@ -458,13 +435,6 @@ Reply.prototype.type = function (type) {
|
||||
}
|
||||
|
||||
Reply.prototype.redirect = function (url, code) {
|
||||
if (typeof url === 'number') {
|
||||
FSTDEP021()
|
||||
const temp = code
|
||||
code = url
|
||||
url = temp
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
code = this[kReplyHasStatusCode] ? this.raw.statusCode : 302
|
||||
}
|
||||
@@ -477,13 +447,6 @@ Reply.prototype.callNotFound = function () {
|
||||
return this
|
||||
}
|
||||
|
||||
// TODO: should be removed in fastify@5
|
||||
Reply.prototype.getResponseTime = function () {
|
||||
FSTDEP020()
|
||||
|
||||
return this.elapsedTime
|
||||
}
|
||||
|
||||
// Make reply a thenable, so it could be used with async/await.
|
||||
// See
|
||||
// - https://github.com/fastify/fastify/issues/1864 for the discussions
|
||||
@@ -509,6 +472,19 @@ Reply.prototype.then = function (fulfilled, rejected) {
|
||||
})
|
||||
}
|
||||
|
||||
Reply.prototype.getDecorator = function (name) {
|
||||
if (!decorators.hasKey(this, name) && !decorators.exist(this, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'reply')
|
||||
}
|
||||
|
||||
const decorator = this[name]
|
||||
if (typeof decorator === 'function') {
|
||||
return decorator.bind(this)
|
||||
}
|
||||
|
||||
return decorator
|
||||
}
|
||||
|
||||
function preSerializationHook (reply, payload) {
|
||||
if (reply[kRouteContext].preSerialization !== null) {
|
||||
preSerializationHookRunner(
|
||||
@@ -519,11 +495,11 @@ function preSerializationHook (reply, payload) {
|
||||
preSerializationHookEnd
|
||||
)
|
||||
} else {
|
||||
preSerializationHookEnd(null, reply.request, reply, payload)
|
||||
preSerializationHookEnd(null, undefined, reply, payload)
|
||||
}
|
||||
}
|
||||
|
||||
function preSerializationHookEnd (err, request, reply, payload) {
|
||||
function preSerializationHookEnd (err, _request, reply, payload) {
|
||||
if (err != null) {
|
||||
onErrorHook(reply, err)
|
||||
return
|
||||
@@ -679,9 +655,9 @@ function onSendEnd (reply, payload) {
|
||||
if (reply[kReplyTrailers] === null) {
|
||||
const contentLength = reply[kReplyHeaders]['content-length']
|
||||
if (!contentLength ||
|
||||
(req.raw.method !== 'HEAD' &&
|
||||
Number(contentLength) !== Buffer.byteLength(payload)
|
||||
)
|
||||
(req.raw.method !== 'HEAD' &&
|
||||
Number(contentLength) !== Buffer.byteLength(payload)
|
||||
)
|
||||
) {
|
||||
reply[kReplyHeaders]['content-length'] = '' + Buffer.byteLength(payload)
|
||||
}
|
||||
@@ -705,8 +681,62 @@ function logStreamError (logger, err, res) {
|
||||
}
|
||||
|
||||
function sendWebStream (payload, res, reply) {
|
||||
const nodeStream = Readable.fromWeb(payload)
|
||||
sendStream(nodeStream, res, reply)
|
||||
if (payload.locked) {
|
||||
throw new FST_ERR_REP_READABLE_STREAM_LOCKED()
|
||||
}
|
||||
|
||||
let sourceOpen = true
|
||||
let errorLogged = false
|
||||
const reader = payload.getReader()
|
||||
|
||||
eos(res, function (err) {
|
||||
if (sourceOpen) {
|
||||
if (err != null && res.headersSent && !errorLogged) {
|
||||
errorLogged = true
|
||||
logStreamError(reply.log, err, res)
|
||||
}
|
||||
reader.cancel().catch(noop)
|
||||
}
|
||||
})
|
||||
|
||||
if (!res.headersSent) {
|
||||
for (const key in reply[kReplyHeaders]) {
|
||||
res.setHeader(key, reply[kReplyHeaders][key])
|
||||
}
|
||||
} else {
|
||||
reply.log.warn('response will send, but you shouldn\'t use res.writeHead in stream mode')
|
||||
}
|
||||
|
||||
function onRead (result) {
|
||||
if (result.done) {
|
||||
sourceOpen = false
|
||||
sendTrailer(null, res, reply)
|
||||
return
|
||||
}
|
||||
/* c8 ignore next 5 - race condition: eos handler typically fires first */
|
||||
if (res.destroyed) {
|
||||
sourceOpen = false
|
||||
reader.cancel().catch(noop)
|
||||
return
|
||||
}
|
||||
res.write(result.value)
|
||||
reader.read().then(onRead, onReadError)
|
||||
}
|
||||
|
||||
function onReadError (err) {
|
||||
sourceOpen = false
|
||||
if (res.headersSent || reply.request.raw.aborted === true) {
|
||||
if (!errorLogged) {
|
||||
errorLogged = true
|
||||
logStreamError(reply.log, err, reply)
|
||||
}
|
||||
res.destroy()
|
||||
} else {
|
||||
onErrorHook(reply, err)
|
||||
}
|
||||
}
|
||||
|
||||
reader.read().then(onRead, onReadError)
|
||||
}
|
||||
|
||||
function sendStream (payload, res, reply) {
|
||||
@@ -810,10 +840,6 @@ function sendTrailer (payload, res, reply) {
|
||||
const result = reply[kReplyTrailers][trailerName](reply, payload, cb)
|
||||
if (typeof result === 'object' && typeof result.then === 'function') {
|
||||
result.then((v) => cb(null, v), cb)
|
||||
} else if (result !== null && result !== undefined) {
|
||||
// TODO: should be removed in fastify@5
|
||||
FSTDEP013()
|
||||
cb(null, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,10 +932,9 @@ function buildReply (R) {
|
||||
this[kReplyEndTime] = undefined
|
||||
this.log = log
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var prop
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
let prop
|
||||
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
prop = props[i]
|
||||
this[prop.key] = prop.value
|
||||
}
|
||||
|
||||
168
backend/node_modules/fastify/lib/request.js
generated
vendored
168
backend/node_modules/fastify/lib/request.js
generated
vendored
@@ -1,15 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const proxyAddr = require('proxy-addr')
|
||||
const semver = require('semver')
|
||||
const {
|
||||
FSTDEP005,
|
||||
FSTDEP012,
|
||||
FSTDEP015,
|
||||
FSTDEP016,
|
||||
FSTDEP017,
|
||||
FSTDEP018
|
||||
} = require('./warnings')
|
||||
const proxyAddr = require('@fastify/proxy-addr')
|
||||
const {
|
||||
kHasBeenDecorated,
|
||||
kSchemaBody,
|
||||
@@ -20,10 +11,10 @@ const {
|
||||
kOptions,
|
||||
kRequestCacheValidateFns,
|
||||
kRouteContext,
|
||||
kPublicRouteContext,
|
||||
kRequestOriginalUrl
|
||||
} = require('./symbols')
|
||||
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION } = require('./errors')
|
||||
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION, FST_ERR_DEC_UNDECLARED } = require('./errors')
|
||||
const decorators = require('./decorate')
|
||||
|
||||
const HTTP_PART_SYMBOL_MAP = {
|
||||
body: kSchemaBody,
|
||||
@@ -49,8 +40,8 @@ function getTrustProxyFn (tp) {
|
||||
return tp
|
||||
}
|
||||
if (tp === true) {
|
||||
// Support plain true/false
|
||||
return function () { return true }
|
||||
// Support trusting everything
|
||||
return null
|
||||
}
|
||||
if (typeof tp === 'number') {
|
||||
// Support trusting hop count
|
||||
@@ -83,10 +74,8 @@ function buildRegularRequest (R) {
|
||||
this.log = log
|
||||
this.body = undefined
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var prop
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
let prop
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
prop = props[i]
|
||||
this[prop.key] = prop.value
|
||||
}
|
||||
@@ -115,7 +104,8 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
Object.defineProperties(_Request.prototype, {
|
||||
ip: {
|
||||
get () {
|
||||
return proxyAddr(this.raw, proxyFn)
|
||||
const addrs = proxyAddr.all(this.raw, proxyFn)
|
||||
return addrs[addrs.length - 1]
|
||||
}
|
||||
},
|
||||
ips: {
|
||||
@@ -123,12 +113,18 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
return proxyAddr.all(this.raw, proxyFn)
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
host: {
|
||||
get () {
|
||||
if (this.ip !== undefined && this.headers['x-forwarded-host']) {
|
||||
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-host'])
|
||||
}
|
||||
return this.headers.host || this.headers[':authority']
|
||||
/**
|
||||
* The last fallback supports the following cases:
|
||||
* 1. http.requireHostHeader === false
|
||||
* 2. HTTP/1.0 without a Host Header
|
||||
* 3. Headers schema that may remove the Host Header
|
||||
*/
|
||||
return this.headers.host ?? this.headers[':authority'] ?? ''
|
||||
}
|
||||
},
|
||||
protocol: {
|
||||
@@ -146,6 +142,12 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
return _Request
|
||||
}
|
||||
|
||||
function assertsRequestDecoration (request, name) {
|
||||
if (!decorators.hasKey(request, name) && !decorators.exist(request, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'request')
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(Request.prototype, {
|
||||
server: {
|
||||
get () {
|
||||
@@ -171,18 +173,6 @@ Object.defineProperties(Request.prototype, {
|
||||
return this.raw.method
|
||||
}
|
||||
},
|
||||
context: {
|
||||
get () {
|
||||
FSTDEP012()
|
||||
return this[kRouteContext]
|
||||
}
|
||||
},
|
||||
routerPath: {
|
||||
get () {
|
||||
FSTDEP017()
|
||||
return this[kRouteContext].config?.url
|
||||
}
|
||||
},
|
||||
routeOptions: {
|
||||
get () {
|
||||
const context = this[kRouteContext]
|
||||
@@ -198,37 +188,12 @@ Object.defineProperties(Request.prototype, {
|
||||
exposeHeadRoute: context.exposeHeadRoute,
|
||||
prefixTrailingSlash: context.prefixTrailingSlash,
|
||||
handler: context.handler,
|
||||
config: context.config,
|
||||
schema: context.schema,
|
||||
version
|
||||
}
|
||||
|
||||
Object.defineProperties(options, {
|
||||
config: {
|
||||
get: () => context.config
|
||||
},
|
||||
schema: {
|
||||
get: () => context.schema
|
||||
}
|
||||
})
|
||||
|
||||
return Object.freeze(options)
|
||||
}
|
||||
},
|
||||
routerMethod: {
|
||||
get () {
|
||||
FSTDEP018()
|
||||
return this[kRouteContext].config?.method
|
||||
}
|
||||
},
|
||||
routeConfig: {
|
||||
get () {
|
||||
FSTDEP016()
|
||||
return this[kRouteContext][kPublicRouteContext]?.config
|
||||
}
|
||||
},
|
||||
routeSchema: {
|
||||
get () {
|
||||
FSTDEP015()
|
||||
return this[kRouteContext][kPublicRouteContext].schema
|
||||
return options
|
||||
}
|
||||
},
|
||||
is404: {
|
||||
@@ -236,15 +201,6 @@ Object.defineProperties(Request.prototype, {
|
||||
return this[kRouteContext].config?.url === undefined
|
||||
}
|
||||
},
|
||||
connection: {
|
||||
get () {
|
||||
/* istanbul ignore next */
|
||||
if (semver.gte(process.versions.node, '13.0.0')) {
|
||||
FSTDEP005()
|
||||
}
|
||||
return this.raw.connection
|
||||
}
|
||||
},
|
||||
socket: {
|
||||
get () {
|
||||
return this.raw.socket
|
||||
@@ -257,9 +213,42 @@ Object.defineProperties(Request.prototype, {
|
||||
}
|
||||
}
|
||||
},
|
||||
host: {
|
||||
get () {
|
||||
/**
|
||||
* The last fallback supports the following cases:
|
||||
* 1. http.requireHostHeader === false
|
||||
* 2. HTTP/1.0 without a Host Header
|
||||
* 3. Headers schema that may remove the Host Header
|
||||
*/
|
||||
return this.raw.headers.host ?? this.raw.headers[':authority'] ?? ''
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
get () {
|
||||
return this.raw.headers.host || this.raw.headers[':authority']
|
||||
// Check for IPV6 Host
|
||||
if (this.host[0] === '[') {
|
||||
return this.host.slice(0, this.host.indexOf(']') + 1)
|
||||
}
|
||||
|
||||
return this.host.split(':', 1)[0]
|
||||
}
|
||||
},
|
||||
port: {
|
||||
get () {
|
||||
// first try taking port from host
|
||||
const portFromHost = parseInt(this.host.split(':').slice(-1)[0])
|
||||
if (!isNaN(portFromHost)) {
|
||||
return portFromHost
|
||||
}
|
||||
// now fall back to port from host/:authority header
|
||||
const host = (this.headers.host ?? this.headers[':authority'] ?? '')
|
||||
const portFromHeader = parseInt(host.split(':').slice(-1)[0])
|
||||
if (!isNaN(portFromHeader)) {
|
||||
return portFromHeader
|
||||
}
|
||||
// fall back to null
|
||||
return null
|
||||
}
|
||||
},
|
||||
protocol: {
|
||||
@@ -299,13 +288,13 @@ Object.defineProperties(Request.prototype, {
|
||||
}
|
||||
|
||||
const validatorCompiler = this[kRouteContext].validatorCompiler ||
|
||||
this.server[kSchemaController].validatorCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom validatorCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].validatorCompiler
|
||||
)
|
||||
this.server[kSchemaController].validatorCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom validatorCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].validatorCompiler
|
||||
)
|
||||
|
||||
const validateFn = validatorCompiler({
|
||||
schema,
|
||||
@@ -342,8 +331,8 @@ Object.defineProperties(Request.prototype, {
|
||||
|
||||
// We cannot compile if the schema is missed
|
||||
if (validate == null && (schema == null ||
|
||||
typeof schema !== 'object' ||
|
||||
Array.isArray(schema))
|
||||
typeof schema !== 'object' ||
|
||||
Array.isArray(schema))
|
||||
) {
|
||||
throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)
|
||||
}
|
||||
@@ -359,6 +348,25 @@ Object.defineProperties(Request.prototype, {
|
||||
|
||||
return validate(input)
|
||||
}
|
||||
},
|
||||
getDecorator: {
|
||||
value: function (name) {
|
||||
assertsRequestDecoration(this, name)
|
||||
|
||||
const decorator = this[name]
|
||||
if (typeof decorator === 'function') {
|
||||
return decorator.bind(this)
|
||||
}
|
||||
|
||||
return decorator
|
||||
}
|
||||
},
|
||||
setDecorator: {
|
||||
value: function (name, value) {
|
||||
assertsRequestDecoration(this, name)
|
||||
|
||||
this[name] = value
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
211
backend/node_modules/fastify/lib/route.js
generated
vendored
211
backend/node_modules/fastify/lib/route.js
generated
vendored
@@ -2,16 +2,10 @@
|
||||
|
||||
const FindMyWay = require('find-my-way')
|
||||
const Context = require('./context')
|
||||
const handleRequest = require('./handleRequest')
|
||||
const handleRequest = require('./handle-request.js')
|
||||
const { onRequestAbortHookRunner, lifecycleHooks, preParsingHookRunner, onTimeoutHookRunner, onRequestHookRunner } = require('./hooks')
|
||||
const { supportedMethods } = require('./httpMethods')
|
||||
const { normalizeSchema } = require('./schemas')
|
||||
const { parseHeadOnSendHandlers } = require('./headRoute')
|
||||
const {
|
||||
FSTDEP007,
|
||||
FSTDEP008,
|
||||
FSTDEP014
|
||||
} = require('./warnings')
|
||||
const { parseHeadOnSendHandlers } = require('./head-route.js')
|
||||
|
||||
const {
|
||||
compileSchemasForValidation,
|
||||
@@ -21,7 +15,6 @@ const {
|
||||
const {
|
||||
FST_ERR_SCH_VALIDATION_BUILD,
|
||||
FST_ERR_SCH_SERIALIZATION_BUILD,
|
||||
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
|
||||
FST_ERR_DUPLICATED_ROUTE,
|
||||
FST_ERR_INVALID_URL,
|
||||
FST_ERR_HOOK_INVALID_HANDLER,
|
||||
@@ -38,6 +31,7 @@ const {
|
||||
|
||||
const {
|
||||
kRoutePrefix,
|
||||
kSupportedHTTPMethods,
|
||||
kLogLevel,
|
||||
kLogSerializers,
|
||||
kHooks,
|
||||
@@ -55,11 +49,26 @@ const {
|
||||
kRouteContext
|
||||
} = require('./symbols.js')
|
||||
const { buildErrorHandler } = require('./error-handler')
|
||||
const { createChildLogger } = require('./logger')
|
||||
const { getGenReqId } = require('./reqIdGenFactory.js')
|
||||
const { createChildLogger } = require('./logger-factory.js')
|
||||
const { getGenReqId } = require('./req-id-gen-factory.js')
|
||||
const { FSTDEP022 } = require('./warnings')
|
||||
|
||||
const routerKeys = [
|
||||
'allowUnsafeRegex',
|
||||
'buildPrettyMeta',
|
||||
'caseSensitive',
|
||||
'constraints',
|
||||
'defaultRoute',
|
||||
'ignoreDuplicateSlashes',
|
||||
'ignoreTrailingSlash',
|
||||
'maxParamLength',
|
||||
'onBadUrl',
|
||||
'querystringParser',
|
||||
'useSemicolonDelimiter'
|
||||
]
|
||||
|
||||
function buildRouting (options) {
|
||||
const router = FindMyWay(options.config)
|
||||
const router = FindMyWay(options)
|
||||
|
||||
let avvio
|
||||
let fourOhFour
|
||||
@@ -68,11 +77,11 @@ function buildRouting (options) {
|
||||
let setupResponseListeners
|
||||
let throwIfAlreadyStarted
|
||||
let disableRequestLogging
|
||||
let disableRequestLoggingFn
|
||||
let ignoreTrailingSlash
|
||||
let ignoreDuplicateSlashes
|
||||
let return503OnClosing
|
||||
let globalExposeHeadRoutes
|
||||
let validateHTTPVersion
|
||||
let keepAliveConnections
|
||||
|
||||
let closing = false
|
||||
@@ -85,35 +94,26 @@ function buildRouting (options) {
|
||||
setup (options, fastifyArgs) {
|
||||
avvio = fastifyArgs.avvio
|
||||
fourOhFour = fastifyArgs.fourOhFour
|
||||
logger = fastifyArgs.logger
|
||||
logger = options.logger
|
||||
hasLogger = fastifyArgs.hasLogger
|
||||
setupResponseListeners = fastifyArgs.setupResponseListeners
|
||||
throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
|
||||
validateHTTPVersion = fastifyArgs.validateHTTPVersion
|
||||
|
||||
globalExposeHeadRoutes = options.exposeHeadRoutes
|
||||
disableRequestLogging = options.disableRequestLogging
|
||||
ignoreTrailingSlash = options.ignoreTrailingSlash
|
||||
ignoreDuplicateSlashes = options.ignoreDuplicateSlashes
|
||||
return503OnClosing = Object.prototype.hasOwnProperty.call(options, 'return503OnClosing') ? options.return503OnClosing : true
|
||||
if (typeof disableRequestLogging === 'function') {
|
||||
disableRequestLoggingFn = options.disableRequestLogging
|
||||
}
|
||||
|
||||
ignoreTrailingSlash = options.routerOptions.ignoreTrailingSlash
|
||||
ignoreDuplicateSlashes = options.routerOptions.ignoreDuplicateSlashes
|
||||
return503OnClosing = Object.hasOwn(options, 'return503OnClosing') ? options.return503OnClosing : true
|
||||
keepAliveConnections = fastifyArgs.keepAliveConnections
|
||||
},
|
||||
routing: router.lookup.bind(router), // router func to find the right handler to call
|
||||
route, // configure a route in the fastify instance
|
||||
hasRoute,
|
||||
prepareRoute,
|
||||
getDefaultRoute: function () {
|
||||
FSTDEP014()
|
||||
return router.defaultRoute
|
||||
},
|
||||
setDefaultRoute: function (defaultRoute) {
|
||||
FSTDEP014()
|
||||
if (typeof defaultRoute !== 'function') {
|
||||
throw new FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
|
||||
}
|
||||
|
||||
router.defaultRoute = defaultRoute
|
||||
},
|
||||
routeHandler,
|
||||
closeRoutes: () => { closing = true },
|
||||
printRoutes: router.prettyPrint.bind(router),
|
||||
@@ -169,10 +169,11 @@ function buildRouting (options) {
|
||||
|
||||
function hasRoute ({ options }) {
|
||||
const normalizedMethod = options.method?.toUpperCase() ?? ''
|
||||
return findRoute({
|
||||
...options,
|
||||
method: normalizedMethod
|
||||
}) !== null
|
||||
return router.hasRoute(
|
||||
normalizedMethod,
|
||||
options.url || '',
|
||||
options.constraints
|
||||
)
|
||||
}
|
||||
|
||||
function findRoute (options) {
|
||||
@@ -200,36 +201,13 @@ function buildRouting (options) {
|
||||
* @param {{ options: import('../fastify').RouteOptions, isFastify: boolean }}
|
||||
*/
|
||||
function route ({ options, isFastify }) {
|
||||
throwIfAlreadyStarted('Cannot add route!')
|
||||
|
||||
// Since we are mutating/assigning only top level props, it is fine to have a shallow copy using the spread operator
|
||||
const opts = { ...options }
|
||||
|
||||
const { exposeHeadRoute } = opts
|
||||
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
|
||||
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes
|
||||
|
||||
const isGetRoute = opts.method === 'GET' ||
|
||||
(Array.isArray(opts.method) && opts.method.includes('GET'))
|
||||
const isHeadRoute = opts.method === 'HEAD' ||
|
||||
(Array.isArray(opts.method) && opts.method.includes('HEAD'))
|
||||
|
||||
// we need to clone a set of initial options for HEAD route
|
||||
const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
|
||||
|
||||
throwIfAlreadyStarted('Cannot add route!')
|
||||
|
||||
const path = opts.url || opts.path || ''
|
||||
|
||||
if (Array.isArray(opts.method)) {
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i < opts.method.length; ++i) {
|
||||
opts.method[i] = normalizeAndValidateMethod(opts.method[i])
|
||||
validateSchemaBodyOption(opts.method[i], path, opts.schema)
|
||||
}
|
||||
} else {
|
||||
opts.method = normalizeAndValidateMethod(opts.method)
|
||||
validateSchemaBodyOption(opts.method, path, opts.schema)
|
||||
}
|
||||
|
||||
if (!opts.handler) {
|
||||
throw new FST_ERR_ROUTE_MISSING_HANDLER(opts.method, path)
|
||||
}
|
||||
@@ -240,6 +218,30 @@ function buildRouting (options) {
|
||||
|
||||
validateBodyLimitOption(opts.bodyLimit)
|
||||
|
||||
const shouldExposeHead = opts.exposeHeadRoute ?? globalExposeHeadRoutes
|
||||
|
||||
let isGetRoute = false
|
||||
let isHeadRoute = false
|
||||
|
||||
if (Array.isArray(opts.method)) {
|
||||
for (let i = 0; i < opts.method.length; ++i) {
|
||||
opts.method[i] = normalizeAndValidateMethod.call(this, opts.method[i])
|
||||
validateSchemaBodyOption.call(this, opts.method[i], path, opts.schema)
|
||||
|
||||
isGetRoute = opts.method.includes('GET')
|
||||
isHeadRoute = opts.method.includes('HEAD')
|
||||
}
|
||||
} else {
|
||||
opts.method = normalizeAndValidateMethod.call(this, opts.method)
|
||||
validateSchemaBodyOption.call(this, opts.method, path, opts.schema)
|
||||
|
||||
isGetRoute = opts.method === 'GET'
|
||||
isHeadRoute = opts.method === 'HEAD'
|
||||
}
|
||||
|
||||
// we need to clone a set of initial options for HEAD route
|
||||
const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
|
||||
|
||||
const prefix = this[kRoutePrefix]
|
||||
|
||||
if (path === '/' && prefix.length > 0 && opts.method !== 'HEAD') {
|
||||
@@ -347,19 +349,9 @@ function buildRouting (options) {
|
||||
isFastify
|
||||
})
|
||||
|
||||
if (opts.version) {
|
||||
FSTDEP008()
|
||||
constraints.version = opts.version
|
||||
}
|
||||
|
||||
const headHandler = router.findRoute('HEAD', opts.url, constraints)
|
||||
const hasHEADHandler = headHandler !== null
|
||||
|
||||
// remove the head route created by fastify
|
||||
if (isHeadRoute && hasHEADHandler && !context[kRouteByFastify] && headHandler.store[kRouteByFastify]) {
|
||||
router.off('HEAD', opts.url, constraints)
|
||||
}
|
||||
|
||||
try {
|
||||
router.on(opts.method, opts.url, { constraints }, routeHandler, context)
|
||||
} catch (error) {
|
||||
@@ -377,13 +369,16 @@ function buildRouting (options) {
|
||||
|
||||
this.after((notHandledErr, done) => {
|
||||
// Send context async
|
||||
context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
|
||||
context.errorHandler = opts.errorHandler
|
||||
? buildErrorHandler(this[kErrorHandler], opts.errorHandler)
|
||||
: this[kErrorHandler]
|
||||
context._parserOptions.limit = opts.bodyLimit || null
|
||||
context.logLevel = opts.logLevel
|
||||
context.logSerializers = opts.logSerializers
|
||||
context.attachValidation = opts.attachValidation
|
||||
context[kReplySerializerDefault] = this[kReplySerializerDefault]
|
||||
context.schemaErrorFormatter = opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
|
||||
context.schemaErrorFormatter =
|
||||
opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
|
||||
|
||||
// Run hooks and more
|
||||
avvio.once('preReady', () => {
|
||||
@@ -407,15 +402,24 @@ function buildRouting (options) {
|
||||
fourOhFour.setContext(this, context)
|
||||
|
||||
if (opts.schema) {
|
||||
context.schema = normalizeSchema(opts, context.schema, this.initialConfig)
|
||||
context.schema = normalizeSchema(context.schema, this.initialConfig)
|
||||
|
||||
const schemaController = this[kSchemaController]
|
||||
if (!opts.validatorCompiler && (opts.schema.body || opts.schema.headers || opts.schema.querystring || opts.schema.params)) {
|
||||
const hasValidationSchema = opts.schema.body ||
|
||||
opts.schema.headers ||
|
||||
opts.schema.querystring ||
|
||||
opts.schema.params
|
||||
if (!opts.validatorCompiler && hasValidationSchema) {
|
||||
schemaController.setupValidator(this[kOptions])
|
||||
}
|
||||
try {
|
||||
const isCustom = typeof opts?.validatorCompiler === 'function' || schemaController.isCustomValidatorCompiler
|
||||
compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler, isCustom)
|
||||
const isCustom = typeof opts?.validatorCompiler === 'function' ||
|
||||
schemaController.isCustomValidatorCompiler
|
||||
compileSchemasForValidation(
|
||||
context,
|
||||
opts.validatorCompiler || schemaController.validatorCompiler,
|
||||
isCustom
|
||||
)
|
||||
} catch (error) {
|
||||
throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message)
|
||||
}
|
||||
@@ -440,8 +444,6 @@ function buildRouting (options) {
|
||||
if (shouldExposeHead && isGetRoute && !isHeadRoute && !hasHEADHandler) {
|
||||
const onSendHandlers = parseHeadOnSendHandlers(headOpts.onSend)
|
||||
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true })
|
||||
} else if (hasHEADHandler && exposeHeadRoute) {
|
||||
FSTDEP007()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -458,20 +460,8 @@ function buildRouting (options) {
|
||||
loggerOpts.serializers = context.logSerializers
|
||||
}
|
||||
const childLogger = createChildLogger(context, logger, req, id, loggerOpts)
|
||||
childLogger[kDisableRequestLogging] = disableRequestLogging
|
||||
|
||||
// TODO: The check here should be removed once https://github.com/nodejs/node/issues/43115 resolve in core.
|
||||
if (!validateHTTPVersion(req.httpVersion)) {
|
||||
childLogger.info({ res: { statusCode: 505 } }, 'request aborted - invalid HTTP version')
|
||||
const message = '{"error":"HTTP Version Not Supported","message":"HTTP Version Not Supported","statusCode":505}'
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': message.length
|
||||
}
|
||||
res.writeHead(505, headers)
|
||||
res.end(message)
|
||||
return
|
||||
}
|
||||
// Set initial value; will be re-evaluated after FastifyRequest is constructed if it's a function
|
||||
childLogger[kDisableRequestLogging] = disableRequestLoggingFn ? false : disableRequestLogging
|
||||
|
||||
if (closing === true) {
|
||||
/* istanbul ignore next mac, windows */
|
||||
@@ -515,7 +505,15 @@ function buildRouting (options) {
|
||||
|
||||
const request = new context.Request(id, params, req, query, childLogger, context)
|
||||
const reply = new context.Reply(res, request, childLogger)
|
||||
if (disableRequestLogging === false) {
|
||||
|
||||
// Evaluate disableRequestLogging after FastifyRequest is constructed
|
||||
// so the caller has access to decorations and customizations
|
||||
const resolvedDisableRequestLogging = disableRequestLoggingFn
|
||||
? disableRequestLoggingFn(request)
|
||||
: disableRequestLogging
|
||||
childLogger[kDisableRequestLogging] = resolvedDisableRequestLogging
|
||||
|
||||
if (resolvedDisableRequestLogging === false) {
|
||||
childLogger.info({ req: request }, 'incoming request')
|
||||
}
|
||||
|
||||
@@ -577,7 +575,8 @@ function normalizeAndValidateMethod (method) {
|
||||
throw new FST_ERR_ROUTE_METHOD_INVALID()
|
||||
}
|
||||
method = method.toUpperCase()
|
||||
if (supportedMethods.indexOf(method) === -1) {
|
||||
if (!this[kSupportedHTTPMethods].bodyless.has(method) &&
|
||||
!this[kSupportedHTTPMethods].bodywith.has(method)) {
|
||||
throw new FST_ERR_ROUTE_METHOD_NOT_SUPPORTED(method)
|
||||
}
|
||||
|
||||
@@ -585,7 +584,7 @@ function normalizeAndValidateMethod (method) {
|
||||
}
|
||||
|
||||
function validateSchemaBodyOption (method, path, schema) {
|
||||
if ((method === 'GET' || method === 'HEAD') && schema && schema.body) {
|
||||
if (this[kSupportedHTTPMethods].bodyless.has(method) && schema?.body) {
|
||||
throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path)
|
||||
}
|
||||
}
|
||||
@@ -608,12 +607,30 @@ function runPreParsing (err, request, reply) {
|
||||
request[kRequestPayloadStream] = request.raw
|
||||
|
||||
if (request[kRouteContext].preParsing !== null) {
|
||||
preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest)
|
||||
preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest.bind(request.server))
|
||||
} else {
|
||||
handleRequest(null, request, reply)
|
||||
handleRequest.call(request.server, null, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function buildRouterOptions (options, defaultOptions) {
|
||||
const routerOptions = options.routerOptions || Object.create(null)
|
||||
|
||||
const usedDeprecatedOptions = routerKeys.filter(key => Object.hasOwn(options, key))
|
||||
|
||||
if (usedDeprecatedOptions.length > 0) {
|
||||
FSTDEP022(usedDeprecatedOptions.join(', '))
|
||||
}
|
||||
|
||||
for (const key of routerKeys) {
|
||||
if (!Object.hasOwn(routerOptions, key)) {
|
||||
routerOptions[key] = options[key] ?? defaultOptions[key]
|
||||
}
|
||||
}
|
||||
|
||||
return routerOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* Used within the route handler as a `net.Socket.close` event handler.
|
||||
* The purpose is to remove a socket from the tracked sockets collection when
|
||||
@@ -625,4 +642,4 @@ function removeTrackedSocket () {
|
||||
|
||||
function noop () { }
|
||||
|
||||
module.exports = { buildRouting, validateBodyLimitOption }
|
||||
module.exports = { buildRouting, validateBodyLimitOption, buildRouterOptions }
|
||||
|
||||
4
backend/node_modules/fastify/lib/schema-controller.js
generated
vendored
4
backend/node_modules/fastify/lib/schema-controller.js
generated
vendored
@@ -1,8 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const { buildSchemas } = require('./schemas')
|
||||
const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
|
||||
const ValidatorSelector = require('@fastify/ajv-compiler')
|
||||
|
||||
/**
|
||||
* Called at every fastify context that is being created.
|
||||
@@ -21,9 +19,11 @@ function buildSchemaController (parentSchemaCtrl, opts) {
|
||||
}, opts?.compilersFactory)
|
||||
|
||||
if (!compilersFactory.buildValidator) {
|
||||
const ValidatorSelector = require('@fastify/ajv-compiler')
|
||||
compilersFactory.buildValidator = ValidatorSelector()
|
||||
}
|
||||
if (!compilersFactory.buildSerializer) {
|
||||
const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
|
||||
compilersFactory.buildSerializer = SerializerSelector()
|
||||
}
|
||||
|
||||
|
||||
44
backend/node_modules/fastify/lib/schemas.js
generated
vendored
44
backend/node_modules/fastify/lib/schemas.js
generated
vendored
@@ -4,9 +4,6 @@ const fastClone = require('rfdc')({ circles: false, proto: true })
|
||||
const { kSchemaVisited, kSchemaResponse } = require('./symbols')
|
||||
const kFluentSchema = Symbol.for('fluent-schema-object')
|
||||
|
||||
const {
|
||||
FSTDEP022
|
||||
} = require('./warnings')
|
||||
const {
|
||||
FST_ERR_SCH_MISSING_ID,
|
||||
FST_ERR_SCH_ALREADY_PRESENT,
|
||||
@@ -57,7 +54,7 @@ function isCustomSchemaPrototype (schema) {
|
||||
return typeof schema === 'object' && Object.getPrototypeOf(schema) !== Object.prototype
|
||||
}
|
||||
|
||||
function normalizeSchema (opts, routeSchemas, serverOptions) {
|
||||
function normalizeSchema (routeSchemas, serverOptions) {
|
||||
if (routeSchemas[kSchemaVisited]) {
|
||||
return routeSchemas
|
||||
}
|
||||
@@ -85,11 +82,9 @@ function normalizeSchema (opts, routeSchemas, serverOptions) {
|
||||
if (!contentSchema) {
|
||||
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(contentType)
|
||||
}
|
||||
routeSchemas.body.content[contentType].schema = getSchemaAnyway(opts.url, contentSchema, serverOptions.jsonShorthand)
|
||||
}
|
||||
continue
|
||||
}
|
||||
routeSchemas[key] = getSchemaAnyway(opts.url, schema, serverOptions.jsonShorthand)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,25 +97,15 @@ function normalizeSchema (opts, routeSchemas, serverOptions) {
|
||||
|
||||
const contentProperty = routeSchemas.response[code].content
|
||||
|
||||
let hasContentMultipleContentTypes = false
|
||||
if (contentProperty) {
|
||||
const keys = Object.keys(contentProperty)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const mediaName = keys[i]
|
||||
if (!contentProperty[mediaName].schema) {
|
||||
if (keys.length === 1) { break }
|
||||
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(mediaName)
|
||||
}
|
||||
routeSchemas.response[code].content[mediaName].schema = getSchemaAnyway(opts.url, contentProperty[mediaName].schema, serverOptions.jsonShorthand)
|
||||
if (i === keys.length - 1) {
|
||||
hasContentMultipleContentTypes = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasContentMultipleContentTypes) {
|
||||
routeSchemas.response[code] = getSchemaAnyway(opts.url, routeSchemas.response[code], serverOptions.jsonShorthand)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,18 +130,6 @@ function generateFluentSchema (schema) {
|
||||
}
|
||||
}
|
||||
|
||||
function getSchemaAnyway (url, schema, jsonShorthand) {
|
||||
if (!jsonShorthand || schema.$ref || schema.oneOf || schema.allOf || schema.anyOf || schema.$merge || schema.$patch) return schema
|
||||
if (!schema.type && !schema.properties) {
|
||||
FSTDEP022(url)
|
||||
return {
|
||||
type: 'object',
|
||||
properties: schema
|
||||
}
|
||||
}
|
||||
return schema
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the right JSON schema compiled function in the request context
|
||||
* setup by the route configuration `schema.response`.
|
||||
@@ -180,6 +153,11 @@ function getSchemaSerializer (context, statusCode, contentType) {
|
||||
return responseSchemaDef[statusCode][mediaName]
|
||||
}
|
||||
|
||||
// fallback to match all media-type
|
||||
if (responseSchemaDef[statusCode]['*/*']) {
|
||||
return responseSchemaDef[statusCode]['*/*']
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
return responseSchemaDef[statusCode]
|
||||
@@ -192,6 +170,11 @@ function getSchemaSerializer (context, statusCode, contentType) {
|
||||
return responseSchemaDef[fallbackStatusCode][mediaName]
|
||||
}
|
||||
|
||||
// fallback to match all media-type
|
||||
if (responseSchemaDef[fallbackStatusCode]['*/*']) {
|
||||
return responseSchemaDef[fallbackStatusCode]['*/*']
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -204,6 +187,11 @@ function getSchemaSerializer (context, statusCode, contentType) {
|
||||
return responseSchemaDef.default[mediaName]
|
||||
}
|
||||
|
||||
// fallback to match all media-type
|
||||
if (responseSchemaDef.default['*/*']) {
|
||||
return responseSchemaDef.default['*/*']
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
426
backend/node_modules/fastify/lib/server.js
generated
vendored
426
backend/node_modules/fastify/lib/server.js
generated
vendored
@@ -2,20 +2,23 @@
|
||||
|
||||
const http = require('node:http')
|
||||
const https = require('node:https')
|
||||
const http2 = require('node:http2')
|
||||
const dns = require('node:dns')
|
||||
const os = require('node:os')
|
||||
|
||||
const { FSTDEP011 } = require('./warnings')
|
||||
const { kState, kOptions, kServerBindings } = require('./symbols')
|
||||
const { kState, kOptions, kServerBindings, kHttp2ServerSessions } = require('./symbols')
|
||||
const { FSTWRN003 } = require('./warnings')
|
||||
const { onListenHookRunner } = require('./hooks')
|
||||
const {
|
||||
FST_ERR_HTTP2_INVALID_VERSION,
|
||||
FST_ERR_REOPENED_CLOSE_SERVER,
|
||||
FST_ERR_REOPENED_SERVER,
|
||||
FST_ERR_LISTEN_OPTIONS_INVALID
|
||||
FST_ERR_LISTEN_OPTIONS_INVALID,
|
||||
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE
|
||||
} = require('./errors')
|
||||
const noopSet = require('./noop-set')
|
||||
const PonyPromise = require('./promise')
|
||||
|
||||
module.exports.createServer = createServer
|
||||
module.exports.compileValidateHTTPVersion = compileValidateHTTPVersion
|
||||
|
||||
function defaultResolveServerListeningText (address) {
|
||||
return `Server listening at ${address}`
|
||||
@@ -25,27 +28,15 @@ function createServer (options, httpHandler) {
|
||||
const server = getServerInstance(options, httpHandler)
|
||||
|
||||
// `this` is the Fastify object
|
||||
function listen (listenOptions, ...args) {
|
||||
let cb = args.slice(-1).pop()
|
||||
// When the variadic signature deprecation is complete, the function
|
||||
// declaration should become:
|
||||
// function listen (listenOptions = { port: 0, host: 'localhost' }, cb = undefined)
|
||||
// Upon doing so, the `normalizeListenArgs` function is no longer needed,
|
||||
// and all of this preamble to feed it correctly also no longer needed.
|
||||
const firstArgType = Object.prototype.toString.call(arguments[0])
|
||||
if (arguments.length === 0) {
|
||||
listenOptions = normalizeListenArgs([])
|
||||
} else if (arguments.length > 0 && (firstArgType !== '[object Object]' && firstArgType !== '[object Function]')) {
|
||||
FSTDEP011()
|
||||
listenOptions = normalizeListenArgs(Array.from(arguments))
|
||||
cb = listenOptions.cb
|
||||
} else if (args.length > 1) {
|
||||
// `.listen(obj, a, ..., n, callback )`
|
||||
FSTDEP011()
|
||||
// Deal with `.listen(port, host, backlog, [cb])`
|
||||
const hostPath = listenOptions.path ? [listenOptions.path] : [listenOptions.port ?? 0, listenOptions.host ?? 'localhost']
|
||||
Object.assign(listenOptions, normalizeListenArgs([...hostPath, ...args]))
|
||||
} else {
|
||||
function listen (
|
||||
listenOptions = { port: 0, host: 'localhost' },
|
||||
cb = undefined
|
||||
) {
|
||||
if (typeof cb === 'function') {
|
||||
if (cb.constructor.name === 'AsyncFunction') {
|
||||
FSTWRN003('listen method')
|
||||
}
|
||||
|
||||
listenOptions.cb = cb
|
||||
}
|
||||
if (listenOptions.signal) {
|
||||
@@ -53,10 +44,14 @@ function createServer (options, httpHandler) {
|
||||
throw new FST_ERR_LISTEN_OPTIONS_INVALID('Invalid options.signal')
|
||||
}
|
||||
|
||||
if (listenOptions.signal.aborted) {
|
||||
this.close()
|
||||
// copy the current signal state
|
||||
this[kState].aborted = listenOptions.signal.aborted
|
||||
|
||||
if (this[kState].aborted) {
|
||||
return this.close()
|
||||
} else {
|
||||
const onAborted = () => {
|
||||
this[kState].aborted = true
|
||||
this.close()
|
||||
}
|
||||
listenOptions.signal.addEventListener('abort', onAborted, { once: true })
|
||||
@@ -72,7 +67,7 @@ function createServer (options, httpHandler) {
|
||||
} else {
|
||||
host = listenOptions.host
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(listenOptions, 'host') === false ||
|
||||
if (!Object.hasOwn(listenOptions, 'host') ||
|
||||
listenOptions.host == null) {
|
||||
listenOptions.host = host
|
||||
}
|
||||
@@ -110,27 +105,47 @@ function createServer (options, httpHandler) {
|
||||
|
||||
if (cb === undefined) {
|
||||
const listening = listenPromise.call(this, server, listenOptions)
|
||||
/* istanbul ignore else */
|
||||
return listening.then(address => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (host === 'localhost') {
|
||||
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
||||
this[kState].listening = true
|
||||
resolve(address)
|
||||
onListenHookRunner(this)
|
||||
})
|
||||
} else {
|
||||
const { promise, resolve } = PonyPromise.withResolvers()
|
||||
if (host === 'localhost') {
|
||||
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
||||
this[kState].listening = true
|
||||
resolve(address)
|
||||
onListenHookRunner(this)
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
resolve(address)
|
||||
onListenHookRunner(this)
|
||||
}
|
||||
return promise
|
||||
})
|
||||
}
|
||||
|
||||
this.ready(listenCallback.call(this, server, listenOptions))
|
||||
}
|
||||
|
||||
return { server, listen }
|
||||
const serverHasCloseAllConnections = typeof server.closeAllConnections === 'function'
|
||||
const serverHasCloseIdleConnections = typeof server.closeIdleConnections === 'function'
|
||||
const serverHasCloseHttp2Sessions = typeof server.closeHttp2Sessions === 'function'
|
||||
|
||||
let forceCloseConnections = options.forceCloseConnections
|
||||
if (forceCloseConnections === 'idle' && !serverHasCloseIdleConnections) {
|
||||
throw new FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE()
|
||||
} else if (typeof forceCloseConnections !== 'boolean') {
|
||||
/* istanbul ignore next: only one branch can be valid in a given Node.js version */
|
||||
forceCloseConnections = serverHasCloseIdleConnections ? 'idle' : false
|
||||
}
|
||||
|
||||
const keepAliveConnections = !serverHasCloseAllConnections && forceCloseConnections === true ? new Set() : noopSet()
|
||||
|
||||
return {
|
||||
server,
|
||||
listen,
|
||||
forceCloseConnections,
|
||||
serverHasCloseAllConnections,
|
||||
serverHasCloseHttp2Sessions,
|
||||
keepAliveConnections
|
||||
}
|
||||
}
|
||||
|
||||
function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, onListen) {
|
||||
@@ -139,7 +154,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
|
||||
// let's check if we need to bind additional addresses
|
||||
dns.lookup(listenOptions.host, { all: true }, (dnsErr, addresses) => {
|
||||
if (dnsErr) {
|
||||
if (dnsErr || this[kState].aborted) {
|
||||
// not blocking the main server listening
|
||||
// this.log.warn('dns.lookup error:', dnsErr)
|
||||
onListen()
|
||||
@@ -161,7 +176,6 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
cb: (_ignoreErr) => {
|
||||
bound++
|
||||
|
||||
/* istanbul ignore next: the else won't be taken unless listening fails */
|
||||
if (!_ignoreErr) {
|
||||
this[kServerBindings].push(secondaryServer)
|
||||
}
|
||||
@@ -175,20 +189,18 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
|
||||
const secondaryServer = getServerInstance(serverOpts, httpHandler)
|
||||
const closeSecondary = () => {
|
||||
// To avoid fall into situations where the close of the
|
||||
// To avoid falling into situations where the close of the
|
||||
// secondary server is triggered before the preClose hook
|
||||
// is done running, we better wait until the main server
|
||||
// is closed.
|
||||
// is done running, we better wait until the main server is closed.
|
||||
// No new TCP connections are accepted
|
||||
// We swallow any error from the secondary
|
||||
// server
|
||||
// We swallow any error from the secondary server
|
||||
secondaryServer.close(() => {})
|
||||
if (serverOpts.forceCloseConnections === 'idle') {
|
||||
// Not needed in Node 19
|
||||
secondaryServer.closeIdleConnections()
|
||||
} else if (typeof secondaryServer.closeAllConnections === 'function' && serverOpts.forceCloseConnections) {
|
||||
if (typeof secondaryServer.closeAllConnections === 'function' && serverOpts.forceCloseConnections === true) {
|
||||
secondaryServer.closeAllConnections()
|
||||
}
|
||||
if (typeof secondaryServer.closeHttp2Sessions === 'function') {
|
||||
secondaryServer.closeHttp2Sessions()
|
||||
}
|
||||
}
|
||||
|
||||
secondaryServer.on('upgrade', mainServer.emit.bind(mainServer, 'upgrade'))
|
||||
@@ -210,7 +222,6 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
// to the secondary servers. It is valid only when the user is
|
||||
// listening on localhost
|
||||
const originUnref = mainServer.unref
|
||||
/* c8 ignore next 4 */
|
||||
mainServer.unref = function () {
|
||||
originUnref.call(mainServer)
|
||||
mainServer.emit('unref')
|
||||
@@ -223,7 +234,11 @@ function listenCallback (server, listenOptions) {
|
||||
server.removeListener('error', wrap)
|
||||
server.removeListener('listening', wrap)
|
||||
if (!err) {
|
||||
const address = logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText)
|
||||
const address = logServerAddress.call(
|
||||
this,
|
||||
server,
|
||||
listenOptions.listenTextResolver || defaultResolveServerListeningText
|
||||
)
|
||||
listenOptions.cb(null, address)
|
||||
} else {
|
||||
this[kState].listening = false
|
||||
@@ -236,7 +251,8 @@ function listenCallback (server, listenOptions) {
|
||||
|
||||
if (this[kState].listening && this[kState].closing) {
|
||||
return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
||||
} else if (this[kState].listening) {
|
||||
}
|
||||
if (this[kState].listening) {
|
||||
return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
|
||||
}
|
||||
|
||||
@@ -252,196 +268,174 @@ function listenCallback (server, listenOptions) {
|
||||
function listenPromise (server, listenOptions) {
|
||||
if (this[kState].listening && this[kState].closing) {
|
||||
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
||||
} else if (this[kState].listening) {
|
||||
}
|
||||
if (this[kState].listening) {
|
||||
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
||||
}
|
||||
|
||||
return this.ready().then(() => {
|
||||
let errEventHandler
|
||||
let listeningEventHandler
|
||||
// skip listen when aborted during ready
|
||||
if (this[kState].aborted) return
|
||||
|
||||
const { promise, resolve, reject } = PonyPromise.withResolvers()
|
||||
|
||||
const errEventHandler = (err) => {
|
||||
cleanup()
|
||||
this[kState].listening = false
|
||||
reject(err)
|
||||
}
|
||||
const listeningEventHandler = () => {
|
||||
cleanup()
|
||||
this[kState].listening = true
|
||||
resolve(logServerAddress.call(
|
||||
this,
|
||||
server,
|
||||
listenOptions.listenTextResolver || defaultResolveServerListeningText
|
||||
))
|
||||
}
|
||||
function cleanup () {
|
||||
server.removeListener('error', errEventHandler)
|
||||
server.removeListener('listening', listeningEventHandler)
|
||||
}
|
||||
const errEvent = new Promise((resolve, reject) => {
|
||||
errEventHandler = (err) => {
|
||||
cleanup()
|
||||
this[kState].listening = false
|
||||
reject(err)
|
||||
}
|
||||
server.once('error', errEventHandler)
|
||||
})
|
||||
const listeningEvent = new Promise((resolve, reject) => {
|
||||
listeningEventHandler = () => {
|
||||
cleanup()
|
||||
this[kState].listening = true
|
||||
resolve(logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText))
|
||||
}
|
||||
server.once('listening', listeningEventHandler)
|
||||
})
|
||||
server.once('error', errEventHandler)
|
||||
server.once('listening', listeningEventHandler)
|
||||
|
||||
server.listen(listenOptions)
|
||||
|
||||
return Promise.race([
|
||||
errEvent, // e.g invalid port range error is always emitted before the server listening
|
||||
listeningEvent
|
||||
])
|
||||
return promise
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, based upon initial configuration, will
|
||||
* verify that every incoming request conforms to allowed
|
||||
* HTTP versions for the Fastify instance, e.g. a Fastify HTTP/1.1
|
||||
* server will not serve HTTP/2 requests upon the result of the
|
||||
* verification function.
|
||||
*
|
||||
* @param {object} options fastify option
|
||||
* @param {function} [options.serverFactory] If present, the
|
||||
* validator function will skip all checks.
|
||||
* @param {boolean} [options.http2 = false] If true, the validator
|
||||
* function will allow HTTP/2 requests.
|
||||
* @param {object} [options.https = null] https server options
|
||||
* @param {boolean} [options.https.allowHTTP1] If true and use
|
||||
* with options.http2 the validator function will allow HTTP/1
|
||||
* request to http2 server.
|
||||
*
|
||||
* @returns {function} HTTP version validator function.
|
||||
*/
|
||||
function compileValidateHTTPVersion (options) {
|
||||
let bypass = false
|
||||
// key-value map to store valid http version
|
||||
const map = new Map()
|
||||
if (options.serverFactory) {
|
||||
// When serverFactory is passed, we cannot identify how to check http version reliably
|
||||
// So, we should skip the http version check
|
||||
bypass = true
|
||||
}
|
||||
if (options.http2) {
|
||||
// HTTP2 must serve HTTP/2.0
|
||||
map.set('2.0', true)
|
||||
if (options.https && options.https.allowHTTP1 === true) {
|
||||
// HTTP2 with HTTPS.allowHTTP1 allow fallback to HTTP/1.1 and HTTP/1.0
|
||||
map.set('1.1', true)
|
||||
map.set('1.0', true)
|
||||
}
|
||||
} else {
|
||||
// HTTP must server HTTP/1.1 and HTTP/1.0
|
||||
map.set('1.1', true)
|
||||
map.set('1.0', true)
|
||||
}
|
||||
// The compiled function here placed in one of the hottest path inside fastify
|
||||
// the implementation here must be as performant as possible
|
||||
return function validateHTTPVersion (httpVersion) {
|
||||
// `bypass` skip the check when custom server factory provided
|
||||
// `httpVersion in obj` check for the valid http version we should support
|
||||
return bypass || map.has(httpVersion)
|
||||
}
|
||||
}
|
||||
|
||||
function getServerInstance (options, httpHandler) {
|
||||
let server = null
|
||||
// node@20 do not accepts options as boolean
|
||||
// we need to provide proper https option
|
||||
const httpsOptions = options.https === true ? {} : options.https
|
||||
if (options.serverFactory) {
|
||||
server = options.serverFactory(httpHandler, options)
|
||||
} else if (options.http2) {
|
||||
if (typeof httpsOptions === 'object') {
|
||||
server = http2().createSecureServer(httpsOptions, httpHandler)
|
||||
} else {
|
||||
server = http2().createServer(httpHandler)
|
||||
}
|
||||
server.on('session', sessionTimeout(options.http2SessionTimeout))
|
||||
} else {
|
||||
// this is http1
|
||||
if (httpsOptions) {
|
||||
server = https.createServer(httpsOptions, httpHandler)
|
||||
} else {
|
||||
server = http.createServer(options.http, httpHandler)
|
||||
}
|
||||
server.keepAliveTimeout = options.keepAliveTimeout
|
||||
server.requestTimeout = options.requestTimeout
|
||||
// we treat zero as null
|
||||
// and null is the default setting from nodejs
|
||||
// so we do not pass the option to server
|
||||
if (options.maxRequestsPerSocket > 0) {
|
||||
server.maxRequestsPerSocket = options.maxRequestsPerSocket
|
||||
}
|
||||
// User provided server instance
|
||||
return options.serverFactory(httpHandler, options)
|
||||
}
|
||||
|
||||
if (!options.serverFactory) {
|
||||
// We have accepted true as a valid way to init https but node requires an options obj
|
||||
const httpsOptions = options.https === true ? {} : options.https
|
||||
|
||||
if (options.http2) {
|
||||
const server = typeof httpsOptions === 'object' ? http2.createSecureServer(httpsOptions, httpHandler) : http2.createServer(options.http, httpHandler)
|
||||
server.on('session', (session) => session.setTimeout(options.http2SessionTimeout, () => {
|
||||
session.close()
|
||||
}))
|
||||
|
||||
// This is only needed for Node.js versions < 24.0.0 since Node.js added native
|
||||
// closeAllSessions() on server.close() support for HTTP/2 servers in v24.0.0
|
||||
if (options.forceCloseConnections === true) {
|
||||
server.closeHttp2Sessions = createCloseHttp2SessionsByHttp2Server(server)
|
||||
}
|
||||
|
||||
server.setTimeout(options.connectionTimeout)
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
// HTTP1 server instance
|
||||
const server = httpsOptions
|
||||
? https.createServer(httpsOptions, httpHandler)
|
||||
: http.createServer(options.http, httpHandler)
|
||||
server.keepAliveTimeout = options.keepAliveTimeout
|
||||
server.requestTimeout = options.requestTimeout
|
||||
server.setTimeout(options.connectionTimeout)
|
||||
// We treat zero as null(node default) so we do not pass zero to the server instance
|
||||
if (options.maxRequestsPerSocket > 0) {
|
||||
server.maxRequestsPerSocket = options.maxRequestsPerSocket
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
function normalizeListenArgs (args) {
|
||||
if (args.length === 0) {
|
||||
return { port: 0, host: 'localhost' }
|
||||
/**
|
||||
* Inspects the provided `server.address` object and returns a
|
||||
* normalized list of IP address strings. Normalization in this
|
||||
* case refers to mapping wildcard `0.0.0.0` to the list of IP
|
||||
* addresses the wildcard refers to.
|
||||
*
|
||||
* @see https://nodejs.org/docs/latest/api/net.html#serveraddress
|
||||
*
|
||||
* @param {object} A server address object as described in the
|
||||
* linked docs.
|
||||
*
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function getAddresses (address) {
|
||||
if (address.address === '0.0.0.0') {
|
||||
return Object.values(os.networkInterfaces()).flatMap((iface) => {
|
||||
return iface.filter((iface) => iface.family === 'IPv4')
|
||||
}).sort((iface) => {
|
||||
/* c8 ignore next 2 */
|
||||
// Order the interfaces so that internal ones come first
|
||||
return iface.internal ? -1 : 1
|
||||
}).map((iface) => { return iface.address })
|
||||
}
|
||||
|
||||
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
|
||||
const options = { cb }
|
||||
|
||||
const firstArg = args[0]
|
||||
const argsLength = args.length
|
||||
const lastArg = args[argsLength - 1]
|
||||
if (typeof firstArg === 'string' && isNaN(firstArg)) {
|
||||
/* Deal with listen (pipe[, backlog]) */
|
||||
options.path = firstArg
|
||||
options.backlog = argsLength > 1 ? lastArg : undefined
|
||||
} else {
|
||||
/* Deal with listen ([port[, host[, backlog]]]) */
|
||||
options.port = argsLength >= 1 && Number.isInteger(firstArg) ? firstArg : normalizePort(firstArg)
|
||||
// This will listen to what localhost is.
|
||||
// It can be 127.0.0.1 or ::1, depending on the operating system.
|
||||
// Fixes https://github.com/fastify/fastify/issues/1022.
|
||||
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
|
||||
options.backlog = argsLength >= 3 ? args[2] : undefined
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
function normalizePort (firstArg) {
|
||||
const port = Number(firstArg)
|
||||
return port >= 0 && !Number.isNaN(port) && Number.isInteger(port) ? port : 0
|
||||
return [address.address]
|
||||
}
|
||||
|
||||
function logServerAddress (server, listenTextResolver) {
|
||||
let address = server.address()
|
||||
const isUnixSocket = typeof address === 'string'
|
||||
/* istanbul ignore next */
|
||||
let addresses
|
||||
const isUnixSocket = typeof server.address() === 'string'
|
||||
if (!isUnixSocket) {
|
||||
if (address.address.indexOf(':') === -1) {
|
||||
address = address.address + ':' + address.port
|
||||
if (server.address().address.indexOf(':') === -1) {
|
||||
// IPv4
|
||||
addresses = getAddresses(server.address()).map((address) => address + ':' + server.address().port)
|
||||
} else {
|
||||
address = '[' + address.address + ']:' + address.port
|
||||
// IPv6
|
||||
addresses = ['[' + server.address().address + ']:' + server.address().port]
|
||||
}
|
||||
|
||||
addresses = addresses.map((address) => ('http' + (this[kOptions].https ? 's' : '') + '://') + address)
|
||||
} else {
|
||||
addresses = [server.address()]
|
||||
}
|
||||
|
||||
for (const address of addresses) {
|
||||
this.log.info(listenTextResolver(address))
|
||||
}
|
||||
return addresses[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http2.Http2Server} http2Server
|
||||
* @returns {() => void}
|
||||
*/
|
||||
function createCloseHttp2SessionsByHttp2Server (http2Server) {
|
||||
/**
|
||||
* @type {Set<http2.Http2Session>}
|
||||
*/
|
||||
http2Server[kHttp2ServerSessions] = new Set()
|
||||
|
||||
http2Server.on('session', function (session) {
|
||||
session.once('connect', function () {
|
||||
http2Server[kHttp2ServerSessions].add(session)
|
||||
})
|
||||
|
||||
session.once('close', function () {
|
||||
http2Server[kHttp2ServerSessions].delete(session)
|
||||
})
|
||||
|
||||
session.once('frameError', function (type, code, streamId) {
|
||||
if (streamId === 0) {
|
||||
// The stream ID is 0, which means that the error is related to the session itself.
|
||||
// If the event is not associated with a stream, the Http2Session will be shut down immediately
|
||||
http2Server[kHttp2ServerSessions].delete(session)
|
||||
}
|
||||
})
|
||||
|
||||
session.once('goaway', function () {
|
||||
// The Http2Session instance will be shut down automatically when the 'goaway' event is emitted.
|
||||
http2Server[kHttp2ServerSessions].delete(session)
|
||||
})
|
||||
})
|
||||
|
||||
return function closeHttp2Sessions () {
|
||||
if (http2Server[kHttp2ServerSessions].size === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const session of http2Server[kHttp2ServerSessions]) {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
|
||||
|
||||
const serverListeningText = listenTextResolver(address)
|
||||
this.log.info(serverListeningText)
|
||||
return address
|
||||
}
|
||||
|
||||
function http2 () {
|
||||
try {
|
||||
return require('node:http2')
|
||||
} catch (err) {
|
||||
throw new FST_ERR_HTTP2_INVALID_VERSION()
|
||||
}
|
||||
}
|
||||
|
||||
function sessionTimeout (timeout) {
|
||||
return function (session) {
|
||||
session.setTimeout(timeout, close)
|
||||
}
|
||||
}
|
||||
|
||||
function close () {
|
||||
this.close()
|
||||
}
|
||||
|
||||
4
backend/node_modules/fastify/lib/symbols.js
generated
vendored
4
backend/node_modules/fastify/lib/symbols.js
generated
vendored
@@ -5,6 +5,7 @@ const keys = {
|
||||
kChildren: Symbol('fastify.children'),
|
||||
kServerBindings: Symbol('fastify.serverBindings'),
|
||||
kBodyLimit: Symbol('fastify.bodyLimit'),
|
||||
kSupportedHTTPMethods: Symbol('fastify.acceptedHTTPMethods'),
|
||||
kRoutePrefix: Symbol('fastify.routePrefix'),
|
||||
kLogLevel: Symbol('fastify.logLevel'),
|
||||
kLogSerializers: Symbol('fastify.logSerializers'),
|
||||
@@ -15,8 +16,8 @@ const keys = {
|
||||
kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
|
||||
kPluginNameChain: Symbol('fastify.pluginNameChain'),
|
||||
kRouteContext: Symbol('fastify.context'),
|
||||
kPublicRouteContext: Symbol('fastify.routeOptions'),
|
||||
kGenReqId: Symbol('fastify.genReqId'),
|
||||
kHttp2ServerSessions: Symbol('fastify.http2ServerSessions'),
|
||||
// Schema
|
||||
kSchemaController: Symbol('fastify.schemaController'),
|
||||
kSchemaHeaders: Symbol('headers-schema'),
|
||||
@@ -56,6 +57,7 @@ const keys = {
|
||||
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
|
||||
kTestInternals: Symbol('fastify.testInternals'),
|
||||
kErrorHandler: Symbol('fastify.errorHandler'),
|
||||
kErrorHandlerAlreadySet: Symbol('fastify.errorHandlerAlreadySet'),
|
||||
kChildLoggerFactory: Symbol('fastify.childLoggerFactory'),
|
||||
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
|
||||
kKeepAliveConnections: Symbol('fastify.keepAliveConnections'),
|
||||
|
||||
24
backend/node_modules/fastify/lib/validation.js
generated
vendored
24
backend/node_modules/fastify/lib/validation.js
generated
vendored
@@ -7,7 +7,7 @@ const {
|
||||
kSchemaBody: bodySchema,
|
||||
kSchemaResponse: responseSchema
|
||||
} = require('./symbols')
|
||||
const scChecker = /^[1-5]{1}[0-9]{2}$|^[1-5]xx$|^default$/
|
||||
const scChecker = /^[1-5](?:\d{2}|xx)$|^default$/
|
||||
|
||||
const {
|
||||
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX
|
||||
@@ -24,7 +24,7 @@ function compileSchemasForSerialization (context, compile) {
|
||||
.reduce(function (acc, statusCode) {
|
||||
const schema = context.schema.response[statusCode]
|
||||
statusCode = statusCode.toLowerCase()
|
||||
if (!scChecker.exec(statusCode)) {
|
||||
if (!scChecker.test(statusCode)) {
|
||||
throw new FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX()
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ function compileSchemasForValidation (context, compile, isCustom) {
|
||||
})
|
||||
}
|
||||
context[headersSchema] = compile({ schema: headersSchemaLowerCase, method, url, httpPart: 'headers' })
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'headers')) {
|
||||
} else if (Object.hasOwn(schema, 'headers')) {
|
||||
FSTWRN001('headers', method, url)
|
||||
}
|
||||
|
||||
@@ -98,28 +98,36 @@ function compileSchemasForValidation (context, compile, isCustom) {
|
||||
} else {
|
||||
context[bodySchema] = compile({ schema: schema.body, method, url, httpPart: 'body' })
|
||||
}
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'body')) {
|
||||
} else if (Object.hasOwn(schema, 'body')) {
|
||||
FSTWRN001('body', method, url)
|
||||
}
|
||||
|
||||
if (schema.querystring) {
|
||||
context[querystringSchema] = compile({ schema: schema.querystring, method, url, httpPart: 'querystring' })
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'querystring')) {
|
||||
} else if (Object.hasOwn(schema, 'querystring')) {
|
||||
FSTWRN001('querystring', method, url)
|
||||
}
|
||||
|
||||
if (schema.params) {
|
||||
context[paramsSchema] = compile({ schema: schema.params, method, url, httpPart: 'params' })
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'params')) {
|
||||
} else if (Object.hasOwn(schema, 'params')) {
|
||||
FSTWRN001('params', method, url)
|
||||
}
|
||||
}
|
||||
|
||||
function validateParam (validatorFunction, request, paramName) {
|
||||
const isUndefined = request[paramName] === undefined
|
||||
const ret = validatorFunction && validatorFunction(isUndefined ? null : request[paramName])
|
||||
let ret
|
||||
|
||||
if (ret?.then) {
|
||||
try {
|
||||
ret = validatorFunction?.(isUndefined ? null : request[paramName])
|
||||
} catch (err) {
|
||||
// If validator throws synchronously, ensure it propagates as an internal error
|
||||
err.statusCode = 500
|
||||
return err
|
||||
}
|
||||
|
||||
if (ret && typeof ret.then === 'function') {
|
||||
return ret
|
||||
.then((res) => { return answer(res) })
|
||||
.catch(err => { return err }) // return as simple error (not throw)
|
||||
|
||||
151
backend/node_modules/fastify/lib/warnings.js
generated
vendored
151
backend/node_modules/fastify/lib/warnings.js
generated
vendored
@@ -1,96 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
const { createDeprecation, createWarning } = require('process-warning')
|
||||
const { createWarning } = require('process-warning')
|
||||
|
||||
const FSTDEP005 = createDeprecation({
|
||||
code: 'FSTDEP005',
|
||||
message: 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.'
|
||||
})
|
||||
|
||||
const FSTDEP006 = createDeprecation({
|
||||
code: 'FSTDEP006',
|
||||
message: 'You are decorating Request/Reply with a reference type. This reference is shared amongst all requests. Use onRequest hook instead. Property: %s'
|
||||
})
|
||||
|
||||
const FSTDEP007 = createDeprecation({
|
||||
code: 'FSTDEP007',
|
||||
message: 'You are trying to set a HEAD route using "exposeHeadRoute" route flag when a sibling route is already set. See documentation for more info.'
|
||||
})
|
||||
|
||||
const FSTDEP008 = createDeprecation({
|
||||
code: 'FSTDEP008',
|
||||
message: 'You are using route constraints via the route { version: "..." } option, use { constraints: { version: "..." } } option instead.'
|
||||
})
|
||||
|
||||
const FSTDEP009 = createDeprecation({
|
||||
code: 'FSTDEP009',
|
||||
message: 'You are using a custom route versioning strategy via the server { versioning: "..." } option, use { constraints: { version: "..." } } option instead.'
|
||||
})
|
||||
|
||||
const FSTDEP010 = createDeprecation({
|
||||
code: 'FSTDEP010',
|
||||
message: 'Modifying the "reply.sent" property is deprecated. Use the "reply.hijack()" method instead.'
|
||||
})
|
||||
|
||||
const FSTDEP011 = createDeprecation({
|
||||
code: 'FSTDEP011',
|
||||
message: 'Variadic listen method is deprecated. Please use ".listen(optionsObject)" instead. The variadic signature will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP012 = createDeprecation({
|
||||
code: 'FSTDEP012',
|
||||
message: 'request.context property access is deprecated. Please use "request.routeOptions.config" or "request.routeOptions.schema" instead for accessing Route settings. The "request.context" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP013 = createDeprecation({
|
||||
code: 'FSTDEP013',
|
||||
message: 'Direct return of "trailers" function is deprecated. Please use "callback" or "async-await" for return value. The support of direct return will removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP014 = createDeprecation({
|
||||
code: 'FSTDEP014',
|
||||
message: 'You are trying to set/access the default route. This property is deprecated. Please, use setNotFoundHandler if you want to custom a 404 handler or the wildcard (*) to match all routes.'
|
||||
})
|
||||
|
||||
const FSTDEP015 = createDeprecation({
|
||||
code: 'FSTDEP015',
|
||||
message: 'You are accessing the deprecated "request.routeSchema" property. Use "request.routeOptions.schema" instead. Property "req.routeSchema" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP016 = createDeprecation({
|
||||
code: 'FSTDEP016',
|
||||
message: 'You are accessing the deprecated "request.routeConfig" property. Use "request.routeOptions.config" instead. Property "req.routeConfig" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP017 = createDeprecation({
|
||||
code: 'FSTDEP017',
|
||||
message: 'You are accessing the deprecated "request.routerPath" property. Use "request.routeOptions.url" instead. Property "req.routerPath" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP018 = createDeprecation({
|
||||
code: 'FSTDEP018',
|
||||
message: 'You are accessing the deprecated "request.routerMethod" property. Use "request.routeOptions.method" instead. Property "req.routerMethod" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP019 = createDeprecation({
|
||||
code: 'FSTDEP019',
|
||||
message: 'reply.context property access is deprecated. Please use "request.routeOptions.config" or "request.routeOptions.schema" instead for accessing Route settings. The "reply.context" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP020 = createDeprecation({
|
||||
code: 'FSTDEP020',
|
||||
message: 'You are using the deprecated "reply.getResponseTime()" method. Use the "reply.elapsedTime" property instead. Method "reply.getResponseTime()" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP021 = createDeprecation({
|
||||
code: 'FSTDEP021',
|
||||
message: 'The `reply.redirect()` method has a new signature: `reply.redirect(url: string, code?: number)`. It will be enforced in `fastify@v5`'
|
||||
})
|
||||
|
||||
const FSTDEP022 = createDeprecation({
|
||||
code: 'FSTDEP021',
|
||||
message: 'You are using the deprecated json shorthand schema on route %s. Specify full object schema instead. It will be removed in `fastify@v5`'
|
||||
})
|
||||
/**
|
||||
* Deprecation codes:
|
||||
* - FSTWRN001
|
||||
* - FSTSEC001
|
||||
* - FSTDEP022
|
||||
*
|
||||
* Deprecation Codes FSTDEP001 - FSTDEP021 were used by v4 and MUST NOT not be reused.
|
||||
* - FSTDEP022 is used by v5 and MUST NOT be reused.
|
||||
* Warning Codes FSTWRN001 - FSTWRN002 were used by v4 and MUST NOT not be reused.
|
||||
*/
|
||||
|
||||
const FSTWRN001 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
@@ -99,32 +20,38 @@ const FSTWRN001 = createWarning({
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTWRN002 = createWarning({
|
||||
const FSTWRN003 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
code: 'FSTWRN002',
|
||||
message: 'The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`',
|
||||
code: 'FSTWRN003',
|
||||
message: 'The %s mixes async and callback styles that may lead to unhandled rejections. Please use only one of them.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTWRN004 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
code: 'FSTWRN004',
|
||||
message: 'It seems that you are overriding an errorHandler in the same scope, which can lead to subtle bugs.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTSEC001 = createWarning({
|
||||
name: 'FastifySecurity',
|
||||
code: 'FSTSEC001',
|
||||
message: 'You are using /%s/ Content-Type which may be vulnerable to CORS attack. Please make sure your RegExp start with "^" or include ";?" to proper detection of the essence MIME type.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTDEP022 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
code: 'FSTDEP022',
|
||||
message: 'The router options for %s property access is deprecated. Please use "options.routerOptions" instead for accessing router options. The router options will be removed in `fastify@6`.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
FSTDEP005,
|
||||
FSTDEP006,
|
||||
FSTDEP007,
|
||||
FSTDEP008,
|
||||
FSTDEP009,
|
||||
FSTDEP010,
|
||||
FSTDEP011,
|
||||
FSTDEP012,
|
||||
FSTDEP013,
|
||||
FSTDEP014,
|
||||
FSTDEP015,
|
||||
FSTDEP016,
|
||||
FSTDEP017,
|
||||
FSTDEP018,
|
||||
FSTDEP019,
|
||||
FSTDEP020,
|
||||
FSTDEP021,
|
||||
FSTDEP022,
|
||||
FSTWRN001,
|
||||
FSTWRN002
|
||||
FSTWRN003,
|
||||
FSTWRN004,
|
||||
FSTSEC001,
|
||||
FSTDEP022
|
||||
}
|
||||
|
||||
84
backend/node_modules/fastify/lib/wrap-thenable.js
generated
vendored
Normal file
84
backend/node_modules/fastify/lib/wrap-thenable.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
kReplyIsError,
|
||||
kReplyHijacked
|
||||
} = require('./symbols')
|
||||
const { setErrorStatusCode } = require('./error-status')
|
||||
|
||||
const diagnostics = require('node:diagnostics_channel')
|
||||
const channels = diagnostics.tracingChannel('fastify.request.handler')
|
||||
|
||||
function wrapThenable (thenable, reply, store) {
|
||||
if (store) store.async = true
|
||||
thenable.then(function (payload) {
|
||||
if (reply[kReplyHijacked] === true) {
|
||||
return
|
||||
}
|
||||
|
||||
if (store) {
|
||||
channels.asyncStart.publish(store)
|
||||
}
|
||||
|
||||
try {
|
||||
// this is for async functions that are using reply.send directly
|
||||
//
|
||||
// since wrap-thenable will be called when using reply.send directly
|
||||
// without actual return. the response can be sent already or
|
||||
// the request may be terminated during the reply. in this situation,
|
||||
// it require an extra checking of request.aborted to see whether
|
||||
// the request is killed by client.
|
||||
if (payload !== undefined || //
|
||||
(reply.sent === false && //
|
||||
reply.raw.headersSent === false &&
|
||||
reply.request.raw.aborted === false &&
|
||||
reply.request.socket &&
|
||||
!reply.request.socket.destroyed
|
||||
)
|
||||
) {
|
||||
// we use a try-catch internally to avoid adding a catch to another
|
||||
// promise, increase promise perf by 10%
|
||||
try {
|
||||
reply.send(payload)
|
||||
} catch (err) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (store) {
|
||||
channels.asyncEnd.publish(store)
|
||||
}
|
||||
}
|
||||
}, function (err) {
|
||||
if (store) {
|
||||
store.error = err
|
||||
// Set status code before publishing so subscribers see the correct value
|
||||
setErrorStatusCode(reply, err)
|
||||
channels.error.publish(store) // note that error happens before asyncStart
|
||||
channels.asyncStart.publish(store)
|
||||
}
|
||||
|
||||
try {
|
||||
if (reply.sent === true) {
|
||||
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
|
||||
return
|
||||
}
|
||||
|
||||
reply[kReplyIsError] = true
|
||||
|
||||
reply.send(err)
|
||||
// The following should not happen
|
||||
/* c8 ignore next 3 */
|
||||
} catch (err) {
|
||||
// try-catch allow to re-throw error in error handler for async handler
|
||||
reply.send(err)
|
||||
} finally {
|
||||
if (store) {
|
||||
channels.asyncEnd.publish(store)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = wrapThenable
|
||||
50
backend/node_modules/fastify/lib/wrapThenable.js
generated
vendored
50
backend/node_modules/fastify/lib/wrapThenable.js
generated
vendored
@@ -1,50 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
kReplyIsError,
|
||||
kReplyHijacked
|
||||
} = require('./symbols')
|
||||
|
||||
function wrapThenable (thenable, reply) {
|
||||
thenable.then(function (payload) {
|
||||
if (reply[kReplyHijacked] === true) {
|
||||
return
|
||||
}
|
||||
|
||||
// this is for async functions that are using reply.send directly
|
||||
//
|
||||
// since wrap-thenable will be called when using reply.send directly
|
||||
// without actual return. the response can be sent already or
|
||||
// the request may be terminated during the reply. in this situation,
|
||||
// it require an extra checking of request.aborted to see whether
|
||||
// the request is killed by client.
|
||||
if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false)) {
|
||||
// we use a try-catch internally to avoid adding a catch to another
|
||||
// promise, increase promise perf by 10%
|
||||
try {
|
||||
reply.send(payload)
|
||||
} catch (err) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
}
|
||||
}
|
||||
}, function (err) {
|
||||
if (reply.sent === true) {
|
||||
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
|
||||
return
|
||||
}
|
||||
|
||||
reply[kReplyIsError] = true
|
||||
|
||||
// try-catch allow to re-throw error in error handler for async handler
|
||||
try {
|
||||
reply.send(err)
|
||||
// The following should not happen
|
||||
/* c8 ignore next 3 */
|
||||
} catch (err) {
|
||||
reply.send(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = wrapThenable
|
||||
Reference in New Issue
Block a user