@nodefony/http 10.0.0-alpha.1

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.
Files changed (155) hide show
  1. package/LICENSE +544 -0
  2. package/README.md +77 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
  5. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateParam.js +8 -0
  6. package/dist/index.js +108 -0
  7. package/dist/nodefony/command/assetsPublishCommand.js +102 -0
  8. package/dist/nodefony/command/certificatesCommand.js +47 -0
  9. package/dist/nodefony/command/networkCommand.js +27 -0
  10. package/dist/nodefony/command/proxyGenerateCommand.js +66 -0
  11. package/dist/nodefony/config/config.js +335 -0
  12. package/dist/nodefony/config/defineModuleConfig.js +93 -0
  13. package/dist/nodefony/interfaces/IContext.js +1 -0
  14. package/dist/nodefony/interfaces/ICookie.js +1 -0
  15. package/dist/nodefony/interfaces/IErrorRenderer.js +1 -0
  16. package/dist/nodefony/interfaces/IHttpConfig.js +1 -0
  17. package/dist/nodefony/interfaces/IHttpKernel.js +1 -0
  18. package/dist/nodefony/interfaces/IRequest.js +1 -0
  19. package/dist/nodefony/interfaces/IRequestLogger.js +1 -0
  20. package/dist/nodefony/interfaces/IResponse.js +1 -0
  21. package/dist/nodefony/interfaces/ISession.js +1 -0
  22. package/dist/nodefony/interfaces/IUpload.js +1 -0
  23. package/dist/nodefony/interfaces/index.js +1 -0
  24. package/dist/nodefony/service/HttpAdminApi.js +376 -0
  25. package/dist/nodefony/service/ProfilerAdminApi.js +73 -0
  26. package/dist/nodefony/service/audit-logger.js +159 -0
  27. package/dist/nodefony/service/certificates.js +545 -0
  28. package/dist/nodefony/service/error-renderer.js +320 -0
  29. package/dist/nodefony/service/http-kernel.js +948 -0
  30. package/dist/nodefony/service/pretty-request-logger.js +72 -0
  31. package/dist/nodefony/service/request-logger.js +54 -0
  32. package/dist/nodefony/service/servers/clientError.js +20 -0
  33. package/dist/nodefony/service/servers/server-http.js +135 -0
  34. package/dist/nodefony/service/servers/server-https.js +204 -0
  35. package/dist/nodefony/service/servers/server-static.js +192 -0
  36. package/dist/nodefony/service/servers/server-websocket-secure.js +104 -0
  37. package/dist/nodefony/service/servers/server-websocket.js +104 -0
  38. package/dist/nodefony/service/servers/serverShutdown.js +31 -0
  39. package/dist/nodefony/service/servers/wsHeartbeat.js +64 -0
  40. package/dist/nodefony/service/sessions/sessions-service.js +580 -0
  41. package/dist/nodefony/service/trace.js +72 -0
  42. package/dist/nodefony/service/upload/upload-service.js +171 -0
  43. package/dist/nodefony/src/assets/collectAssets.js +34 -0
  44. package/dist/nodefony/src/assets/prebuiltUi.js +125 -0
  45. package/dist/nodefony/src/context/Context.js +415 -0
  46. package/dist/nodefony/src/context/domainMatcher.js +88 -0
  47. package/dist/nodefony/src/context/forwarded.js +185 -0
  48. package/dist/nodefony/src/context/http/HttpContext.js +309 -0
  49. package/dist/nodefony/src/context/http/Request.js +543 -0
  50. package/dist/nodefony/src/context/http/Response.js +368 -0
  51. package/dist/nodefony/src/context/http/parser.js +188 -0
  52. package/dist/nodefony/src/context/http/urlFastPath.js +103 -0
  53. package/dist/nodefony/src/context/http2/Request.js +29 -0
  54. package/dist/nodefony/src/context/http2/Response.js +97 -0
  55. package/dist/nodefony/src/context/metaData.js +47 -0
  56. package/dist/nodefony/src/context/requestId.js +41 -0
  57. package/dist/nodefony/src/context/trustProxy.js +167 -0
  58. package/dist/nodefony/src/context/websocket/Response.js +181 -0
  59. package/dist/nodefony/src/context/websocket/WebsocketContext.js +389 -0
  60. package/dist/nodefony/src/context/websocket/wsBackpressure.js +56 -0
  61. package/dist/nodefony/src/context/websocket/wsLogContent.js +68 -0
  62. package/dist/nodefony/src/cookies/cookie.js +258 -0
  63. package/dist/nodefony/src/errors/httpError.js +69 -0
  64. package/dist/nodefony/src/profiler/FrameProfile.js +95 -0
  65. package/dist/nodefony/src/profiler/Profiler.js +139 -0
  66. package/dist/nodefony/src/proxy/generateProxyConfig.js +157 -0
  67. package/dist/nodefony/src/rateLimit/IRateLimitStore.js +1 -0
  68. package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +146 -0
  69. package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +64 -0
  70. package/dist/nodefony/src/rateLimit/rateLimitFilters.js +20 -0
  71. package/dist/nodefony/src/servers/portBinder.js +114 -0
  72. package/dist/nodefony/src/session/session.js +390 -0
  73. package/dist/nodefony/src/session/storage/MemorySessionStorage.js +185 -0
  74. package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +137 -0
  75. package/dist/nodefony/src/session/storage/sessionFilters.js +83 -0
  76. package/dist/nodefony/src/session/storage/sessionSort.js +53 -0
  77. package/dist/types/index.d.ts +83 -0
  78. package/dist/types/nodefony/command/assetsPublishCommand.d.ts +23 -0
  79. package/dist/types/nodefony/command/certificatesCommand.d.ts +17 -0
  80. package/dist/types/nodefony/command/networkCommand.d.ts +8 -0
  81. package/dist/types/nodefony/command/proxyGenerateCommand.d.ts +19 -0
  82. package/dist/types/nodefony/config/config.d.ts +197 -0
  83. package/dist/types/nodefony/config/defineModuleConfig.d.ts +39 -0
  84. package/dist/types/nodefony/interfaces/IContext.d.ts +138 -0
  85. package/dist/types/nodefony/interfaces/ICookie.d.ts +47 -0
  86. package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +55 -0
  87. package/dist/types/nodefony/interfaces/IHttpConfig.d.ts +12 -0
  88. package/dist/types/nodefony/interfaces/IHttpKernel.d.ts +10 -0
  89. package/dist/types/nodefony/interfaces/IRequest.d.ts +35 -0
  90. package/dist/types/nodefony/interfaces/IRequestLogger.d.ts +31 -0
  91. package/dist/types/nodefony/interfaces/IResponse.d.ts +39 -0
  92. package/dist/types/nodefony/interfaces/ISession.d.ts +283 -0
  93. package/dist/types/nodefony/interfaces/IUpload.d.ts +66 -0
  94. package/dist/types/nodefony/interfaces/index.d.ts +7 -0
  95. package/dist/types/nodefony/service/HttpAdminApi.d.ts +18 -0
  96. package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +23 -0
  97. package/dist/types/nodefony/service/audit-logger.d.ts +143 -0
  98. package/dist/types/nodefony/service/certificates.d.ts +246 -0
  99. package/dist/types/nodefony/service/error-renderer.d.ts +74 -0
  100. package/dist/types/nodefony/service/http-kernel.d.ts +377 -0
  101. package/dist/types/nodefony/service/pretty-request-logger.d.ts +25 -0
  102. package/dist/types/nodefony/service/request-logger.d.ts +18 -0
  103. package/dist/types/nodefony/service/servers/clientError.d.ts +14 -0
  104. package/dist/types/nodefony/service/servers/server-http.d.ts +42 -0
  105. package/dist/types/nodefony/service/servers/server-https.d.ts +41 -0
  106. package/dist/types/nodefony/service/servers/server-static.d.ts +62 -0
  107. package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +29 -0
  108. package/dist/types/nodefony/service/servers/server-websocket.d.ts +29 -0
  109. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +27 -0
  110. package/dist/types/nodefony/service/servers/wsHeartbeat.d.ts +46 -0
  111. package/dist/types/nodefony/service/sessions/sessions-service.d.ts +218 -0
  112. package/dist/types/nodefony/service/trace.d.ts +39 -0
  113. package/dist/types/nodefony/service/upload/upload-service.d.ts +61 -0
  114. package/dist/types/nodefony/src/assets/collectAssets.d.ts +35 -0
  115. package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +99 -0
  116. package/dist/types/nodefony/src/context/Context.d.ts +195 -0
  117. package/dist/types/nodefony/src/context/domainMatcher.d.ts +67 -0
  118. package/dist/types/nodefony/src/context/forwarded.d.ts +95 -0
  119. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +85 -0
  120. package/dist/types/nodefony/src/context/http/Request.d.ts +203 -0
  121. package/dist/types/nodefony/src/context/http/Response.d.ts +68 -0
  122. package/dist/types/nodefony/src/context/http/parser.d.ts +65 -0
  123. package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +52 -0
  124. package/dist/types/nodefony/src/context/http2/Request.d.ts +14 -0
  125. package/dist/types/nodefony/src/context/http2/Response.d.ts +20 -0
  126. package/dist/types/nodefony/src/context/metaData.d.ts +58 -0
  127. package/dist/types/nodefony/src/context/requestId.d.ts +28 -0
  128. package/dist/types/nodefony/src/context/trustProxy.d.ts +77 -0
  129. package/dist/types/nodefony/src/context/websocket/Response.d.ts +53 -0
  130. package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +125 -0
  131. package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +73 -0
  132. package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +37 -0
  133. package/dist/types/nodefony/src/cookies/cookie.d.ts +88 -0
  134. package/dist/types/nodefony/src/errors/httpError.d.ts +15 -0
  135. package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +110 -0
  136. package/dist/types/nodefony/src/profiler/Profiler.d.ts +192 -0
  137. package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +76 -0
  138. package/dist/types/nodefony/src/rateLimit/IRateLimitStore.d.ts +98 -0
  139. package/dist/types/nodefony/src/rateLimit/MemoryRateLimitStore.d.ts +40 -0
  140. package/dist/types/nodefony/src/rateLimit/WsConnectionCounter.d.ts +37 -0
  141. package/dist/types/nodefony/src/rateLimit/rateLimitFilters.d.ts +18 -0
  142. package/dist/types/nodefony/src/servers/portBinder.d.ts +102 -0
  143. package/dist/types/nodefony/src/session/session.d.ts +171 -0
  144. package/dist/types/nodefony/src/session/storage/MemorySessionStorage.d.ts +77 -0
  145. package/dist/types/nodefony/src/session/storage/RevocationGuardStorage.d.ts +81 -0
  146. package/dist/types/nodefony/src/session/storage/sessionFilters.d.ts +102 -0
  147. package/dist/types/nodefony/src/session/storage/sessionSort.d.ts +45 -0
  148. package/docs/cookies.md +365 -0
  149. package/docs/index.md +163 -0
  150. package/docs/observabilite.md +460 -0
  151. package/docs/rate-limit.md +372 -0
  152. package/docs/servers.md +935 -0
  153. package/docs/session.md +768 -0
  154. package/docs/upload.md +460 -0
  155. package/package.json +101 -0
@@ -0,0 +1,195 @@
1
+ import { Container, Service, Severity, Msgid, Message, Pci, Pdu, KernelEventsType, nodefonyError, Scope } from "nodefony";
2
+ import type { IProfilerQuery } from "nodefony";
3
+ import type { Resolver, Router } from "@nodefony/framework";
4
+ import { WebSocketServer } from "ws";
5
+ import http2 from "node:http2";
6
+ import http from "node:http";
7
+ import https from "node:https";
8
+ import HttpKernel, { ServerType, Data, SchemeType } from "../../service/http-kernel.js";
9
+ import HttpResponse from "./http/Response.js";
10
+ import Http2Response from "./http2/Response.js";
11
+ import WebsocketResponse from "./websocket/Response.js";
12
+ import HttpRequest from "./http/Request.js";
13
+ import Http2Request from "./http2/Request.js";
14
+ import SessionsService from "../../service/sessions/sessions-service.js";
15
+ import { URL } from "node:url";
16
+ import Session from "../session/session.js";
17
+ import Cookie from "../cookies/cookie.js";
18
+ import HttpError from "../errors/httpError.js";
19
+ import { SecuredArea } from "@nodefony/security";
20
+ /**
21
+ * Bascule runtime du gate des logs d'events lifecycle. Réservé HORS hot path :
22
+ * tests et futur « Audit à chaud » (fenêtre bornée prod→verbeux, auto-revert
23
+ * serveur) — le canal Studio `nodefony:syslog` retrouve alors les events sans
24
+ * redémarrage. `null` → re-résolution depuis l'env au prochain event.
25
+ */
26
+ export declare function setLifecycleEventLogging(value: boolean | null): void;
27
+ export type WebSocketState = "handshake" | "connected" | "closed" | "error" | "message" | null;
28
+ export type contextRequest = HttpRequest | Http2Request | http.IncomingMessage | null;
29
+ export type contextResponse = HttpResponse | Http2Response | WebsocketResponse | null;
30
+ export type HTTPMethod = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE" | "PATCH" | "WEBSOCKET";
31
+ export type Cookies = Record<string, Cookie>;
32
+ import type { IContext as IContextInterface, PhaseTiming, PhaseName, AfterResponseHandler, ISecurityTrace } from "../../interfaces/IContext.js";
33
+ import type { SessionIntent } from "../../interfaces/ISession.js";
34
+ /**
35
+ * Rend le prochain nonce CSP (16 octets CSPRNG, base64) depuis le pool amorti.
36
+ *
37
+ * Exporté UNIQUEMENT pour le banc d'épuisement du pool (unicité à travers
38
+ * plusieurs refills) — le code produit passe par `context.cspNonce`.
39
+ */
40
+ export declare function nextCspNonce(): string;
41
+ declare class Context extends Service implements IContextInterface {
42
+ #private;
43
+ secure: boolean;
44
+ security?: SecuredArea | null;
45
+ cleaned: boolean;
46
+ isControlledAccess: boolean;
47
+ validDomain: boolean;
48
+ finished: boolean;
49
+ pushAllowed: boolean;
50
+ requestEnded: boolean;
51
+ requested: boolean;
52
+ sessionStarting: boolean;
53
+ domain: string;
54
+ type: ServerType;
55
+ server?: WebSocketServer | http.Server | https.Server | http2.Http2SecureServer | null;
56
+ httpKernel: HttpKernel | null;
57
+ request: contextRequest | null;
58
+ response: contextResponse | null;
59
+ url: string;
60
+ method: HTTPMethod | null;
61
+ remoteAddress: string | undefined | null;
62
+ protected _originUrl: URL | undefined | null;
63
+ get originUrl(): URL | undefined | null;
64
+ set originUrl(value: URL | undefined | null);
65
+ cookies: Cookies;
66
+ error: Error | HttpError | nodefonyError | null | undefined;
67
+ sessionService?: SessionsService | null;
68
+ session: Session | null | undefined;
69
+ cookieSession: Cookie | null | undefined;
70
+ user: unknown;
71
+ waitAsync: boolean;
72
+ isJson: boolean;
73
+ protected _isHtml: boolean | null;
74
+ get isHtml(): boolean;
75
+ set isHtml(value: boolean);
76
+ /**
77
+ * Défaut paresseux d'{@link isHtml} — overridé par HttpContext (négociation
78
+ * `Accept`). Base et WS : jamais HTML.
79
+ */
80
+ protected resolveIsHtml(): boolean;
81
+ crossDomain: boolean;
82
+ router: Router | null;
83
+ resolver: Resolver | null;
84
+ /**
85
+ * Intent de session de la route courante (posé par le Resolver depuis
86
+ * `@UseSession` / paramètre `@Session`). Pilote le point d'activation unique
87
+ * (HTTP + WS). `null` = aucune session sauf cookie existant (reprise L1).
88
+ */
89
+ sessionIntent: SessionIntent | null;
90
+ /**
91
+ * Directives CSP additionnelles de la route courante (`@Csp`), posées par le
92
+ * Resolver au match. `null` = la route n'en déclare pas (cas courant) → le
93
+ * firewall compose le CSP standard (0 surcoût). Lu par `applySecurityHeaders`
94
+ * APRÈS le resolve. Forme `directive → sources` (compatible `CspFragment`).
95
+ */
96
+ cspDirectives: Record<string, readonly string[]> | null;
97
+ /**
98
+ * CSRF per-route (`@CsrfProtect`/`@CsrfExempt`), posés par le Resolver au match,
99
+ * lus par `Firewall.enforceCsrf` (post-resolve). `csrfProtect` exige le
100
+ * synchronizer token sur la mutation ; `csrfExempt` sort la route de la défense
101
+ * CSRF (auth conservée). `csrfToken` = token émis par le firewall (cookie lisible
102
+ * + ce champ) sur une requête sûre vers une route protégée, à surfacer côté vue.
103
+ */
104
+ csrfProtect: boolean;
105
+ csrfExempt: boolean;
106
+ csrfToken: string | null;
107
+ requestId: string;
108
+ get cspNonce(): string;
109
+ traceparent: string | null;
110
+ profilerQueries: IProfilerQuery[] | null;
111
+ profiling: boolean;
112
+ securityTrace: ISecurityTrace | null;
113
+ private _timingEnabled;
114
+ private _timingVerbose;
115
+ readonly phases: PhaseTiming[];
116
+ private _phaseIndex;
117
+ private _afterResponseFns;
118
+ private _afterResponseFired;
119
+ private _abortController;
120
+ metaData: Data;
121
+ scheme: SchemeType;
122
+ webSocketState: WebSocketState;
123
+ constructor(container: Container | Scope, type: ServerType);
124
+ /**
125
+ * Assemble l'enveloppe `metaData` de la requête (`nodefony.*` + `route`
126
+ * snapshot per-requête + overrides appelant). Délègue au builder monomorphe
127
+ * pur {@link buildMetaData} — pas de `extend(true, …)` (deep-clone + dispatch
128
+ * polymorphe inutiles : `this.metaData` est per-requête, jamais partagé). `this`
129
+ * satisfait structurellement {@link IMetaDataSource} (kernel/request/scheme/
130
+ * requestId/resolver) → zéro alloc d'objet intermédiaire.
131
+ */
132
+ setMetaData(obj?: Record<string, unknown>): Data;
133
+ setScheme(): SchemeType;
134
+ /**
135
+ * Le timing est-il actif sur CETTE requête ? (dev/test par défaut, opt-out en
136
+ * production — cf constructeur.)
137
+ *
138
+ * Exposé pour que les appelants qui devraient **payer** pour mesurer (un
139
+ * `try/finally` autour d'une chaîne de promesses = une microtask de plus par
140
+ * requête) puissent garder leur chemin nominal INTACT quand la mesure est
141
+ * éteinte : `if (!ctx.timingEnabled) return fastPath()`. Les autres n'ont rien
142
+ * à tester — {@link phaseStart}/{@link phaseEnd} sont déjà des no-ops.
143
+ */
144
+ get timingEnabled(): boolean;
145
+ phaseStart(name: PhaseName): void;
146
+ phaseEnd(name: PhaseName): void;
147
+ onAfterResponse(fn: AfterResponseHandler): void;
148
+ _runAfterResponse(): Promise<void>;
149
+ get signal(): AbortSignal;
150
+ _abortIfPending(reason?: string): void;
151
+ log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu;
152
+ clean(): void;
153
+ /**
154
+ * Log d'un event du cycle de vie — gate boot-time (V2.1) : en production le
155
+ * Pdu n'est PAS construit (return avant toute allocation). Hors prod, jalon
156
+ * notable → INFO (EVENT_SEVERITY), event technique → DEBUG.
157
+ */
158
+ private logEvent;
159
+ fire(event: KernelEventsType, ...args: unknown[]): boolean;
160
+ emit(event: KernelEventsType, ...args: unknown[]): boolean;
161
+ emitAsync(event: KernelEventsType, ...args: unknown[]): Promise<unknown>;
162
+ fireAsync(event: KernelEventsType, ...args: unknown[]): Promise<unknown>;
163
+ logRequest(httpError?: Error | HttpError | nodefonyError | null): Pdu | undefined;
164
+ /**
165
+ * P3.7 — Émet au teardown un log DEBUG détaillant la durée de chaque phase du
166
+ * pipeline (`parse · action · firewall · …` + total). Opt-in via
167
+ * `kernel.options.timing.verbose`. Triple gate perf-first : `_timingVerbose`
168
+ * résolu 1× (false en prod/par défaut) → timing actif → phases non vides ;
169
+ * hors mode verbose, early-return AVANT toute allocation/`toFixed` (coût nul).
170
+ */
171
+ logPhasesVerbose(): void;
172
+ addRequestCookie(cookie: Cookie): Cookie;
173
+ getRequestCookies(name?: string): Cookies | Cookie | null;
174
+ setCookie(cookie: Cookie): void | Cookie;
175
+ getRequest(): contextRequest;
176
+ getResponse(): contextResponse;
177
+ isValidDomain(): boolean;
178
+ saveSession(): Promise<Session | null>;
179
+ hasSession(): boolean;
180
+ getCookieSession(name: string): Cookie | null;
181
+ /**
182
+ * Nom effectif du cookie de session pour CE transport. Sur TLS (https/wss) on
183
+ * applique le préfixe **`__Host-`** (RFC 6265bis §4.1.3 / OWASP : recommandé
184
+ * pour les identifiants de session — impose Secure + Path=/ + interdit Domain,
185
+ * anti session-fixation cross-subdomain). En clair (http/ws) le préfixe est
186
+ * omis (le navigateur le rejetterait sans Secure) → dégradation gracieuse,
187
+ * notamment derrière un proxy qui termine le TLS. Lecture **et** écriture du
188
+ * cookie passent par ce nom unique → cohérence de la reprise (L1).
189
+ */
190
+ getSessionCookieName(): string;
191
+ parseCookies(): void;
192
+ setContextJson(_encoding?: BufferEncoding): void;
193
+ setContextHtml(_encoding?: BufferEncoding): void;
194
+ }
195
+ export default Context;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Matching de domaine (`Host`) — fonctions PURES, politique UNIQUE partagée par
3
+ * les deux étages de Nodefony :
4
+ *
5
+ * - **`trustedHosts` (kernel, sécu)** : barrière testée AVANT le routing. Quels
6
+ * `Host` ce serveur accepte de traiter (anti Host-header injection). Host non
7
+ * trusté → 401 (`HttpKernel.checkValidDomain`). Grossier, optionnel (en prod,
8
+ * typiquement délégué au reverse-proxy via `trustedHosts: true`).
9
+ * - **`@Domain` (route, routing)** : restreint une route / un contrôleur à un
10
+ * vhost. Source de vérité du « qui sert quoi ». Testé PENDANT le routing
11
+ * (`Route.matchHostname`) → 403 si la route ne sert pas ce domaine.
12
+ *
13
+ * Politique de compilation (sûre, ancrée, ReDoS-free) :
14
+ * - string sans `*` → match EXACT ancré (`^...$`, le `.` est littéral).
15
+ * - string avec `*` → wildcard UN label (`*.example.com` → `^[^.]+\.example\.com$`,
16
+ * RFC 6125 TLS-wildcard : matche `img.example.com`, pas `a.b.example.com` ni `example.com`).
17
+ * - `RegExp` → reprise telle quelle (l'auteur assume l'ancrage).
18
+ *
19
+ * Compilation faite UNE fois (boot / enregistrement de route) ; le test par
20
+ * requête est un simple `RegExp.test` sur une liste pré-compilée (zéro alloc hot-path).
21
+ */
22
+ /** Un pattern de domaine : string (exact ou `*`-wildcard) ou `RegExp` (libre). */
23
+ export type DomainPattern = string | RegExp;
24
+ /**
25
+ * Valeur de configuration `http.trustedHosts` (barrière sécu avant routing) :
26
+ * - `false` / absent : défaut (domaine canonique + loopback en dev).
27
+ * - `true` : bypass total — tout `Host` passe (déploiement où un reverse-proxy
28
+ * filtre déjà le `Host`, cf doctrine cloud-native).
29
+ * - `string` / `string[]` : patterns additionnels (exact ou `*`-wildcard).
30
+ */
31
+ export type TrustedHostsConfig = boolean | DomainPattern | DomainPattern[];
32
+ /**
33
+ * Compile UN pattern de domaine en `RegExp` selon la politique sûre.
34
+ *
35
+ * @param pattern - string (exact / `*`-wildcard) ou `RegExp` (reprise telle quelle).
36
+ * @returns une `RegExp` ancrée (pour les string) ou le `RegExp` fourni.
37
+ */
38
+ export declare function compileDomainPattern(pattern: DomainPattern): RegExp;
39
+ /**
40
+ * Compile une liste de patterns. Les string vides sont ignorées (un `^$` ne
41
+ * sert à rien et masque une coquille de config).
42
+ *
43
+ * @param patterns - un pattern ou un tableau de patterns.
44
+ * @returns liste de `RegExp` à tester contre le `Host` entrant.
45
+ */
46
+ export declare function compileDomainPatterns(patterns: DomainPattern | DomainPattern[]): RegExp[];
47
+ /**
48
+ * Construit la liste `RegExp` de la barrière `trustedHosts` (kernel, avant routing).
49
+ *
50
+ * Toujours : le domaine canonique (`kernel.domain`). En development : + loopback
51
+ * (`localhost`/`127.0.0.1`/`[::1]`) pour que l'URL tapée (nom OU IP) passe.
52
+ * `trustedHosts: true` → bypass total (un seul `/^.*$/`).
53
+ *
54
+ * @param domain - domaine canonique du serveur (`kernel.domain`).
55
+ * @param trusted - config `http.trustedHosts` (optionnelle).
56
+ * @param isDev - vrai en environnement `development` (ajoute le loopback).
57
+ * @returns liste de `RegExp` pour {@link isDomainAllowed}.
58
+ */
59
+ export declare function compileTrustedHosts(domain: string, trusted: TrustedHostsConfig | undefined, isDev: boolean): RegExp[];
60
+ /**
61
+ * Teste un `Host` entrant contre une liste de `RegExp` pré-compilée.
62
+ *
63
+ * @param regAlias - sortie de {@link compileTrustedHosts} ou {@link compileDomainPatterns}.
64
+ * @param domain - `Host` de la requête (`context.domain`, port déjà strippé).
65
+ * @returns `true` dès le premier match (court-circuit), `false` sinon.
66
+ */
67
+ export declare function isDomainAllowed(regAlias: RegExp[], domain: string): boolean;
@@ -0,0 +1,95 @@
1
+ import type { TrustProxyChecker } from "./trustProxy.js";
2
+ /**
3
+ * Parsing et résolution **canonique** des en-têtes de transfert (forwarded),
4
+ * conforme **RFC 7239** (« Forwarded HTTP Extension ») et compatible avec les
5
+ * en-têtes `X-Forwarded-*` de-facto (non normalisés).
6
+ *
7
+ * Le header standard `Forwarded` est **prioritaire** ; les `X-Forwarded-*`
8
+ * servent de repli. Une **seule** résolution produit le scheme, le host et l'IP
9
+ * cliente effectifs (supprime la double source `x-forwarded-proto` /
10
+ * `x-forwarded-scheme`).
11
+ *
12
+ * ⚠️ Toujours appelé en aval d'un contrôle `trustProxy` (RFC 7239 §8.1) : ces
13
+ * en-têtes ne sont honorés que derrière un reverse-proxy de confiance, sinon ils
14
+ * sont forgeables (IP/scheme spoofing).
15
+ */
16
+ /** Sous-ensemble des en-têtes lus (compatible `http`/`http2` IncomingHttpHeaders). */
17
+ export type ForwardedHeaders = Record<string, string | string[] | undefined>;
18
+ /**
19
+ * Un `forwarded-element` parsé (RFC 7239 §4) : un saut de la chaîne de proxy.
20
+ * Les paramètres inconnus (extensibilité §5.4) sont ignorés silencieusement.
21
+ */
22
+ export interface ForwardedElement {
23
+ /** §5.1 — interface du proxy par laquelle la requête est entrée (node id). */
24
+ by?: string;
25
+ /** §5.2 — client à l'origine de la requête (node id, éventuellement obfusqué). */
26
+ for?: string;
27
+ /** §5.3 — Host original tel que reçu par le proxy. */
28
+ host?: string;
29
+ /** §5.4 — protocole employé par le client (`http` / `https`), normalisé en minuscules. */
30
+ proto?: string;
31
+ }
32
+ /** Résolution canonique unifiée des en-têtes forwarded. */
33
+ export interface ResolvedProxy {
34
+ /** Scheme effectif côté client (`http` / `https`), ou `undefined` si indéterminé. */
35
+ proto?: string;
36
+ /** Host effectif côté client (Host d'origine), ou `undefined` si non fourni. */
37
+ host?: string;
38
+ /** Chaîne `for` brute (node identifiers, gauche→droite) — pour log/metadata interne. */
39
+ forwardedFor?: string;
40
+ /** IP cliente réelle, résolue from-right (toujours fiable, jamais l'IP forgée). */
41
+ clientIp: string | null;
42
+ /** Le header standard `Forwarded` a-t-il été la source (sinon `X-Forwarded-*`) ? */
43
+ fromStandard: boolean;
44
+ }
45
+ /**
46
+ * Parse le header `Forwarded` (RFC 7239 §4) en liste de `forwarded-element`,
47
+ * dans l'ordre **gauche→droite** (le plus à gauche = le plus proche du client).
48
+ *
49
+ * Grammaire honorée : `Forwarded = 1#forwarded-element`,
50
+ * `forwarded-element = [ forwarded-pair ] *( ";" [ forwarded-pair ] )`,
51
+ * `forwarded-pair = token "=" value`, `value = token / quoted-string`.
52
+ * Les noms de paramètres sont insensibles à la casse (§7.1) → normalisés.
53
+ *
54
+ * @param raw - valeur brute du header (string, ou string[] si répété), ou `undefined`.
55
+ * @returns les éléments parsés, ou `null` si le header est absent/vide.
56
+ */
57
+ export declare function parseForwarded(raw: string | string[] | undefined): ForwardedElement[] | null;
58
+ /**
59
+ * Extrait l'**IP nue** d'un node identifier RFC 7239 §6
60
+ * (`node = nodename [ ":" node-port ]`).
61
+ *
62
+ * - IPv6 entre crochets (`[2001:db8::1]`, éventuel `]:port`) → l'IPv6 sans crochets.
63
+ * - IPv4 (`192.0.2.43`, éventuel `:port`) → l'IPv4 sans le port.
64
+ * - `unknown` et identifiants obfusqués (`obfnode` commençant par `_`, §6.3) →
65
+ * `null` : non comparables à une politique de confiance (barrière from-right).
66
+ *
67
+ * @param node - valeur d'un paramètre `for`/`by`, déjà déquotée.
68
+ * @returns l'IP exploitable, ou `null` si absente/obfusquée/illisible.
69
+ */
70
+ export declare function forwardedNodeIp(node: string | undefined): string | null;
71
+ /**
72
+ * Résout, en **une seule passe**, le scheme, le host et l'IP cliente effectifs à
73
+ * partir des en-têtes forwarded — header standard `Forwarded` (RFC 7239)
74
+ * **prioritaire**, repli sur les `X-Forwarded-*` de-facto.
75
+ *
76
+ * Le scheme/host effectifs sont pris sur l'élément le plus à GAUCHE (côté client) ;
77
+ * l'IP cliente est résolue **from-right** ({@link resolveFromRight}) en partant du
78
+ * socket réel, donc non spoofable. La priorité unique `Forwarded.proto` >
79
+ * `x-forwarded-proto` > `x-forwarded-scheme` supprime l'ancienne double source.
80
+ *
81
+ * À n'appeler que derrière un proxy de confiance (RFC 7239 §8.1) : la décision
82
+ * `isTrusted(socket)` est prise par l'appelant (lazy : pas d'allocation hors proxy).
83
+ *
84
+ * @param headers - en-têtes de la requête.
85
+ * @param socketAddress - `socket.remoteAddress` (connexion TCP réelle).
86
+ * @param checker - politique de confiance ({@link buildTrustProxy}).
87
+ * @returns la résolution canonique unifiée.
88
+ */
89
+ export declare function resolveForwarded(headers: ForwardedHeaders, socketAddress: string | undefined | null, checker: TrustProxyChecker): ResolvedProxy;
90
+ /**
91
+ * Au moins un en-tête forwarded (standard ou de-facto) est-il présent ? Permet à
92
+ * l'appelant de n'allouer la résolution que quand c'est utile (hot path : 0 alloc
93
+ * sur une requête directe sans proxy).
94
+ */
95
+ export declare function hasForwardingHeaders(headers: ForwardedHeaders): boolean;
@@ -0,0 +1,85 @@
1
+ import { ServerType, SchemeType } from "../../../service/http-kernel.js";
2
+ import Context, { HTTPMethod } from "../Context.js";
3
+ import { Container, Scope } from "nodefony";
4
+ import { Csrf } from "@nodefony/security";
5
+ import HttpRequest from "./Request.js";
6
+ import HttpResponse from "./Response.js";
7
+ import Http2Request from "../http2/Request.js";
8
+ import Http2Response from "../http2/Response.js";
9
+ import http2 from "node:http2";
10
+ import http from "node:http";
11
+ import { URL } from "node:url";
12
+ import uploadService from "../../../service/upload/upload-service.js";
13
+ /**
14
+ * Métadonnées de topologie de proxy (en-têtes `X-Forwarded-*`), renseignées
15
+ * seulement derrière un proxy de confiance.
16
+ *
17
+ * ⚠️ RFC 7239 §8.2 (Information Leak) — DONNÉES INTERNES : ne JAMAIS recopier
18
+ * dans une réponse HTTP ni sérialiser en metaData exposée au client (révélerait
19
+ * la chaîne de proxy et les hôtes/IP internes). Lecture interne uniquement
20
+ * (logs, prédicat « derrière un proxy »).
21
+ */
22
+ export interface ProxyType {
23
+ proxyServer?: string;
24
+ proxyProto?: string;
25
+ proxyScheme?: SchemeType;
26
+ proxyPort?: string;
27
+ proxyFor?: string;
28
+ proxyHost?: string;
29
+ proxyUri?: string;
30
+ proxyRealIp?: string;
31
+ proxyVia?: string;
32
+ }
33
+ export type HttpRequestType = Http2Request | HttpRequest;
34
+ export type HttpRsponseType = Http2Response | HttpResponse;
35
+ import type { IHttpContext as IHttpContextInterface } from "../../../interfaces/IContext.js";
36
+ declare class HttpContext extends Context implements IHttpContextInterface {
37
+ #private;
38
+ proxy: ProxyType | null;
39
+ isRedirect: boolean;
40
+ sended: boolean;
41
+ request: HttpRequestType;
42
+ response: HttpRsponseType;
43
+ uploadService: uploadService | null;
44
+ csrf?: Csrf;
45
+ constructor(container: Container | Scope, request: http.IncomingMessage | http2.Http2ServerRequest, response: http.ServerResponse | http2.Http2ServerResponse, type: ServerType);
46
+ /**
47
+ * URL d'origine effective, construite À LA DEMANDE (1ʳᵉ lecture, puis
48
+ * mémoïsée). `Origin` invalide ou `null` (RFC 6454) → repli sur l'URL de la
49
+ * requête, comme le WS — jamais de throw.
50
+ */
51
+ get originUrl(): URL | undefined | null;
52
+ set originUrl(value: URL | undefined | null);
53
+ /**
54
+ * Chemin timeout direct — appelé par les handlers socket/stream de
55
+ * `setTimeout()`. T4 : remplace l'ancien `once("onTimeout")` posé au ctor
56
+ * (1 onceWrapper node + 1 closure alloués à CHAQUE requête pour un event
57
+ * qui ne fire presque jamais). L'event `onTimeout` reste émis pour
58
+ * d'éventuels listeners externes — guard 0-listener : 0 alloc sinon.
59
+ */
60
+ _onTimeout(): void;
61
+ setScheme(): SchemeType;
62
+ handle(): Promise<this>;
63
+ setTimeout(): void;
64
+ render(chunk: unknown, encoding?: BufferEncoding, status?: string | number, headers?: Record<string, string | number>): Promise<Http2Response | HttpResponse>;
65
+ end(): Promise<Http2Response | HttpResponse>;
66
+ send(chunk?: unknown, encoding?: BufferEncoding): Promise<Http2Response | HttpResponse>;
67
+ writeHead(statusCode?: number, headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): void;
68
+ write(chunk: unknown, encoding?: BufferEncoding, _flush?: boolean): Promise<Http2Response | HttpResponse>;
69
+ flush(chunk: unknown, encoding: BufferEncoding): Promise<HttpResponse>;
70
+ close(): Promise<Http2Response | HttpResponse>;
71
+ redirect(Url: string, status?: number | string, headers?: Record<string, string | number>): HttpResponse;
72
+ redirectHttps(status?: number | string, headers?: Record<string, string | number>): HttpResponse;
73
+ redirectHttp(status?: number | string, headers?: Record<string, string | number>): HttpResponse;
74
+ getHostName(): string;
75
+ getRemoteAddress(): string | null;
76
+ getHost(): string | undefined;
77
+ getUserAgent(): string | undefined;
78
+ getMethod(): HTTPMethod;
79
+ setContentType(type?: string, encoding?: BufferEncoding): void | http.ServerResponse<http.IncomingMessage>;
80
+ protected resolveIsHtml(): boolean;
81
+ setDefaultContentType(): void;
82
+ setContextJson(encoding?: BufferEncoding): void;
83
+ setContextHtml(encoding?: BufferEncoding): void;
84
+ }
85
+ export default HttpContext;
@@ -0,0 +1,203 @@
1
+ import http from "node:http";
2
+ import http2 from "node:http2";
3
+ import HttpContext from "../http/HttpContext.js";
4
+ import { URL } from "node:url";
5
+ import { HTTPMethod, Cookies } from "../Context.js";
6
+ import QS from "qs";
7
+ import { ParserXml, ParserQs, Parser, acceptParser } from "./parser.js";
8
+ import { UploadedFile } from "../../../service/upload/upload-service.js";
9
+ import type { IParsedUploadFile, IUploadOptions } from "../../../interfaces/IUpload.js";
10
+ import { Pci, Pdu, Message, Severity, Msgid } from "nodefony";
11
+ import Session from "../../session/session.js";
12
+ import { type ResolvedProxy } from "../forwarded.js";
13
+ declare class BodyHandled {
14
+ }
15
+ declare module "url" {
16
+ interface URL {
17
+ query: QS.ParsedQs;
18
+ }
19
+ }
20
+ declare module "http" {
21
+ interface IncomingMessage {
22
+ body: unknown;
23
+ session: Session;
24
+ cookie: Cookies;
25
+ }
26
+ }
27
+ declare module "http2" {
28
+ interface Http2ServerRequest {
29
+ body: unknown;
30
+ session: Session;
31
+ }
32
+ }
33
+ type ParserType = ParserXml | ParserQs | Parser | BodyHandled;
34
+ declare class HttpRequest {
35
+ #private;
36
+ context: HttpContext;
37
+ request: http.IncomingMessage | http2.Http2ServerRequest;
38
+ headers: http.IncomingHttpHeaders;
39
+ host: string | undefined;
40
+ method: HTTPMethod;
41
+ contentType: string | null;
42
+ rawContentType: Record<string, string>;
43
+ domain: string;
44
+ remoteAddress: string | null | undefined;
45
+ hostname: string;
46
+ sUrl: string;
47
+ /**
48
+ * Scheme effectif côté client (`http` | `https`, ou le proto `Forwarded`
49
+ * brut derrière un proxy de confiance) — posé par {@link getFullUrl}, seule
50
+ * source de cette décision. `HttpContext.setScheme` le lit sans toucher à
51
+ * l'URL.
52
+ */
53
+ scheme: string;
54
+ /**
55
+ * Pathname de la requête, TOUJOURS sous forme normalisée WHATWG : découpe
56
+ * du target quand elle est prouvablement identique au parse (fast-path),
57
+ * `URL.pathname` sinon. C'est la valeur que consomment le router et le
58
+ * matching de zones du firewall — sans jamais construire l'URL.
59
+ */
60
+ pathname: string;
61
+ /** Query string au format `URL.search` (`?…`, ou `""`) — même provenance. */
62
+ search: string;
63
+ /** L'objet {@link url} a-t-il déjà été construit ? (diagnostic/sonde). */
64
+ get hasParsedUrl(): boolean;
65
+ /**
66
+ * Sérialisation de l'URL de la requête — `URL.href` si l'objet existe,
67
+ * sinon `sUrl` (identique par construction sur le fast-path). Les lecteurs
68
+ * descriptifs (logs, profiler, `context.url`) passent par ici : 0 parse.
69
+ */
70
+ get href(): string;
71
+ /**
72
+ * URL WHATWG complète de la requête, construite au premier accès (fast-path)
73
+ * ou dès le ctor (bail-out). Porte `query` (le GET parsé) comme toujours.
74
+ */
75
+ get url(): URL;
76
+ set url(u: URL);
77
+ parser: ParserType | null;
78
+ queryPost: Record<string, unknown>;
79
+ queryGet: Record<string, unknown>;
80
+ queryFile: UploadedFile[];
81
+ query: Record<string, unknown>;
82
+ /**
83
+ * Le CORPS de la requête, parsé — nom universel de l'écosystème (Express,
84
+ * Fastify, NestJS), alias de {@link queryPost}.
85
+ *
86
+ * Ne pas confondre avec {@link query}, qui FUSIONNE la query string et le
87
+ * corps : `body` ne rend jamais un paramètre d'URL. Le data plane admin
88
+ * expose déjà cette sémantique (`IAdminRequest.body`) ; ce getter la rend
89
+ * disponible partout.
90
+ *
91
+ * Getter (aucune allocation) : `queryPost` reste la source unique.
92
+ */
93
+ get body(): Record<string, unknown>;
94
+ queryStringOptions: (QS.IParseOptions & {
95
+ decoder?: undefined;
96
+ }) | undefined;
97
+ charset: BufferEncoding;
98
+ uploadOption: IUploadOptions;
99
+ maxBodySize: number;
100
+ data: Buffer;
101
+ /** Media-ranges de l'en-tête `Accept`, parsés au premier accès (mémoïsé). */
102
+ get accept(): ReturnType<typeof acceptParser>;
103
+ /** `true` si le client accepte `text/html` — résolu au premier accès (mémoïsé). */
104
+ get acceptHtml(): boolean;
105
+ origin: string | undefined;
106
+ trustedProxy: boolean;
107
+ forwarded: ResolvedProxy | null;
108
+ constructor(request: http.IncomingMessage | http2.Http2ServerRequest, context: HttpContext);
109
+ /**
110
+ * Fin de corps — émission unique d'`onRequestEnd`. L'alias `body` est posé
111
+ * ICI sur la requête Node brute (au moment du fire, le corps est parsé) —
112
+ * remplace le `once("onRequestEnd")` du ctor qui allouait 1 onceWrapper +
113
+ * 1 closure à CHAQUE requête.
114
+ *
115
+ * Il porte le CORPS (`queryPost`), pas la fusion `query` : un seul sens de
116
+ * `body` dans tout le framework, celui de l'écosystème et d'`IAdminRequest`.
117
+ */
118
+ private fireRequestEnd;
119
+ initialize(): Promise<unknown>;
120
+ /**
121
+ * B1 — Pré-contrôle de taille du corps via l'en-tête `Content-Length` :
122
+ * rejette en 413 (RFC 9110 §15.5.14 « Content Too Large ») AVANT toute lecture
123
+ * quand le client annonce une taille supérieure à `maxBodySize`. Rideau de
124
+ * tête (client honnête) ; le compteur streaming de {@link Parser.write} couvre
125
+ * le cas sans `Content-Length` (chunked) ou menteur. No-op si limite à 0.
126
+ *
127
+ * @throws {HttpError} 413 si `Content-Length` dépasse `maxBodySize`.
128
+ */
129
+ private enforceBodyLimit;
130
+ parseRequest(): Promise<ParserType | null>;
131
+ /**
132
+ * Parse un corps `multipart/form-data` via **busboy** (streaming pur).
133
+ *
134
+ * Contrairement à l'ancien chemin formidable, le corps brut n'est **jamais**
135
+ * bufferisé en RAM : busboy lit le flux, les fichiers sont écrits au fil de
136
+ * l'eau dans le répertoire temp (`UploadService.path`), seuls les champs
137
+ * texte (petits) restent en mémoire → fin de la double-bufferisation
138
+ * (`Parser.chunks` + parser de fichiers) qui doublait la RAM par upload.
139
+ *
140
+ * Robustesse / sécurité :
141
+ * - `new Busboy()` lève **synchroniquement** si le Content-Type n'est pas un
142
+ * multipart exploitable (boundary manquant, en-tête absent) → le flux n'a
143
+ * pas encore été consommé → bascule sur le `Parser` de secours.
144
+ * - `limits.fileSize` borne CHAQUE fichier ; `maxTotalFileSize` borne le
145
+ * CUMUL par requête (compteur Nodefony) ; `files`/`fields`/`parts` bornent
146
+ * la quantité → 413. Toute erreur nettoie les temporaires déjà posés
147
+ * (anti-orphelins / saturation disque sur endpoint d'upload public).
148
+ * - nom temp = `randomUUID()` + extension d'origine → jamais le nom client
149
+ * dans le chemin (anti path-traversal).
150
+ *
151
+ * @returns la sentinelle `BODY_DONE` (corps déjà traité), ou le `Parser`
152
+ * de secours quand le corps n'est pas un multipart.
153
+ * @throws {HttpError} 413 si une limite de taille/quantité est dépassée.
154
+ */
155
+ parseMultipart(): Promise<ParserType>;
156
+ /**
157
+ * Pilote busboy : pipe le flux requête, écrit chaque fichier dans un temp au
158
+ * fil de l'eau, accumule les champs texte. Résout `{ fields, files }` à
159
+ * `finish` (après flush de tous les writes), rejette — avec cleanup des temp
160
+ * déjà posés — à la moindre erreur ou dépassement de limite.
161
+ */
162
+ private streamMultipart;
163
+ /**
164
+ * Accumule un champ texte multipart. `foo[]` (ou répétition de `foo`) →
165
+ * tableau ; sinon valeur scalaire. (Anciennement délégué à formidable.)
166
+ */
167
+ private assignField;
168
+ accepts(Type: string): boolean;
169
+ createFileUpload(name: string, file: IParsedUploadFile): Promise<UploadedFile | undefined>;
170
+ getMethod(): HTTPMethod;
171
+ getContentType(request: http.IncomingMessage | http2.Http2ServerRequest): string | null;
172
+ /**
173
+ * Charset du corps déduit du `Content-Type` (`charset=…`), normalisé en un
174
+ * `BufferEncoding` Node valide. Les alias IANA courants sont mappés
175
+ * (`iso-8859-1` → `latin1`, `us-ascii` → `ascii`…) ; tout charset inconnu ou
176
+ * non supporté par Node retombe sur `utf8` — JAMAIS de throw `.toString()`
177
+ * sur un encoding invalide (erreur propre, pas de 500 sur charset exotique).
178
+ */
179
+ getCharset(): BufferEncoding;
180
+ getDomain(): string;
181
+ getUserAgent(): string | undefined;
182
+ getHostName(host?: string): string;
183
+ getHost(): string | undefined;
184
+ getRemoteAddress(): string | null;
185
+ /**
186
+ * Request-target brut (origin-form) tel que reçu du transport — SOURCE
187
+ * UNIQUE partagée par la concaténation de {@link getFullUrl} et la découpe
188
+ * fast-path du ctor. HTTP/2 lit le pseudo-header `:path` (override).
189
+ */
190
+ getRawTarget(): string | undefined;
191
+ /**
192
+ * Scheme effectif côté client : `Forwarded`/`X-Forwarded-*` résolu de façon
193
+ * canonique (this.forwarded, gated proxy de confiance) ; sinon le transport
194
+ * réel. HTTP/2 remplace la lecture du socket par le pseudo-header `:scheme`.
195
+ */
196
+ protected resolveScheme(request: http.IncomingMessage | http2.Http2ServerRequest): string;
197
+ getFullUrl(request?: http.IncomingMessage | http2.Http2ServerRequest): string;
198
+ getHeader(name: string): string | string[] | null | undefined;
199
+ setUrl(Url: string): URL;
200
+ getUrl(sUrl: string, baseUrl?: string): URL;
201
+ log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu;
202
+ }
203
+ export default HttpRequest;