@nodefony/http 10.0.0-beta.5 → 10.0.0-beta.7
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/README.md +24 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +30 -26
- package/dist/nodefony/command/proxyGenerateCommand.js +2 -2
- package/dist/nodefony/config/config.js +29 -4
- package/dist/nodefony/grpc/GrpcCall.js +298 -0
- package/dist/nodefony/grpc/GrpcEndpoint.js +528 -0
- package/dist/nodefony/grpc/index.js +4 -0
- package/dist/nodefony/interfaces/IRpcCall.js +1 -0
- package/dist/nodefony/service/ProfilerAdminApi.js +5 -2
- package/dist/nodefony/service/audit-logger.js +52 -6
- package/dist/nodefony/service/error-renderer.js +47 -13
- package/dist/nodefony/service/http-kernel.js +306 -49
- package/dist/nodefony/service/pretty-request-logger.js +5 -3
- package/dist/nodefony/service/request-logger.js +21 -6
- package/dist/nodefony/service/reverse-proxy.js +8 -3
- package/dist/nodefony/service/servers/clientError.js +53 -4
- package/dist/nodefony/service/servers/server-h2c.js +6 -6
- package/dist/nodefony/service/servers/server-http.js +6 -4
- package/dist/nodefony/service/servers/server-https.js +14 -7
- package/dist/nodefony/service/servers/server-static.js +1 -6
- package/dist/nodefony/service/servers/server-websocket-secure.js +7 -11
- package/dist/nodefony/service/servers/server-websocket.js +7 -11
- package/dist/nodefony/service/servers/serverShutdown.js +43 -6
- package/dist/nodefony/service/sessions/sessions-service.js +7 -7
- package/dist/nodefony/service/upload/upload-service.js +2 -2
- package/dist/nodefony/src/assets/prebuiltUi.js +23 -5
- package/dist/nodefony/src/context/Context.js +12 -1
- package/dist/nodefony/src/context/http/ByteStream.js +364 -0
- package/dist/nodefony/src/context/http/HttpContext.js +139 -32
- package/dist/nodefony/src/context/http/Request.js +111 -22
- package/dist/nodefony/src/context/http/Response.js +459 -37
- package/dist/nodefony/src/context/http/SseStream.js +83 -148
- package/dist/nodefony/src/context/http/StreamLifecycle.js +582 -0
- package/dist/nodefony/src/context/http/parser.js +29 -11
- package/dist/nodefony/src/context/http/urlFastPath.js +80 -1
- package/dist/nodefony/src/context/http/webResponse.js +56 -0
- package/dist/nodefony/src/context/http2/Request.js +1 -1
- package/dist/nodefony/src/context/http2/Response.js +55 -12
- package/dist/nodefony/src/context/requestTrace.js +6 -2
- package/dist/nodefony/src/context/rpcOutcome.js +20 -0
- package/dist/nodefony/src/context/transport.js +20 -1
- package/dist/nodefony/src/context/websocket/Response.js +15 -3
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +86 -18
- package/dist/nodefony/src/context/websocket/websocketUrl.js +7 -0
- package/dist/nodefony/src/context/websocket/wsBackpressure.js +15 -15
- package/dist/nodefony/src/context/websocket/wsFrameRate.js +71 -0
- package/dist/nodefony/src/context/websocket/wsLogContent.js +55 -17
- package/dist/nodefony/src/cookies/cookie.js +57 -14
- package/dist/nodefony/src/errors/httpError.js +58 -25
- package/dist/nodefony/src/grpc/cors.js +59 -0
- package/dist/nodefony/src/grpc/limits.js +16 -0
- package/dist/nodefony/src/grpc/refusal.js +271 -0
- package/dist/nodefony/src/profiler/Profiler.js +14 -1
- package/dist/nodefony/src/profiler/aggregate.js +2 -2
- package/dist/nodefony/src/proxy/forward.js +109 -9
- package/dist/nodefony/src/proxy/generateProxyConfig.js +97 -17
- package/dist/nodefony/src/proxy/rules.js +29 -14
- package/dist/nodefony/src/servers/http2Goaway.js +76 -0
- package/dist/nodefony/src/servers/http2Limits.js +41 -15
- package/dist/nodefony/src/servers/http2StreamGrace.js +100 -0
- package/dist/nodefony/src/servers/receiveDeadline.js +177 -0
- package/dist/nodefony/src/servers/upgradeDispatch.js +62 -4
- package/dist/types/index.d.ts +11 -2
- package/dist/types/nodefony/config/config.d.ts +14 -0
- package/dist/types/nodefony/grpc/GrpcCall.d.ts +142 -0
- package/dist/types/nodefony/grpc/GrpcEndpoint.d.ts +98 -0
- package/dist/types/nodefony/grpc/index.d.ts +15 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +9 -0
- package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +14 -0
- package/dist/types/nodefony/interfaces/IRequest.d.ts +2 -1
- package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +10 -0
- package/dist/types/nodefony/interfaces/IRouting.d.ts +19 -0
- package/dist/types/nodefony/interfaces/IRpcCall.d.ts +83 -0
- package/dist/types/nodefony/interfaces/ISecurity.d.ts +27 -2
- package/dist/types/nodefony/interfaces/IUpload.d.ts +51 -4
- package/dist/types/nodefony/interfaces/index.d.ts +2 -1
- package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +2 -1
- package/dist/types/nodefony/service/audit-logger.d.ts +33 -3
- package/dist/types/nodefony/service/error-renderer.d.ts +27 -5
- package/dist/types/nodefony/service/http-kernel.d.ts +36 -3
- package/dist/types/nodefony/service/request-logger.d.ts +10 -0
- package/dist/types/nodefony/service/servers/clientError.d.ts +3 -2
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +7 -5
- package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +9 -4
- package/dist/types/nodefony/src/context/Context.d.ts +9 -1
- package/dist/types/nodefony/src/context/http/ByteStream.d.ts +109 -0
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +99 -3
- package/dist/types/nodefony/src/context/http/Request.d.ts +46 -9
- package/dist/types/nodefony/src/context/http/Response.d.ts +188 -8
- package/dist/types/nodefony/src/context/http/SseStream.d.ts +33 -8
- package/dist/types/nodefony/src/context/http/StreamLifecycle.d.ts +106 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +17 -3
- package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +40 -0
- package/dist/types/nodefony/src/context/http/webResponse.d.ts +31 -0
- package/dist/types/nodefony/src/context/http2/Response.d.ts +40 -5
- package/dist/types/nodefony/src/context/requestTrace.d.ts +3 -1
- package/dist/types/nodefony/src/context/rpcOutcome.d.ts +11 -0
- package/dist/types/nodefony/src/context/transport.d.ts +17 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +6 -1
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +48 -0
- package/dist/types/nodefony/src/context/websocket/websocketUrl.d.ts +4 -0
- package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +12 -2
- package/dist/types/nodefony/src/context/websocket/wsFrameRate.d.ts +69 -0
- package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +16 -8
- package/dist/types/nodefony/src/cookies/cookie.d.ts +20 -2
- package/dist/types/nodefony/src/errors/httpError.d.ts +29 -4
- package/dist/types/nodefony/src/grpc/cors.d.ts +32 -0
- package/dist/types/nodefony/src/grpc/limits.d.ts +14 -0
- package/dist/types/nodefony/src/grpc/refusal.d.ts +136 -0
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +11 -1
- package/dist/types/nodefony/src/proxy/forward.d.ts +37 -2
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +15 -2
- package/dist/types/nodefony/src/proxy/rules.d.ts +20 -0
- package/dist/types/nodefony/src/servers/http2Goaway.d.ts +41 -0
- package/dist/types/nodefony/src/servers/http2Limits.d.ts +27 -14
- package/dist/types/nodefony/src/servers/http2StreamGrace.d.ts +34 -0
- package/dist/types/nodefony/src/servers/receiveDeadline.d.ts +77 -0
- package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +41 -1
- package/docs/byte-stream.md +406 -0
- package/docs/cookies.md +13 -3
- package/docs/diagnostics-channel.md +45 -1
- package/docs/index.md +8 -0
- package/docs/reverse-proxy.md +15 -3
- package/docs/servers.md +67 -43
- package/docs/session.md +3 -3
- package/docs/sse.md +27 -20
- package/docs/upload.md +43 -17
- package/package.json +38 -18
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type http from "node:http";
|
|
2
|
+
/**
|
|
3
|
+
* Refus d'un appel gRPC au format de son protocole (ADR-0026 D5 point 2, D13
|
|
4
|
+
* point 2). Sans Connect : une application sans service gRPC charge ce module
|
|
5
|
+
* avec le noyau, et n'y paie rien tant qu'aucune erreur n'est rendue.
|
|
6
|
+
*
|
|
7
|
+
* Le protocole se reconnaît aux en-têtes de la requête et se code en petit
|
|
8
|
+
* entier (`GRPC_WIRE_*`, 0 = aucun) : une valeur toujours du même type, lue
|
|
9
|
+
* sur le chemin d'erreur seulement.
|
|
10
|
+
*/
|
|
11
|
+
/** Requête qui ne parle aucun protocole gRPC. */
|
|
12
|
+
export declare const GRPC_WIRE_NONE = 0;
|
|
13
|
+
/** gRPC natif (`application/grpc`, `application/grpc+proto`…). */
|
|
14
|
+
export declare const GRPC_WIRE_GRPC = 1;
|
|
15
|
+
/** gRPC-Web (`application/grpc-web`, `application/grpc-web-text`…). */
|
|
16
|
+
export declare const GRPC_WIRE_WEB = 2;
|
|
17
|
+
/** Connect unaire (`connect-protocol-version`, ou GET `?connect=v1`). */
|
|
18
|
+
export declare const GRPC_WIRE_CONNECT = 3;
|
|
19
|
+
/** Connect en flux (`application/connect+proto`, `application/connect+json`). */
|
|
20
|
+
export declare const GRPC_WIRE_CONNECT_STREAM = 4;
|
|
21
|
+
/** Le protocole gRPC d'une requête, `GRPC_WIRE_NONE` s'il n'y en a aucun. */
|
|
22
|
+
export type GrpcWire = typeof GRPC_WIRE_NONE | typeof GRPC_WIRE_GRPC | typeof GRPC_WIRE_WEB | typeof GRPC_WIRE_CONNECT | typeof GRPC_WIRE_CONNECT_STREAM;
|
|
23
|
+
/**
|
|
24
|
+
* Reconnaît le protocole gRPC d'une requête à ses en-têtes : `content-type`
|
|
25
|
+
* d'abord, puis `connect-protocol-version`. Une API JSON ordinaire rend
|
|
26
|
+
* `GRPC_WIRE_NONE`.
|
|
27
|
+
*
|
|
28
|
+
* @param headers - les en-têtes de la requête.
|
|
29
|
+
* @param connectGet - `true` pour un GET qui porte `connect=v1` (Connect
|
|
30
|
+
* unaire en GET, sans en-tête propre).
|
|
31
|
+
* @returns le protocole reconnu.
|
|
32
|
+
*/
|
|
33
|
+
export declare function grpcWireOf(headers: http.IncomingHttpHeaders, connectGet?: boolean): GrpcWire;
|
|
34
|
+
/** 16 `UNAUTHENTICATED`. */
|
|
35
|
+
export declare const GRPC_UNAUTHENTICATED = 16;
|
|
36
|
+
/** 7 `PERMISSION_DENIED`. */
|
|
37
|
+
export declare const GRPC_PERMISSION_DENIED = 7;
|
|
38
|
+
/**
|
|
39
|
+
* Le nom d'un code gRPC (`unimplemented`, `unauthenticated`…) — le libellé
|
|
40
|
+
* générique d'un refus (ADR-0026 D5 point 4).
|
|
41
|
+
*
|
|
42
|
+
* @param code - le code gRPC, de 0 à 16.
|
|
43
|
+
* @returns son nom ; `unknown` hors de la plage.
|
|
44
|
+
*/
|
|
45
|
+
export declare function grpcCodeName(code: number): string;
|
|
46
|
+
/**
|
|
47
|
+
* Le nom d'un code gRPC tel que le publient la ligne d'accès et le canal de
|
|
48
|
+
* traçage (`UNAVAILABLE`) — ADR-0026 D10 point 1.
|
|
49
|
+
*
|
|
50
|
+
* @param code - le code gRPC, de 0 à 16.
|
|
51
|
+
* @returns son nom ; `UNKNOWN` hors de la plage.
|
|
52
|
+
*/
|
|
53
|
+
export declare function grpcStatusName(code: number): string;
|
|
54
|
+
/**
|
|
55
|
+
* Le code gRPC d'un refus de transport — rendu avant l'implémentation (chemin
|
|
56
|
+
* inconnu, méthode refusée, limite de débit, pare-feu) — en gRPC natif et en
|
|
57
|
+
* gRPC-Web (ADR-0026 D13 point 2). Distincte de la table des erreurs de
|
|
58
|
+
* l'application (D7) ; seule la règle d'identité de 401/403 est commune (D5).
|
|
59
|
+
*
|
|
60
|
+
* @param status - le statut HTTP que le noyau aurait rendu.
|
|
61
|
+
* @param identified - un appelant authentifié est connu.
|
|
62
|
+
* @returns le code gRPC.
|
|
63
|
+
*/
|
|
64
|
+
export declare function transportRefusalCode(status: number, identified: boolean): number;
|
|
65
|
+
/**
|
|
66
|
+
* Le code gRPC d'une erreur levée par l'APPLICATION pendant un appel — une
|
|
67
|
+
* `HttpError` d'un service partagé avec des routes HTTP, une validation, un
|
|
68
|
+
* conflit (ADR-0026 D7, table « HTTP Mapping » de `google/rpc/code.proto`).
|
|
69
|
+
* Distincte de la table des refus de transport ({@link transportRefusalCode}) :
|
|
70
|
+
* un 404 levé par un service dit « entité introuvable » (5), un chemin inconnu
|
|
71
|
+
* dit « méthode absente » (12). Seule la règle d'identité de 401/403 est
|
|
72
|
+
* commune (D5).
|
|
73
|
+
*
|
|
74
|
+
* `code.proto` associe 409 à `ABORTED` et à `ALREADY_EXISTS` : `ABORTED`, le
|
|
75
|
+
* sens le plus large, est retenu ; `ALREADY_EXISTS` se lève en `ConnectError`.
|
|
76
|
+
*
|
|
77
|
+
* @param status - le statut HTTP que rendrait une route HTTP.
|
|
78
|
+
* @param identified - un appelant authentifié est connu.
|
|
79
|
+
* @returns le code gRPC.
|
|
80
|
+
*/
|
|
81
|
+
export declare function applicationErrorCode(status: number, identified: boolean): number;
|
|
82
|
+
/**
|
|
83
|
+
* Le code d'un refus en protocole Connect : celui qu'un client DÉDUIT du
|
|
84
|
+
* statut HTTP (`connect-protocol.md`, « HTTP to Error Code »), puisque le
|
|
85
|
+
* statut voyage avec la réponse et doit s'accorder au code. 405 et 421 y
|
|
86
|
+
* valent donc `unknown` (ADR-0026 D13, précision du lot 3) ; 401/403 suivent
|
|
87
|
+
* la règle d'identité (D5).
|
|
88
|
+
*
|
|
89
|
+
* @param status - le statut HTTP du refus.
|
|
90
|
+
* @param identified - un appelant authentifié est connu.
|
|
91
|
+
* @returns le code gRPC.
|
|
92
|
+
*/
|
|
93
|
+
export declare function connectRefusalCode(status: number, identified: boolean): number;
|
|
94
|
+
/** Ce que le refus touche de la réponse : son statut et ses en-têtes. */
|
|
95
|
+
export interface IGrpcRefusalTarget {
|
|
96
|
+
setStatusCode(status: number, message?: string): void;
|
|
97
|
+
setHeader(name: string, value: string): void;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Pose le statut et les en-têtes d'un refus au format du protocole, et rend
|
|
101
|
+
* le corps à envoyer — vide en gRPC et gRPC-Web, dont le statut voyage dans
|
|
102
|
+
* les en-têtes (_Trailers-Only_ ; en HTTP/2, `Http2Response.writeHead` termine
|
|
103
|
+
* alors le flux sur la trame d'en-têtes).
|
|
104
|
+
*
|
|
105
|
+
* | Protocole | Statut HTTP | Corps |
|
|
106
|
+
* | --------------- | ------------------------------ | -------------------------------------- |
|
|
107
|
+
* | gRPC, gRPC-Web | 200 | aucun |
|
|
108
|
+
* | Connect unaire | celui du refus (401/403 : D5) | `{"code":"<nom>"}` |
|
|
109
|
+
* | Connect en flux | 200 | message de fin `{"error":{…}}` |
|
|
110
|
+
*
|
|
111
|
+
* Le message n'est jamais celui de l'erreur, qui nomme parfois la zone
|
|
112
|
+
* refusée : seul le nom du code part (D5 point 4).
|
|
113
|
+
*
|
|
114
|
+
* @param response - la réponse du contexte, pas encore envoyée.
|
|
115
|
+
* @param wire - le protocole de la requête, autre que `GRPC_WIRE_NONE`.
|
|
116
|
+
* @param status - le statut HTTP que le noyau aurait rendu.
|
|
117
|
+
* @param identified - un appelant authentifié est connu.
|
|
118
|
+
* @param contentType - le `content-type` de la requête, recopié en gRPC,
|
|
119
|
+
* gRPC-Web et Connect en flux (déjà reconnu par {@link grpcWireOf}).
|
|
120
|
+
* @returns le corps : texte vide, JSON, ou octets d'un message de fin.
|
|
121
|
+
*/
|
|
122
|
+
export declare function prepareGrpcRefusal(response: IGrpcRefusalTarget, wire: GrpcWire, status: number, identified: boolean, contentType: string | undefined): string | Uint8Array;
|
|
123
|
+
/**
|
|
124
|
+
* Marque une route comme servie par un point d'entrée gRPC — au démarrage,
|
|
125
|
+
* par `@nodefony/framework/grpc`. Allume la garde qui refuse en 12 une requête
|
|
126
|
+
* gRPC native aboutie à une route qui n'est pas gRPC (ADR-0026 D13 point 3) :
|
|
127
|
+
* tant qu'aucune route n'est marquée, la garde coûte une lecture de booléen.
|
|
128
|
+
*
|
|
129
|
+
* @param route - la route montée pour une méthode du contrat.
|
|
130
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
131
|
+
*/
|
|
132
|
+
export declare function markGrpcRoute(route: {
|
|
133
|
+
grpc?: boolean | undefined;
|
|
134
|
+
}): void;
|
|
135
|
+
/** `true` dès qu'une route gRPC est déclarée dans le processus. */
|
|
136
|
+
export declare function hasGrpcRoutes(): boolean;
|
|
@@ -116,6 +116,14 @@ export declare class Profiler implements IProfilerReader {
|
|
|
116
116
|
private readonly _caps;
|
|
117
117
|
/** Dernier numéro d'ordre attribué (0 = aucun profil collecté). */
|
|
118
118
|
private _seq;
|
|
119
|
+
/**
|
|
120
|
+
* Démarrage du profileur, donc du processus (ms epoch, horloge du serveur) :
|
|
121
|
+
* aucune requête servie avant n'est connue. Rendu avec un profil absent, pour
|
|
122
|
+
* que le lecteur dise « le serveur a redémarré » plutôt que « évincé ».
|
|
123
|
+
*/
|
|
124
|
+
readonly startedAt: number;
|
|
125
|
+
/** Dernier vidage des anneaux (ms epoch), `null` s'il n'y en a jamais eu. */
|
|
126
|
+
private _clearedAt;
|
|
119
127
|
/**
|
|
120
128
|
* @param cap - capacité de l'anneau de l'application.
|
|
121
129
|
* @param sideCap - capacité de chacun des anneaux de l'outillage et des
|
|
@@ -155,7 +163,9 @@ export declare class Profiler implements IProfilerReader {
|
|
|
155
163
|
since(cursor: number): IProfileBatch;
|
|
156
164
|
/** Nombre de profils en mémoire. */
|
|
157
165
|
get size(): number;
|
|
158
|
-
/** Vide les anneaux. */
|
|
166
|
+
/** Vide les anneaux, et retient l'instant du vidage ({@link clearedAt}). */
|
|
159
167
|
clear(): void;
|
|
168
|
+
/** Dernier vidage des anneaux (ms epoch, horloge du serveur), `null` si aucun. */
|
|
169
|
+
get clearedAt(): number | null;
|
|
160
170
|
}
|
|
161
171
|
export default Profiler;
|
|
@@ -38,6 +38,13 @@ export interface IRelaySettings {
|
|
|
38
38
|
*/
|
|
39
39
|
agent: http.Agent | false | undefined;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* En-têtes de CONNEXION (RFC 9110 §7.6.1) : ils décrivent un saut, jamais le
|
|
43
|
+
* message — un intermédiaire ne les transmet pas. Les cinq premiers sont en
|
|
44
|
+
* outre INTERDITS en HTTP/2 (RFC 9113 §8.2.2) : Node lève
|
|
45
|
+
* `ERR_HTTP2_INVALID_CONNECTION_HEADERS` si une réponse les porte.
|
|
46
|
+
*/
|
|
47
|
+
export declare const HOP_BY_HOP: ReadonlySet<string>;
|
|
41
48
|
/**
|
|
42
49
|
* Sauts `Via` au-delà desquels un message est tenu pour une boucle. Notre
|
|
43
50
|
* pseudonyme ne repère une boucle qu'au RETOUR dans ce processus : derrière un
|
|
@@ -55,6 +62,19 @@ export declare const MAX_VIA_HOPS = 10;
|
|
|
55
62
|
* @param pseudonym - pseudonyme de ce processus
|
|
56
63
|
*/
|
|
57
64
|
export declare function viaLoops(via: string | string[] | undefined, pseudonym: string): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* `Max-Forwards` reçu, tel qu'un intermédiaire doit le lire (RFC 9110 §7.6.2) :
|
|
67
|
+
* sur `OPTIONS` et `TRACE` seulement — la même section permet de l'ignorer
|
|
68
|
+
* pour toute autre méthode, et il part alors tel quel.
|
|
69
|
+
*
|
|
70
|
+
* @param method - méthode de la requête
|
|
71
|
+
* @param value - en-tête `Max-Forwards` reçu
|
|
72
|
+
* @returns `null` s'il n'y a rien à faire (autre méthode, en-tête absent) ;
|
|
73
|
+
* `-1` si la valeur n'est pas `1*DIGIT` — elle ne se décrémente pas, l'en-tête
|
|
74
|
+
* n'est donc pas transmis ; sinon la valeur reçue (`0` : le proxy répond
|
|
75
|
+
* lui-même, sans joindre l'amont).
|
|
76
|
+
*/
|
|
77
|
+
export declare function receivedMaxForwards(method: string, value: string | string[] | undefined): number | null;
|
|
58
78
|
/**
|
|
59
79
|
* Cadrage du corps transmis à l'amont (RFC 9112 §6). `unsupported` : un
|
|
60
80
|
* codage de transfert autre que `chunked` seul — le proxy ne sait pas le
|
|
@@ -118,8 +138,9 @@ export declare function upstreamPath(url: string, mount: IProxyMount): string;
|
|
|
118
138
|
* Relaie une requête HTTP vers l'amont et renvoie sa réponse au client.
|
|
119
139
|
*
|
|
120
140
|
* Le corps est transmis avec un cadrage cohérent ({@link bodyFramingOf}). Un
|
|
121
|
-
* message qui porte déjà notre `Via` rend 508 sans contacter l'amont.
|
|
122
|
-
*
|
|
141
|
+
* message qui porte déjà notre `Via` rend 508 sans contacter l'amont. Sur
|
|
142
|
+
* `OPTIONS` et `TRACE`, `Max-Forwards` est décrémenté ; à `0`, le proxy répond
|
|
143
|
+
* lui-même en destinataire final (RFC 9110 §7.6.2). Un client parti coupe l'échange amont ; un amont injoignable rend 502 ; une
|
|
123
144
|
* connexion non établie à temps ou un amont muet rendent 504 — à condition
|
|
124
145
|
* que rien n'ait encore été envoyé, sinon la réponse est interrompue (un
|
|
125
146
|
* statut ne se rattrape pas). Un amont coupé en plein corps interrompt la
|
|
@@ -154,6 +175,20 @@ export declare function rawHead(status: string, rawHeaders: readonly string[], s
|
|
|
154
175
|
* @param headers - en-têtes du refus (`WWW-Authenticate`, `Retry-After`…)
|
|
155
176
|
*/
|
|
156
177
|
export declare function refuseUpgrade(socket: Duplex, status: number, reason: string, headers?: Readonly<Record<string, string | number>> | null): void;
|
|
178
|
+
/**
|
|
179
|
+
* Refuse un handshake WebSocket non conforme — la réponse qui convient à la
|
|
180
|
+
* raison rendue par `websocketHandshakeProblem`, seule implémentation pour le
|
|
181
|
+
* serveur WebSocket ET le proxy inverse.
|
|
182
|
+
*
|
|
183
|
+
* Une version inconnue reçoit `426` avec `Sec-WebSocket-Version: 13` : le
|
|
184
|
+
* client apprend vers quelle version se rabattre (RFC 6455 §4.2.2 point 6,
|
|
185
|
+
* §4.4), et le 426 porte l'`Upgrade` qu'exige RFC 9110 §15.5.22. Tout autre
|
|
186
|
+
* défaut de forme reçoit `400`.
|
|
187
|
+
*
|
|
188
|
+
* @param socket - socket du client, encore en attente de sa réponse
|
|
189
|
+
* @param problem - la raison rendue par `websocketHandshakeProblem`
|
|
190
|
+
*/
|
|
191
|
+
export declare function refuseMalformedHandshake(socket: Duplex, problem: string): void;
|
|
157
192
|
/**
|
|
158
193
|
* Relaie un upgrade WebSocket DÉJÀ validé (méthode, `Upgrade`, clé, version,
|
|
159
194
|
* `Origin` — cf `ReverseProxy.handleUpgrade`) : rejoue le handshake vers
|
|
@@ -44,8 +44,9 @@ export interface ProxyIntrospection {
|
|
|
44
44
|
httpsPort: number;
|
|
45
45
|
/**
|
|
46
46
|
* Port h2c du backend (`servers.h2c`), ou `null` s'il n'est pas activé. Le
|
|
47
|
-
* générateur haproxy y envoie le trafic
|
|
48
|
-
* ne parle
|
|
47
|
+
* générateur haproxy y envoie tout le trafic hors WebSocket (`proto h2`) ;
|
|
48
|
+
* nginx, qui ne parle HTTP/2 à ses amonts que par `grpc_pass`, n'y envoie
|
|
49
|
+
* que gRPC. Règle d'usage : {@link upstreamH2cPort}.
|
|
49
50
|
*/
|
|
50
51
|
h2cPort?: number | null;
|
|
51
52
|
/** Dossiers statiques servis à la racine `/` (ordre = priorité). */
|
|
@@ -98,6 +99,18 @@ export interface ProxyIntrospection {
|
|
|
98
99
|
}
|
|
99
100
|
/** Valeurs par défaut d'un modèle d'introspection (complété par la commande). */
|
|
100
101
|
export declare const defaultIntrospection: ProxyIntrospection;
|
|
102
|
+
/**
|
|
103
|
+
* Port h2c que le proxy doit joindre, ou `null` — règle UNIQUE des deux
|
|
104
|
+
* générateurs.
|
|
105
|
+
*
|
|
106
|
+
* Seulement vers un backend en clair : le re-chiffrement vise le port TLS, qui
|
|
107
|
+
* négocie déjà HTTP/2 par ALPN, et mélanger les deux liens ferait voyager une
|
|
108
|
+
* partie du trafic en clair alors que l'utilisateur a demandé le chiffrement.
|
|
109
|
+
*
|
|
110
|
+
* @param intro - modèle d'introspection Nodefony.
|
|
111
|
+
* @returns le port h2c à joindre, ou `null` s'il n'y a pas de lien h2c.
|
|
112
|
+
*/
|
|
113
|
+
export declare function upstreamH2cPort(intro: ProxyIntrospection): number | null;
|
|
101
114
|
/**
|
|
102
115
|
* Génère une configuration nginx complète (reverse-proxy + offload statiques).
|
|
103
116
|
*
|
|
@@ -73,6 +73,26 @@ export declare function proxyMountProblems(prefix: string, mount: IProxyMountSha
|
|
|
73
73
|
* @returns `true` si le chemin doit être refusé
|
|
74
74
|
*/
|
|
75
75
|
export declare function isAmbiguousPath(url: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Le corps reçu porte-t-il un codage de transfert que le serveur ne sait pas
|
|
78
|
+
* défaire ? Seul `chunked` est compris : Node le retire, mais laisse en place
|
|
79
|
+
* tout codage qui le précède (`gzip, chunked`) — le corps livré serait encore
|
|
80
|
+
* compressé. RFC 9112 §6.1 : un tel message reçoit 501. Un `chunked` qui n'est
|
|
81
|
+
* pas le DERNIER codage est déjà refusé par Node en 400 (§6.3).
|
|
82
|
+
*
|
|
83
|
+
* Seule règle, pour le serveur d'origine et pour le proxy inverse. Chemin de
|
|
84
|
+
* chaque requête : une lecture d'en-tête, rien d'autre sans `Transfer-Encoding`.
|
|
85
|
+
*
|
|
86
|
+
* @param coding - valeur de l'en-tête `Transfer-Encoding`, absente le plus souvent
|
|
87
|
+
* @returns `true` quand le corps ne peut pas être lu tel qu'annoncé
|
|
88
|
+
*/
|
|
89
|
+
export declare function isUnsupportedTransferCoding(coding: string | undefined): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Raison rendue par {@link websocketHandshakeProblem} quand le client parle une
|
|
92
|
+
* autre version du protocole : la seule qui appelle une réponse distincte —
|
|
93
|
+
* le client doit apprendre vers quelle version se rabattre (RFC 6455 §4.4).
|
|
94
|
+
*/
|
|
95
|
+
export declare const WS_UNSUPPORTED_VERSION = "Sec-WebSocket-Version \u2260 13";
|
|
76
96
|
/**
|
|
77
97
|
* Un upgrade est-il un handshake WebSocket conforme (RFC 6455 §4.2.1) ? Seul
|
|
78
98
|
* un tel handshake est relayé : un `Upgrade` quelconque (`h2c`…) raccordé
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ServerHttp2Session } from "node:http2";
|
|
2
|
+
/** Plus long délai d'annonce (ms) : un pair qui ne répond pas au PING ne retient pas la fermeture. */
|
|
3
|
+
export declare const ANNOUNCE_CAP_MS = 1000;
|
|
4
|
+
/**
|
|
5
|
+
* Annonce à UNE session HTTP/2 qu'elle va fermer, SANS écarter un flux déjà en route.
|
|
6
|
+
*
|
|
7
|
+
* Un PING mesure l'aller-retour, puis GOAWAY à `2^31-1`, puis l'attente de cet
|
|
8
|
+
* aller-retour : après elle, tout flux ouvert par le client avant l'annonce est
|
|
9
|
+
* arrivé, et le GOAWAY définitif (`session.close()`, dernier flux traité) peut
|
|
10
|
+
* suivre. RFC 9113 §6.8 : « SHOULD send an initial GOAWAY frame with the last
|
|
11
|
+
* stream identifier set to 2^31-1 […] After allowing time for any in-flight
|
|
12
|
+
* stream creation (at least one round-trip time) ». Sans annonce, un flux croisé
|
|
13
|
+
* avec le GOAWAY est refusé alors qu'il aurait pu être servi.
|
|
14
|
+
*
|
|
15
|
+
* L'aller-retour se MESURE avant l'annonce : après un GOAWAY, un client Node ne
|
|
16
|
+
* répond plus aux PING (constaté sur Node 26.13).
|
|
17
|
+
*
|
|
18
|
+
* @param session - la session à annoncer, ni fermée ni détruite
|
|
19
|
+
* @param settle - appelé UNE fois : après l'attente, à la fermeture de la
|
|
20
|
+
* session, ou aussitôt si le PING ne part pas. Un pair muet ne l'appelle
|
|
21
|
+
* jamais — le délai maximal appartient à l'appelant.
|
|
22
|
+
*/
|
|
23
|
+
export declare function announceSessionClose(session: ServerHttp2Session, settle: () => void): void;
|
|
24
|
+
/**
|
|
25
|
+
* Ferme EN DOUCEUR une session HTTP/2 restée inactive au-delà du délai du serveur.
|
|
26
|
+
*
|
|
27
|
+
* RFC 9113 §9.1 : un serveur est « permitted to terminate idle connections »,
|
|
28
|
+
* et « SHOULD first send a GOAWAY ». La fermeture suit l'annonce en deux temps
|
|
29
|
+
* ({@link announceSessionClose}), puis `session.close()` : aucun nouveau flux,
|
|
30
|
+
* mais les flux en cours vont à leur terme — un flux long et muet (abonnement
|
|
31
|
+
* gRPC) n'est pas coupé, seuls les NOUVEAUX flux repartent sur une autre
|
|
32
|
+
* connexion, ce que tout client HTTP/2 fait sur GOAWAY.
|
|
33
|
+
*
|
|
34
|
+
* Le délai de la session est désarmé d'abord : Node (26.13) marque une session
|
|
35
|
+
* détruite AVANT de désarmer son minuteur, qui la retiendrait alors jusqu'à son
|
|
36
|
+
* échéance (nodejs/node#66885).
|
|
37
|
+
*
|
|
38
|
+
* @param session - la session inactive
|
|
39
|
+
* @param capMs - délai maximal d'attente de l'écho du PING (ms)
|
|
40
|
+
*/
|
|
41
|
+
export declare function closeIdleSession(session: ServerHttp2Session, capMs?: number): void;
|
|
@@ -14,24 +14,37 @@ import type { IHttpConfig } from "../../config/config.js";
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function http2ServerLimits(limits: Partial<IHttpConfig["http2"]> | undefined): Pick<ServerOptions, "maxSessionMemory" | "settings">;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
* et contourne un défaut de Node qui garde
|
|
19
|
-
* l'échéance de ce délai.
|
|
17
|
+
* Ferme les sessions d'un serveur HTTP/2 — TLS (5152) comme h2c — restées
|
|
18
|
+
* inactives au-delà de `timeoutMs`, et contourne un défaut de Node qui garde
|
|
19
|
+
* chaque session fermée en vie jusqu'à l'échéance de ce délai.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* **La fermeture est À NOUS.** Node arme chaque session par
|
|
22
|
+
* `session.setTimeout(server.timeout, sessionOnTimeout)` — un écouteur `once` —
|
|
23
|
+
* et `sessionOnTimeout` ne détruit la session que si le serveur n'a AUCUN
|
|
24
|
+
* écouteur `timeout` ; s'il en a un, il lui passe la main, UNE fois par session
|
|
25
|
+
* (`internal/http2/core`, Node 26.13). Le serveur 5152 en a toujours un
|
|
26
|
+
* (`routeSocketTimeout`, pour ses sockets HTTP/1.1), et ce délai doit prévenir
|
|
27
|
+
* l'application (`onTimeout`) : sans fermeture ici, une session inactive vivait
|
|
28
|
+
* jusqu'à ce que le CLIENT la ferme (#763). À l'échéance, la session est fermée
|
|
29
|
+
* en douceur — GOAWAY annoncé puis définitif, les flux en cours vont à leur
|
|
30
|
+
* terme ({@link closeIdleSession}, RFC 9113 §9.1 et §6.8).
|
|
26
31
|
*
|
|
27
|
-
* Le contournement
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
+
* **Le contournement** (Node 24, 26) : `closeSession` marque la session détruite
|
|
33
|
+
* PUIS appelle `session.setTimeout(0)`, qui sort aussitôt sur un objet détruit ;
|
|
34
|
+
* le minuteur retient alors la session (~2,4 Ko) pendant `timeoutMs`. Il est
|
|
35
|
+
* désarmé à la réception du GOAWAY, AVANT la destruction — c'est ainsi que
|
|
36
|
+
* ferment un proxy et un client Node, même par `destroy()` ; et
|
|
37
|
+
* `closeIdleSession` le désarme avant de fermer. Signalé à Node :
|
|
38
|
+
* https://github.com/nodejs/node/issues/66885 (corrigé par nodejs/node#66886,
|
|
39
|
+
* absent de la 26.13). Une coupure TCP sans GOAWAY garde la rétention, bornée
|
|
40
|
+
* au délai.
|
|
41
|
+
*
|
|
42
|
+
* Coût par requête : nul — un écouteur par serveur, et la fermeture n'agit qu'à
|
|
43
|
+
* l'échéance.
|
|
32
44
|
*
|
|
33
45
|
* @param server - le serveur HTTP/2.
|
|
34
46
|
* @param timeoutMs - délai d'inactivité ; 0 ou absent le laisse désactivé.
|
|
35
|
-
* @param onTimeout - appelé à l'échéance (événement `timeout` du
|
|
47
|
+
* @param onTimeout - appelé à l'échéance d'une session (événement `timeout` du
|
|
48
|
+
* serveur), après le début de sa fermeture.
|
|
36
49
|
*/
|
|
37
50
|
export declare function setHttp2SessionTimeout(server: Http2Server | Http2SecureServer, timeoutMs: number | undefined, onTimeout: () => void): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Http2Stream } from "node:http2";
|
|
2
|
+
/**
|
|
3
|
+
* Ferme en `NO_ERROR` un flux HTTP/2 dont la réponse est partie mais dont le
|
|
4
|
+
* client émet encore, après la grâce d'un aller-retour (`PING`, RFC 9113 §6.7).
|
|
5
|
+
*
|
|
6
|
+
* RFC 9113 §8.1 : après une réponse complète, le serveur PEUT demander au
|
|
7
|
+
* client d'arrêter d'émettre par un `RST_STREAM` `NO_ERROR`. La coupe ne doit
|
|
8
|
+
* jamais précéder l'envoi de la réponse : un `RST_STREAM` soumis pendant que
|
|
9
|
+
* les en-têtes attendent encore dans la file de nghttp2 les fait JETER, et le
|
|
10
|
+
* client reçoit une fin de flux sans statut (un client gRPC la lit INTERNAL).
|
|
11
|
+
* Le `PING` part derrière la réponse ; son écho prouve qu'elle est arrivée.
|
|
12
|
+
*
|
|
13
|
+
* **Un seul `PING` par session** couvre tous les flux qui attendent : un flux
|
|
14
|
+
* arrivé pendant qu'un `PING` est en vol attend le suivant. Le plafond de
|
|
15
|
+
* `PING` en vol de Node (10 par session) n'est donc jamais atteint par ce
|
|
16
|
+
* chemin, et aucun flux n'est coupé sans grâce — ce que faisait la coupe
|
|
17
|
+
* immédiate quand `ping()` rendait `false`, au-delà de 10 refus simultanés.
|
|
18
|
+
*
|
|
19
|
+
* Session en fermeture GRACIEUSE (délai d'inactivité, arrêt) : Node n'envoie
|
|
20
|
+
* plus de `PING`, et la session attend la fin de ses flux — un client muet la
|
|
21
|
+
* retiendrait. La coupe part alors au tour de boucle suivant, le temps que les
|
|
22
|
+
* réponses déjà soumises quittent la file de nghttp2.
|
|
23
|
+
*
|
|
24
|
+
* Après la grâce : client qui a fini d'émettre → rien (le flux se ferme seul,
|
|
25
|
+
* sans `RST_STREAM`) ; sinon → coupé. L'écho d'un `PING` passe avant les autres
|
|
26
|
+
* trames (§6.7) : une trame DATA encore en route peut arriver après lui, la
|
|
27
|
+
* coupe reste conforme (§8.1).
|
|
28
|
+
*
|
|
29
|
+
* Coût : chemin d'erreur seulement — une entrée de `WeakMap` par session tant
|
|
30
|
+
* que des flux attendent, un `PING` par aller-retour et par session.
|
|
31
|
+
*
|
|
32
|
+
* @param stream - flux dont la réponse est ÉCRITE (`finish` passé).
|
|
33
|
+
*/
|
|
34
|
+
export declare function closeStreamAfterGrace(stream: Http2Stream): void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Une échéance ABSOLUE pour des réceptions en cours, sans un minuteur par
|
|
3
|
+
* réception : un seul balayage périodique pour toutes.
|
|
4
|
+
*
|
|
5
|
+
* ## Pourquoi
|
|
6
|
+
*
|
|
7
|
+
* `node:http2` ne borne pas la réception d'une requête : il n'a que des délais
|
|
8
|
+
* d'INACTIVITÉ (`http2stream.setTimeout`, `http2session.setTimeout`), qu'un
|
|
9
|
+
* client tient en vie avec un octet avant chaque échéance. `requestTimeout`,
|
|
10
|
+
* la borne absolue anti « slow-loris », n'existe que pour HTTP/1.1.
|
|
11
|
+
*
|
|
12
|
+
* ## Le coût, et pourquoi cette forme
|
|
13
|
+
*
|
|
14
|
+
* C'est la forme que Node donne lui-même à `requestTimeout` : aucun minuteur
|
|
15
|
+
* par requête, un contrôle périodique (`connectionsCheckingInterval`). Les
|
|
16
|
+
* réceptions suivies vivent dans un ANNEAU — un tableau des éléments et un
|
|
17
|
+
* `Int32Array` des tours d'entrée, indexés par un numéro de séquence :
|
|
18
|
+
* - suivre = deux écritures ; libérer = une comparaison et une écriture. Ni
|
|
19
|
+
* minuteur, ni fermeture, ni lecture d'horloge (le temps se compte en TOURS),
|
|
20
|
+
* ni champ ajouté à l'élément suivi ;
|
|
21
|
+
* - mesuré contre une `Map` (hachage d'identité de la clé) : ~26–32 ns par
|
|
22
|
+
* réception contre ~90–150 ns, de 1 à 10 000 réceptions simultanées.
|
|
23
|
+
*
|
|
24
|
+
* Toutes les entrées ont le même délai : l'ordre d'insertion EST l'ordre
|
|
25
|
+
* d'échéance. Un tour avance la tête et s'arrête à la première entrée vivante
|
|
26
|
+
* non échue — il ne coûte que ce qu'il expire ou saute.
|
|
27
|
+
*
|
|
28
|
+
* Contrepartie, bornée : une case libérée DERRIÈRE une entrée vivante attend
|
|
29
|
+
* que la tête la dépasse, soit au plus un délai de réception — 12 octets par
|
|
30
|
+
* réception commencée dans cette fenêtre. Sous charge, l'anneau garde sa
|
|
31
|
+
* capacité d'un tour à l'autre (jamais rétréci puis recrû) ; il la rend au
|
|
32
|
+
* premier tour sans réception nouvelle. Le minuteur unique est `unref`, et s'arrête au
|
|
33
|
+
* même moment.
|
|
34
|
+
*
|
|
35
|
+
* ## Précision
|
|
36
|
+
*
|
|
37
|
+
* Une entrée expire entre `timeoutMs` et `timeoutMs + periodMs` après son
|
|
38
|
+
* suivi — jamais AVANT le délai configuré.
|
|
39
|
+
*
|
|
40
|
+
* @typeParam T - l'élément suivi (un contexte de requête)
|
|
41
|
+
*/
|
|
42
|
+
export declare class ReceiveDeadline<T extends object> {
|
|
43
|
+
#private;
|
|
44
|
+
/**
|
|
45
|
+
* @param timeoutMs - le délai de réception (> 0)
|
|
46
|
+
* @param onExpire - appelé une fois par entrée échue, déjà retirée
|
|
47
|
+
* @param periodMs - la période du balayage, bornée par le délai (défaut 1 s)
|
|
48
|
+
* @throws RangeError si `timeoutMs` ou `periodMs` n'est pas un entier > 0
|
|
49
|
+
*/
|
|
50
|
+
constructor(timeoutMs: number, onExpire: (item: T) => void, periodMs?: number);
|
|
51
|
+
/** Cases occupées, libérées ou non, entre la tête et la queue. */
|
|
52
|
+
get size(): number;
|
|
53
|
+
/** Capacité courante de l'anneau. */
|
|
54
|
+
get capacity(): number;
|
|
55
|
+
/** Vrai tant que le balayage tourne. */
|
|
56
|
+
get running(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Suit une réception qui commence ; démarre le balayage s'il dormait.
|
|
59
|
+
*
|
|
60
|
+
* @param item - la réception
|
|
61
|
+
* @returns le numéro à rendre à {@link ReceiveDeadline.release}
|
|
62
|
+
*/
|
|
63
|
+
track(item: T): number;
|
|
64
|
+
/**
|
|
65
|
+
* Cesse de suivre une réception terminée (reçue, refusée ou échue). Sans
|
|
66
|
+
* effet si la case a déjà été balayée ou réattribuée : l'identité de
|
|
67
|
+
* l'élément est vérifiée. Le balayage ne s'arrête pas ici mais au tour
|
|
68
|
+
* suivant s'il ne reste rien — jamais un minuteur armé puis désarmé par
|
|
69
|
+
* requête.
|
|
70
|
+
*
|
|
71
|
+
* @param seq - le numéro rendu par {@link ReceiveDeadline.track}
|
|
72
|
+
* @param item - la réception suivie
|
|
73
|
+
*/
|
|
74
|
+
release(seq: number, item: T): void;
|
|
75
|
+
/** Arrête le balayage et oublie toutes les réceptions (arrêt du serveur). */
|
|
76
|
+
close(): void;
|
|
77
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type IncomingMessage } from "node:http";
|
|
2
2
|
import type { Duplex } from "node:stream";
|
|
3
|
-
import type
|
|
3
|
+
import { WebSocketServer, type ServerOptions, type WebSocket } from "ws";
|
|
4
4
|
/** Serveur qui émet `upgrade` : HTTP/1.1, HTTPS ou HTTP/2 sécurisé (`allowHTTP1`). */
|
|
5
5
|
interface IUpgradeEmitter {
|
|
6
6
|
on(event: "upgrade", listener: (req: IncomingMessage, socket: Duplex, head: Buffer) => void): unknown;
|
|
@@ -26,6 +26,18 @@ export interface IUpgradeAdmission {
|
|
|
26
26
|
* le handshake) — il n'y a alors rien à servir
|
|
27
27
|
*/
|
|
28
28
|
accept(): WebSocket | null | Promise<WebSocket | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Retient le sous-protocole que le serveur renverra dans le `101` (RFC 6455
|
|
31
|
+
* §4.2.2 : « the subprotocol the server is ready to use »), à appeler AVANT
|
|
32
|
+
* {@link accept}. Sans choix, la règle d'avant s'applique : l'option
|
|
33
|
+
* `handleProtocols` de la configuration `ws`, sinon le premier offert.
|
|
34
|
+
*
|
|
35
|
+
* Un choix absent de l'offre du client n'est jamais renvoyé — la norme ne
|
|
36
|
+
* permet que l'un des sous-protocoles offerts, ou aucun.
|
|
37
|
+
*
|
|
38
|
+
* @param protocol - le sous-protocole choisi, `false` pour n'en renvoyer aucun
|
|
39
|
+
*/
|
|
40
|
+
selectSubprotocol(protocol: string | false): void;
|
|
29
41
|
/**
|
|
30
42
|
* Refuse par un statut HTTP, AVANT le `101` (RFC 6455 §4.2.2).
|
|
31
43
|
*
|
|
@@ -36,6 +48,34 @@ export interface IUpgradeAdmission {
|
|
|
36
48
|
}
|
|
37
49
|
/** Ce qui décide d'un upgrade : reçoit la requête et rend son verdict, plus tard s'il le faut. */
|
|
38
50
|
export type UpgradeAdmit = (req: IncomingMessage, admission: IUpgradeAdmission) => void;
|
|
51
|
+
/** Signature de l'option `handleProtocols` de `ws` (`ServerOptions`). */
|
|
52
|
+
export type SubprotocolHandler = (protocols: Set<string>, request: IncomingMessage) => string | false;
|
|
53
|
+
/**
|
|
54
|
+
* Fabrique l'option `handleProtocols` du serveur `ws` de Nodefony : le choix
|
|
55
|
+
* retenu par l'admission ({@link IUpgradeAdmission.selectSubprotocol}) s'il y
|
|
56
|
+
* en a un, sinon `fallback` (celle de la configuration), sinon le premier
|
|
57
|
+
* offert — le défaut de `ws` 8, conservé pour tout contrôleur qui ne choisit
|
|
58
|
+
* pas.
|
|
59
|
+
*
|
|
60
|
+
* @param fallback - l'option `handleProtocols` de la configuration, s'il y en a une
|
|
61
|
+
* @returns le rappel à passer à `new WebSocketServer({ handleProtocols })`
|
|
62
|
+
*/
|
|
63
|
+
export declare function createSubprotocolHandler(fallback?: SubprotocolHandler): SubprotocolHandler;
|
|
64
|
+
/**
|
|
65
|
+
* Construit le serveur `ws` de Nodefony à partir des options de la
|
|
66
|
+
* configuration, en forçant ce que Nodefony gère — seul endroit où ces
|
|
67
|
+
* options sont posées, pour le serveur clair comme pour le sécurisé :
|
|
68
|
+
*
|
|
69
|
+
* - `noServer` : l'upgrade passe d'abord par le proxy inverse, puis par
|
|
70
|
+
* {@link attachUpgradeDispatch} ;
|
|
71
|
+
* - `clientTracking` : requis par `broadcast()` et le heartbeat ;
|
|
72
|
+
* - `handleProtocols` : le sous-protocole CHOISI par le contrôleur
|
|
73
|
+
* ({@link createSubprotocolHandler}), celui de la configuration à défaut.
|
|
74
|
+
*
|
|
75
|
+
* @param options - options `ws` issues de la configuration du serveur WebSocket
|
|
76
|
+
* @returns le serveur, sans écoute propre
|
|
77
|
+
*/
|
|
78
|
+
export declare function createNodefonyWebSocketServer(options: ServerOptions): WebSocketServer;
|
|
39
79
|
/**
|
|
40
80
|
* Pose l'UNIQUE écouteur `upgrade` d'un serveur : le proxy inverse d'abord,
|
|
41
81
|
* puis le serveur WebSocket de Nodefony.
|