braid-http 1.3.21 → 1.3.23
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 +56 -21
- package/braid-http-server.js +53 -11
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -236,7 +236,7 @@ async function braid_fetch (url, params = {}) {
|
|
|
236
236
|
// then we want to multiplex
|
|
237
237
|
var subscription_counts_on_close = null
|
|
238
238
|
if (params.headers.has('subscribe')) {
|
|
239
|
-
var origin = url
|
|
239
|
+
var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
|
|
240
240
|
if (!braid_fetch.subscription_counts)
|
|
241
241
|
braid_fetch.subscription_counts = {}
|
|
242
242
|
braid_fetch.subscription_counts[origin] =
|
|
@@ -845,30 +845,51 @@ async function multiplex_fetch(url, params) {
|
|
|
845
845
|
// make up a new multiplexer id (unless it is being overriden)
|
|
846
846
|
var multiplexer = params.headers.get('multiplexer')?.split('/')[1] ?? Math.random().toString(36).slice(2)
|
|
847
847
|
|
|
848
|
-
// attempt to establish a multiplexed connection
|
|
849
|
-
try {
|
|
850
|
-
var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', retry: true})
|
|
851
|
-
} catch (e) {
|
|
852
|
-
// fallback to normal fetch if multiplexed connection fails
|
|
853
|
-
console.error(`Could not establish multiplexed connection.\nGot error: ${e}.\nFalling back to normal connection.`)
|
|
854
|
-
return (url, params) => normal_fetch(url, params)
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// parse the multiplexed stream,
|
|
858
|
-
// and send messages to the appropriate streams
|
|
859
848
|
var streams = new Map()
|
|
860
849
|
var mux_error = null
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
//
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
850
|
+
var using_multiplex_header = false
|
|
851
|
+
|
|
852
|
+
var mux_promise = (async () => {
|
|
853
|
+
// attempt to establish a multiplexed connection
|
|
854
|
+
try {
|
|
855
|
+
if (params.use_multiplex_header) throw 'skip to trying header'
|
|
856
|
+
var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', retry: true})
|
|
857
|
+
} catch (e) {
|
|
858
|
+
// some servers don't like custom methods,
|
|
859
|
+
// so let's try with a custom header
|
|
860
|
+
try {
|
|
861
|
+
using_multiplex_header = true
|
|
862
|
+
r = await braid_fetch(`${origin}/${multiplexer}`, {headers: {MULTIPLEX: true}, retry: true})
|
|
863
|
+
} catch (e) {
|
|
864
|
+
// fallback to normal fetch if multiplexed connection fails
|
|
865
|
+
console.error(`Could not establish multiplexed connection.\nGot error: ${e}.\nFalling back to normal connection.`)
|
|
866
|
+
return false
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// parse the multiplexed stream,
|
|
871
|
+
// and send messages to the appropriate streams
|
|
872
|
+
parse_multiplex_stream(r.body.getReader(), (stream, bytes) => {
|
|
873
|
+
streams.get(stream)?.(bytes)
|
|
874
|
+
}, e => {
|
|
875
|
+
// the multiplexer stream has died.. let everyone know..
|
|
876
|
+
mux_error = e
|
|
877
|
+
for (var f of streams.values()) f()
|
|
878
|
+
delete multiplex_fetch.multiplexers[mux_key]
|
|
879
|
+
})
|
|
880
|
+
})()
|
|
869
881
|
|
|
870
882
|
// return a "fetch" for this multiplexer
|
|
871
883
|
return async (url, params) => {
|
|
884
|
+
// maybe wait for multiplexer to be connected..
|
|
885
|
+
if (!params.experimental_do_not_wait_for_multiplexer) {
|
|
886
|
+
if ((await mux_promise) === false) {
|
|
887
|
+
// it failed to connect the multiplexer,
|
|
888
|
+
// so fallback to normal fetch
|
|
889
|
+
return await normal_fetch(url, params)
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
872
893
|
// make up a new stream id (unless it is being overriden)
|
|
873
894
|
var stream = params.headers.get('multiplexer')?.split('/')[2] ?? Math.random().toString(36).slice(2)
|
|
874
895
|
|
|
@@ -912,7 +933,7 @@ async function multiplex_fetch(url, params) {
|
|
|
912
933
|
stream_error = e
|
|
913
934
|
bytes_available()
|
|
914
935
|
try {
|
|
915
|
-
await braid_fetch(`${origin}${params.headers.get('multiplexer')}`, {method: 'MULTIPLEX', retry: true})
|
|
936
|
+
await braid_fetch(`${origin}${params.headers.get('multiplexer')}`, {...using_multiplex_header ? {headers: {MULTIPLEX: true}} : {method: 'MULTIPLEX'}, retry: true})
|
|
916
937
|
} catch (e) {
|
|
917
938
|
console.error(`Could not cancel multiplexed connection:`, e)
|
|
918
939
|
throw e
|
|
@@ -922,6 +943,14 @@ async function multiplex_fetch(url, params) {
|
|
|
922
943
|
// do the underlying fetch
|
|
923
944
|
try {
|
|
924
945
|
var res = await normal_fetch(url, params)
|
|
946
|
+
|
|
947
|
+
if (params.experimental_do_not_wait_for_multiplexer &&
|
|
948
|
+
res.status === 422 &&
|
|
949
|
+
!(await promise_done(mux_promise))) {
|
|
950
|
+
// this error will trigger a retry if the user is using that
|
|
951
|
+
throw new Error('multiplexer not yet connected')
|
|
952
|
+
}
|
|
953
|
+
|
|
925
954
|
if (res.status !== 293) throw new Error('Could not establish multiplexed stream ' + params.headers.get('multiplexer') + ' got status: ' + res.status)
|
|
926
955
|
|
|
927
956
|
// we want to present the illusion that the connection is still open,
|
|
@@ -1126,6 +1155,12 @@ function create_abort_error(msg) {
|
|
|
1126
1155
|
return e
|
|
1127
1156
|
}
|
|
1128
1157
|
|
|
1158
|
+
async function promise_done(promise) {
|
|
1159
|
+
var pending = {}
|
|
1160
|
+
var ret = await Promise.race([promise, Promise.resolve(pending)])
|
|
1161
|
+
return ret !== pending
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1129
1164
|
// ****************************
|
|
1130
1165
|
// Exports
|
|
1131
1166
|
// ****************************
|
package/braid-http-server.js
CHANGED
|
@@ -243,7 +243,7 @@ function braidify (req, res, next) {
|
|
|
243
243
|
req.subscribe = subscribe
|
|
244
244
|
|
|
245
245
|
// Multiplexer stuff
|
|
246
|
-
if (braidify.use_multiplexing && req.method === 'MULTIPLEX') {
|
|
246
|
+
if (braidify.use_multiplexing && (req.method === 'MULTIPLEX' || req.headers.multiplex)) {
|
|
247
247
|
// parse the multiplexer id and stream id from the url
|
|
248
248
|
var [multiplexer, stream] = req.url.slice(1).split('/')
|
|
249
249
|
|
|
@@ -304,7 +304,7 @@ function braidify (req, res, next) {
|
|
|
304
304
|
var [multiplexer, stream] = req.headers.multiplexer.slice(1).split('/')
|
|
305
305
|
|
|
306
306
|
var end_things = (msg) => {
|
|
307
|
-
res.statusCode =
|
|
307
|
+
res.statusCode = 422 // Unprocessable Entity (but good syntax!)
|
|
308
308
|
res.end(msg)
|
|
309
309
|
}
|
|
310
310
|
|
|
@@ -334,14 +334,19 @@ function braidify (req, res, next) {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
_write(chunk, encoding, callback) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
337
|
+
try {
|
|
338
|
+
var len = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding)
|
|
339
|
+
this.multiplexer.res.write(`${len} bytes for stream ${this.stream}\r\n`)
|
|
340
|
+
this.multiplexer.res.write(chunk, encoding, callback)
|
|
341
|
+
|
|
342
|
+
// console.log(`wrote:`)
|
|
343
|
+
// console.log(`${len} bytes for stream /${this.stream}\r\n`)
|
|
344
|
+
// if (Buffer.isBuffer(chunk)) console.log(new TextDecoder().decode(chunk))
|
|
345
|
+
// else console.log('STRING?: ' + chunk)
|
|
346
|
+
|
|
347
|
+
} catch (e) {
|
|
348
|
+
callback(e)
|
|
349
|
+
}
|
|
345
350
|
}
|
|
346
351
|
}
|
|
347
352
|
var mw = new MultiplexedWritable(m, stream)
|
|
@@ -368,7 +373,31 @@ function braidify (req, res, next) {
|
|
|
368
373
|
} while (obj = Object.getPrototypeOf(obj))
|
|
369
374
|
}
|
|
370
375
|
for (let key of get_props(res)) {
|
|
371
|
-
|
|
376
|
+
// skip keys that break stuff for some reason
|
|
377
|
+
if (
|
|
378
|
+
// just touching these seems to cause issues
|
|
379
|
+
key === '_events' || key === 'emit'
|
|
380
|
+
|
|
381
|
+
// because we called res.end above,
|
|
382
|
+
// in http 1, node is going to wait
|
|
383
|
+
// for the event loop to fire again,
|
|
384
|
+
// and then call these keys:
|
|
385
|
+
// "socket" to set it to null,
|
|
386
|
+
// "detachSocket" to do that,
|
|
387
|
+
// "_closed" to determine if the socket is closed;
|
|
388
|
+
// we're going to override that to say true,
|
|
389
|
+
// we do that below..
|
|
390
|
+
// we do it so we don't need to add "destroyed" here,
|
|
391
|
+
// because if _closed was false,
|
|
392
|
+
// it would try to set destroyed to true
|
|
393
|
+
|| key === 'socket'
|
|
394
|
+
|| key === 'detachSocket'
|
|
395
|
+
|| key === '_closed'
|
|
396
|
+
|
|
397
|
+
// adding these lines gets rid of some deprecation warnings.. keep?
|
|
398
|
+
|| key === '_headers'
|
|
399
|
+
|| key === '_headerNames') continue
|
|
400
|
+
|
|
372
401
|
if (res2[key] === undefined) continue
|
|
373
402
|
var value = res[key]
|
|
374
403
|
if (typeof value === 'function') {
|
|
@@ -383,6 +412,19 @@ function braidify (req, res, next) {
|
|
|
383
412
|
}
|
|
384
413
|
}
|
|
385
414
|
|
|
415
|
+
// node http 1 has the issue that when we call res.end,
|
|
416
|
+
// which we do above, not everything happens right away..
|
|
417
|
+
// in the next js event loop tick, it is going to
|
|
418
|
+
// try to tear down the stream,
|
|
419
|
+
// but we have proxied all the properties,
|
|
420
|
+
// so it would tear down our new res2 stream..
|
|
421
|
+
// to prevent that, we sacrafice this property
|
|
422
|
+
// (which the end-user hopefully won't be accessing anyway)
|
|
423
|
+
// to make the http 1 tear down code think its job is complete already,
|
|
424
|
+
// otherwise it would want to set "destroyed",
|
|
425
|
+
// and we would need to not proxy that key as well
|
|
426
|
+
res._closed = true
|
|
427
|
+
|
|
386
428
|
// this is provided so code can know if the response has been multiplexed
|
|
387
429
|
res.multiplexer = res2
|
|
388
430
|
}
|