@@ -7,17 +7,19 @@ import esbuild from 'esbuild'
7
7
8
8
import { unicodeLines } from './fixtures.js'
9
9
10
+ const isDeno = typeof globalThis . Deno !== 'undefined'
11
+
10
12
export function getServer ( port : number ) : Promise < Server > {
11
13
return new Promise ( ( resolve , reject ) => {
12
14
const server = createServer ( onRequest )
13
15
. on ( 'error' , reject )
14
- . listen ( port , '::' , ( ) => resolve ( server ) )
16
+ . listen ( port , isDeno ? '127.0.0.1' : '::' , ( ) => resolve ( server ) )
15
17
} )
16
18
}
17
19
18
20
function onRequest ( req : IncomingMessage , res : ServerResponse ) {
19
21
// Disable Nagle's algorithm for testing
20
- if ( res . socket ) {
22
+ if ( res . socket && 'setNoDelay' in res . socket ) {
21
23
res . socket . setNoDelay ( true )
22
24
}
23
25
@@ -65,15 +67,16 @@ function writeDefault(_req: IncomingMessage, res: ServerResponse) {
65
67
Connection : 'keep-alive' ,
66
68
} )
67
69
68
- res . write (
70
+ tryWrite (
71
+ res ,
69
72
formatEvent ( {
70
73
event : 'welcome' ,
71
74
data : 'Hello, world!' ,
72
75
} ) ,
73
76
)
74
77
75
78
// For some reason, Bun seems to need this to flush
76
- res . write ( ':\n' )
79
+ tryWrite ( res , ':\n' )
77
80
}
78
81
79
82
/**
@@ -87,12 +90,13 @@ async function writeCounter(req: IncomingMessage, res: ServerResponse) {
87
90
Connection : 'keep-alive' ,
88
91
} )
89
92
90
- res . write ( formatEvent ( { retry : 50 , data : '' } ) )
93
+ tryWrite ( res , formatEvent ( { retry : 50 , data : '' } ) )
91
94
92
95
let counter = parseInt ( getLastEventId ( req ) || '0' , 10 )
93
96
for ( let i = 0 ; i < 3 ; i ++ ) {
94
97
counter ++
95
- res . write (
98
+ tryWrite (
99
+ res ,
96
100
formatEvent ( {
97
101
event : 'counter' ,
98
102
data : `Counter is at ${ counter } ` ,
@@ -114,8 +118,9 @@ function writeOne(req: IncomingMessage, res: ServerResponse) {
114
118
} )
115
119
116
120
if ( ! last ) {
117
- res . write ( formatEvent ( { retry : 50 , data : '' } ) )
118
- res . write (
121
+ tryWrite ( res , formatEvent ( { retry : 50 , data : '' } ) )
122
+ tryWrite (
123
+ res ,
119
124
formatEvent ( {
120
125
event : 'progress' ,
121
126
data : '100%' ,
@@ -136,7 +141,8 @@ async function writeSlowConnect(_req: IncomingMessage, res: ServerResponse) {
136
141
Connection : 'keep-alive' ,
137
142
} )
138
143
139
- res . write (
144
+ tryWrite (
145
+ res ,
140
146
formatEvent ( {
141
147
event : 'welcome' ,
142
148
data : 'That was a slow connect, was it not?' ,
@@ -156,7 +162,8 @@ async function writeStalledConnection(req: IncomingMessage, res: ServerResponse)
156
162
const lastId = getLastEventId ( req )
157
163
const reconnected = lastId === '1'
158
164
159
- res . write (
165
+ tryWrite (
166
+ res ,
160
167
formatEvent ( {
161
168
id : reconnected ? '2' : '1' ,
162
169
event : 'welcome' ,
@@ -168,7 +175,8 @@ async function writeStalledConnection(req: IncomingMessage, res: ServerResponse)
168
175
169
176
if ( reconnected ) {
170
177
await delay ( 250 )
171
- res . write (
178
+ tryWrite (
179
+ res ,
172
180
formatEvent ( {
173
181
id : '3' ,
174
182
event : 'success' ,
@@ -189,14 +197,16 @@ async function writeUnicode(_req: IncomingMessage, res: ServerResponse) {
189
197
Connection : 'keep-alive' ,
190
198
} )
191
199
192
- res . write (
200
+ tryWrite (
201
+ res ,
193
202
formatEvent ( {
194
203
event : 'welcome' ,
195
204
data : 'Connected - I will now send some chonks (cuter chunks) with unicode' ,
196
205
} ) ,
197
206
)
198
207
199
- res . write (
208
+ tryWrite (
209
+ res ,
200
210
formatEvent ( {
201
211
event : 'unicode' ,
202
212
data : unicodeLines [ 0 ] ,
@@ -206,22 +216,22 @@ async function writeUnicode(_req: IncomingMessage, res: ServerResponse) {
206
216
await delay ( 100 )
207
217
208
218
// Start of a valid SSE chunk
209
- res . write ( 'event: unicode\ndata: ' )
219
+ tryWrite ( res , 'event: unicode\ndata: ' )
210
220
211
221
// Write "Espen ❤️ Kokos" in two halves:
212
222
// 1st: Espen � [..., 226, 153]
213
223
// 2st: � Kokos [165, 32, ...]
214
- res . write ( new Uint8Array ( [ 69 , 115 , 112 , 101 , 110 , 32 , 226 , 153 ] ) )
224
+ tryWrite ( res , new Uint8Array ( [ 69 , 115 , 112 , 101 , 110 , 32 , 226 , 153 ] ) )
215
225
216
226
// Give time to the client to process the first half
217
227
await delay ( 1000 )
218
228
219
- res . write ( new Uint8Array ( [ 165 , 32 , 75 , 111 , 107 , 111 , 115 ] ) )
229
+ tryWrite ( res , new Uint8Array ( [ 165 , 32 , 75 , 111 , 107 , 111 , 115 ] ) )
220
230
221
231
// Closing end of packet
222
- res . write ( '\n\n\n\n' )
232
+ tryWrite ( res , '\n\n\n\n' )
223
233
224
- res . write ( formatEvent ( { event : 'disconnect' , data : 'Thanks for listening' } ) )
234
+ tryWrite ( res , formatEvent ( { event : 'disconnect' , data : 'Thanks for listening' } ) )
225
235
res . end ( )
226
236
}
227
237
@@ -232,7 +242,8 @@ async function writeTricklingConnection(_req: IncomingMessage, res: ServerRespon
232
242
Connection : 'keep-alive' ,
233
243
} )
234
244
235
- res . write (
245
+ tryWrite (
246
+ res ,
236
247
formatEvent ( {
237
248
event : 'welcome' ,
238
249
data : 'Connected - now I will keep sending "comments" for a while' ,
@@ -241,10 +252,10 @@ async function writeTricklingConnection(_req: IncomingMessage, res: ServerRespon
241
252
242
253
for ( let i = 0 ; i < 60 ; i ++ ) {
243
254
await delay ( 500 )
244
- res . write ( ':\n' )
255
+ tryWrite ( res , ':\n' )
245
256
}
246
257
247
- res . write ( formatEvent ( { event : 'disconnect' , data : 'Thanks for listening' } ) )
258
+ tryWrite ( res , formatEvent ( { event : 'disconnect' , data : 'Thanks for listening' } ) )
248
259
res . end ( )
249
260
}
250
261
@@ -259,7 +270,8 @@ function writeCors(req: IncomingMessage, res: ServerResponse) {
259
270
...cors ,
260
271
} )
261
272
262
- res . write (
273
+ tryWrite (
274
+ res ,
263
275
formatEvent ( {
264
276
event : 'origin' ,
265
277
data : origin || '<none>' ,
@@ -282,7 +294,7 @@ async function writeDebug(req: IncomingMessage, res: ServerResponse) {
282
294
bodyHash = await hash
283
295
} catch ( err : unknown ) {
284
296
res . writeHead ( 500 , 'Internal Server Error' )
285
- res . write ( err instanceof Error ? err . message : `${ err } ` )
297
+ tryWrite ( res , err instanceof Error ? err . message : `${ err } ` )
286
298
res . end ( )
287
299
return
288
300
}
@@ -293,7 +305,8 @@ async function writeDebug(req: IncomingMessage, res: ServerResponse) {
293
305
Connection : 'keep-alive' ,
294
306
} )
295
307
296
- res . write (
308
+ tryWrite (
309
+ res ,
297
310
formatEvent ( {
298
311
event : 'debug' ,
299
312
data : JSON . stringify ( {
@@ -319,7 +332,7 @@ function writeCookies(_req: IncomingMessage, res: ServerResponse) {
319
332
'Set-Cookie' : 'someSession=someValue; Path=/authed; HttpOnly; SameSite=Lax;' ,
320
333
Connection : 'keep-alive' ,
321
334
} )
322
- res . write ( JSON . stringify ( { cookiesWritten : true } ) )
335
+ tryWrite ( res , JSON . stringify ( { cookiesWritten : true } ) )
323
336
res . end ( )
324
337
}
325
338
@@ -330,7 +343,8 @@ function writeAuthed(req: IncomingMessage, res: ServerResponse) {
330
343
Connection : 'keep-alive' ,
331
344
} )
332
345
333
- res . write (
346
+ tryWrite (
347
+ res ,
334
348
formatEvent ( {
335
349
event : 'authInfo' ,
336
350
data : JSON . stringify ( { cookies : req . headers . cookie || '' } ) ,
@@ -347,7 +361,7 @@ function writeFallback(_req: IncomingMessage, res: ServerResponse) {
347
361
Connection : 'close' ,
348
362
} )
349
363
350
- res . write ( 'File not found' )
364
+ tryWrite ( res , 'File not found' )
351
365
res . end ( )
352
366
}
353
367
@@ -377,7 +391,7 @@ async function writeBrowserTestScript(_req: IncomingMessage, res: ServerResponse
377
391
outdir : 'out' ,
378
392
} )
379
393
380
- res . write ( build . outputFiles . map ( ( file ) => file . text ) . join ( '\n\n' ) )
394
+ tryWrite ( res , build . outputFiles . map ( ( file ) => file . text ) . join ( '\n\n' ) )
381
395
res . end ( )
382
396
}
383
397
@@ -443,3 +457,16 @@ export function encodeData(text: string): string {
443
457
444
458
return output
445
459
}
460
+
461
+ function tryWrite ( res : ServerResponse , chunk : string | Uint8Array ) {
462
+ try {
463
+ res . write ( chunk )
464
+ } catch ( err : unknown ) {
465
+ // Deno randomly throws on write after close, it seems
466
+ if ( err instanceof TypeError && err . message . includes ( 'cannot close or enqueue' ) ) {
467
+ return
468
+ }
469
+
470
+ throw err
471
+ }
472
+ }
0 commit comments