braid-http 1.3.40 → 1.3.42

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.
@@ -265,7 +265,7 @@ async function braid_fetch (url, params = {}) {
265
265
  var retry = params.retry && // only try to reconnect if the user has chosen to
266
266
  e.name !== "AbortError" && // don't retry if the user has chosen to abort
267
267
  !e.startsWith?.('Parse error in headers') && // in this case, the server is spewing garbage, so reconnecting might be bad
268
- !e.message?.startsWith?.('Could not establish multiplexed stream') && // the server has told us no, or is using a different version of multiplexing
268
+ !e.message?.startsWith?.('Could not establish multiplexed request') && // the server has told us no, or is using a different version of multiplexing
269
269
  !cb_running // if an error is thrown in the callback, then it may not be good to reconnect, and generate more errors
270
270
 
271
271
  if (retry && !original_signal?.aborted) {
@@ -842,7 +842,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
842
842
  // make up a new multiplexer id (unless it is being overriden)
843
843
  var multiplexer = params.headers.get('multiplex-at')?.split('/')[3] ?? Math.random().toString(36).slice(2)
844
844
 
845
- var streams = new Map()
845
+ var requests = new Map()
846
846
  var mux_error = null
847
847
 
848
848
  var mux_promise = (async () => {
@@ -861,19 +861,30 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
861
861
  if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
862
862
  } catch (e) {
863
863
  // fallback to normal fetch if multiplexed connection fails
864
- console.error(`Could not establish multiplexed connection.\nGot error: ${e}.\nFalling back to normal connection.`)
864
+ console.error(`Could not establish multiplexer.\nGot error: ${e}.\nFalling back to normal connection.`)
865
865
  return false
866
866
  }
867
867
  }
868
868
 
869
869
  // parse the multiplexed stream,
870
- // and send messages to the appropriate streams
871
- parse_multiplex_stream(r.body.getReader(), (stream, bytes) => {
872
- streams.get(stream)?.(bytes)
870
+ // and send messages to the appropriate requests
871
+ var try_deleting = new Set()
872
+ parse_multiplex_stream(r.body.getReader(), async (request, bytes) => {
873
+ if (requests.has(request)) {
874
+ requests.get(request)(bytes)
875
+ } else if (!try_deleting.has(request)) {
876
+ try_deleting.add(request)
877
+ try {
878
+ await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}/${request}`, {
879
+ method: 'DELETE',
880
+ headers: { 'Multiplex-Version': multiplex_version }, retry: true
881
+ })
882
+ } finally { try_deleting.delete(request) }
883
+ }
873
884
  }, e => {
874
885
  // the multiplexer stream has died.. let everyone know..
875
886
  mux_error = e
876
- for (var f of streams.values()) f()
887
+ for (var f of requests.values()) f()
877
888
  delete multiplex_fetch.multiplexers[mux_key]
878
889
  })
879
890
  })()
@@ -887,27 +898,27 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
887
898
  if ((await promise_done(mux_promise)) && (await mux_promise) === false && !params.headers.get('multiplex-at'))
888
899
  return await normal_fetch(url, params)
889
900
 
890
- // make up a new stream id (unless it is being overriden)
891
- var stream = params.headers.get('multiplex-at')?.split('/')[4] ?? Math.random().toString(36).slice(2)
901
+ // make up a new request id (unless it is being overriden)
902
+ var request = params.headers.get('multiplex-at')?.split('/')[4] ?? Math.random().toString(36).slice(2)
892
903
 
893
904
  // add the Multiplex-At header without affecting the underlying params
894
905
  var mux_headers = new Headers(params.headers)
895
- mux_headers.set('Multiplex-At', `/.well-known/multiplex/${multiplexer}/${stream}`)
906
+ mux_headers.set('Multiplex-At', `/.well-known/multiplex/${multiplexer}/${request}`)
896
907
  mux_headers.set('Multiplex-Version', multiplex_version)
897
908
  params = {...params, headers: mux_headers}
898
909
 
899
910
  // setup a way to receive incoming data from the multiplexer
900
911
  var buffers = []
901
912
  var bytes_available = () => {}
902
- var stream_error = null
913
+ var request_error = null
903
914
 
904
915
  // this utility calls the callback whenever new data is available to process
905
916
  async function process_buffers(cb) {
906
917
  while (true) {
907
918
  // wait for data if none is available
908
- if (!mux_error && !stream_error && !buffers.length)
919
+ if (!mux_error && !request_error && !buffers.length)
909
920
  await new Promise(done => bytes_available = done)
910
- if (mux_error || stream_error) throw (mux_error || stream_error)
921
+ if (mux_error || request_error) throw (mux_error || request_error)
911
922
 
912
923
  // process the data
913
924
  let ret = cb()
@@ -915,20 +926,18 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
915
926
  }
916
927
  }
917
928
 
918
- // tell the multiplexer to send bytes for this stream to us
919
- streams.set(stream, bytes => {
920
- if (!bytes) {
921
- streams.delete(stream)
922
- buffers.push(bytes)
923
- } else if (!mux_error) buffers.push(bytes)
929
+ // tell the multiplexer to send bytes for this request to us
930
+ requests.set(request, bytes => {
931
+ if (!bytes) buffers.push(bytes)
932
+ else if (!mux_error) buffers.push(bytes)
924
933
  bytes_available()
925
934
  })
926
935
 
927
936
  // prepare a function that we'll call to cleanly tear things down
928
937
  var unset = async e => {
929
938
  unset = () => {}
930
- streams.delete(stream)
931
- stream_error = e
939
+ requests.delete(request)
940
+ request_error = e
932
941
  bytes_available()
933
942
  try {
934
943
  var r = await braid_fetch(`${origin}${params.headers.get('multiplex-at')}`, {
@@ -939,7 +948,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
939
948
  if (!r.ok) throw new Error('status not ok: ' + r.status)
940
949
  if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
941
950
  } catch (e) {
942
- e = new Error(`Could not cancel multiplexed connection: ${e}`)
951
+ e = new Error(`Could not cancel multiplexed request: ${e}`)
943
952
  console.error('' + e)
944
953
  throw e
945
954
  }
@@ -947,9 +956,11 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
947
956
 
948
957
  // do the underlying fetch
949
958
  try {
959
+ var mux_was_done = await promise_done(mux_promise)
960
+
950
961
  var res = await normal_fetch(url, params)
951
962
 
952
- if (res.status === 424 && !(await promise_done(mux_promise))) {
963
+ if (res.status === 424 && !mux_was_done) {
953
964
  // this error will trigger a retry if the user is using that option
954
965
  throw new Error('multiplexer not yet connected')
955
966
  }
@@ -959,29 +970,29 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
959
970
  // fall back to as if it was a normal fetch
960
971
  if (res.ok && res.status !== 293) return res
961
972
 
962
- if (res.status !== 293) throw new Error('Could not establish multiplexed stream ' + params.headers.get('multiplex-at') + ', got status: ' + res.status)
973
+ if (res.status !== 293) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-at') + ', got status: ' + res.status)
963
974
 
964
- if (res.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('Could not establish multiplexed stream ' + params.headers.get('multiplex-at') + ', got unknown version: ' + res.headers.get('Multiplex-Version'))
975
+ if (res.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-at') + ', got unknown version: ' + res.headers.get('Multiplex-Version'))
965
976
 
966
977
  // we want to present the illusion that the connection is still open,
967
978
  // and therefor closable with "abort",
968
- // so we handle the abort ourselves to close the multiplexed stream
979
+ // so we handle the abort ourselves to close the multiplexed request
969
980
  params.signal?.addEventListener('abort', () =>
970
- unset(create_abort_error('stream aborted')))
981
+ unset(create_abort_error('request aborted')))
971
982
 
972
983
  // first, we need to listen for the headers..
973
984
  var headers_buffer = new Uint8Array()
974
985
  var parsed_headers = await process_buffers(() => {
975
- // check if the stream has been closed
976
- var stream_ended = !buffers[buffers.length - 1]
977
- if (stream_ended) buffers.pop()
986
+ // check if the request has been closed
987
+ var request_ended = !buffers[buffers.length - 1]
988
+ if (request_ended) buffers.pop()
978
989
 
979
990
  // aggregate all the new buffers into our big headers_buffer
980
991
  headers_buffer = concat_buffers([headers_buffer, ...buffers])
981
992
  buffers = []
982
993
 
983
- // and if the stream had ended, put that information back
984
- if (stream_ended) buffers.push(null)
994
+ // and if the request had ended, put that information back
995
+ if (request_ended) buffers.push(null)
985
996
 
986
997
  // try parsing what we got so far as headers..
987
998
  var x = parse_headers(headers_buffer)
@@ -992,7 +1003,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
992
1003
  console.log(`headers_buffer: ` + new TextDecoder().decode(headers_buffer))
993
1004
  throw new Error('error parsing headers')
994
1005
  } else if (x.result === 'waiting') {
995
- if (stream_ended) throw new Error('Multiplexed stream ended before headers received.')
1006
+ if (request_ended) throw new Error('Multiplexed request ended before headers received.')
996
1007
  } else return x
997
1008
  })
998
1009
 
@@ -1006,7 +1017,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
1006
1017
 
1007
1018
  // create our own fake response object,
1008
1019
  // to mimik fetch's response object,
1009
- // feeding the user our stream data from the multiplexer
1020
+ // feeding the user our request data from the multiplexer
1010
1021
  var res = new Response(new ReadableStream({
1011
1022
  async start(controller) {
1012
1023
  try {
@@ -1047,7 +1058,7 @@ async function parse_multiplex_stream(reader, cb, on_error) {
1047
1058
  var buffers = [new Uint8Array(0)]
1048
1059
  var buffers_size = 0
1049
1060
  var chunk_size = null
1050
- var stream_id = null
1061
+ var request_id = null
1051
1062
  var header_length = 0
1052
1063
  var header_started = false
1053
1064
 
@@ -1074,16 +1085,18 @@ async function parse_multiplex_stream(reader, cb, on_error) {
1074
1085
  }
1075
1086
  if (headerComplete) {
1076
1087
  var headerStr = new TextDecoder().decode(buffers[0].slice(0, header_length))
1077
- var m = headerStr.match(/^[\r\n]*((\d+) bytes for|close) request ([A-Za-z0-9_-]+)\r\n$/)
1088
+ var m = headerStr.match(/^[\r\n]*((\d+) bytes for|close|start) request ([A-Za-z0-9_-]+)\r\n$/)
1089
+
1078
1090
  if (!m) throw new Error('invalid multiplex header')
1079
- stream_id = m[3]
1091
+ request_id = m[3]
1080
1092
 
1081
1093
  buffers[0] = buffers[0].slice(header_length)
1082
1094
  buffers_size -= header_length
1083
1095
 
1084
- if (m[1] === 'close') {
1085
- cb(stream_id)
1086
- break
1096
+ if (m[1] === 'close' || m[1] === 'start') {
1097
+ cb(request_id, m[1] === 'start' ? new Uint8Array() : undefined)
1098
+ header_length = 0
1099
+ header_started = false
1087
1100
  } else chunk_size = 1 * m[2]
1088
1101
  } else break
1089
1102
  } else if (chunk_size !== null && buffers_size >= chunk_size) {
@@ -1093,12 +1106,11 @@ async function parse_multiplex_stream(reader, cb, on_error) {
1093
1106
  buffers[0] = buffers[0].slice(chunk_size)
1094
1107
  buffers_size -= chunk_size
1095
1108
 
1096
- // console.log(`stream_id: ${stream_id}, ${new TextDecoder().decode(chunk)}`)
1109
+ // console.log(`request_id: ${request_id}, ${new TextDecoder().decode(chunk)}`)
1097
1110
 
1098
- cb(stream_id, chunk)
1111
+ cb(request_id, chunk)
1099
1112
 
1100
1113
  chunk_size = null
1101
- stream_id = null
1102
1114
  header_length = 0
1103
1115
  header_started = false
1104
1116
  } else break
@@ -256,11 +256,11 @@ function braidify (req, res, next) {
256
256
  res.setHeader("Access-Control-Allow-Methods", "*")
257
257
  res.setHeader("Access-Control-Allow-Headers", "*")
258
258
 
259
- // parse the multiplexer id and stream id from the url
260
- var [multiplexer, stream] = req.url.split('/').slice(req.method === 'MULTIPLEX' ? 1 : 3)
259
+ // parse the multiplexer id and request id from the url
260
+ var [multiplexer, request] = req.url.split('/').slice(req.method === 'MULTIPLEX' ? 1 : 3)
261
261
 
262
262
  // if there's just a multiplexer, then we're creating a multiplexer..
263
- if (!stream) {
263
+ if (!request) {
264
264
  // maintain a Map of all the multiplexers
265
265
  if (!braidify.multiplexers) braidify.multiplexers = new Map()
266
266
 
@@ -274,12 +274,12 @@ function braidify (req, res, next) {
274
274
  }))
275
275
  }
276
276
 
277
- braidify.multiplexers.set(multiplexer, {streams: new Map(), res})
277
+ braidify.multiplexers.set(multiplexer, {requests: new Map(), res})
278
278
 
279
279
  // when the response closes,
280
280
  // let everyone know the multiplexer has died
281
281
  res.on('close', () => {
282
- for (var f of braidify.multiplexers.get(multiplexer).streams.values()) f()
282
+ for (var f of braidify.multiplexers.get(multiplexer).requests.values()) f()
283
283
  braidify.multiplexers.delete(multiplexer)
284
284
  })
285
285
 
@@ -293,11 +293,11 @@ function braidify (req, res, next) {
293
293
  ...req.httpVersion !== '2.0' && {'Connection': 'keep-alive'}
294
294
  })
295
295
 
296
- // but write something.. won't interfere with stream,
296
+ // but write something.. won't interfere with multiplexer,
297
297
  // and helps flush the headers
298
298
  return res.write(`\r\n`)
299
299
  } else {
300
- // in this case, we're closing the given stream
300
+ // in this case, we're closing the given request
301
301
 
302
302
  // if the multiplexer doesn't exist, send an error
303
303
  var m = braidify.multiplexers?.get(multiplexer)
@@ -306,15 +306,15 @@ function braidify (req, res, next) {
306
306
  return res.end(`multiplexer ${multiplexer} does not exist`)
307
307
  }
308
308
 
309
- // if the stream doesn't exist, send an error
310
- let s = m.streams.get(stream)
309
+ // if the request doesn't exist, send an error
310
+ let s = m.requests.get(request)
311
311
  if (!s) {
312
- res.writeHead(404, 'Stream no exist', {'Bad-Stream': stream})
313
- return res.end(`stream ${stream} does not exist`)
312
+ res.writeHead(404, 'Multiplexed request not found', {'Bad-Request': request})
313
+ return res.end(`request ${request} does not exist`)
314
314
  }
315
315
 
316
- // remove this stream, and notify it
317
- m.streams.delete(stream)
316
+ // remove this request, and notify it
317
+ m.requests.delete(request)
318
318
  s()
319
319
 
320
320
  // let the requester know we succeeded
@@ -323,15 +323,15 @@ function braidify (req, res, next) {
323
323
  }
324
324
  }
325
325
 
326
- // a multiplexer header means the user wants to send the
326
+ // a Multiplex-At header means the user wants to send the
327
327
  // results of this request to the provided multiplexer,
328
- // tagged with the given stream id
328
+ // tagged with the given request id
329
329
  if ((braidify.enable_multiplex ?? true) &&
330
330
  req.headers['multiplex-at'] &&
331
331
  req.headers['multiplex-version'] === multiplex_version) {
332
332
 
333
- // parse the multiplexer id and stream id from the header
334
- var [multiplexer, stream] = req.headers['multiplex-at'].split('/').slice(3)
333
+ // parse the multiplexer id and request id from the header
334
+ var [multiplexer, request] = req.headers['multiplex-at'].split('/').slice(3)
335
335
 
336
336
  // find the multiplexer object (contains a response object)
337
337
  var m = braidify.multiplexers?.get(multiplexer)
@@ -340,6 +340,8 @@ function braidify (req, res, next) {
340
340
  return res.end(`multiplexer ${multiplexer} does not exist`)
341
341
  }
342
342
 
343
+ m.res.write(`start request ${request}\r\n`)
344
+
343
345
  // let the requester know we've multiplexed their response
344
346
  var og_stream = res.stream
345
347
  var og_socket = res.socket
@@ -384,10 +386,10 @@ function braidify (req, res, next) {
384
386
 
385
387
  // first we create a kind of fake socket
386
388
  class MultiplexedWritable extends require('stream').Writable {
387
- constructor(multiplexer, stream) {
389
+ constructor(multiplexer, request) {
388
390
  super()
389
391
  this.multiplexer = multiplexer
390
- this.stream = stream
392
+ this.request = request
391
393
  }
392
394
 
393
395
  _write(chunk, encoding, callback) {
@@ -395,11 +397,11 @@ function braidify (req, res, next) {
395
397
 
396
398
  try {
397
399
  var len = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding)
398
- this.multiplexer.res.write(`${len} bytes for request ${this.stream}\r\n`)
400
+ this.multiplexer.res.write(`${len} bytes for request ${this.request}\r\n`)
399
401
  this.multiplexer.res.write(chunk, encoding, callback)
400
402
 
401
403
  // console.log(`wrote:`)
402
- // console.log(`${len} bytes for request /${this.stream}\r\n`)
404
+ // console.log(`${len} bytes for request /${this.request}\r\n`)
403
405
  // if (Buffer.isBuffer(chunk)) console.log(new TextDecoder().decode(chunk))
404
406
  // else console.log('STRING?: ' + chunk)
405
407
 
@@ -408,7 +410,7 @@ function braidify (req, res, next) {
408
410
  }
409
411
  }
410
412
  }
411
- var mw = new MultiplexedWritable(m, stream)
413
+ var mw = new MultiplexedWritable(m, request)
412
414
 
413
415
  // then we create a fake server response,
414
416
  // that pipes data to our fake socket
@@ -417,15 +419,15 @@ function braidify (req, res, next) {
417
419
  res2.assignSocket(mw)
418
420
 
419
421
  // register a handler for when the multiplexer closes,
420
- // to close our fake response stream
421
- m.streams.set(stream, () => {
422
+ // to close our fake response
423
+ m.requests.set(request, () => {
422
424
  og_res_end?.()
423
425
  res2.destroy()
424
426
  })
425
427
 
426
428
  // when our fake response is done,
427
429
  // we want to send a special message to the multiplexer saying so
428
- res2.on('finish', () => m.res.write(`close stream ${stream}\r\n`))
430
+ res2.on('finish', () => m.res.write(`close request ${request}\r\n`))
429
431
 
430
432
  // we want access to "res" to be forwarded to our fake "res2",
431
433
  // so that it goes into the multiplexer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.3.40",
3
+ "version": "1.3.42",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"