braid-http 1.3.36 → 1.3.38
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/braid-http-client.js +15 -22
- package/braid-http-server.js +65 -46
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -306,15 +306,14 @@ async function braid_fetch (url, params = {}) {
|
|
|
306
306
|
|
|
307
307
|
// Now we run the original fetch....
|
|
308
308
|
|
|
309
|
-
// try multiplexing if
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
var mux_params = params.multiplexer ?? braid_fetch.multiplexer
|
|
313
|
-
if (mux_params &&
|
|
309
|
+
// try multiplexing if the multiplex flag is set, and conditions are met
|
|
310
|
+
var mux_params = params.multiplex ?? braid_fetch.multiplex
|
|
311
|
+
if (mux_params !== false &&
|
|
314
312
|
(params.headers.has('multiplexer') ||
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
(params.headers.has('subscribe') &&
|
|
314
|
+
braid_fetch.subscription_counts?.[origin] >
|
|
315
|
+
(!mux_params ? 1 : (mux_params.after ?? 0))))) {
|
|
316
|
+
res = await multiplex_fetch(url, params, mux_params?.via === 'POST')
|
|
318
317
|
} else {
|
|
319
318
|
res = await normal_fetch(url, params)
|
|
320
319
|
}
|
|
@@ -828,24 +827,18 @@ function parse_body (state) {
|
|
|
828
827
|
|
|
829
828
|
// multiplex_fetch provides a fetch-like experience for HTTP requests
|
|
830
829
|
// where the result is actually being sent over a separate multiplexed connection.
|
|
831
|
-
|
|
832
|
-
// This function assumes a header in params called 'multiplexer' with a value
|
|
833
|
-
// that looks like /multiplexer_id/stream_id. It creates a multiplexer if it
|
|
834
|
-
// doesn't exist already, then performs a fetch providing the multiplexer header.
|
|
835
|
-
// This tells the server to send the results to the given multiplexer.
|
|
836
|
-
//
|
|
837
|
-
async function multiplex_fetch(url, params, mux_params) {
|
|
830
|
+
async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
838
831
|
var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
|
|
839
832
|
|
|
840
833
|
// the mux_key is the same as the origin, unless it is being overriden
|
|
841
834
|
// (the overriding is done by the tests)
|
|
842
|
-
var mux_key = params.headers.get('multiplexer')?.split('/')[
|
|
835
|
+
var mux_key = params.headers.get('multiplexer')?.split('/')[3] ?? origin
|
|
843
836
|
|
|
844
837
|
// create a new multiplexer if it doesn't exist for this origin
|
|
845
838
|
if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
|
|
846
839
|
if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (async () => {
|
|
847
840
|
// make up a new multiplexer id (unless it is being overriden)
|
|
848
|
-
var multiplexer = params.headers.get('multiplexer')?.split('/')[
|
|
841
|
+
var multiplexer = params.headers.get('multiplexer')?.split('/')[3] ?? Math.random().toString(36).slice(2)
|
|
849
842
|
|
|
850
843
|
var streams = new Map()
|
|
851
844
|
var mux_error = null
|
|
@@ -853,14 +846,14 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
853
846
|
var mux_promise = (async () => {
|
|
854
847
|
// attempt to establish a multiplexed connection
|
|
855
848
|
try {
|
|
856
|
-
if (
|
|
849
|
+
if (skip_multiplex_method) throw 'skip multiplex method'
|
|
857
850
|
var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', headers: {'Multiplex-Version': '0.0.1'}, retry: true})
|
|
858
851
|
if (!r.ok || r.headers.get('Multiplex-Version') !== '0.0.1') throw 'bad'
|
|
859
852
|
} catch (e) {
|
|
860
853
|
// some servers don't like custom methods,
|
|
861
854
|
// so let's try with a custom header
|
|
862
855
|
try {
|
|
863
|
-
r = await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}`, {headers: {'Multiplex-Version': '0.0.1'}, retry: true})
|
|
856
|
+
r = await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}`, {method: 'POST', headers: {'Multiplex-Version': '0.0.1'}, retry: true})
|
|
864
857
|
|
|
865
858
|
if (!r.ok) throw new Error('status not ok: ' + r.status)
|
|
866
859
|
if (r.headers.get('Multiplex-Version') !== '0.0.1') throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected 0.0.1')
|
|
@@ -893,11 +886,11 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
893
886
|
return await normal_fetch(url, params)
|
|
894
887
|
|
|
895
888
|
// make up a new stream id (unless it is being overriden)
|
|
896
|
-
var stream = params.headers.get('multiplexer')?.split('/')[
|
|
889
|
+
var stream = params.headers.get('multiplexer')?.split('/')[4] ?? Math.random().toString(36).slice(2)
|
|
897
890
|
|
|
898
891
|
// add the multiplexer header without affecting the underlying params
|
|
899
892
|
var mux_headers = new Headers(params.headers)
|
|
900
|
-
mux_headers.set('Multiplexer',
|
|
893
|
+
mux_headers.set('Multiplexer', `/.well-known/multiplex/${multiplexer}/${stream}`)
|
|
901
894
|
mux_headers.set('Multiplex-Version', '0.0.1')
|
|
902
895
|
params = {...params, headers: mux_headers}
|
|
903
896
|
|
|
@@ -936,7 +929,7 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
936
929
|
stream_error = e
|
|
937
930
|
bytes_available()
|
|
938
931
|
try {
|
|
939
|
-
var r = await braid_fetch(`${origin}
|
|
932
|
+
var r = await braid_fetch(`${origin}${params.headers.get('multiplexer')}`, {
|
|
940
933
|
method: 'DELETE',
|
|
941
934
|
headers: { 'Multiplex-Version': '0.0.1' }, retry: true
|
|
942
935
|
})
|
package/braid-http-server.js
CHANGED
|
@@ -247,6 +247,14 @@ function braidify (req, res, next) {
|
|
|
247
247
|
(req.method === 'MULTIPLEX' || req.url.startsWith('/.well-known/multiplex/')) &&
|
|
248
248
|
req.headers['multiplex-version'] === '0.0.1') {
|
|
249
249
|
|
|
250
|
+
// let the caller know we're handling things
|
|
251
|
+
req.is_multiplexer = res.is_multiplexer = true
|
|
252
|
+
|
|
253
|
+
// free the cors
|
|
254
|
+
res.setHeader("Access-Control-Allow-Origin", "*")
|
|
255
|
+
res.setHeader("Access-Control-Allow-Methods", "*")
|
|
256
|
+
res.setHeader("Access-Control-Allow-Headers", "*")
|
|
257
|
+
|
|
250
258
|
// parse the multiplexer id and stream id from the url
|
|
251
259
|
var [multiplexer, stream] = req.url.split('/').slice(req.method === 'MULTIPLEX' ? 1 : 3)
|
|
252
260
|
|
|
@@ -265,7 +273,7 @@ function braidify (req, res, next) {
|
|
|
265
273
|
|
|
266
274
|
// keep the connection open,
|
|
267
275
|
// so people can send multiplexed data to it
|
|
268
|
-
res.writeHead(200, {
|
|
276
|
+
res.writeHead(200, 'OK', {
|
|
269
277
|
'Multiplex-Version': '0.0.1',
|
|
270
278
|
'Incremental': '?1',
|
|
271
279
|
'Cache-Control': 'no-cache',
|
|
@@ -282,15 +290,15 @@ function braidify (req, res, next) {
|
|
|
282
290
|
// if the multiplexer doesn't exist, send an error
|
|
283
291
|
var m = braidify.multiplexers?.get(multiplexer)
|
|
284
292
|
if (!m) {
|
|
285
|
-
res.writeHead(
|
|
286
|
-
return res.end(`multiplexer
|
|
293
|
+
res.writeHead(422, 'Multiplexer no exist', {'Bad-Multiplexer': multiplexer})
|
|
294
|
+
return res.end(`multiplexer ${multiplexer} does not exist`)
|
|
287
295
|
}
|
|
288
296
|
|
|
289
297
|
// if the stream doesn't exist, send an error
|
|
290
298
|
let s = m.streams.get(stream)
|
|
291
299
|
if (!s) {
|
|
292
|
-
res.writeHead(
|
|
293
|
-
return res.end(`stream
|
|
300
|
+
res.writeHead(422, 'Stream no exist', {'Bad-Stream': stream})
|
|
301
|
+
return res.end(`stream ${stream} does not exist`)
|
|
294
302
|
}
|
|
295
303
|
|
|
296
304
|
// remove this stream, and notify it
|
|
@@ -298,7 +306,7 @@ function braidify (req, res, next) {
|
|
|
298
306
|
s()
|
|
299
307
|
|
|
300
308
|
// let the requester know we succeeded
|
|
301
|
-
res.writeHead(200, { 'Multiplex-Version': '0.0.1' })
|
|
309
|
+
res.writeHead(200, 'OK', { 'Multiplex-Version': '0.0.1' })
|
|
302
310
|
return res.end(``)
|
|
303
311
|
}
|
|
304
312
|
}
|
|
@@ -310,23 +318,54 @@ function braidify (req, res, next) {
|
|
|
310
318
|
req.headers.multiplexer &&
|
|
311
319
|
req.headers['multiplex-version'] === '0.0.1') {
|
|
312
320
|
|
|
313
|
-
// parse the multiplexer id and stream id from the
|
|
314
|
-
var [multiplexer, stream] = req.headers.multiplexer.
|
|
321
|
+
// parse the multiplexer id and stream id from the header
|
|
322
|
+
var [multiplexer, stream] = req.headers.multiplexer.split('/').slice(3)
|
|
315
323
|
|
|
316
324
|
// find the multiplexer object (contains a response object)
|
|
317
325
|
var m = braidify.multiplexers?.get(multiplexer)
|
|
318
326
|
if (!m) {
|
|
319
|
-
|
|
320
|
-
res.
|
|
321
|
-
res.end(`multiplexer ${multiplexer} does not exist`)
|
|
327
|
+
res.writeHead(422, 'Multiplexer no exist', {'Bad-Multiplexer': multiplexer})
|
|
328
|
+
return res.end(`multiplexer ${multiplexer} does not exist`)
|
|
322
329
|
}
|
|
323
330
|
|
|
324
331
|
// let the requester know we've multiplexed their response
|
|
325
|
-
res.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
332
|
+
var og_stream = res.stream
|
|
333
|
+
var og_socket = res.socket
|
|
334
|
+
var og_res_end = () => {
|
|
335
|
+
og_res_end = null
|
|
336
|
+
if (!braidify.cors_headers) braidify.cors_headers = new Set([
|
|
337
|
+
'Access-Control-Allow-Origin',
|
|
338
|
+
'Access-Control-Allow-Methods',
|
|
339
|
+
'Access-Control-Allow-Headers',
|
|
340
|
+
'Access-Control-Allow-Credentials',
|
|
341
|
+
'Access-Control-Expose-Headers',
|
|
342
|
+
'Access-Control-Max-Age'
|
|
343
|
+
].map(x => x.toLowerCase()))
|
|
344
|
+
|
|
345
|
+
// copy any CORS headers from the user
|
|
346
|
+
var cors_headers = Object.entries(res2.getHeaders()).
|
|
347
|
+
filter(x => braidify.cors_headers.has(x.key))
|
|
348
|
+
|
|
349
|
+
if (og_stream) {
|
|
350
|
+
og_stream.respond({
|
|
351
|
+
':status': 293,
|
|
352
|
+
Multiplexer: req.headers.multiplexer,
|
|
353
|
+
'Multiplex-Version': '0.0.1',
|
|
354
|
+
...Object.fromEntries(cors_headers)
|
|
355
|
+
})
|
|
356
|
+
og_stream.write('Ok.')
|
|
357
|
+
og_stream.end()
|
|
358
|
+
} else {
|
|
359
|
+
og_socket.write('HTTP/1.1 293 Responded via multiplexer\r\n')
|
|
360
|
+
og_socket.write(`Multiplexer: ${req.headers.multiplexer}\r\n`)
|
|
361
|
+
og_socket.write(`Multiplex-Version: 0.0.1\r\n`)
|
|
362
|
+
cors_headers.forEach(([key, value]) =>
|
|
363
|
+
og_socket.write(`${key}: ${value}\r\n`))
|
|
364
|
+
og_socket.write('\r\n')
|
|
365
|
+
og_socket.write('Ok.')
|
|
366
|
+
og_socket.end()
|
|
367
|
+
}
|
|
368
|
+
}
|
|
330
369
|
|
|
331
370
|
// and now set things up so that future use of the
|
|
332
371
|
// response object forwards stuff into the multiplexer
|
|
@@ -340,6 +379,8 @@ function braidify (req, res, next) {
|
|
|
340
379
|
}
|
|
341
380
|
|
|
342
381
|
_write(chunk, encoding, callback) {
|
|
382
|
+
og_res_end?.()
|
|
383
|
+
|
|
343
384
|
try {
|
|
344
385
|
var len = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding)
|
|
345
386
|
this.multiplexer.res.write(`${len} bytes for stream ${this.stream}\r\n`)
|
|
@@ -365,7 +406,10 @@ function braidify (req, res, next) {
|
|
|
365
406
|
|
|
366
407
|
// register a handler for when the multiplexer closes,
|
|
367
408
|
// to close our fake response stream
|
|
368
|
-
m.streams.set(stream, () =>
|
|
409
|
+
m.streams.set(stream, () => {
|
|
410
|
+
og_res_end?.()
|
|
411
|
+
res2.destroy()
|
|
412
|
+
})
|
|
369
413
|
|
|
370
414
|
// when our fake response is done,
|
|
371
415
|
// we want to send a special message to the multiplexer saying so
|
|
@@ -384,21 +428,9 @@ function braidify (req, res, next) {
|
|
|
384
428
|
// just touching these seems to cause issues
|
|
385
429
|
key === '_events' || key === 'emit'
|
|
386
430
|
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
|
|
390
|
-
// and then call these keys:
|
|
391
|
-
// "socket" to set it to null,
|
|
392
|
-
// "detachSocket" to do that,
|
|
393
|
-
// "_closed" to determine if the socket is closed;
|
|
394
|
-
// we're going to override that to say true,
|
|
395
|
-
// we do that below..
|
|
396
|
-
// we do it so we don't need to add "destroyed" here,
|
|
397
|
-
// because if _closed was false,
|
|
398
|
-
// it would try to set destroyed to true
|
|
399
|
-
|| key === 'socket'
|
|
400
|
-
|| key === 'detachSocket'
|
|
401
|
-
|| key === '_closed'
|
|
431
|
+
// empirically, on an http1 server,
|
|
432
|
+
// this causes res2 to close prematurely
|
|
433
|
+
|| key === 'destroyed'
|
|
402
434
|
|
|
403
435
|
// adding these lines gets rid of some deprecation warnings.. keep?
|
|
404
436
|
|| key === '_headers'
|
|
@@ -418,21 +450,8 @@ function braidify (req, res, next) {
|
|
|
418
450
|
}
|
|
419
451
|
}
|
|
420
452
|
|
|
421
|
-
// node http 1 has the issue that when we call res.end,
|
|
422
|
-
// which we do above, not everything happens right away..
|
|
423
|
-
// in the next js event loop tick, it is going to
|
|
424
|
-
// try to tear down the stream,
|
|
425
|
-
// but we have proxied all the properties,
|
|
426
|
-
// so it would tear down our new res2 stream..
|
|
427
|
-
// to prevent that, we sacrafice this property
|
|
428
|
-
// (which the end-user hopefully won't be accessing anyway)
|
|
429
|
-
// to make the http 1 tear down code think its job is complete already,
|
|
430
|
-
// otherwise it would want to set "destroyed",
|
|
431
|
-
// and we would need to not proxy that key as well
|
|
432
|
-
res._closed = true
|
|
433
|
-
|
|
434
453
|
// this is provided so code can know if the response has been multiplexed
|
|
435
|
-
res.multiplexer =
|
|
454
|
+
res.multiplexer = m.res
|
|
436
455
|
}
|
|
437
456
|
|
|
438
457
|
// Add the braidly request/response helper methods
|