@duplojs/http 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/getBody.cjs +1 -1
- package/dist/client/getBody.mjs +1 -1
- package/dist/client/hooks.d.ts +1 -25
- package/dist/client/httpClient.d.ts +29 -25
- package/dist/client/promiseRequest.cjs +3 -0
- package/dist/client/promiseRequest.d.ts +31 -39
- package/dist/client/promiseRequest.mjs +4 -1
- package/dist/client/types/clientResponse.d.ts +6 -6
- package/dist/client/types/hooks.d.ts +25 -0
- package/dist/client/types/index.cjs +2 -0
- package/dist/client/types/index.d.ts +2 -0
- package/dist/client/types/index.mjs +2 -0
- package/dist/client/types/promiseRequestParams.cjs +2 -0
- package/dist/client/types/promiseRequestParams.d.ts +9 -0
- package/dist/client/types/promiseRequestParams.mjs +1 -0
- package/dist/client/types/serverRoute.d.ts +19 -1
- package/dist/client/unexpectedResponseError.d.ts +1 -2
- package/dist/core/builders/preflight/route.cjs +1 -0
- package/dist/core/builders/preflight/route.d.ts +4 -2
- package/dist/core/builders/preflight/route.mjs +1 -0
- package/dist/core/builders/route/builder.cjs +1 -0
- package/dist/core/builders/route/builder.d.ts +4 -2
- package/dist/core/builders/route/builder.mjs +1 -0
- package/dist/core/clean/constraint.cjs +24 -0
- package/dist/core/clean/constraint.d.ts +8 -0
- package/dist/core/clean/constraint.mjs +22 -0
- package/dist/core/clean/constraintsSet.cjs +27 -0
- package/dist/core/clean/constraintsSet.d.ts +8 -0
- package/dist/core/clean/constraintsSet.mjs +25 -0
- package/dist/core/clean/entity.cjs +33 -0
- package/dist/core/clean/entity.d.ts +20 -0
- package/dist/core/clean/entity.mjs +31 -0
- package/dist/core/clean/index.cjs +8 -0
- package/dist/core/clean/index.d.ts +5 -0
- package/dist/core/clean/index.mjs +5 -0
- package/dist/core/clean/newType.cjs +15 -0
- package/dist/core/clean/newType.d.ts +8 -0
- package/dist/core/clean/newType.mjs +13 -0
- package/dist/core/clean/primitive.cjs +12 -0
- package/dist/core/clean/primitive.d.ts +8 -0
- package/dist/core/clean/primitive.mjs +10 -0
- package/dist/core/defaultHooks/index.cjs +50 -0
- package/dist/core/defaultHooks/index.d.ts +5 -0
- package/dist/core/defaultHooks/index.mjs +48 -0
- package/dist/{interfaces/node/error → core/errors}/bodyParseWrongChunkReceived.cjs +6 -4
- package/dist/core/errors/bodyParseWrongChunkReceived.d.ts +9 -0
- package/dist/core/errors/bodyParseWrongChunkReceived.mjs +14 -0
- package/dist/{interfaces/node/error → core/errors}/bodySizeExceedsLimitError.cjs +2 -2
- package/dist/{interfaces/node/error → core/errors}/bodySizeExceedsLimitError.d.ts +2 -2
- package/dist/{interfaces/node/error → core/errors}/bodySizeExceedsLimitError.mjs +2 -2
- package/dist/{interfaces/node/error → core/errors}/index.cjs +6 -4
- package/dist/{interfaces/node/error → core/errors}/index.d.ts +3 -2
- package/dist/{interfaces/node/error → core/errors}/index.mjs +3 -2
- package/dist/core/errors/parseJsonError.cjs +16 -0
- package/dist/core/errors/parseJsonError.d.ts +9 -0
- package/dist/core/errors/parseJsonError.mjs +14 -0
- package/dist/core/errors/wrongContentTypeError.cjs +16 -0
- package/dist/core/errors/wrongContentTypeError.d.ts +9 -0
- package/dist/core/errors/wrongContentTypeError.mjs +14 -0
- package/dist/core/functionsBuilders/route/create.d.ts +2 -2
- package/dist/core/functionsBuilders/route/default.cjs +0 -11
- package/dist/core/functionsBuilders/route/default.mjs +0 -11
- package/dist/core/functionsBuilders/route/hook.d.ts +2 -2
- package/dist/core/functionsBuilders/steps/create.d.ts +2 -2
- package/dist/core/functionsBuilders/steps/defaults/cutStep.cjs +15 -18
- package/dist/core/functionsBuilders/steps/defaults/cutStep.mjs +15 -18
- package/dist/core/functionsBuilders/steps/defaults/extractStep.cjs +43 -19
- package/dist/core/functionsBuilders/steps/defaults/extractStep.d.ts +2 -1
- package/dist/core/functionsBuilders/steps/defaults/extractStep.mjs +44 -20
- package/dist/core/functionsBuilders/steps/defaults/handlerStep.cjs +14 -8
- package/dist/core/functionsBuilders/steps/defaults/handlerStep.mjs +14 -8
- package/dist/core/hub/defaultBodyController.cjs +8 -0
- package/dist/core/hub/defaultBodyController.d.ts +1 -0
- package/dist/core/hub/defaultBodyController.mjs +6 -0
- package/dist/core/hub/hooks.cjs +3 -1
- package/dist/core/hub/hooks.d.ts +2 -3
- package/dist/core/hub/hooks.mjs +3 -1
- package/dist/core/hub/index.cjs +101 -127
- package/dist/core/hub/index.d.ts +33 -34
- package/dist/core/hub/index.mjs +100 -128
- package/dist/core/implementHttpServer.cjs +5 -5
- package/dist/core/implementHttpServer.d.ts +2 -1
- package/dist/core/implementHttpServer.mjs +5 -5
- package/dist/core/index.cjs +35 -10
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.mjs +14 -2
- package/dist/core/request/bodyController/base.cjs +36 -0
- package/dist/core/request/bodyController/base.d.ts +28 -0
- package/dist/core/request/bodyController/base.mjs +34 -0
- package/dist/core/request/bodyController/formData.cjs +28 -0
- package/dist/core/request/bodyController/formData.d.ts +22 -0
- package/dist/core/request/bodyController/formData.mjs +25 -0
- package/dist/core/request/bodyController/index.cjs +13 -0
- package/dist/core/request/bodyController/index.d.ts +3 -0
- package/dist/core/request/bodyController/index.mjs +3 -0
- package/dist/core/request/bodyController/text.cjs +14 -0
- package/dist/core/request/bodyController/text.d.ts +10 -0
- package/dist/core/request/bodyController/text.mjs +11 -0
- package/dist/core/{request.cjs → request/index.cjs} +21 -3
- package/dist/core/{request.d.ts → request/index.d.ts} +10 -3
- package/dist/core/request/index.mjs +50 -0
- package/dist/core/response/contract.d.ts +1 -1
- package/dist/core/route/hooks.d.ts +0 -2
- package/dist/core/route/index.d.ts +2 -1
- package/dist/core/router/index.cjs +27 -8
- package/dist/core/router/index.d.ts +2 -1
- package/dist/core/router/index.mjs +28 -10
- package/dist/core/router/notFoundBodyReaderImplementationError.cjs +16 -0
- package/dist/core/router/notFoundBodyReaderImplementationError.d.ts +11 -0
- package/dist/core/router/notFoundBodyReaderImplementationError.mjs +14 -0
- package/dist/core/router/types/buildedRouter.d.ts +3 -3
- package/dist/core/steps/extract.d.ts +3 -1
- package/dist/core/steps/types/steps.d.ts +1 -3
- package/dist/core/types/hosts.cjs +2 -0
- package/dist/core/types/hosts.d.ts +4 -0
- package/dist/core/types/hosts.mjs +1 -0
- package/dist/core/types/httpServerParams.cjs +2 -0
- package/dist/core/types/httpServerParams.d.ts +11 -0
- package/dist/core/types/httpServerParams.mjs +1 -0
- package/dist/core/types/index.cjs +2 -0
- package/dist/core/types/index.d.ts +2 -0
- package/dist/core/types/index.mjs +2 -0
- package/dist/interfaces/bun/types/request.cjs +1 -1
- package/dist/interfaces/bun/types/request.mjs +1 -1
- package/dist/interfaces/node/bodyReaders/formData/error.cjs +14 -0
- package/dist/interfaces/node/bodyReaders/formData/error.d.ts +8 -0
- package/dist/interfaces/node/bodyReaders/formData/error.mjs +12 -0
- package/dist/interfaces/node/bodyReaders/formData/index.cjs +94 -0
- package/dist/interfaces/node/bodyReaders/formData/index.d.ts +4 -0
- package/dist/interfaces/node/bodyReaders/formData/index.mjs +90 -0
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.cjs +175 -0
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.d.ts +21 -0
- package/dist/interfaces/node/bodyReaders/formData/readRequestFormData.mjs +173 -0
- package/dist/interfaces/node/bodyReaders/index.cjs +9 -0
- package/dist/interfaces/node/bodyReaders/index.d.ts +2 -0
- package/dist/interfaces/node/bodyReaders/index.mjs +2 -0
- package/dist/interfaces/node/bodyReaders/text/index.cjs +41 -0
- package/dist/interfaces/node/bodyReaders/text/index.d.ts +3 -0
- package/dist/interfaces/node/bodyReaders/text/index.mjs +38 -0
- package/dist/interfaces/node/bodyReaders/text/readRequestText.cjs +37 -0
- package/dist/interfaces/node/bodyReaders/text/readRequestText.d.ts +6 -0
- package/dist/interfaces/node/bodyReaders/text/readRequestText.mjs +35 -0
- package/dist/interfaces/node/createHttpServer.cjs +13 -5
- package/dist/interfaces/node/createHttpServer.d.ts +13 -12
- package/dist/interfaces/node/createHttpServer.mjs +13 -5
- package/dist/interfaces/node/hooks/index.cjs +47 -0
- package/dist/interfaces/node/hooks/index.d.ts +5 -0
- package/dist/interfaces/node/hooks/index.mjs +45 -0
- package/dist/interfaces/node/index.cjs +13 -9
- package/dist/interfaces/node/index.d.ts +1 -1
- package/dist/interfaces/node/index.mjs +7 -5
- package/dist/interfaces/node/types/index.cjs +0 -1
- package/dist/interfaces/node/types/index.d.ts +0 -1
- package/dist/interfaces/node/types/index.mjs +0 -1
- package/dist/interfaces/node/types/request.cjs +1 -1
- package/dist/interfaces/node/types/request.mjs +1 -1
- package/dist/plugins/codeGenerator/index.cjs +2 -0
- package/dist/plugins/codeGenerator/index.mjs +1 -1
- package/dist/plugins/codeGenerator/plugin.cjs +8 -4
- package/dist/plugins/codeGenerator/plugin.mjs +9 -5
- package/dist/plugins/codeGenerator/routeToDataParser.cjs +24 -1
- package/dist/plugins/codeGenerator/routeToDataParser.d.ts +34 -0
- package/dist/plugins/codeGenerator/routeToDataParser.mjs +24 -3
- package/dist/plugins/codeGenerator/typescriptTransfomer.cjs +9 -0
- package/dist/plugins/codeGenerator/typescriptTransfomer.d.ts +1 -0
- package/dist/plugins/codeGenerator/typescriptTransfomer.mjs +7 -0
- package/dist/plugins/openApiGenerator/makeOpenApiRoute.d.ts +3 -0
- package/dist/plugins/openApiGenerator/plugin.cjs +3 -3
- package/dist/plugins/openApiGenerator/plugin.mjs +4 -4
- package/dist/plugins/openApiGenerator/routeToOpenApi.cjs +16 -1
- package/dist/plugins/openApiGenerator/routeToOpenApi.d.ts +10 -1
- package/dist/plugins/openApiGenerator/routeToOpenApi.mjs +16 -1
- package/dist/plugins/openApiGenerator/types/entrypoint.d.ts +6 -1
- package/dist/plugins/openApiGenerator/types/openApiMethod.d.ts +1 -1
- package/package.json +5 -6
- package/dist/core/request.mjs +0 -32
- package/dist/interfaces/node/error/bodyParseUnknownError.cjs +0 -16
- package/dist/interfaces/node/error/bodyParseUnknownError.d.ts +0 -9
- package/dist/interfaces/node/error/bodyParseUnknownError.mjs +0 -14
- package/dist/interfaces/node/error/bodyParseWrongChunkReceived.d.ts +0 -8
- package/dist/interfaces/node/error/bodyParseWrongChunkReceived.mjs +0 -12
- package/dist/interfaces/node/hooks.cjs +0 -126
- package/dist/interfaces/node/hooks.d.ts +0 -8
- package/dist/interfaces/node/hooks.mjs +0 -124
- package/dist/interfaces/node/types/host.d.ts +0 -4
- /package/dist/{interfaces/node/types/host.cjs → client/types/hooks.cjs} +0 -0
- /package/dist/{interfaces/node/types/host.mjs → client/types/hooks.mjs} +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@duplojs/utils');
|
|
4
|
+
var error = require('./error.cjs');
|
|
5
|
+
require('../../../../core/errors/index.cjs');
|
|
6
|
+
var bodySizeExceedsLimitError = require('../../../../core/errors/bodySizeExceedsLimitError.cjs');
|
|
7
|
+
var bodyParseWrongChunkReceived = require('../../../../core/errors/bodyParseWrongChunkReceived.cjs');
|
|
8
|
+
|
|
9
|
+
const endHeaderPart = Buffer.from("\r\n\r\n");
|
|
10
|
+
const bufferStart = Buffer.from("\r\n");
|
|
11
|
+
const regexBoundary = /boundary=(?<boundary>[^; ]+)/i;
|
|
12
|
+
const regexHeaderPart = /name="(?<name>(?:\\"|[^"])+)"(?:; filename="(?<filename>(?:\\"|[^"])+)")?(?:;\s+filename\*=[^']+'[^']*'(?<encodedFilename>[^;\r\n\s]+))?/i;
|
|
13
|
+
function safeDecode(value) {
|
|
14
|
+
try {
|
|
15
|
+
return decodeURIComponent(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function readRequestFormData(request, firstValueAccumulator, params, onReceiveHeader) {
|
|
22
|
+
const boundary = utils.S.extract(request.headers["content-type"] ?? "", regexBoundary)?.namedGroups?.boundary;
|
|
23
|
+
if (!boundary) {
|
|
24
|
+
return utils.E.error(new error.BodyParseFormDataError("Wrong boundary."));
|
|
25
|
+
}
|
|
26
|
+
let valueAccumulator = firstValueAccumulator;
|
|
27
|
+
const startPart = Buffer.from(`\r\n--${boundary}`);
|
|
28
|
+
const endMultiPart = Buffer.from(`\r\n--${boundary}--`);
|
|
29
|
+
let currentBuffer = bufferStart;
|
|
30
|
+
let size = 0;
|
|
31
|
+
const keep = endMultiPart.length - 1;
|
|
32
|
+
let currentStream = undefined;
|
|
33
|
+
let fileQuantity = 0;
|
|
34
|
+
let currentFileSize = undefined;
|
|
35
|
+
const checkSize = (receivedChunk) => {
|
|
36
|
+
size += receivedChunk.length;
|
|
37
|
+
return size > params.maxBodySize
|
|
38
|
+
? new bodySizeExceedsLimitError.BodySizeExceedsLimitError(params.maxBodySize)
|
|
39
|
+
: true;
|
|
40
|
+
};
|
|
41
|
+
const flushReceiveHeader = async (headerPart) => {
|
|
42
|
+
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
43
|
+
const sizeResult = checkSize(headerPart);
|
|
44
|
+
if (sizeResult !== true) {
|
|
45
|
+
return sizeResult;
|
|
46
|
+
}
|
|
47
|
+
const extract = utils.S.extract(headerPart.toString("utf-8"), regexHeaderPart)?.namedGroups;
|
|
48
|
+
const header = extract?.name
|
|
49
|
+
? {
|
|
50
|
+
name: extract.name.trim(),
|
|
51
|
+
filename: (extract.encodedFilename !== undefined
|
|
52
|
+
? safeDecode(extract.encodedFilename)
|
|
53
|
+
: extract.filename)?.trim(),
|
|
54
|
+
}
|
|
55
|
+
: null;
|
|
56
|
+
if (!header) {
|
|
57
|
+
return new error.BodyParseFormDataError("Bad content header part.");
|
|
58
|
+
}
|
|
59
|
+
if (header.name.length > params.maxKeyLength) {
|
|
60
|
+
return new error.BodyParseFormDataError("key length exceeds limit.");
|
|
61
|
+
}
|
|
62
|
+
if (header.filename !== undefined) {
|
|
63
|
+
currentFileSize = 0;
|
|
64
|
+
fileQuantity++;
|
|
65
|
+
if (fileQuantity > params.maxFileQuantity) {
|
|
66
|
+
return new error.BodyParseFormDataError("File quantity exceeds limit.");
|
|
67
|
+
}
|
|
68
|
+
else if (params.mimeType !== undefined
|
|
69
|
+
&& !params.mimeType.test(utils.Path.getExtensionName(header.filename) ?? "")) {
|
|
70
|
+
return new error.BodyParseFormDataError("File have wrong mimeType.");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
currentFileSize = undefined;
|
|
75
|
+
}
|
|
76
|
+
const newStream = await onReceiveHeader(header);
|
|
77
|
+
if (newStream instanceof Error) {
|
|
78
|
+
return newStream;
|
|
79
|
+
}
|
|
80
|
+
currentStream = newStream;
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
const flushReceiveChunk = async (chunk) => {
|
|
84
|
+
if (chunk.length === 0) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
const sizeResult = checkSize(chunk);
|
|
88
|
+
if (sizeResult !== true) {
|
|
89
|
+
return sizeResult;
|
|
90
|
+
}
|
|
91
|
+
if (!currentStream) {
|
|
92
|
+
return new error.BodyParseFormDataError("Receive chunk before header part.");
|
|
93
|
+
}
|
|
94
|
+
if (typeof currentFileSize === "number") {
|
|
95
|
+
currentFileSize += chunk.length;
|
|
96
|
+
if (params.fileMaxSize !== undefined && currentFileSize > params.fileMaxSize) {
|
|
97
|
+
return new error.BodyParseFormDataError("File size exceeds limit.");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
await currentStream.onReceiveChunk(chunk);
|
|
101
|
+
return true;
|
|
102
|
+
};
|
|
103
|
+
const treatError = async (error) => {
|
|
104
|
+
await currentStream?.onError?.(error, valueAccumulator);
|
|
105
|
+
return utils.E.error(error);
|
|
106
|
+
};
|
|
107
|
+
try {
|
|
108
|
+
for await (const chunk of request) {
|
|
109
|
+
if (!(chunk instanceof Buffer)) {
|
|
110
|
+
return await treatError(new bodyParseWrongChunkReceived.BodyParseWrongChunkReceived("Buffer.", chunk));
|
|
111
|
+
}
|
|
112
|
+
currentBuffer = Buffer.concat([currentBuffer, chunk]);
|
|
113
|
+
if (currentBuffer.length > params.maxBufferSize) {
|
|
114
|
+
return await treatError(new error.BodyParseFormDataError("Buffer size exceeds limit."));
|
|
115
|
+
}
|
|
116
|
+
while (true) {
|
|
117
|
+
const endMultiPartIndex = currentBuffer.indexOf(endMultiPart);
|
|
118
|
+
if (endMultiPartIndex !== -1) {
|
|
119
|
+
// check if buffer contain end of transmissions
|
|
120
|
+
currentBuffer = currentBuffer.subarray(0, endMultiPartIndex);
|
|
121
|
+
}
|
|
122
|
+
const startPartIndex = currentBuffer.indexOf(startPart);
|
|
123
|
+
const endHeaderPartIndex = currentBuffer.indexOf(endHeaderPart);
|
|
124
|
+
if (startPartIndex !== -1 && endHeaderPartIndex !== -1) {
|
|
125
|
+
// check if buffer contain an entire header of part
|
|
126
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, startPartIndex));
|
|
127
|
+
if (resultChunk !== true) {
|
|
128
|
+
return await treatError(resultChunk);
|
|
129
|
+
}
|
|
130
|
+
const endIndex = endHeaderPartIndex + endHeaderPart.length;
|
|
131
|
+
const resultHeader = await flushReceiveHeader(currentBuffer.subarray(startPartIndex, endIndex));
|
|
132
|
+
if (resultHeader !== true) {
|
|
133
|
+
return await treatError(resultHeader);
|
|
134
|
+
}
|
|
135
|
+
currentBuffer = currentBuffer.subarray(endIndex);
|
|
136
|
+
}
|
|
137
|
+
else if (startPartIndex === -1 && endHeaderPartIndex === -1) {
|
|
138
|
+
// check if buffer contain only data
|
|
139
|
+
if (currentBuffer.length > keep) {
|
|
140
|
+
const bufferRestIndex = currentBuffer.length - keep;
|
|
141
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, bufferRestIndex));
|
|
142
|
+
if (resultChunk !== true) {
|
|
143
|
+
return await treatError(resultChunk);
|
|
144
|
+
}
|
|
145
|
+
currentBuffer = currentBuffer.subarray(bufferRestIndex);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
else if (startPartIndex !== -1 && endHeaderPartIndex === -1) {
|
|
150
|
+
// check if buffer contain start of header but not contain end
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// check if buffer contain only end of header part
|
|
155
|
+
return await treatError(new error.BodyParseFormDataError("Wrong content."));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const resultChunk = await flushReceiveChunk(currentBuffer);
|
|
160
|
+
if (resultChunk !== true) {
|
|
161
|
+
return await treatError(resultChunk);
|
|
162
|
+
}
|
|
163
|
+
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
164
|
+
return valueAccumulator;
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
await currentStream?.onError?.(error, valueAccumulator);
|
|
168
|
+
return utils.E.left("server-error", error);
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
request.destroy();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
exports.readRequestFormData = readRequestFormData;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { E, type MaybePromise } from "@duplojs/utils";
|
|
2
|
+
import type http from "http";
|
|
3
|
+
interface HeaderPartInformation {
|
|
4
|
+
name: string;
|
|
5
|
+
filename?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ReadRequestFormDataStreamChunkEvent<GenericValueAccumulator extends unknown = unknown> {
|
|
8
|
+
onReceiveChunk(chunk: Buffer): MaybePromise<void>;
|
|
9
|
+
onEndPart(valueAccumulator: GenericValueAccumulator): MaybePromise<GenericValueAccumulator>;
|
|
10
|
+
onError: ((error: unknown, valueAccumulator: GenericValueAccumulator) => MaybePromise<void>) | null;
|
|
11
|
+
}
|
|
12
|
+
export interface ReadRequestFormDataParams {
|
|
13
|
+
maxBodySize: number;
|
|
14
|
+
maxFileQuantity: number;
|
|
15
|
+
maxBufferSize: number;
|
|
16
|
+
maxKeyLength: number;
|
|
17
|
+
fileMaxSize?: number;
|
|
18
|
+
mimeType?: RegExp;
|
|
19
|
+
}
|
|
20
|
+
export declare function readRequestFormData<GenericValueAccumulator extends unknown, GenericOutputHeader extends E.Left = never>(request: http.IncomingMessage, firstValueAccumulator: GenericValueAccumulator, params: ReadRequestFormDataParams, onReceiveHeader: (header: HeaderPartInformation) => MaybePromise<ReadRequestFormDataStreamChunkEvent<GenericValueAccumulator> | Error>): Promise<E.Left<"server-error", unknown> | GenericOutputHeader | E.Error<Error> | GenericValueAccumulator>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { S, E, Path } from '@duplojs/utils';
|
|
2
|
+
import { BodyParseFormDataError } from './error.mjs';
|
|
3
|
+
import '../../../../core/errors/index.mjs';
|
|
4
|
+
import { BodySizeExceedsLimitError } from '../../../../core/errors/bodySizeExceedsLimitError.mjs';
|
|
5
|
+
import { BodyParseWrongChunkReceived } from '../../../../core/errors/bodyParseWrongChunkReceived.mjs';
|
|
6
|
+
|
|
7
|
+
const endHeaderPart = Buffer.from("\r\n\r\n");
|
|
8
|
+
const bufferStart = Buffer.from("\r\n");
|
|
9
|
+
const regexBoundary = /boundary=(?<boundary>[^; ]+)/i;
|
|
10
|
+
const regexHeaderPart = /name="(?<name>(?:\\"|[^"])+)"(?:; filename="(?<filename>(?:\\"|[^"])+)")?(?:;\s+filename\*=[^']+'[^']*'(?<encodedFilename>[^;\r\n\s]+))?/i;
|
|
11
|
+
function safeDecode(value) {
|
|
12
|
+
try {
|
|
13
|
+
return decodeURIComponent(value);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function readRequestFormData(request, firstValueAccumulator, params, onReceiveHeader) {
|
|
20
|
+
const boundary = S.extract(request.headers["content-type"] ?? "", regexBoundary)?.namedGroups?.boundary;
|
|
21
|
+
if (!boundary) {
|
|
22
|
+
return E.error(new BodyParseFormDataError("Wrong boundary."));
|
|
23
|
+
}
|
|
24
|
+
let valueAccumulator = firstValueAccumulator;
|
|
25
|
+
const startPart = Buffer.from(`\r\n--${boundary}`);
|
|
26
|
+
const endMultiPart = Buffer.from(`\r\n--${boundary}--`);
|
|
27
|
+
let currentBuffer = bufferStart;
|
|
28
|
+
let size = 0;
|
|
29
|
+
const keep = endMultiPart.length - 1;
|
|
30
|
+
let currentStream = undefined;
|
|
31
|
+
let fileQuantity = 0;
|
|
32
|
+
let currentFileSize = undefined;
|
|
33
|
+
const checkSize = (receivedChunk) => {
|
|
34
|
+
size += receivedChunk.length;
|
|
35
|
+
return size > params.maxBodySize
|
|
36
|
+
? new BodySizeExceedsLimitError(params.maxBodySize)
|
|
37
|
+
: true;
|
|
38
|
+
};
|
|
39
|
+
const flushReceiveHeader = async (headerPart) => {
|
|
40
|
+
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
41
|
+
const sizeResult = checkSize(headerPart);
|
|
42
|
+
if (sizeResult !== true) {
|
|
43
|
+
return sizeResult;
|
|
44
|
+
}
|
|
45
|
+
const extract = S.extract(headerPart.toString("utf-8"), regexHeaderPart)?.namedGroups;
|
|
46
|
+
const header = extract?.name
|
|
47
|
+
? {
|
|
48
|
+
name: extract.name.trim(),
|
|
49
|
+
filename: (extract.encodedFilename !== undefined
|
|
50
|
+
? safeDecode(extract.encodedFilename)
|
|
51
|
+
: extract.filename)?.trim(),
|
|
52
|
+
}
|
|
53
|
+
: null;
|
|
54
|
+
if (!header) {
|
|
55
|
+
return new BodyParseFormDataError("Bad content header part.");
|
|
56
|
+
}
|
|
57
|
+
if (header.name.length > params.maxKeyLength) {
|
|
58
|
+
return new BodyParseFormDataError("key length exceeds limit.");
|
|
59
|
+
}
|
|
60
|
+
if (header.filename !== undefined) {
|
|
61
|
+
currentFileSize = 0;
|
|
62
|
+
fileQuantity++;
|
|
63
|
+
if (fileQuantity > params.maxFileQuantity) {
|
|
64
|
+
return new BodyParseFormDataError("File quantity exceeds limit.");
|
|
65
|
+
}
|
|
66
|
+
else if (params.mimeType !== undefined
|
|
67
|
+
&& !params.mimeType.test(Path.getExtensionName(header.filename) ?? "")) {
|
|
68
|
+
return new BodyParseFormDataError("File have wrong mimeType.");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
currentFileSize = undefined;
|
|
73
|
+
}
|
|
74
|
+
const newStream = await onReceiveHeader(header);
|
|
75
|
+
if (newStream instanceof Error) {
|
|
76
|
+
return newStream;
|
|
77
|
+
}
|
|
78
|
+
currentStream = newStream;
|
|
79
|
+
return true;
|
|
80
|
+
};
|
|
81
|
+
const flushReceiveChunk = async (chunk) => {
|
|
82
|
+
if (chunk.length === 0) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const sizeResult = checkSize(chunk);
|
|
86
|
+
if (sizeResult !== true) {
|
|
87
|
+
return sizeResult;
|
|
88
|
+
}
|
|
89
|
+
if (!currentStream) {
|
|
90
|
+
return new BodyParseFormDataError("Receive chunk before header part.");
|
|
91
|
+
}
|
|
92
|
+
if (typeof currentFileSize === "number") {
|
|
93
|
+
currentFileSize += chunk.length;
|
|
94
|
+
if (params.fileMaxSize !== undefined && currentFileSize > params.fileMaxSize) {
|
|
95
|
+
return new BodyParseFormDataError("File size exceeds limit.");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
await currentStream.onReceiveChunk(chunk);
|
|
99
|
+
return true;
|
|
100
|
+
};
|
|
101
|
+
const treatError = async (error) => {
|
|
102
|
+
await currentStream?.onError?.(error, valueAccumulator);
|
|
103
|
+
return E.error(error);
|
|
104
|
+
};
|
|
105
|
+
try {
|
|
106
|
+
for await (const chunk of request) {
|
|
107
|
+
if (!(chunk instanceof Buffer)) {
|
|
108
|
+
return await treatError(new BodyParseWrongChunkReceived("Buffer.", chunk));
|
|
109
|
+
}
|
|
110
|
+
currentBuffer = Buffer.concat([currentBuffer, chunk]);
|
|
111
|
+
if (currentBuffer.length > params.maxBufferSize) {
|
|
112
|
+
return await treatError(new BodyParseFormDataError("Buffer size exceeds limit."));
|
|
113
|
+
}
|
|
114
|
+
while (true) {
|
|
115
|
+
const endMultiPartIndex = currentBuffer.indexOf(endMultiPart);
|
|
116
|
+
if (endMultiPartIndex !== -1) {
|
|
117
|
+
// check if buffer contain end of transmissions
|
|
118
|
+
currentBuffer = currentBuffer.subarray(0, endMultiPartIndex);
|
|
119
|
+
}
|
|
120
|
+
const startPartIndex = currentBuffer.indexOf(startPart);
|
|
121
|
+
const endHeaderPartIndex = currentBuffer.indexOf(endHeaderPart);
|
|
122
|
+
if (startPartIndex !== -1 && endHeaderPartIndex !== -1) {
|
|
123
|
+
// check if buffer contain an entire header of part
|
|
124
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, startPartIndex));
|
|
125
|
+
if (resultChunk !== true) {
|
|
126
|
+
return await treatError(resultChunk);
|
|
127
|
+
}
|
|
128
|
+
const endIndex = endHeaderPartIndex + endHeaderPart.length;
|
|
129
|
+
const resultHeader = await flushReceiveHeader(currentBuffer.subarray(startPartIndex, endIndex));
|
|
130
|
+
if (resultHeader !== true) {
|
|
131
|
+
return await treatError(resultHeader);
|
|
132
|
+
}
|
|
133
|
+
currentBuffer = currentBuffer.subarray(endIndex);
|
|
134
|
+
}
|
|
135
|
+
else if (startPartIndex === -1 && endHeaderPartIndex === -1) {
|
|
136
|
+
// check if buffer contain only data
|
|
137
|
+
if (currentBuffer.length > keep) {
|
|
138
|
+
const bufferRestIndex = currentBuffer.length - keep;
|
|
139
|
+
const resultChunk = await flushReceiveChunk(currentBuffer.subarray(0, bufferRestIndex));
|
|
140
|
+
if (resultChunk !== true) {
|
|
141
|
+
return await treatError(resultChunk);
|
|
142
|
+
}
|
|
143
|
+
currentBuffer = currentBuffer.subarray(bufferRestIndex);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
else if (startPartIndex !== -1 && endHeaderPartIndex === -1) {
|
|
148
|
+
// check if buffer contain start of header but not contain end
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// check if buffer contain only end of header part
|
|
153
|
+
return await treatError(new BodyParseFormDataError("Wrong content."));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const resultChunk = await flushReceiveChunk(currentBuffer);
|
|
158
|
+
if (resultChunk !== true) {
|
|
159
|
+
return await treatError(resultChunk);
|
|
160
|
+
}
|
|
161
|
+
valueAccumulator = await currentStream?.onEndPart(valueAccumulator) ?? valueAccumulator;
|
|
162
|
+
return valueAccumulator;
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
await currentStream?.onError?.(error, valueAccumulator);
|
|
166
|
+
return E.left("server-error", error);
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
request.destroy();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { readRequestFormData };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./formData/index.cjs');
|
|
4
|
+
var index$1 = require('./text/index.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
exports.createFormDataBodyReaderImplementation = index.createFormDataBodyReaderImplementation;
|
|
9
|
+
exports.createTextBodyReaderImplementation = index$1.createTextBodyReaderImplementation;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('../../../../core/request/index.cjs');
|
|
4
|
+
var readRequestText = require('./readRequestText.cjs');
|
|
5
|
+
var utils = require('@duplojs/utils');
|
|
6
|
+
require('../../../../core/errors/index.cjs');
|
|
7
|
+
var text = require('../../../../core/request/bodyController/text.cjs');
|
|
8
|
+
var wrongContentTypeError = require('../../../../core/errors/wrongContentTypeError.cjs');
|
|
9
|
+
var parseJsonError = require('../../../../core/errors/parseJsonError.cjs');
|
|
10
|
+
|
|
11
|
+
function createTextBodyReaderImplementation(serverParams) {
|
|
12
|
+
const serverMaxBodySize = utils.stringToBytes(serverParams.maxBodySize);
|
|
13
|
+
return text.TextBodyController.createReaderImplementation(async (request, params) => {
|
|
14
|
+
if (!request.headers["content-type"]?.includes("application/json")
|
|
15
|
+
&& !request.headers["content-type"]?.includes("text/plain")) {
|
|
16
|
+
return utils.E.error(new wrongContentTypeError.WrongContentTypeError("application/json or text/plain", utils.A.join(utils.A.coalescing(request.headers["content-type"] ?? ""), " ")));
|
|
17
|
+
}
|
|
18
|
+
const result = await readRequestText.readRequestText(request.raw.request, { maxBodySize: params.bodyMaxSize ?? serverMaxBodySize }, (result) => {
|
|
19
|
+
if (request.headers["content-type"]?.includes("application/json")) {
|
|
20
|
+
try {
|
|
21
|
+
return utils.E.success(JSON.parse(result));
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return utils.E.error(new parseJsonError.ParseJsonError(result, error));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return utils.E.success(result);
|
|
28
|
+
});
|
|
29
|
+
if (utils.E.isLeft(result)) {
|
|
30
|
+
// mandatory in case of error to avoid monopolizing the client connection if a stream is not finished.
|
|
31
|
+
request.raw.response.setHeader("Connection", "close");
|
|
32
|
+
}
|
|
33
|
+
if (utils.E.hasInformation(result, "server-error")) {
|
|
34
|
+
throw utils.unwrap(result);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.readRequestText = readRequestText.readRequestText;
|
|
41
|
+
exports.createTextBodyReaderImplementation = createTextBodyReaderImplementation;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type HttpServerParams } from "../../../../core/types";
|
|
2
|
+
export * from "./readRequestText";
|
|
3
|
+
export declare function createTextBodyReaderImplementation(serverParams: HttpServerParams): import("../../../../core/request").BodyReaderImplementation<"text", import("../../../../core/request").TextBodyReaderParams>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import '../../../../core/request/index.mjs';
|
|
2
|
+
import { readRequestText } from './readRequestText.mjs';
|
|
3
|
+
import { stringToBytes, E, A, unwrap } from '@duplojs/utils';
|
|
4
|
+
import '../../../../core/errors/index.mjs';
|
|
5
|
+
import { TextBodyController } from '../../../../core/request/bodyController/text.mjs';
|
|
6
|
+
import { WrongContentTypeError } from '../../../../core/errors/wrongContentTypeError.mjs';
|
|
7
|
+
import { ParseJsonError } from '../../../../core/errors/parseJsonError.mjs';
|
|
8
|
+
|
|
9
|
+
function createTextBodyReaderImplementation(serverParams) {
|
|
10
|
+
const serverMaxBodySize = stringToBytes(serverParams.maxBodySize);
|
|
11
|
+
return TextBodyController.createReaderImplementation(async (request, params) => {
|
|
12
|
+
if (!request.headers["content-type"]?.includes("application/json")
|
|
13
|
+
&& !request.headers["content-type"]?.includes("text/plain")) {
|
|
14
|
+
return E.error(new WrongContentTypeError("application/json or text/plain", A.join(A.coalescing(request.headers["content-type"] ?? ""), " ")));
|
|
15
|
+
}
|
|
16
|
+
const result = await readRequestText(request.raw.request, { maxBodySize: params.bodyMaxSize ?? serverMaxBodySize }, (result) => {
|
|
17
|
+
if (request.headers["content-type"]?.includes("application/json")) {
|
|
18
|
+
try {
|
|
19
|
+
return E.success(JSON.parse(result));
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return E.error(new ParseJsonError(result, error));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return E.success(result);
|
|
26
|
+
});
|
|
27
|
+
if (E.isLeft(result)) {
|
|
28
|
+
// mandatory in case of error to avoid monopolizing the client connection if a stream is not finished.
|
|
29
|
+
request.raw.response.setHeader("Connection", "close");
|
|
30
|
+
}
|
|
31
|
+
if (E.hasInformation(result, "server-error")) {
|
|
32
|
+
throw unwrap(result);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { createTextBodyReaderImplementation, readRequestText };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('../../../../core/errors/index.cjs');
|
|
4
|
+
var utils = require('@duplojs/utils');
|
|
5
|
+
var bodyParseWrongChunkReceived = require('../../../../core/errors/bodyParseWrongChunkReceived.cjs');
|
|
6
|
+
var bodySizeExceedsLimitError = require('../../../../core/errors/bodySizeExceedsLimitError.cjs');
|
|
7
|
+
|
|
8
|
+
async function readRequestText(request, params, onEnd) {
|
|
9
|
+
let result = "";
|
|
10
|
+
let size = 0;
|
|
11
|
+
try {
|
|
12
|
+
for await (const chunk of request) {
|
|
13
|
+
if (!(chunk instanceof Buffer) && typeof chunk !== "string") {
|
|
14
|
+
return utils.E.error(new bodyParseWrongChunkReceived.BodyParseWrongChunkReceived("Buffer or String.", chunk));
|
|
15
|
+
}
|
|
16
|
+
size += chunk instanceof Buffer
|
|
17
|
+
? chunk.byteLength
|
|
18
|
+
: Buffer.byteLength(chunk);
|
|
19
|
+
if (size > params.maxBodySize) {
|
|
20
|
+
return utils.E.error(new bodySizeExceedsLimitError.BodySizeExceedsLimitError(params.maxBodySize));
|
|
21
|
+
}
|
|
22
|
+
result += chunk.toString();
|
|
23
|
+
}
|
|
24
|
+
if (onEnd) {
|
|
25
|
+
return await onEnd(result);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return utils.E.left("server-error", error);
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
request.destroy();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.readRequestText = readRequestText;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { E } from "@duplojs/utils";
|
|
2
|
+
import type http from "http";
|
|
3
|
+
export interface ReadRequestTextParams {
|
|
4
|
+
maxBodySize: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function readRequestText<GenericOutputValue extends unknown = string>(request: http.IncomingMessage, params: ReadRequestTextParams, onEnd?: (result: string) => GenericOutputValue): Promise<E.Left<"server-error", unknown> | E.Error<Error> | GenericOutputValue>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import '../../../../core/errors/index.mjs';
|
|
2
|
+
import { E } from '@duplojs/utils';
|
|
3
|
+
import { BodyParseWrongChunkReceived } from '../../../../core/errors/bodyParseWrongChunkReceived.mjs';
|
|
4
|
+
import { BodySizeExceedsLimitError } from '../../../../core/errors/bodySizeExceedsLimitError.mjs';
|
|
5
|
+
|
|
6
|
+
async function readRequestText(request, params, onEnd) {
|
|
7
|
+
let result = "";
|
|
8
|
+
let size = 0;
|
|
9
|
+
try {
|
|
10
|
+
for await (const chunk of request) {
|
|
11
|
+
if (!(chunk instanceof Buffer) && typeof chunk !== "string") {
|
|
12
|
+
return E.error(new BodyParseWrongChunkReceived("Buffer or String.", chunk));
|
|
13
|
+
}
|
|
14
|
+
size += chunk instanceof Buffer
|
|
15
|
+
? chunk.byteLength
|
|
16
|
+
: Buffer.byteLength(chunk);
|
|
17
|
+
if (size > params.maxBodySize) {
|
|
18
|
+
return E.error(new BodySizeExceedsLimitError(params.maxBodySize));
|
|
19
|
+
}
|
|
20
|
+
result += chunk.toString();
|
|
21
|
+
}
|
|
22
|
+
if (onEnd) {
|
|
23
|
+
return await onEnd(result);
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return E.left("server-error", error);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
request.destroy();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { readRequestText };
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var utils = require('@duplojs/utils');
|
|
4
3
|
var http = require('http');
|
|
5
4
|
var https = require('https');
|
|
6
|
-
var
|
|
5
|
+
var index$3 = require('./hooks/index.cjs');
|
|
7
6
|
var implementHttpServer = require('../../core/implementHttpServer.cjs');
|
|
7
|
+
var utils = require('@duplojs/utils');
|
|
8
|
+
var index$2 = require('../../core/defaultHooks/index.cjs');
|
|
9
|
+
require('./bodyReaders/index.cjs');
|
|
10
|
+
var index = require('./bodyReaders/text/index.cjs');
|
|
11
|
+
var index$1 = require('./bodyReaders/formData/index.cjs');
|
|
8
12
|
|
|
9
|
-
function createHttpServer(
|
|
13
|
+
function createHttpServer(hub, params) {
|
|
10
14
|
const httpServerParams = utils.O.override({
|
|
11
15
|
host: "localhost",
|
|
12
16
|
port: 80,
|
|
@@ -15,9 +19,13 @@ function createHttpServer(inputHub, params) {
|
|
|
15
19
|
predictedHeaderKey: "predicted",
|
|
16
20
|
fromHookHeaderKey: "from-hook",
|
|
17
21
|
interface: "node",
|
|
22
|
+
uploadFolder: "./upload",
|
|
18
23
|
}, params);
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
hub.addBodyReaderImplementation([
|
|
25
|
+
index.createTextBodyReaderImplementation(httpServerParams),
|
|
26
|
+
index$1.createFormDataBodyReaderImplementation(httpServerParams),
|
|
27
|
+
]);
|
|
28
|
+
hub.addRouteHooks([index$2.initDefaultHook(hub, httpServerParams), index$3.nodeHook]);
|
|
21
29
|
function whenUncaughtError(error, routerInitializationData) {
|
|
22
30
|
const serverResponse = routerInitializationData.raw.response;
|
|
23
31
|
if (!serverResponse.headersSent && !serverResponse.writableEnded) {
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type Hosts } from "./types/host";
|
|
3
|
-
import { type BytesInString, O } from "@duplojs/utils";
|
|
1
|
+
import { type Hub } from "../../core/hub";
|
|
4
2
|
import http from "http";
|
|
5
3
|
import https from "https";
|
|
6
|
-
|
|
4
|
+
import { O } from "@duplojs/utils";
|
|
5
|
+
import { type HttpServerParams } from "../../core/types";
|
|
6
|
+
declare module "../../core/types" {
|
|
7
7
|
interface HttpServerParams {
|
|
8
8
|
readonly interface: "node";
|
|
9
|
-
readonly host: Hosts;
|
|
10
|
-
readonly port: number;
|
|
11
|
-
readonly maxBodySize: BytesInString | number;
|
|
12
|
-
readonly informationHeaderKey: string;
|
|
13
|
-
readonly predictedHeaderKey: string;
|
|
14
|
-
readonly fromHookHeaderKey: string;
|
|
15
9
|
readonly http?: http.ServerOptions;
|
|
16
10
|
readonly https?: https.ServerOptions;
|
|
17
11
|
}
|
|
12
|
+
interface HostCustom {
|
|
13
|
+
"::": true;
|
|
14
|
+
"0.0.0.0": true;
|
|
15
|
+
localhost: true;
|
|
16
|
+
"127.0.0.1": true;
|
|
17
|
+
"::1": true;
|
|
18
|
+
}
|
|
18
19
|
}
|
|
19
|
-
export type CreateHttpServerParams = O.PartialKeys<Omit<HttpServerParams, "interface">, "maxBodySize" | "informationHeaderKey" | "predictedHeaderKey" | "fromHookHeaderKey">;
|
|
20
|
-
export declare function createHttpServer(
|
|
20
|
+
export type CreateHttpServerParams = O.PartialKeys<Omit<HttpServerParams, "interface">, "maxBodySize" | "informationHeaderKey" | "predictedHeaderKey" | "fromHookHeaderKey" | "uploadFolder">;
|
|
21
|
+
export declare function createHttpServer(hub: Hub, params: CreateHttpServerParams): Promise<https.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>>;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { O } from '@duplojs/utils';
|
|
2
1
|
import http from 'http';
|
|
3
2
|
import https from 'https';
|
|
4
|
-
import {
|
|
3
|
+
import { nodeHook } from './hooks/index.mjs';
|
|
5
4
|
import { implementHttpServer } from '../../core/implementHttpServer.mjs';
|
|
5
|
+
import { O } from '@duplojs/utils';
|
|
6
|
+
import { initDefaultHook } from '../../core/defaultHooks/index.mjs';
|
|
7
|
+
import './bodyReaders/index.mjs';
|
|
8
|
+
import { createTextBodyReaderImplementation } from './bodyReaders/text/index.mjs';
|
|
9
|
+
import { createFormDataBodyReaderImplementation } from './bodyReaders/formData/index.mjs';
|
|
6
10
|
|
|
7
|
-
function createHttpServer(
|
|
11
|
+
function createHttpServer(hub, params) {
|
|
8
12
|
const httpServerParams = O.override({
|
|
9
13
|
host: "localhost",
|
|
10
14
|
port: 80,
|
|
@@ -13,9 +17,13 @@ function createHttpServer(inputHub, params) {
|
|
|
13
17
|
predictedHeaderKey: "predicted",
|
|
14
18
|
fromHookHeaderKey: "from-hook",
|
|
15
19
|
interface: "node",
|
|
20
|
+
uploadFolder: "./upload",
|
|
16
21
|
}, params);
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
hub.addBodyReaderImplementation([
|
|
23
|
+
createTextBodyReaderImplementation(httpServerParams),
|
|
24
|
+
createFormDataBodyReaderImplementation(httpServerParams),
|
|
25
|
+
]);
|
|
26
|
+
hub.addRouteHooks([initDefaultHook(hub, httpServerParams), nodeHook]);
|
|
19
27
|
function whenUncaughtError(error, routerInitializationData) {
|
|
20
28
|
const serverResponse = routerInitializationData.raw.response;
|
|
21
29
|
if (!serverResponse.headersSent && !serverResponse.writableEnded) {
|