braid-http 1.3.104 → 1.3.106
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 +88 -47
- package/braid-http-client.js +3 -1
- package/braid-http-server.js +122 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ for await (var update of subscription_iterator) {
|
|
|
165
165
|
|
|
166
166
|
You can braidify your nodejs server with:
|
|
167
167
|
|
|
168
|
-
```
|
|
168
|
+
```javascript
|
|
169
169
|
var braidify = require('braid-http').http_server
|
|
170
170
|
```
|
|
171
171
|
|
|
@@ -210,7 +210,9 @@ require('http').createServer(
|
|
|
210
210
|
).listen(9935)
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
If you are working from a library, or from code that does not have access to
|
|
214
|
+
the root of the HTTP handler or `next` in `(req, res, next)`, you can also
|
|
215
|
+
call `braidify` inline:
|
|
214
216
|
|
|
215
217
|
```javascript
|
|
216
218
|
require('http').createServer(
|
|
@@ -223,8 +225,9 @@ require('http').createServer(
|
|
|
223
225
|
).listen(9935)
|
|
224
226
|
```
|
|
225
227
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
This works, but the inline form [leaks the multiplexing
|
|
229
|
+
abstraction](#inline-braidifyreq-res-leaks-the-abstraction) in three minor
|
|
230
|
+
ways.
|
|
228
231
|
|
|
229
232
|
### Example Nodejs server with Express
|
|
230
233
|
|
|
@@ -337,79 +340,117 @@ fetch('https://localhost:3009/chat',
|
|
|
337
340
|
)
|
|
338
341
|
```
|
|
339
342
|
|
|
340
|
-
##
|
|
341
|
-
|
|
342
|
-
You shouldn't need to, but can, configure which requests the library will
|
|
343
|
-
[multiplex](https://braid.org/protocol/multiplexing). You can configure
|
|
344
|
-
multiplexing on both the client and the server. They both need multiplexing
|
|
345
|
-
enabled for it to happen.
|
|
346
|
-
|
|
347
|
-
### Client
|
|
343
|
+
## Testing
|
|
348
344
|
|
|
349
|
-
|
|
345
|
+
Run all tests from the command line:
|
|
350
346
|
|
|
351
|
-
```
|
|
352
|
-
|
|
347
|
+
```bash
|
|
348
|
+
npm test
|
|
353
349
|
```
|
|
354
350
|
|
|
355
|
-
|
|
351
|
+
Run tests in a browser (auto-opens):
|
|
356
352
|
|
|
357
|
-
```
|
|
358
|
-
|
|
353
|
+
```bash
|
|
354
|
+
npm run test:browser
|
|
359
355
|
```
|
|
360
356
|
|
|
361
|
-
|
|
357
|
+
You can also filter tests by name:
|
|
362
358
|
|
|
363
|
-
```
|
|
364
|
-
|
|
359
|
+
```bash
|
|
360
|
+
node test/test.js --filter="version"
|
|
365
361
|
```
|
|
366
362
|
|
|
367
|
-
|
|
363
|
+
## Multiplexing
|
|
368
364
|
|
|
369
|
-
|
|
370
|
-
|
|
365
|
+
This library automatically
|
|
366
|
+
[multiplexes](https://braid.org/protocol/multiplexing) subscriptions behind
|
|
367
|
+
the scenes to overcome web browsers' 6-connection limit (with HTTP/1) and
|
|
368
|
+
100-connection limit (with HTTP/2). When you setup a server's `braidify` in
|
|
369
|
+
the recommended ways, you don't need to know it's happening — the abstraction
|
|
370
|
+
is completely transparent.
|
|
371
371
|
|
|
372
372
|
```javascript
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
373
|
+
// Recommendation #1: Wrapping the entire request handler
|
|
374
|
+
require('http').createServer(
|
|
375
|
+
braidify((req, res) => {
|
|
376
|
+
...
|
|
377
|
+
})
|
|
378
|
+
)
|
|
377
379
|
```
|
|
378
380
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
+
```javascript
|
|
382
|
+
// Recommendation #2: As middleware
|
|
383
|
+
var app = require('express')()
|
|
384
|
+
app.use(braidify)
|
|
381
385
|
```
|
|
382
|
-
|
|
386
|
+
|
|
387
|
+
```javascript
|
|
388
|
+
// Recommendation #3: With braidify(req, res, next)
|
|
389
|
+
// (Equivalent to the middleware form.)
|
|
390
|
+
app.use(
|
|
391
|
+
(req, res, next) => {
|
|
392
|
+
...
|
|
393
|
+
braidify(req, res, next)
|
|
394
|
+
...
|
|
395
|
+
}
|
|
396
|
+
)
|
|
383
397
|
```
|
|
384
398
|
|
|
385
|
-
You can ignore this message.
|
|
386
399
|
|
|
387
|
-
###
|
|
400
|
+
### Inline `braidify(req, res)` leaks the abstraction
|
|
388
401
|
|
|
389
|
-
|
|
402
|
+
If you are using braidify from within a library, or in another context without
|
|
403
|
+
access to the entire request handler, or a `next()` method, then you can use
|
|
404
|
+
the inline `braidify(req, res)` form:
|
|
390
405
|
|
|
391
406
|
```javascript
|
|
392
|
-
|
|
393
|
-
|
|
407
|
+
require('http').createServer(
|
|
408
|
+
(req, res) => {
|
|
409
|
+
...
|
|
410
|
+
braidify(req, res); if (req.is_multiplexer) return
|
|
411
|
+
...
|
|
412
|
+
}
|
|
413
|
+
)
|
|
394
414
|
```
|
|
395
415
|
|
|
396
|
-
|
|
416
|
+
Just know that there are three abstraction leaks when using this form:
|
|
397
417
|
|
|
398
|
-
|
|
418
|
+
1. You must add `if (req.is_multiplexer) return` after
|
|
419
|
+
the `braidify(req, res)` call.
|
|
420
|
+
2. The library will disable the [buffering
|
|
421
|
+
optimization](https://braid.org/protocol/multiplexing#buffering-optimization)
|
|
422
|
+
on optimistic multiplexer creation. This buffering prevents two minor
|
|
423
|
+
inconveniences that occur on about ~15% of page loads:
|
|
424
|
+
1. One round trip of additional latency on the first subscription to a host
|
|
425
|
+
2. A harmless `424` error in the javascript console, which can be safely
|
|
426
|
+
ignored:
|
|
427
|
+

|
|
399
428
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
429
|
+
The buffering works like this: when the client connects to a new host, it
|
|
430
|
+
sends a POST to create the multiplexer and GETs to subscribe — all in
|
|
431
|
+
parallel. Sometimes a GET arrives before the POST. With the recommended
|
|
432
|
+
forms, the server briefly buffers the GET (70ms, event-driven) until the
|
|
433
|
+
POST lands, then processes it normally. Without `next`, the server can't
|
|
434
|
+
re-run the handler, so it returns 424 immediately and the client retries.
|
|
403
435
|
|
|
404
|
-
|
|
436
|
+
### Configuring multiplexing
|
|
405
437
|
|
|
406
|
-
|
|
407
|
-
npm run test:browser
|
|
408
|
-
```
|
|
438
|
+
You can tune multiplexing on the client, per-request or globally:
|
|
409
439
|
|
|
410
|
-
|
|
440
|
+
```javascript
|
|
441
|
+
braid_fetch('/a', {multiplex: true}) // force on for this request
|
|
442
|
+
braid_fetch('/a', {multiplex: false}) // force off for this request
|
|
411
443
|
|
|
444
|
+
braid_fetch.enable_multiplex = true // on for all GETs
|
|
445
|
+
braid_fetch.enable_multiplex = false // off globally
|
|
446
|
+
braid_fetch.enable_multiplex = {after: 1} // on after N connections (default)
|
|
412
447
|
```
|
|
413
|
-
|
|
448
|
+
|
|
449
|
+
And on the server:
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
braidify.enable_multiplex = true // default; set false to disable
|
|
453
|
+
braidify.multiplex_wait = 10 // ms; timeout for the buffering optimization (default 10)
|
|
454
|
+
// set to 0 to disable buffering
|
|
414
455
|
```
|
|
415
456
|
|
package/braid-http-client.js
CHANGED
|
@@ -1143,7 +1143,7 @@ async function create_multiplexer(origin, mux_key, params, mux_params, attempt)
|
|
|
1143
1143
|
})()
|
|
1144
1144
|
|
|
1145
1145
|
// return a "fetch" for this multiplexer
|
|
1146
|
-
|
|
1146
|
+
var f = async (url, params, mux_params, attempt) => {
|
|
1147
1147
|
|
|
1148
1148
|
// if we already know the multiplexer is not working,
|
|
1149
1149
|
// then fallback to normal fetch
|
|
@@ -1349,6 +1349,8 @@ async function create_multiplexer(origin, mux_key, params, mux_params, attempt)
|
|
|
1349
1349
|
throw (e === 'retry' && e) || mux_error || e
|
|
1350
1350
|
}
|
|
1351
1351
|
}
|
|
1352
|
+
f.cleanup = () => cleanup_multiplexer(new Error('manual cleanup'))
|
|
1353
|
+
return f
|
|
1352
1354
|
}
|
|
1353
1355
|
|
|
1354
1356
|
// waits on reader for chunks like: 123 bytes for request ABC\r\n..123 bytes..
|
package/braid-http-server.js
CHANGED
|
@@ -255,6 +255,39 @@ function warn_braidify_dupe (req) {
|
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
// Like setTimeout, but can be aborted in a batch (via batch_id) and calls
|
|
259
|
+
// on_abort on each timeout when aborted, instead of on_timeout.
|
|
260
|
+
function abortable_set_timeout(batch_id, on_timeout, on_abort, timeout_ms) {
|
|
261
|
+
if (!braidify.pending_timeouts)
|
|
262
|
+
braidify.pending_timeouts = new Map()
|
|
263
|
+
|
|
264
|
+
var timers = braidify.pending_timeouts.get(batch_id)
|
|
265
|
+
if (!timers) {
|
|
266
|
+
timers = new Set()
|
|
267
|
+
braidify.pending_timeouts.set(batch_id, timers)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
var timer = { on_abort: on_abort }
|
|
271
|
+
timer.timeout = setTimeout(function() {
|
|
272
|
+
timers.delete(timer)
|
|
273
|
+
if (!timers.size)
|
|
274
|
+
braidify.pending_timeouts.delete(batch_id)
|
|
275
|
+
on_timeout()
|
|
276
|
+
}, timeout_ms)
|
|
277
|
+
|
|
278
|
+
timers.add(timer)
|
|
279
|
+
}
|
|
280
|
+
// Aborts an abortable_timeout created above.
|
|
281
|
+
function abort_timeouts(batch_id) {
|
|
282
|
+
var timers = braidify.pending_timeouts?.get(batch_id)
|
|
283
|
+
if (!timers) return
|
|
284
|
+
braidify.pending_timeouts.delete(batch_id)
|
|
285
|
+
for (var t of timers) {
|
|
286
|
+
clearTimeout(t.timeout)
|
|
287
|
+
t.on_abort()
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
258
291
|
|
|
259
292
|
// The main server function!
|
|
260
293
|
function braidify (req, res, next) {
|
|
@@ -266,10 +299,16 @@ function braidify (req, res, next) {
|
|
|
266
299
|
|
|
267
300
|
|
|
268
301
|
// Guard against double-braidification.
|
|
269
|
-
if (req._braidified) {
|
|
302
|
+
if (req._braidified && !req.reprocess_me) {
|
|
303
|
+
// If this was already braidified, then print a warning
|
|
270
304
|
warn_braidify_dupe(req)
|
|
305
|
+
// and stop braidifying it any further
|
|
271
306
|
return next?.()
|
|
272
307
|
}
|
|
308
|
+
// But some potential 424 responses get delayed and reprocessed.
|
|
309
|
+
// So let's clear the reprocess_me flag on those, since we're doing it.
|
|
310
|
+
delete req.reprocess_me
|
|
311
|
+
|
|
273
312
|
|
|
274
313
|
req._braidified = braidify_version
|
|
275
314
|
|
|
@@ -321,30 +360,30 @@ function braidify (req, res, next) {
|
|
|
321
360
|
}
|
|
322
361
|
|
|
323
362
|
// parse the multiplexer id and request id from the url
|
|
324
|
-
var [
|
|
363
|
+
var [multiplexer_id, request_id] = req.url.split('/').slice(req.method === 'MULTIPLEX' ? 1 : 3)
|
|
325
364
|
|
|
326
365
|
// if there's just a multiplexer, then we're creating a multiplexer..
|
|
327
|
-
if (!
|
|
366
|
+
if (!request_id) {
|
|
328
367
|
// maintain a Map of all the multiplexers
|
|
329
368
|
if (!braidify.multiplexers) braidify.multiplexers = new Map()
|
|
330
369
|
|
|
331
370
|
// if this multiplexer already exists, respond with an error
|
|
332
|
-
if (braidify.multiplexers.has(
|
|
371
|
+
if (braidify.multiplexers.has(multiplexer_id)) {
|
|
333
372
|
res.writeHead(409, 'Conflict', {'Content-Type': 'application/json'})
|
|
334
373
|
return res.end(JSON.stringify({
|
|
335
374
|
error: 'Multiplexer already exists',
|
|
336
|
-
details: `Cannot create duplicate multiplexer with ID '${
|
|
375
|
+
details: `Cannot create duplicate multiplexer with ID '${multiplexer_id}'`
|
|
337
376
|
}))
|
|
338
377
|
}
|
|
339
378
|
|
|
340
|
-
braidify.multiplexers.set(
|
|
379
|
+
braidify.multiplexers.set(multiplexer_id, {requests: new Map(), res})
|
|
341
380
|
|
|
342
381
|
// Clean up multiplexer on error or close
|
|
343
382
|
function cleanup() {
|
|
344
|
-
var
|
|
345
|
-
if (!
|
|
346
|
-
for (var f of
|
|
347
|
-
braidify.multiplexers.delete(
|
|
383
|
+
var multiplexer = braidify.multiplexers.get(multiplexer_id)
|
|
384
|
+
if (!multiplexer) return
|
|
385
|
+
for (var f of multiplexer.requests.values()) f()
|
|
386
|
+
braidify.multiplexers.delete(multiplexer_id)
|
|
348
387
|
}
|
|
349
388
|
res.on('error', cleanup)
|
|
350
389
|
res.on('close', cleanup)
|
|
@@ -361,27 +400,33 @@ function braidify (req, res, next) {
|
|
|
361
400
|
|
|
362
401
|
// but write something.. won't interfere with multiplexer,
|
|
363
402
|
// and helps flush the headers
|
|
364
|
-
|
|
403
|
+
res.write(`\r\n`)
|
|
404
|
+
|
|
405
|
+
// Notify any requests that arrived before this multiplexer
|
|
406
|
+
// was created. Must happen after writeHead so the POST's
|
|
407
|
+
// response is ready before waiters write through it.
|
|
408
|
+
abort_timeouts(multiplexer_id)
|
|
409
|
+
return
|
|
365
410
|
} else {
|
|
366
411
|
// in this case, we're closing the given request
|
|
367
412
|
|
|
368
413
|
// if the multiplexer doesn't exist, send an error
|
|
369
|
-
var
|
|
370
|
-
if (!
|
|
371
|
-
res.writeHead(404, 'Multiplexer no exist', {'Bad-Multiplexer':
|
|
372
|
-
return res.end(`multiplexer ${
|
|
414
|
+
var multiplexer = braidify.multiplexers?.get(multiplexer_id)
|
|
415
|
+
if (!multiplexer) {
|
|
416
|
+
res.writeHead(404, 'Multiplexer no exist', {'Bad-Multiplexer': multiplexer_id})
|
|
417
|
+
return res.end(`multiplexer ${multiplexer_id} does not exist`)
|
|
373
418
|
}
|
|
374
419
|
|
|
375
420
|
// if the request doesn't exist, send an error
|
|
376
|
-
let
|
|
377
|
-
if (!
|
|
378
|
-
res.writeHead(404, 'Multiplexed request not found', {'Bad-Request':
|
|
379
|
-
return res.end(`request ${
|
|
421
|
+
let request_finisher = multiplexer.requests.get(request_id)
|
|
422
|
+
if (!request_finisher) {
|
|
423
|
+
res.writeHead(404, 'Multiplexed request not found', {'Bad-Request': request_id})
|
|
424
|
+
return res.end(`request ${request_id} does not exist`)
|
|
380
425
|
}
|
|
381
426
|
|
|
382
427
|
// remove this request, and notify it
|
|
383
|
-
|
|
384
|
-
|
|
428
|
+
multiplexer.requests.delete(request_id)
|
|
429
|
+
request_finisher()
|
|
385
430
|
|
|
386
431
|
// let the requester know we succeeded
|
|
387
432
|
res.writeHead(200, 'OK', { 'Multiplex-Version': multiplex_version })
|
|
@@ -397,21 +442,44 @@ function braidify (req, res, next) {
|
|
|
397
442
|
req.headers['multiplex-version'] === multiplex_version) {
|
|
398
443
|
|
|
399
444
|
// parse the multiplexer id and request id from the header
|
|
400
|
-
var [
|
|
445
|
+
var [multiplexer_id, request_id] = req.headers['multiplex-through'].split('/').slice(3)
|
|
401
446
|
|
|
402
447
|
// find the multiplexer object (contains a response object)
|
|
403
|
-
var
|
|
404
|
-
if (!
|
|
405
|
-
|
|
448
|
+
var multiplexer = braidify.multiplexers?.get(multiplexer_id)
|
|
449
|
+
if (!multiplexer) {
|
|
450
|
+
if (braidify.multiplex_wait && next) {
|
|
451
|
+
// Wait for the multiplexer to be created.
|
|
452
|
+
// Handles the race where Multiplex-Through arrives
|
|
453
|
+
// before the POST that creates the multiplexer.
|
|
454
|
+
abortable_set_timeout(multiplexer_id,
|
|
455
|
+
function give_up () {
|
|
456
|
+
// Timed out — send 424
|
|
457
|
+
free_cors(res)
|
|
458
|
+
req.is_multiplexer = res.is_multiplexer = true
|
|
459
|
+
res.writeHead(424, 'Multiplexer not found',
|
|
460
|
+
{'Bad-Multiplexer': multiplexer_id})
|
|
461
|
+
res.end('multiplexer ' + multiplexer_id
|
|
462
|
+
+ ' does not exist')
|
|
463
|
+
},
|
|
464
|
+
function ready_for_mux () {
|
|
465
|
+
// Multiplexer appeared — re-process the request
|
|
466
|
+
req.reprocess_me = true
|
|
467
|
+
braidify(req, res, next)
|
|
468
|
+
},
|
|
469
|
+
braidify.multiplex_wait)
|
|
470
|
+
return
|
|
471
|
+
}
|
|
472
|
+
|
|
406
473
|
free_cors(res)
|
|
407
|
-
|
|
408
474
|
req.is_multiplexer = res.is_multiplexer = true
|
|
409
|
-
res.writeHead(424, 'Multiplexer
|
|
410
|
-
|
|
475
|
+
res.writeHead(424, 'Multiplexer not found',
|
|
476
|
+
{'Bad-Multiplexer': multiplexer_id})
|
|
477
|
+
return res.end('multiplexer ' + multiplexer_id
|
|
478
|
+
+ ' does not exist')
|
|
411
479
|
}
|
|
412
480
|
|
|
413
481
|
// if this request-id already exists, respond with an error
|
|
414
|
-
if (
|
|
482
|
+
if (multiplexer.requests.has(request_id)) {
|
|
415
483
|
// free cors to multiplexer errors
|
|
416
484
|
free_cors(res)
|
|
417
485
|
|
|
@@ -420,13 +488,13 @@ function braidify (req, res, next) {
|
|
|
420
488
|
return res.end(JSON.stringify({
|
|
421
489
|
error: 'Request already multiplexed',
|
|
422
490
|
details: `Cannot multiplex request with duplicate ID '`
|
|
423
|
-
+
|
|
491
|
+
+ request_id + `' for multiplexer '` + multiplexer_id + `'`
|
|
424
492
|
}))
|
|
425
493
|
}
|
|
426
494
|
|
|
427
|
-
|
|
495
|
+
multiplexer.res.write(`start response ${request_id}\r\n`)
|
|
428
496
|
|
|
429
|
-
// let the requester know we've multiplexed
|
|
497
|
+
// let the requester know we've multiplexed his response
|
|
430
498
|
var og_stream = res.stream
|
|
431
499
|
var og_socket = res.socket
|
|
432
500
|
var og_res_end = () => {
|
|
@@ -472,10 +540,10 @@ function braidify (req, res, next) {
|
|
|
472
540
|
|
|
473
541
|
// first we create a kind of fake socket
|
|
474
542
|
class MultiplexedWritable extends require('stream').Writable {
|
|
475
|
-
constructor(multiplexer,
|
|
543
|
+
constructor(multiplexer, request_id) {
|
|
476
544
|
super()
|
|
477
545
|
this.multiplexer = multiplexer
|
|
478
|
-
this.
|
|
546
|
+
this.request_id = request_id
|
|
479
547
|
}
|
|
480
548
|
|
|
481
549
|
_write(chunk, encoding, callback) {
|
|
@@ -483,14 +551,14 @@ function braidify (req, res, next) {
|
|
|
483
551
|
|
|
484
552
|
try {
|
|
485
553
|
var len = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding)
|
|
486
|
-
this.multiplexer.res.write(`${len} bytes for response ${this.
|
|
554
|
+
this.multiplexer.res.write(`${len} bytes for response ${this.request_id}\r\n`)
|
|
487
555
|
this.multiplexer.res.write(chunk, encoding, callback)
|
|
488
556
|
} catch (e) {
|
|
489
557
|
callback(e)
|
|
490
558
|
}
|
|
491
559
|
}
|
|
492
560
|
}
|
|
493
|
-
var mw = new MultiplexedWritable(
|
|
561
|
+
var mw = new MultiplexedWritable(multiplexer, request_id)
|
|
494
562
|
mw.on('error', () => {}) // EPIPE when client disconnects mid-stream
|
|
495
563
|
|
|
496
564
|
// then we create a fake server response,
|
|
@@ -501,14 +569,14 @@ function braidify (req, res, next) {
|
|
|
501
569
|
|
|
502
570
|
// register a handler for when the multiplexer closes,
|
|
503
571
|
// to close our fake response
|
|
504
|
-
|
|
572
|
+
multiplexer.requests.set(request_id, () => {
|
|
505
573
|
og_res_end?.()
|
|
506
574
|
res2.destroy()
|
|
507
575
|
})
|
|
508
576
|
|
|
509
577
|
// when our fake response is done,
|
|
510
578
|
// we want to send a special message to the multiplexer saying so
|
|
511
|
-
res2.on('finish', () =>
|
|
579
|
+
res2.on('finish', () => multiplexer.res.write(`close response ${request_id}\r\n`))
|
|
512
580
|
|
|
513
581
|
// copy over any headers which have already been set on res to res2
|
|
514
582
|
for (let x of Object.entries(res.getHeaders()))
|
|
@@ -551,7 +619,7 @@ function braidify (req, res, next) {
|
|
|
551
619
|
}
|
|
552
620
|
|
|
553
621
|
// this is provided so code can know if the response has been multiplexed
|
|
554
|
-
res.multiplexer =
|
|
622
|
+
res.multiplexer = multiplexer.res
|
|
555
623
|
}
|
|
556
624
|
|
|
557
625
|
// Add the braidly request/response helper methods
|
|
@@ -581,9 +649,19 @@ function braidify (req, res, next) {
|
|
|
581
649
|
res.isSubscription = true
|
|
582
650
|
|
|
583
651
|
// Let's disable the timeouts (if it exists)
|
|
584
|
-
if (req.socket.server)
|
|
652
|
+
if (req.socket.server) {
|
|
585
653
|
req.socket.server.timeout = 0.0
|
|
586
654
|
|
|
655
|
+
// Node 18+ added requestTimeout (default 300s) and
|
|
656
|
+
// headersTimeout (default 60s) which will kill idle
|
|
657
|
+
// long-lived connections — our bread and butter. We disable
|
|
658
|
+
// the requestTimeout, but the headersTimeout is probably
|
|
659
|
+
// fine.
|
|
660
|
+
//
|
|
661
|
+
req.socket.server.requestTimeout = 0
|
|
662
|
+
// req.socket.server.headersTimeout = 0
|
|
663
|
+
}
|
|
664
|
+
|
|
587
665
|
// We have a subscription!
|
|
588
666
|
res.statusCode = 209
|
|
589
667
|
res.statusMessage = 'Multiresponse'
|
|
@@ -685,12 +763,12 @@ async function send_update(res, data, url, peer) {
|
|
|
685
763
|
// Validate the body and patches
|
|
686
764
|
assert(!(patch && patches),
|
|
687
765
|
'sendUpdate: cannot have both `update.patch` and `update.patches` set')
|
|
688
|
-
if (patch)
|
|
689
|
-
patches = [patch]
|
|
690
766
|
assert(!(body && patches),
|
|
691
767
|
'sendUpdate: cannot have both `update.body` and `update.patch(es)')
|
|
692
768
|
assert(!patches || Array.isArray(patches),
|
|
693
769
|
'sendUpdate: `patches` provided is not array')
|
|
770
|
+
if (patch)
|
|
771
|
+
patches = patch
|
|
694
772
|
|
|
695
773
|
// Validate body format
|
|
696
774
|
if (body !== undefined) {
|
|
@@ -803,6 +881,8 @@ function free_cors(res) {
|
|
|
803
881
|
res.setHeader("Access-Control-Expose-Headers", "*")
|
|
804
882
|
}
|
|
805
883
|
|
|
884
|
+
braidify.multiplex_wait = 10 // ms; set to 0 or false to disable
|
|
885
|
+
|
|
806
886
|
module.exports = {
|
|
807
887
|
braidify,
|
|
808
888
|
free_cors
|