1
1
import EventEmitter from "node:events" ;
2
2
import http from "node:http" ;
3
3
import packageJson from "../package.json" with { type : "json" } ;
4
+ import { Authenticator } from "./auth/Authenticator.js" ;
4
5
import { Request } from "./Request.js" ;
5
6
import { EmptyResponse } from "./response/index.js" ;
6
7
import { Response } from "./response/Response.js" ;
@@ -12,19 +13,24 @@ import {ServerErrorRegistry} from "./ServerErrorRegistry.js";
12
13
* An HTTP server.
13
14
* @see {@link Server.Events } for events.
14
15
*/
15
- class Server extends EventEmitter < Server . Events > {
16
+ class Server < A > extends EventEmitter < Server . Events > {
16
17
/**
17
18
* Headers sent with every response.
18
19
*/
19
20
public readonly globalHeaders : Headers ;
21
+
20
22
/**
21
23
* This server's route registry.
22
24
*/
23
- public readonly routes = new RouteRegistry ( ) ;
25
+ public readonly routes = new RouteRegistry < A > ( ) ;
26
+
27
+ /** @internal */
28
+ public readonly _authenticators : Authenticator < A > [ ] ;
29
+
24
30
/**
25
31
* This server's error registry.
26
32
*/
27
- public readonly errors = new ServerErrorRegistry ( ) ;
33
+ public readonly errors = new ServerErrorRegistry < A > ( ) ;
28
34
private readonly server : http . Server ;
29
35
private readonly port ?: number ;
30
36
private readonly copyOrigin : boolean ;
@@ -34,19 +40,20 @@ class Server extends EventEmitter<Server.Events> {
34
40
* Create a new HTTP server.
35
41
* @param options Server options.
36
42
*/
37
- public constructor ( options ?: Server . Options ) {
43
+ public constructor ( options ?: Server . Options < A > ) {
38
44
super ( ) ;
39
45
this . server = http . createServer ( {
40
46
joinDuplicateHeaders : true ,
41
47
} , this . listener . bind ( this ) ) ;
42
48
43
49
this . globalHeaders = new Headers ( options ?. globalHeaders ) ;
44
50
if ( ! this . globalHeaders . has ( "server" ) )
45
- this . globalHeaders . set ( "Server" , `cldn /${ packageJson . version } ` ) ;
51
+ this . globalHeaders . set ( "Server" , `${ packageJson . name } /${ packageJson . version } ` ) ;
46
52
47
53
this . port = options ?. port ;
48
54
this . copyOrigin = options ?. copyOrigin ?? false ;
49
55
this . handleConditionalRequests = options ?. handleConditionalRequests ?? true ;
56
+ this . _authenticators = options ?. authenticators ?? [ ] ;
50
57
51
58
if ( this . port !== undefined ) this . listen ( this . port ) . then ( ) ;
52
59
@@ -101,21 +108,21 @@ class Server extends EventEmitter<Server.Events> {
101
108
}
102
109
103
110
private async listener ( req : http . IncomingMessage , res : http . ServerResponse ) {
104
- let apiRequest : Request ;
111
+ let apiRequest : Request < A > ;
105
112
try {
106
- apiRequest = Request . incomingMessage ( req ) ;
113
+ apiRequest = Request . incomingMessage ( req , this ) ;
107
114
}
108
115
catch ( e ) {
109
116
if ( e instanceof Request . BadUrlError ) {
110
- this . errors . _get ( ServerErrorRegistry . ErrorCodes . BAD_URL , null ) . _send ( res , this ) ;
117
+ await this . errors . _get ( ServerErrorRegistry . ErrorCodes . BAD_URL , null ) . _send ( res ) ;
111
118
return ;
112
119
}
113
120
114
121
if ( e instanceof Request . SocketClosedError )
115
122
return ;
116
123
117
124
this . emit ( "error" , e as any ) ;
118
- this . errors . _get ( ServerErrorRegistry . ErrorCodes . INTERNAL , null ) . _send ( res , this ) ;
125
+ await this . errors . _get ( ServerErrorRegistry . ErrorCodes . INTERNAL , null ) . _send ( res ) ;
119
126
return ;
120
127
}
121
128
@@ -127,7 +134,7 @@ class Server extends EventEmitter<Server.Events> {
127
134
apiRequest . _responseHeaders . set ( "vary" , "origin" ) ;
128
135
}
129
136
130
- let response : Response ;
137
+ let response : Response < A > ;
131
138
try {
132
139
response = await this . routes . handle ( apiRequest ) ;
133
140
}
@@ -148,13 +155,13 @@ class Server extends EventEmitter<Server.Events> {
148
155
await this . sendResponse ( response , res , apiRequest ) ;
149
156
}
150
157
151
- private async sendResponse ( response : Response , res : http . ServerResponse , req : Request ) : Promise < void > {
158
+ private async sendResponse ( response : Response < A > , res : http . ServerResponse , req : Request < A > ) : Promise < void > {
152
159
conditional: if (
153
160
this . handleConditionalRequests
154
161
&& response . statusCode === 200
155
162
&& [ Request . Method . GET , Request . Method . HEAD ] . includes ( req . method )
156
163
) {
157
- const responseHeaders = response . allHeaders ( res , this , req ) ;
164
+ const responseHeaders = response . allHeaders ( res , req ) ;
158
165
const etag = responseHeaders . get ( "etag" ) ;
159
166
const lastModified = responseHeaders . has ( "last-modified" )
160
167
? new Date ( responseHeaders . get ( "last-modified" ) ! )
@@ -166,26 +173,26 @@ class Server extends EventEmitter<Server.Events> {
166
173
if ( ! this . getETags ( req . headers . get ( "if-match" ) ! )
167
174
. filter ( t => ! t . startsWith ( "W/" ) )
168
175
. includes ( etag ! ) )
169
- return this . errors . _get ( ServerErrorRegistry . ErrorCodes . PRECONDITION_FAILED , req ) . _send ( res , this , req ) ;
176
+ return this . errors . _get ( ServerErrorRegistry . ErrorCodes . PRECONDITION_FAILED , req ) . _send ( res , req ) ;
170
177
}
171
178
else if ( req . headers . has ( "if-unmodified-since" ) ) {
172
179
if ( lastModified === null
173
180
|| lastModified . getTime ( ) > new Date ( req . headers . get ( "if-unmodified-since" ) ! ) . getTime ( ) )
174
- return this . errors . _get ( ServerErrorRegistry . ErrorCodes . PRECONDITION_FAILED , req ) . _send ( res , this , req ) ;
181
+ return this . errors . _get ( ServerErrorRegistry . ErrorCodes . PRECONDITION_FAILED , req ) . _send ( res , req ) ;
175
182
}
176
183
177
184
if ( req . headers . has ( "if-none-match" ) ) {
178
185
if ( this . getETags ( req . headers . get ( "if-none-match" ) ! )
179
186
. includes ( etag ! ) )
180
- return new EmptyResponse ( responseHeaders , 304 ) . _send ( res , this , req ) ;
187
+ return new EmptyResponse < A > ( responseHeaders , 304 ) . _send ( res , req ) ;
181
188
}
182
189
else if ( req . headers . has ( "if-modified-since" ) ) {
183
190
if ( lastModified !== null
184
191
&& lastModified . getTime ( ) <= new Date ( req . headers . get ( "if-modified-since" ) ! ) . getTime ( ) )
185
- return new EmptyResponse ( responseHeaders , 304 ) . _send ( res , this , req ) ;
192
+ return new EmptyResponse < A > ( responseHeaders , 304 ) . _send ( res , req ) ;
186
193
}
187
194
}
188
- response . _send ( res , this , req ) ;
195
+ await response . _send ( res , req ) ;
189
196
}
190
197
191
198
private getETags ( header : string ) {
@@ -199,7 +206,7 @@ namespace Server {
199
206
/**
200
207
* Server options
201
208
*/
202
- export interface Options {
209
+ export interface Options < A > {
203
210
/**
204
211
* The HTTP listener port. From 1 to 65535. Ports 1–1023 require
205
212
* privileges. If not set, {@link Server#listen|Server.listen()} must be called manually.
@@ -225,6 +232,11 @@ namespace Server {
225
232
* @default true
226
233
*/
227
234
readonly handleConditionalRequests ?: boolean ;
235
+
236
+ /**
237
+ * Authenticators for handling request authentication.
238
+ */
239
+ readonly authenticators ?: Authenticator < A > [ ] ;
228
240
}
229
241
230
242
/**
0 commit comments