braid-http 1.3.35 → 1.3.37
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 -21
- package/braid-http-server.js +62 -47
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -306,14 +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
|
-
if (braid_fetch.use_multiplexing &&
|
|
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 &&
|
|
313
312
|
(params.headers.has('multiplexer') ||
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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')
|
|
317
317
|
} else {
|
|
318
318
|
res = await normal_fetch(url, params)
|
|
319
319
|
}
|
|
@@ -827,24 +827,18 @@ function parse_body (state) {
|
|
|
827
827
|
|
|
828
828
|
// multiplex_fetch provides a fetch-like experience for HTTP requests
|
|
829
829
|
// where the result is actually being sent over a separate multiplexed connection.
|
|
830
|
-
|
|
831
|
-
// This function assumes a header in params called 'multiplexer' with a value
|
|
832
|
-
// that looks like /multiplexer_id/stream_id. It creates a multiplexer if it
|
|
833
|
-
// doesn't exist already, then performs a fetch providing the multiplexer header.
|
|
834
|
-
// This tells the server to send the results to the given multiplexer.
|
|
835
|
-
//
|
|
836
|
-
async function multiplex_fetch(url, params) {
|
|
830
|
+
async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
837
831
|
var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
|
|
838
832
|
|
|
839
833
|
// the mux_key is the same as the origin, unless it is being overriden
|
|
840
834
|
// (the overriding is done by the tests)
|
|
841
|
-
var mux_key = params.headers.get('multiplexer')?.split('/')[
|
|
835
|
+
var mux_key = params.headers.get('multiplexer')?.split('/')[3] ?? origin
|
|
842
836
|
|
|
843
837
|
// create a new multiplexer if it doesn't exist for this origin
|
|
844
838
|
if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
|
|
845
839
|
if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (async () => {
|
|
846
840
|
// make up a new multiplexer id (unless it is being overriden)
|
|
847
|
-
var multiplexer = params.headers.get('multiplexer')?.split('/')[
|
|
841
|
+
var multiplexer = params.headers.get('multiplexer')?.split('/')[3] ?? Math.random().toString(36).slice(2)
|
|
848
842
|
|
|
849
843
|
var streams = new Map()
|
|
850
844
|
var mux_error = null
|
|
@@ -852,14 +846,14 @@ async function multiplex_fetch(url, params) {
|
|
|
852
846
|
var mux_promise = (async () => {
|
|
853
847
|
// attempt to establish a multiplexed connection
|
|
854
848
|
try {
|
|
855
|
-
if (
|
|
849
|
+
if (skip_multiplex_method) throw 'skip multiplex method'
|
|
856
850
|
var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', headers: {'Multiplex-Version': '0.0.1'}, retry: true})
|
|
857
851
|
if (!r.ok || r.headers.get('Multiplex-Version') !== '0.0.1') throw 'bad'
|
|
858
852
|
} catch (e) {
|
|
859
853
|
// some servers don't like custom methods,
|
|
860
854
|
// so let's try with a custom header
|
|
861
855
|
try {
|
|
862
|
-
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})
|
|
863
857
|
|
|
864
858
|
if (!r.ok) throw new Error('status not ok: ' + r.status)
|
|
865
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')
|
|
@@ -892,11 +886,11 @@ async function multiplex_fetch(url, params) {
|
|
|
892
886
|
return await normal_fetch(url, params)
|
|
893
887
|
|
|
894
888
|
// make up a new stream id (unless it is being overriden)
|
|
895
|
-
var stream = params.headers.get('multiplexer')?.split('/')[
|
|
889
|
+
var stream = params.headers.get('multiplexer')?.split('/')[4] ?? Math.random().toString(36).slice(2)
|
|
896
890
|
|
|
897
891
|
// add the multiplexer header without affecting the underlying params
|
|
898
892
|
var mux_headers = new Headers(params.headers)
|
|
899
|
-
mux_headers.set('Multiplexer',
|
|
893
|
+
mux_headers.set('Multiplexer', `/.well-known/multiplex/${multiplexer}/${stream}`)
|
|
900
894
|
mux_headers.set('Multiplex-Version', '0.0.1')
|
|
901
895
|
params = {...params, headers: mux_headers}
|
|
902
896
|
|
|
@@ -935,7 +929,7 @@ async function multiplex_fetch(url, params) {
|
|
|
935
929
|
stream_error = e
|
|
936
930
|
bytes_available()
|
|
937
931
|
try {
|
|
938
|
-
var r = await braid_fetch(`${origin}
|
|
932
|
+
var r = await braid_fetch(`${origin}${params.headers.get('multiplexer')}`, {
|
|
939
933
|
method: 'DELETE',
|
|
940
934
|
headers: { 'Multiplex-Version': '0.0.1' }, retry: true
|
|
941
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(res.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,22 +428,6 @@ function braidify (req, res, next) {
|
|
|
384
428
|
// just touching these seems to cause issues
|
|
385
429
|
key === '_events' || key === 'emit'
|
|
386
430
|
|
|
387
|
-
// because we called res.end above,
|
|
388
|
-
// in http 1, node is going to wait
|
|
389
|
-
// for the event loop to fire again,
|
|
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'
|
|
402
|
-
|
|
403
431
|
// adding these lines gets rid of some deprecation warnings.. keep?
|
|
404
432
|
|| key === '_headers'
|
|
405
433
|
|| key === '_headerNames') continue
|
|
@@ -418,21 +446,8 @@ function braidify (req, res, next) {
|
|
|
418
446
|
}
|
|
419
447
|
}
|
|
420
448
|
|
|
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
449
|
// this is provided so code can know if the response has been multiplexed
|
|
435
|
-
res.multiplexer =
|
|
450
|
+
res.multiplexer = m.res
|
|
436
451
|
}
|
|
437
452
|
|
|
438
453
|
// Add the braidly request/response helper methods
|