@nodefony/http 10.0.0-beta.3 → 10.0.0-beta.5
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/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
- package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorateParam.js +1 -2
- package/dist/index.js +13 -10
- package/dist/nodefony/command/assetsPublishCommand.js +5 -3
- package/dist/nodefony/command/certificatesCommand.js +5 -3
- package/dist/nodefony/command/networkCommand.js +5 -3
- package/dist/nodefony/command/proxyGenerateCommand.js +8 -3
- package/dist/nodefony/config/config.js +3 -3
- package/dist/nodefony/config/defineModuleConfig.js +1 -2
- package/dist/nodefony/interfaces/IRequestTrace.js +1 -0
- package/dist/nodefony/service/HttpAdminApi.js +2 -2
- package/dist/nodefony/service/ProfilerAdminApi.js +13 -3
- package/dist/nodefony/service/audit-logger.js +23 -30
- package/dist/nodefony/service/certificates.js +97 -13
- package/dist/nodefony/service/error-renderer.js +29 -12
- package/dist/nodefony/service/http-kernel.js +198 -50
- package/dist/nodefony/service/pretty-request-logger.js +15 -13
- package/dist/nodefony/service/request-logger.js +24 -16
- package/dist/nodefony/service/reverse-proxy.js +3 -3
- package/dist/nodefony/service/servers/clientError.js +22 -3
- package/dist/nodefony/service/servers/server-h2c.js +126 -0
- package/dist/nodefony/service/servers/server-http.js +5 -8
- package/dist/nodefony/service/servers/server-https.js +12 -24
- package/dist/nodefony/service/servers/server-static.js +3 -3
- package/dist/nodefony/service/servers/server-websocket-secure.js +10 -18
- package/dist/nodefony/service/servers/server-websocket.js +10 -18
- package/dist/nodefony/service/servers/serverShutdown.js +78 -18
- package/dist/nodefony/service/servers/wsHeartbeat.js +1 -2
- package/dist/nodefony/service/sessions/sessions-service.js +7 -14
- package/dist/nodefony/service/trace.js +1 -2
- package/dist/nodefony/service/upload/upload-service.js +5 -8
- package/dist/nodefony/service/x509.js +1 -2
- package/dist/nodefony/src/assets/collectAssets.js +1 -2
- package/dist/nodefony/src/assets/prebuiltUi.js +1 -2
- package/dist/nodefony/src/context/Context.js +78 -43
- package/dist/nodefony/src/context/domainMatcher.js +1 -2
- package/dist/nodefony/src/context/forwarded.js +1 -2
- package/dist/nodefony/src/context/http/HttpContext.js +28 -6
- package/dist/nodefony/src/context/http/Request.js +33 -29
- package/dist/nodefony/src/context/http/Response.js +23 -6
- package/dist/nodefony/src/context/http/SseStream.js +1 -2
- package/dist/nodefony/src/context/http/parser.js +36 -10
- package/dist/nodefony/src/context/http/urlFastPath.js +1 -2
- package/dist/nodefony/src/context/http2/Request.js +4 -8
- package/dist/nodefony/src/context/http2/Response.js +41 -9
- package/dist/nodefony/src/context/metaData.js +1 -2
- package/dist/nodefony/src/context/requestId.js +1 -2
- package/dist/nodefony/src/context/requestTrace.js +104 -0
- package/dist/nodefony/src/context/responseEnded.js +1 -2
- package/dist/nodefony/src/context/timingMode.js +21 -0
- package/dist/nodefony/src/context/transport.js +45 -0
- package/dist/nodefony/src/context/trustProxy.js +1 -2
- package/dist/nodefony/src/context/unsentResponse.js +30 -0
- package/dist/nodefony/src/context/websocket/Response.js +33 -6
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +104 -25
- package/dist/nodefony/src/context/websocket/isWebsocketContext.js +17 -0
- package/dist/nodefony/src/context/websocket/websocketUrl.js +1 -2
- package/dist/nodefony/src/context/websocket/wsBackpressure.js +1 -2
- package/dist/nodefony/src/context/websocket/wsCloseReason.js +1 -2
- package/dist/nodefony/src/context/websocket/wsLogContent.js +1 -2
- package/dist/nodefony/src/cookies/cookie.js +3 -7
- package/dist/nodefony/src/errors/httpError.js +1 -2
- package/dist/nodefony/src/errors/thrownMessage.js +1 -2
- package/dist/nodefony/src/profiler/FrameProfile.js +23 -2
- package/dist/nodefony/src/profiler/Profiler.js +104 -32
- package/dist/nodefony/src/profiler/aggregate.js +442 -0
- package/dist/nodefony/src/proxy/forward.js +29 -5
- package/dist/nodefony/src/proxy/generateProxyConfig.js +14 -6
- package/dist/nodefony/src/proxy/rules.js +12 -6
- package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +1 -2
- package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +1 -2
- package/dist/nodefony/src/rateLimit/rateLimitFilters.js +1 -2
- package/dist/nodefony/src/servers/http2Limits.js +50 -0
- package/dist/nodefony/src/servers/kernelServers.js +12 -3
- package/dist/nodefony/src/servers/portBinder.js +41 -10
- package/dist/nodefony/src/servers/upgradeDispatch.js +86 -7
- package/dist/nodefony/src/session/session.js +2 -3
- package/dist/nodefony/src/session/sessionStoreFailure.js +1 -2
- package/dist/nodefony/src/session/storage/MemorySessionStorage.js +1 -2
- package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +1 -2
- package/dist/nodefony/src/session/storage/sessionFilters.js +1 -2
- package/dist/nodefony/src/session/storage/sessionSort.js +1 -2
- package/dist/types/index.d.ts +9 -3
- package/dist/types/nodefony/config/config.d.ts +4 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +72 -4
- package/dist/types/nodefony/interfaces/IRequest.d.ts +9 -4
- package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +56 -0
- package/dist/types/nodefony/interfaces/IReverseProxy.d.ts +8 -0
- package/dist/types/nodefony/interfaces/IRouting.d.ts +26 -0
- package/dist/types/nodefony/interfaces/index.d.ts +3 -2
- package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +3 -0
- package/dist/types/nodefony/service/audit-logger.d.ts +3 -11
- package/dist/types/nodefony/service/certificates.d.ts +55 -4
- package/dist/types/nodefony/service/error-renderer.d.ts +31 -0
- package/dist/types/nodefony/service/http-kernel.d.ts +96 -10
- package/dist/types/nodefony/service/servers/clientError.d.ts +16 -0
- package/dist/types/nodefony/service/servers/server-h2c.d.ts +51 -0
- package/dist/types/nodefony/service/servers/server-http.d.ts +3 -3
- package/dist/types/nodefony/service/servers/server-https.d.ts +4 -4
- package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +1 -3
- package/dist/types/nodefony/service/servers/server-websocket.d.ts +1 -3
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +30 -16
- package/dist/types/nodefony/src/context/Context.d.ts +38 -5
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +16 -2
- package/dist/types/nodefony/src/context/http/Request.d.ts +20 -15
- package/dist/types/nodefony/src/context/http/Response.d.ts +11 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +18 -2
- package/dist/types/nodefony/src/context/http2/Request.d.ts +1 -1
- package/dist/types/nodefony/src/context/http2/Response.d.ts +27 -5
- package/dist/types/nodefony/src/context/requestTrace.d.ts +64 -0
- package/dist/types/nodefony/src/context/timingMode.d.ts +23 -0
- package/dist/types/nodefony/src/context/transport.d.ts +53 -0
- package/dist/types/nodefony/src/context/unsentResponse.d.ts +16 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +18 -2
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +58 -8
- package/dist/types/nodefony/src/context/websocket/isWebsocketContext.d.ts +15 -0
- package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +28 -12
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +79 -111
- package/dist/types/nodefony/src/profiler/aggregate.d.ts +132 -0
- package/dist/types/nodefony/src/proxy/forward.d.ts +14 -2
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +16 -0
- package/dist/types/nodefony/src/proxy/rules.d.ts +3 -0
- package/dist/types/nodefony/src/servers/http2Limits.d.ts +37 -0
- package/dist/types/nodefony/src/servers/kernelServers.d.ts +10 -1
- package/dist/types/nodefony/src/servers/portBinder.d.ts +29 -5
- package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +33 -3
- package/docs/cookies.md +85 -78
- package/docs/diagnostics-channel.md +303 -0
- package/docs/index.md +6 -1
- package/docs/observabilite.md +159 -81
- package/docs/rate-limit.md +83 -83
- package/docs/reverse-proxy.md +72 -70
- package/docs/servers.md +338 -224
- package/docs/session.md +179 -179
- package/docs/sse.md +24 -20
- package/docs/upload.md +120 -117
- package/package.json +8 -9
- package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js +0 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Ws from "ws";
|
|
2
|
-
|
|
2
|
+
// nodefony/service/servers/wsHeartbeat.ts
|
|
3
3
|
/**
|
|
4
4
|
* Arme le suivi keep-alive d'UNE connexion : initialise l'horodatage de vie et
|
|
5
5
|
* attache l'unique listener `pong` qui le rafraîchit.
|
|
@@ -76,5 +76,4 @@ const startHeartbeat = (server, options) => {
|
|
|
76
76
|
timer.unref();
|
|
77
77
|
return timer;
|
|
78
78
|
};
|
|
79
|
-
//#endregion
|
|
80
79
|
export { heartbeatTick, startHeartbeat, trackPong };
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { SESSION_FACETS } from "../../src/session/storage/sessionFilters.js";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import http_kernel_default from "../http-kernel.js";
|
|
5
|
-
import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
|
|
2
|
+
import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
|
|
3
|
+
import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
|
|
6
4
|
import Session from "../../src/session/session.js";
|
|
7
5
|
import MemorySessionStorage from "../../src/session/storage/MemorySessionStorage.js";
|
|
8
6
|
import RevocationGuardStorage from "../../src/session/storage/RevocationGuardStorage.js";
|
|
9
|
-
import { AUTO_STORE, EMPTY_INFRA, GcScheduler,
|
|
7
|
+
import { AUTO_STORE, EMPTY_INFRA, GcScheduler, Inject, Nodefony, RequestContext, Service, countFacets, extend, injectable, readStoreConnector, readStoreLocation, resolveAutoStore, storeConnectivity } from "nodefony";
|
|
10
8
|
import { createHash, createHmac } from "node:crypto";
|
|
11
|
-
|
|
9
|
+
// nodefony/service/sessions/sessions-service.ts
|
|
12
10
|
var _SessionsService;
|
|
13
11
|
/**
|
|
14
12
|
* Convertit un timestamp de session (`Date` en mémoire, **string ISO** après
|
|
@@ -143,7 +141,7 @@ let SessionsService = class SessionsService extends Service {
|
|
|
143
141
|
const configured = storeName;
|
|
144
142
|
let reason = `store explicitement configuré ("${configured}")`;
|
|
145
143
|
if (storeName === AUTO_STORE) {
|
|
146
|
-
const auto = resolveAutoStore("session", this.kernel?.infra ?? EMPTY_INFRA, _SessionsService.storageHandlers(), "memory",
|
|
144
|
+
const auto = resolveAutoStore("session", this.kernel?.infra ?? EMPTY_INFRA, _SessionsService.storageHandlers(), "memory", storeConnectivity(this.kernel));
|
|
147
145
|
storeName = auto.store;
|
|
148
146
|
reason = auto.reason;
|
|
149
147
|
this.log(`session.store "auto" → "${storeName}" (${auto.reason})`, "INFO");
|
|
@@ -219,7 +217,7 @@ let SessionsService = class SessionsService extends Service {
|
|
|
219
217
|
return resolve(context.session);
|
|
220
218
|
}
|
|
221
219
|
}
|
|
222
|
-
let inst
|
|
220
|
+
let inst;
|
|
223
221
|
try {
|
|
224
222
|
context.sessionStarting = true;
|
|
225
223
|
inst = this.createSession(this.defaultSessionName);
|
|
@@ -598,12 +596,7 @@ let SessionsService = class SessionsService extends Service {
|
|
|
598
596
|
this.get("auditService")?.record(event);
|
|
599
597
|
}
|
|
600
598
|
};
|
|
601
|
-
SessionsService = _SessionsService = __decorate([
|
|
602
|
-
injectable(),
|
|
603
|
-
__decorateParam(1, inject("HttpKernel")),
|
|
604
|
-
__decorateMetadata("design:paramtypes", [typeof Module === "undefined" ? Object : Module, typeof http_kernel_default === "undefined" ? Object : http_kernel_default])
|
|
605
|
-
], SessionsService);
|
|
599
|
+
SessionsService = _SessionsService = __decorate([injectable(), __decorateParam(1, Inject("HttpKernel"))], SessionsService);
|
|
606
600
|
SessionsService.registerStorage("memory", MemorySessionStorage);
|
|
607
601
|
var sessions_service_default = SessionsService;
|
|
608
|
-
//#endregion
|
|
609
602
|
export { computeSessionRef, sessions_service_default as default, toSessionSummary };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomFillSync } from "node:crypto";
|
|
2
|
-
|
|
2
|
+
// nodefony/service/trace.ts
|
|
3
3
|
/**
|
|
4
4
|
* W3C Trace Context — parse + generate `traceparent` headers (P2.7).
|
|
5
5
|
*
|
|
@@ -69,5 +69,4 @@ function resolveTraceparent(header) {
|
|
|
69
69
|
const hex = randomHex(24);
|
|
70
70
|
return `00-${hex.slice(0, 32)}-${hex.slice(32)}-01`;
|
|
71
71
|
}
|
|
72
|
-
//#endregion
|
|
73
72
|
export { parseTraceparent, resolveTraceparent };
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
|
|
5
|
-
import { Cli, FileClass, Module, Service, inject } from "nodefony";
|
|
1
|
+
import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
|
|
2
|
+
import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
|
|
3
|
+
import { Cli, FileClass, Inject, Service } from "nodefony";
|
|
6
4
|
import fs from "node:fs";
|
|
7
5
|
import fsp from "node:fs/promises";
|
|
8
6
|
import path from "node:path";
|
|
9
|
-
|
|
7
|
+
// nodefony/service/upload/upload-service.ts
|
|
10
8
|
/** Test d'existence non bloquant (`fsp.access`) — remplace `existsSync`. */
|
|
11
9
|
const existsAsync = async (p) => {
|
|
12
10
|
try {
|
|
@@ -58,7 +56,7 @@ let upload = class upload extends Service {
|
|
|
58
56
|
throw new Error(`Syslog not ready`);
|
|
59
57
|
}
|
|
60
58
|
};
|
|
61
|
-
upload = __decorate([__decorateParam(1,
|
|
59
|
+
upload = __decorate([__decorateParam(1, Inject("HttpKernel"))], upload);
|
|
62
60
|
var UploadedFile = class UploadedFile extends FileClass {
|
|
63
61
|
parsedFile;
|
|
64
62
|
size;
|
|
@@ -168,5 +166,4 @@ var UploadedFile = class UploadedFile extends FileClass {
|
|
|
168
166
|
}
|
|
169
167
|
};
|
|
170
168
|
var upload_service_default = upload;
|
|
171
|
-
//#endregion
|
|
172
169
|
export { UploadedFile, upload_service_default as default, upload };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isIPv4, isIPv6 } from "node:net";
|
|
2
2
|
import { createHash, sign } from "node:crypto";
|
|
3
|
-
|
|
3
|
+
// nodefony/service/x509.ts
|
|
4
4
|
/**
|
|
5
5
|
* Fabrique et lecture de certificats X.509 par `node:crypto` seul — aucune
|
|
6
6
|
* dépendance tierce.
|
|
@@ -320,5 +320,4 @@ async function createSelfSignedCertificate(spec) {
|
|
|
320
320
|
const signature = await signAsync(spec.hash, tbs, spec.privateKey);
|
|
321
321
|
return toPem(sequence(tbs, algorithm, bitString(signature)));
|
|
322
322
|
}
|
|
323
|
-
//#endregion
|
|
324
323
|
export { SHA1_WITH_RSA_OID, createSelfSignedCertificate, distinguishedNameField, ipAddressBytes, parseSubjectAltName, signatureAlgorithmName, signatureAlgorithmOid };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stripTrailingSlashes } from "nodefony";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
|
|
3
|
+
// nodefony/src/assets/collectAssets.ts
|
|
4
4
|
/** Normalise un préfixe en segment de chemin (`/_assets/x/` → `_assets/x`). */
|
|
5
5
|
const prefixToSegment = (prefix) => stripTrailingSlashes(prefix.replace(/^\/+/, ""));
|
|
6
6
|
/**
|
|
@@ -30,5 +30,4 @@ function planAssetPublish(sources, outDir) {
|
|
|
30
30
|
}
|
|
31
31
|
return plan;
|
|
32
32
|
}
|
|
33
|
-
//#endregion
|
|
34
33
|
export { planAssetPublish };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
|
|
3
|
+
// nodefony/src/assets/prebuiltUi.ts
|
|
4
4
|
/**
|
|
5
5
|
* Résout le mode de livraison de l'UI embarquée d'un module.
|
|
6
6
|
*
|
|
@@ -121,5 +121,4 @@ var PrebuiltUi = class {
|
|
|
121
121
|
return this.template.replaceAll("<script", `<script nonce="${nonce}"`);
|
|
122
122
|
}
|
|
123
123
|
};
|
|
124
|
-
//#endregion
|
|
125
124
|
export { PrebuiltUi, resolveUiDelivery };
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { buildMetaData } from "./metaData.js";
|
|
2
|
+
import { protocolNameOf } from "./transport.js";
|
|
3
|
+
import { resolveTimingMode } from "./timingMode.js";
|
|
2
4
|
import Cookie, { cookiesParser } from "../cookies/cookie.js";
|
|
3
5
|
import { RequestContext, Service, logColor } from "nodefony";
|
|
4
6
|
import { randomFillSync, randomUUID } from "node:crypto";
|
|
5
7
|
import { performance } from "node:perf_hooks";
|
|
6
8
|
import { AsyncResource } from "node:async_hooks";
|
|
7
|
-
|
|
9
|
+
// nodefony/src/context/Context.ts
|
|
8
10
|
const colorLogEvent = () => logColor.cyanBgBlack("EVENT CONTEXT");
|
|
9
11
|
const PERF_PROBE_SUB = process.env.NF_PERF_PROBE === "1";
|
|
10
|
-
const EVENT_SEVERITY = {
|
|
11
|
-
onRequest: "INFO",
|
|
12
|
-
onSend: "INFO",
|
|
13
|
-
onConnect: "INFO",
|
|
14
|
-
onClose: "INFO"
|
|
15
|
-
};
|
|
16
12
|
let lifecycleEventLogging = null;
|
|
17
13
|
/**
|
|
18
14
|
* Bascule runtime du gate des logs d'events lifecycle. Réservé HORS hot path :
|
|
@@ -54,7 +50,15 @@ var Context = class extends Service {
|
|
|
54
50
|
requested = false;
|
|
55
51
|
sessionStarting = false;
|
|
56
52
|
domain = "";
|
|
53
|
+
/** Famille traitée (`network.protocol.name` d'OpenTelemetry) — union ouverte. */
|
|
57
54
|
type;
|
|
55
|
+
/** Serveur qui a reçu la requête — choisit la configuration par serveur. */
|
|
56
|
+
serverType;
|
|
57
|
+
/**
|
|
58
|
+
* Protocole du saut local (registre IANA ALPN) — union ouverte. Une connexion
|
|
59
|
+
* WebSocket naît d'un upgrade HTTP/1.1 ; `HttpContext` le constate sur la requête.
|
|
60
|
+
*/
|
|
61
|
+
alpnProtocol = "http/1.1";
|
|
58
62
|
server;
|
|
59
63
|
httpKernel;
|
|
60
64
|
request = null;
|
|
@@ -103,6 +107,12 @@ var Context = class extends Service {
|
|
|
103
107
|
router = this.get("router");
|
|
104
108
|
resolver = null;
|
|
105
109
|
/**
|
|
110
|
+
* Module qui signe les lignes de CETTE requête : la ligne d'accès et les
|
|
111
|
+
* lignes du contrôleur. `null` = le module de la route (sans route : le
|
|
112
|
+
* journal du noyau). Un contrôleur le change : `this.context.logModule = "billing"`.
|
|
113
|
+
*/
|
|
114
|
+
logModule = null;
|
|
115
|
+
/**
|
|
106
116
|
* Intent de session de la route courante (posé par le Resolver depuis
|
|
107
117
|
* `@UseSession` / paramètre `@Session`). Pilote le point d'activation unique
|
|
108
118
|
* (HTTP + WS). `null` = aucune session sauf cookie existant (reprise L1).
|
|
@@ -134,8 +144,20 @@ var Context = class extends Service {
|
|
|
134
144
|
profilerQueries = null;
|
|
135
145
|
profiling = false;
|
|
136
146
|
securityTrace = null;
|
|
147
|
+
/**
|
|
148
|
+
* Message du canal `nodefony.http.request` pour CETTE requête, ou `null` si
|
|
149
|
+
* personne n'écoutait à son début (le cas par défaut : un champ, aucune
|
|
150
|
+
* allocation). Posé par `openRequestTrace`, remis à `null` par
|
|
151
|
+
* `closeRequestTrace` — c'est ce `null` qui rend la fin idempotente.
|
|
152
|
+
*
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
requestTrace = null;
|
|
137
156
|
_timingEnabled = false;
|
|
138
157
|
_timingVerbose = false;
|
|
158
|
+
_clockEnabled = false;
|
|
159
|
+
_clockStartMs = 0;
|
|
160
|
+
_durationMs = null;
|
|
139
161
|
phases = EMPTY_PHASES;
|
|
140
162
|
_phaseIndex = null;
|
|
141
163
|
_afterResponseFns = null;
|
|
@@ -148,54 +170,48 @@ var Context = class extends Service {
|
|
|
148
170
|
};
|
|
149
171
|
scheme;
|
|
150
172
|
webSocketState = null;
|
|
151
|
-
constructor(container,
|
|
152
|
-
super(
|
|
173
|
+
constructor(container, serverType) {
|
|
174
|
+
super(serverType, container);
|
|
153
175
|
if (PERF_PROBE_SUB) {
|
|
154
176
|
const p = globalThis.__nfPerfProbe;
|
|
155
177
|
if (p && p.t0 !== 0n) p.svcNs += Number(process.hrtime.bigint() - p.t0);
|
|
156
178
|
}
|
|
157
|
-
|
|
179
|
+
const timing = this.kernel?.options.timing;
|
|
180
|
+
const timingSection = typeof timing === "object" && timing !== null ? timing : null;
|
|
181
|
+
const mode = resolveTimingMode(timingSection !== null && "enabled" in timingSection ? timingSection.enabled : void 0, this.kernel?.environment);
|
|
182
|
+
if (mode !== "off") {
|
|
183
|
+
this._clockEnabled = true;
|
|
184
|
+
this._clockStartMs = performance.now();
|
|
185
|
+
}
|
|
186
|
+
if (mode === "phases") {
|
|
187
|
+
this._timingEnabled = true;
|
|
188
|
+
this.phases = [];
|
|
189
|
+
this._timingVerbose = timingSection !== null && "verbose" in timingSection && timingSection.verbose === true;
|
|
190
|
+
}
|
|
191
|
+
this.serverType = serverType;
|
|
192
|
+
this.type = protocolNameOf(serverType);
|
|
158
193
|
this.set("context", this);
|
|
159
194
|
this.httpKernel = this.get("HttpKernel");
|
|
160
195
|
this.sessionService = this.get("sessions");
|
|
161
196
|
this.setMetaData();
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
else this._timingEnabled = this.kernel?.environment !== "production";
|
|
165
|
-
if (this._timingEnabled) {
|
|
166
|
-
this.phases = [];
|
|
167
|
-
const verbose = (this.kernel?.options)?.timing?.verbose;
|
|
168
|
-
this._timingVerbose = verbose === true;
|
|
169
|
-
}
|
|
170
|
-
this.scheme = "https";
|
|
171
|
-
switch (this.type) {
|
|
197
|
+
this.scheme = serverType;
|
|
198
|
+
switch (serverType) {
|
|
172
199
|
case "http": {
|
|
173
|
-
this.scheme = "http";
|
|
174
200
|
const server = this.get("server-http");
|
|
175
201
|
this.server = server?.server;
|
|
176
202
|
break;
|
|
177
203
|
}
|
|
178
|
-
case "http2":
|
|
179
204
|
case "https": {
|
|
180
|
-
this.scheme = "https";
|
|
181
205
|
const server = this.get("server-https");
|
|
182
206
|
this.server = server?.server;
|
|
183
207
|
break;
|
|
184
208
|
}
|
|
185
|
-
case "
|
|
186
|
-
this.scheme = "https";
|
|
187
|
-
const server = this.get("server-http3");
|
|
188
|
-
this.server = server?.server ?? null;
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
case "websocket": {
|
|
192
|
-
this.scheme = "ws";
|
|
209
|
+
case "ws": {
|
|
193
210
|
const server = this.get("server-websocket");
|
|
194
211
|
this.server = server?.server;
|
|
195
212
|
break;
|
|
196
213
|
}
|
|
197
|
-
case "
|
|
198
|
-
this.scheme = "wss";
|
|
214
|
+
case "wss": {
|
|
199
215
|
const server = this.get("server-websocket-secure");
|
|
200
216
|
this.server = server?.server;
|
|
201
217
|
break;
|
|
@@ -252,6 +268,24 @@ var Context = class extends Service {
|
|
|
252
268
|
p.endMs = performance.now();
|
|
253
269
|
p.durationMs = p.endMs - p.startMs;
|
|
254
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Arrête l'horloge de la requête et rend sa durée, en millisecondes.
|
|
273
|
+
*
|
|
274
|
+
* La durée court de la construction du contexte au PREMIER appel : le
|
|
275
|
+
* démontage HTTP (`close` de la réponse, dernier octet remis — la mesure
|
|
276
|
+
* d'OpenTelemetry et du `$request_time` de nginx), la ligne d'accès pour un
|
|
277
|
+
* handshake WebSocket. Les appels suivants rendent la même valeur : journal
|
|
278
|
+
* d'accès, profiler et trace verbose lisent UNE durée, jamais trois.
|
|
279
|
+
*
|
|
280
|
+
* Active par défaut dans tous les environnements, production comprise :
|
|
281
|
+
* seul `timing.enabled: false` la coupe (cf `resolveTimingMode`).
|
|
282
|
+
*
|
|
283
|
+
* @returns la durée, ou `null` si `timing.enabled` vaut `false`
|
|
284
|
+
*/
|
|
285
|
+
stopClock() {
|
|
286
|
+
if (!this._clockEnabled) return null;
|
|
287
|
+
return this._durationMs ??= performance.now() - this._clockStartMs;
|
|
288
|
+
}
|
|
255
289
|
onAfterResponse(fn) {
|
|
256
290
|
const boundFn = AsyncResource.bind(fn);
|
|
257
291
|
if (this._afterResponseFired) {
|
|
@@ -303,10 +337,10 @@ var Context = class extends Service {
|
|
|
303
337
|
_abortIfPending(reason) {
|
|
304
338
|
if (this._abortController && !this._abortController.signal.aborted) this._abortController.abort(new Error(reason ?? "Context aborted"));
|
|
305
339
|
}
|
|
306
|
-
log(pci, severity, msgid, msg) {
|
|
307
|
-
if (!msgid) msgid = this.
|
|
308
|
-
if (this.requestId && RequestContext.getRequestId() === void 0) return RequestContext.run({ requestId: this.requestId }, () => super.log(pci, severity, msgid, msg));
|
|
309
|
-
return super.log(pci, severity, msgid, msg);
|
|
340
|
+
log(pci, severity, msgid, msg, moduleName) {
|
|
341
|
+
if (!msgid) msgid = this.serverType;
|
|
342
|
+
if (this.requestId && RequestContext.getRequestId() === void 0) return RequestContext.run({ requestId: this.requestId }, () => super.log(pci, severity, msgid, msg, moduleName));
|
|
343
|
+
return super.log(pci, severity, msgid, msg, moduleName);
|
|
310
344
|
}
|
|
311
345
|
/**
|
|
312
346
|
* Confie au contexte le magasin `RequestContext` de son unité de travail
|
|
@@ -334,13 +368,13 @@ var Context = class extends Service {
|
|
|
334
368
|
}
|
|
335
369
|
/**
|
|
336
370
|
* Log d'un event du cycle de vie — gate boot-time (V2.1) : en production le
|
|
337
|
-
* Pdu n'est PAS construit (return avant toute allocation). Hors prod,
|
|
338
|
-
*
|
|
371
|
+
* Pdu n'est PAS construit (return avant toute allocation). Hors prod : DEBUG,
|
|
372
|
+
* pour le Suivi de requête de Studio — la ligne `req` porte le bilan.
|
|
339
373
|
*/
|
|
340
374
|
logEvent(event) {
|
|
341
375
|
lifecycleEventLogging ??= this.kernel?.environment !== "production";
|
|
342
376
|
if (!lifecycleEventLogging) return;
|
|
343
|
-
this.log(`${colorLogEvent()} ${event}`,
|
|
377
|
+
this.log(`${colorLogEvent()} ${event}`, "DEBUG");
|
|
344
378
|
}
|
|
345
379
|
fire(event, ...args) {
|
|
346
380
|
this.logEvent(event);
|
|
@@ -366,7 +400,7 @@ var Context = class extends Service {
|
|
|
366
400
|
if (!logger) return;
|
|
367
401
|
if (logger.shouldSample && !logger.shouldSample(this, err)) return;
|
|
368
402
|
const entry = logger.renderHttp(this, err);
|
|
369
|
-
return this.log(entry.text, entry.severity, entry.msgid);
|
|
403
|
+
return this.log(entry.text, entry.severity, entry.msgid, void 0, this.logModule ?? this.resolver?.route?.module?.name);
|
|
370
404
|
} catch {
|
|
371
405
|
return;
|
|
372
406
|
}
|
|
@@ -394,7 +428,9 @@ var Context = class extends Service {
|
|
|
394
428
|
} else line += `${p.name}=…`;
|
|
395
429
|
i++;
|
|
396
430
|
}
|
|
397
|
-
|
|
431
|
+
const duration = this.stopClock();
|
|
432
|
+
const head = duration === null ? "" : `total ${duration.toFixed(2)}ms · `;
|
|
433
|
+
this.log(`TRACE phases [${head}Σ ${total.toFixed(2)}ms] ${line}`, "DEBUG", `${this.serverType} TIMING`);
|
|
398
434
|
}
|
|
399
435
|
addRequestCookie(cookie) {
|
|
400
436
|
if (cookie instanceof Cookie) return this.cookies[cookie.name] = cookie;
|
|
@@ -453,5 +489,4 @@ var Context = class extends Service {
|
|
|
453
489
|
setContextJson(_encoding = "utf-8") {}
|
|
454
490
|
setContextHtml(_encoding = "utf-8") {}
|
|
455
491
|
};
|
|
456
|
-
//#endregion
|
|
457
492
|
export { Context as default, nextCspNonce, setLifecycleEventLogging };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { escapeRegExp } from "nodefony";
|
|
2
|
-
|
|
2
|
+
// nodefony/src/context/domainMatcher.ts
|
|
3
3
|
/**
|
|
4
4
|
* Matching de domaine (`Host`) — fonctions PURES, politique UNIQUE partagée par
|
|
5
5
|
* les deux étages de Nodefony :
|
|
@@ -135,5 +135,4 @@ function isDomainAllowed(regAlias, domain) {
|
|
|
135
135
|
for (const reg of regAlias) if (reg.test(domain)) return true;
|
|
136
136
|
return false;
|
|
137
137
|
}
|
|
138
|
-
//#endregion
|
|
139
138
|
export { compileDomainPattern, compileDomainPatterns, compileTrustedHosts, hostnameOf, isDomainAllowed, resolveTrustedHostNames };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { extractClientIp, resolveFromRight } from "./trustProxy.js";
|
|
2
2
|
import { isIPv4 } from "node:net";
|
|
3
|
-
|
|
3
|
+
// nodefony/src/context/forwarded.ts
|
|
4
4
|
/**
|
|
5
5
|
* Découpe une chaîne sur `sep` au **niveau supérieur uniquement**, en respectant
|
|
6
6
|
* les `quoted-string` RFC 9110 §5.6.4 (`value = token / quoted-string`, RFC 7239 §4) : un
|
|
@@ -181,5 +181,4 @@ function resolveForwarded(headers, socketAddress, checker) {
|
|
|
181
181
|
function hasForwardingHeaders(headers) {
|
|
182
182
|
return Boolean(headers.forwarded || headers["x-forwarded-for"] || headers["x-forwarded-proto"] || headers["x-forwarded-scheme"] || headers["x-forwarded-host"]);
|
|
183
183
|
}
|
|
184
|
-
//#endregion
|
|
185
184
|
export { forwardedNodeIp, hasForwardingHeaders, parseForwarded, resolveForwarded };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import HttpError from "../../errors/httpError.js";
|
|
2
2
|
import { responseEnded } from "../responseEnded.js";
|
|
3
|
+
import { alpnProtocolOf } from "../transport.js";
|
|
3
4
|
import Cookie from "../../cookies/cookie.js";
|
|
4
5
|
import Context from "../Context.js";
|
|
5
6
|
import { sanitizeRequestId } from "../requestId.js";
|
|
@@ -11,7 +12,7 @@ import { describeSessionStoreFailure } from "../../session/sessionStoreFailure.j
|
|
|
11
12
|
import { openSseStream } from "./SseStream.js";
|
|
12
13
|
import { finallyMaybe, isPromise, thenMaybe, typeOf } from "nodefony";
|
|
13
14
|
import url, { URL } from "node:url";
|
|
14
|
-
|
|
15
|
+
// nodefony/src/context/http/HttpContext.ts
|
|
15
16
|
/**
|
|
16
17
|
* Même URL (chemin, requête, hôte) sous un autre schéma et un autre port.
|
|
17
18
|
* `port` absent → port par défaut du schéma (omis de l'URL).
|
|
@@ -55,15 +56,21 @@ var HttpContext = class extends Context {
|
|
|
55
56
|
activeSocket = null;
|
|
56
57
|
isRedirect = false;
|
|
57
58
|
sended = false;
|
|
59
|
+
/**
|
|
60
|
+
* Requête relayée par le proxy inverse : la politique de ligne d'accès de
|
|
61
|
+
* son montage. `null` = servie par l'application (cas de toute requête).
|
|
62
|
+
*/
|
|
63
|
+
relayAccessLog = null;
|
|
58
64
|
request;
|
|
59
65
|
response;
|
|
60
66
|
uploadService;
|
|
61
|
-
constructor(container, request, response,
|
|
62
|
-
super(container,
|
|
67
|
+
constructor(container, request, response, serverType) {
|
|
68
|
+
super(container, serverType);
|
|
69
|
+
this.alpnProtocol = alpnProtocolOf(request);
|
|
63
70
|
this.uploadService = this.get("upload");
|
|
64
71
|
const perfSub = PERF_PROBE_SUB ? globalThis.__nfPerfProbe : void 0;
|
|
65
72
|
if (perfSub && perfSub.t0 !== 0n) perfSub.uploadNs += Number(process.hrtime.bigint() - perfSub.t0);
|
|
66
|
-
if (this.
|
|
73
|
+
if (this.alpnProtocol === "h2" || this.alpnProtocol === "h2c") {
|
|
67
74
|
this.request = new Http2Request(request, this);
|
|
68
75
|
this.response = new Http2Response(response, this);
|
|
69
76
|
} else {
|
|
@@ -124,7 +131,8 @@ var HttpContext = class extends Context {
|
|
|
124
131
|
_onTimeout() {
|
|
125
132
|
if (this.listenerCount("onTimeout")) this.fire("onTimeout", this);
|
|
126
133
|
this._abortIfPending("Request timeout");
|
|
127
|
-
|
|
134
|
+
this.httpKernel?.warnUnsentResponse(this);
|
|
135
|
+
let error;
|
|
128
136
|
if (this.response.stream) error = new HttpError("Gateway Timeout", 504, this);
|
|
129
137
|
else error = new HttpError("Request Timeout", 408, this);
|
|
130
138
|
this.httpKernel?.onError(error, this);
|
|
@@ -180,6 +188,21 @@ var HttpContext = class extends Context {
|
|
|
180
188
|
}
|
|
181
189
|
}
|
|
182
190
|
/**
|
|
191
|
+
* Ligne d'accès — pour une requête RELAYÉE, avec le statut que l'amont a
|
|
192
|
+
* réellement rendu (le relais écrit la réponse brute, pas celle du
|
|
193
|
+
* contexte) ; un montage `accessLog: "errors"` ne l'écrit qu'en échec.
|
|
194
|
+
*
|
|
195
|
+
* @param httpError - l'erreur de la requête, s'il y en a une
|
|
196
|
+
*/
|
|
197
|
+
logRequest(httpError) {
|
|
198
|
+
if (this.relayAccessLog !== null) {
|
|
199
|
+
const raw = this.response.response;
|
|
200
|
+
if (raw !== null) this.response.statusCode = raw.statusCode;
|
|
201
|
+
if (this.relayAccessLog === "errors" && this.response.statusCode < 400 && !httpError && !this.error) return;
|
|
202
|
+
}
|
|
203
|
+
return super.logRequest(httpError);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
183
206
|
* Nettoie le contexte, et le DÉTACHE de sa socket h1 : la connexion
|
|
184
207
|
* persistante survit à la requête, et l'entrée de `socketActiveContext`
|
|
185
208
|
* retiendrait sinon tout le contexte jusqu'à sa fermeture. Seule l'entrée qui
|
|
@@ -414,5 +437,4 @@ var HttpContext = class extends Context {
|
|
|
414
437
|
this.response.setContentType("html", encoding);
|
|
415
438
|
}
|
|
416
439
|
};
|
|
417
|
-
//#endregion
|
|
418
440
|
export { HttpContext as default, switchUrlScheme };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import HttpError from "../../errors/httpError.js";
|
|
2
2
|
import { hasForwardingHeaders, resolveForwarded } from "../forwarded.js";
|
|
3
3
|
import { hostnameOf } from "../domainMatcher.js";
|
|
4
|
-
import { Parser, ParserJson, ParserQs, ParserXml, acceptParser } from "./parser.js";
|
|
4
|
+
import { Parser, ParserJson, ParserQs, ParserRaw, ParserXml, acceptParser } from "./parser.js";
|
|
5
5
|
import { isCanonicalAuthority, splitTarget } from "./urlFastPath.js";
|
|
6
|
-
import { RequestContext,
|
|
6
|
+
import { RequestContext, useConfig } from "nodefony";
|
|
7
7
|
import { createHash, randomUUID } from "node:crypto";
|
|
8
8
|
import { URL } from "node:url";
|
|
9
9
|
import fs from "node:fs";
|
|
@@ -12,7 +12,7 @@ import os from "node:os";
|
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import QS from "qs";
|
|
14
14
|
import { Busboy } from "@fastify/busboy";
|
|
15
|
-
|
|
15
|
+
// nodefony/src/context/http/Request.ts
|
|
16
16
|
const reg = /(.*)[[][\]]$/u;
|
|
17
17
|
/**
|
|
18
18
|
* Supprime un fichier temporaire d'upload sans jamais faire échouer le nettoyage :
|
|
@@ -34,6 +34,7 @@ const CHARSET_ALIASES = {
|
|
|
34
34
|
"utf-16le": "utf16le"
|
|
35
35
|
};
|
|
36
36
|
const QUOTE_TRIM = /^["']|["']$/gu;
|
|
37
|
+
const NO_FILES = Object.freeze([]);
|
|
37
38
|
const parse = {
|
|
38
39
|
POST: true,
|
|
39
40
|
PUT: true,
|
|
@@ -104,7 +105,7 @@ var HttpRequest = class {
|
|
|
104
105
|
let u = this.#url;
|
|
105
106
|
if (u === null) {
|
|
106
107
|
u = this.getUrl(this.sUrl);
|
|
107
|
-
u.query = this.
|
|
108
|
+
u.query = this.query;
|
|
108
109
|
this.#url = u;
|
|
109
110
|
}
|
|
110
111
|
return u;
|
|
@@ -113,24 +114,28 @@ var HttpRequest = class {
|
|
|
113
114
|
this.#url = u;
|
|
114
115
|
}
|
|
115
116
|
parser = null;
|
|
116
|
-
queryPost = {};
|
|
117
|
-
queryGet = {};
|
|
118
|
-
queryFile = [];
|
|
119
|
-
query = {};
|
|
120
117
|
/**
|
|
121
|
-
* Le CORPS de la requête, parsé
|
|
122
|
-
* Fastify, NestJS)
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
118
|
+
* Le CORPS de la requête, parsé (JSON, urlencoded, XML, champs multipart) —
|
|
119
|
+
* nom universel de l'écosystème (Express, Fastify, NestJS) et celui
|
|
120
|
+
* d'`IAdminRequest.body`. Jamais un paramètre d'URL : ceux-là sont dans
|
|
121
|
+
* {@link query}, et les deux ne fusionnent pas.
|
|
122
|
+
*/
|
|
123
|
+
body = {};
|
|
124
|
+
/** Fichiers reçus, alloués au PREMIER fichier seulement (cf {@link files}). */
|
|
125
|
+
#uploads = null;
|
|
126
|
+
/**
|
|
127
|
+
* Les fichiers reçus dans un corps multipart, déjà écrits dans le répertoire
|
|
128
|
+
* temporaire — lus par `@UploadedFile()` / `@UploadedFiles()`. Les champs
|
|
129
|
+
* texte du même corps sont dans {@link body}.
|
|
128
130
|
*
|
|
129
|
-
*
|
|
131
|
+
* Lecture seule : une requête sans upload rend un vide partagé et gelé,
|
|
132
|
+
* aucune allocation.
|
|
130
133
|
*/
|
|
131
|
-
get
|
|
132
|
-
return this
|
|
134
|
+
get files() {
|
|
135
|
+
return this.#uploads ?? NO_FILES;
|
|
133
136
|
}
|
|
137
|
+
/** Les paramètres d'URL, seuls — jamais un champ du corps ({@link body}). */
|
|
138
|
+
query = {};
|
|
134
139
|
queryStringOptions;
|
|
135
140
|
charset = "utf8";
|
|
136
141
|
uploadOption = {};
|
|
@@ -185,7 +190,6 @@ var HttpRequest = class {
|
|
|
185
190
|
if (this.search) query = QS.parse(this.search.slice(1), this.queryStringOptions ?? {});
|
|
186
191
|
else query = {};
|
|
187
192
|
if (this.#url !== null) this.#url.query = query;
|
|
188
|
-
this.queryGet = query;
|
|
189
193
|
this.query = query;
|
|
190
194
|
if (PERF_PROBE_SUB) perfMark("reqQueryNs");
|
|
191
195
|
this.contentType = this.getContentType(this.request);
|
|
@@ -201,11 +205,11 @@ var HttpRequest = class {
|
|
|
201
205
|
* remplace le `once("onRequestEnd")` du ctor qui allouait 1 onceWrapper +
|
|
202
206
|
* 1 closure à CHAQUE requête.
|
|
203
207
|
*
|
|
204
|
-
* Il porte le CORPS (`
|
|
208
|
+
* Il porte le CORPS (`body`), jamais les paramètres d'URL : un seul sens de
|
|
205
209
|
* `body` dans tout le framework, celui de l'écosystème et d'`IAdminRequest`.
|
|
206
210
|
*/
|
|
207
211
|
fireRequestEnd() {
|
|
208
|
-
this.request.body = this.
|
|
212
|
+
this.request.body = this.body;
|
|
209
213
|
if (this.context.listenerCount("onRequestEnd") === 0) return false;
|
|
210
214
|
return this.context.fireAsync("onRequestEnd", this);
|
|
211
215
|
}
|
|
@@ -315,7 +319,7 @@ var HttpRequest = class {
|
|
|
315
319
|
await this.fireRequestEnd();
|
|
316
320
|
return BODY_DONE;
|
|
317
321
|
}
|
|
318
|
-
this.parser = new
|
|
322
|
+
this.parser = new ParserRaw(this);
|
|
319
323
|
return this.parser;
|
|
320
324
|
}
|
|
321
325
|
}
|
|
@@ -362,8 +366,7 @@ var HttpRequest = class {
|
|
|
362
366
|
return this.parser;
|
|
363
367
|
}
|
|
364
368
|
const { fields, files } = await this.streamMultipart(bb);
|
|
365
|
-
this.
|
|
366
|
-
this.query = extend({}, this.query, this.queryPost);
|
|
369
|
+
this.body = fields;
|
|
367
370
|
for (const pf of files) await this.createFileUpload(pf.field, pf.file);
|
|
368
371
|
this.context.requestEnded = true;
|
|
369
372
|
await this.fireRequestEnd();
|
|
@@ -478,7 +481,7 @@ var HttpRequest = class {
|
|
|
478
481
|
}
|
|
479
482
|
accepts(Type) {
|
|
480
483
|
let parts = [];
|
|
481
|
-
let subtype
|
|
484
|
+
let subtype;
|
|
482
485
|
let type = "*";
|
|
483
486
|
if (Type) parts = Type.split("/");
|
|
484
487
|
switch (parts.length) {
|
|
@@ -496,7 +499,7 @@ var HttpRequest = class {
|
|
|
496
499
|
}
|
|
497
500
|
async createFileUpload(name, file) {
|
|
498
501
|
const fileUpload = await this.context.uploadService?.createUploadFile(file, name);
|
|
499
|
-
if (fileUpload) this.
|
|
502
|
+
if (fileUpload) (this.#uploads ??= []).push(fileUpload);
|
|
500
503
|
return fileUpload;
|
|
501
504
|
}
|
|
502
505
|
getMethod() {
|
|
@@ -561,7 +564,9 @@ var HttpRequest = class {
|
|
|
561
564
|
/**
|
|
562
565
|
* Scheme effectif côté client : `Forwarded`/`X-Forwarded-*` résolu de façon
|
|
563
566
|
* canonique (this.forwarded, gated proxy de confiance) ; sinon le transport
|
|
564
|
-
* réel. HTTP/2
|
|
567
|
+
* réel. Vaut pour HTTP/2 aussi : le pseudo-en-tête `:scheme` vient du client
|
|
568
|
+
* (RFC 9113 §8.3.1) et n'est jamais cru — sur h2c, `:scheme: https` ferait
|
|
569
|
+
* passer une connexion claire pour chiffrée.
|
|
565
570
|
*/
|
|
566
571
|
resolveScheme(request) {
|
|
567
572
|
if (this.forwarded?.proto) return this.forwarded.proto;
|
|
@@ -589,9 +594,8 @@ var HttpRequest = class {
|
|
|
589
594
|
return new URL(sUrl, baseUrl);
|
|
590
595
|
}
|
|
591
596
|
log(pci, severity, msgid, msg) {
|
|
592
|
-
if (!msgid) msgid = `${this.context.
|
|
597
|
+
if (!msgid) msgid = `${this.context.serverType} REQUEST `;
|
|
593
598
|
return this.context.log(pci, severity, msgid, msg);
|
|
594
599
|
}
|
|
595
600
|
};
|
|
596
|
-
//#endregion
|
|
597
601
|
export { HttpRequest as default };
|