braid-http 1.3.53 → 1.3.55

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.
@@ -270,10 +270,6 @@ async function braid_fetch (url, params = {}) {
270
270
  !cb_running // if an error is thrown in the callback,
271
271
  // then it may not be good to reconnect, and generate more errors
272
272
 
273
- // some errors can be fixed by changing something, and retrying right away,
274
- // for instance, for a duplicate multiplexer request id
275
- if (e.dont_wait) waitTime = 0
276
-
277
273
  if (retry && !original_signal?.aborted) {
278
274
  // retry after some time..
279
275
  console.log(`retrying in ${waitTime}s: ${url} after error: ${e}`)
@@ -319,7 +315,7 @@ async function braid_fetch (url, params = {}) {
319
315
  (params.headers.has('subscribe') &&
320
316
  braid_fetch.subscription_counts?.[origin] >
321
317
  (!mux_params ? 1 : (mux_params.after ?? 0))))) {
322
- res = await multiplex_fetch(url, params, mux_params, underlying_aborter)
318
+ res = await multiplex_fetch(url, params, mux_params)
323
319
  } else
324
320
  res = await normal_fetch(url, params)
325
321
 
@@ -896,7 +892,7 @@ function random_base64url(n) {
896
892
 
897
893
  // multiplex_fetch provides a fetch-like experience for HTTP requests
898
894
  // where the result is actually being sent over a separate multiplexed connection.
899
- async function multiplex_fetch(url, params, mux_params, aborter) {
895
+ async function multiplex_fetch(url, params, mux_params) {
900
896
  var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
901
897
 
902
898
  // the mux_key is the same as the origin, unless it is being overriden
@@ -905,20 +901,33 @@ async function multiplex_fetch(url, params, mux_params, aborter) {
905
901
 
906
902
  // create a new multiplexer if it doesn't exist for this origin
907
903
  if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
908
- if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] =
909
- create_multiplexer(origin, mux_key, params, mux_params, aborter)
910
904
 
911
- // call the special fetch function for the multiplexer
912
- return await (await multiplex_fetch.multiplexers[mux_key])(url, params)
905
+ // this for-loop allows us to retry right away,
906
+ // in case of duplicate ids
907
+ for (let attempt = 1; ; attempt++) {
908
+ await new Promise(done => setTimeout(done, attempt >= 3 ? 1000 : 0))
909
+
910
+ if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] =
911
+ create_multiplexer(origin, mux_key, params, mux_params, attempt)
912
+
913
+ // call the special fetch function for the multiplexer
914
+ try {
915
+ return await (await multiplex_fetch.multiplexers[mux_key])(url, params, mux_params, attempt)
916
+ } catch (e) {
917
+ if (e === 'retry') continue
918
+ throw e
919
+ }
920
+ }
913
921
  }
914
922
 
915
923
  // returns a function with a fetch-like interface that transparently multiplexes the fetch
916
- async function create_multiplexer(origin, mux_key, params, mux_params, aborter) {
924
+ async function create_multiplexer(origin, mux_key, params, mux_params, attempt) {
917
925
  var multiplex_version = '1.0'
918
926
 
919
927
  // make up a new multiplexer id (unless it is being overriden)
920
- var multiplexer = params.headers.get('multiplex-through')?.split('/')[3]
921
- ?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
928
+ var multiplexer = (attempt === 1 &&
929
+ params.headers.get('multiplex-through')?.split('/')[3])
930
+ || random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
922
931
 
923
932
  var requests = new Map()
924
933
  var mux_error = null
@@ -926,8 +935,9 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
926
935
  var not_used_timeout = null
927
936
  var mux_aborter = new AbortController()
928
937
 
929
- function cleanup(e, stay_dead) {
938
+ function cleanup_multiplexer(e, stay_dead) {
930
939
  // the multiplexer stream has died.. let everyone know..
940
+ mux_aborter.abort()
931
941
  mux_error = e
932
942
  if (!stay_dead) delete multiplex_fetch.multiplexers[mux_key]
933
943
  for (var f of requests.values()) f()
@@ -969,7 +979,7 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
969
979
  if (r.status === 409) {
970
980
  var e = await r.json()
971
981
  if (e.error === 'Multiplexer already exists')
972
- return cleanup(create_error(e.error, {dont_wait: true}))
982
+ return cleanup_multiplexer('retry')
973
983
  }
974
984
  if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version)
975
985
  throw 'bad'
@@ -985,7 +995,7 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
985
995
  if (r.status === 409) {
986
996
  var e = await r.json()
987
997
  if (e.error === 'Multiplexer already exists')
988
- return cleanup(create_error(e.error, {dont_wait: true}))
998
+ return cleanup_multiplexer('retry')
989
999
  }
990
1000
  if (!r.ok) throw new Error('status not ok: ' + r.status)
991
1001
  if (r.headers.get('Multiplex-Version') !== multiplex_version)
@@ -996,7 +1006,7 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
996
1006
  // fallback to normal fetch if multiplexed connection fails
997
1007
  console.error(`Could not establish multiplexer.\n`
998
1008
  + `Got error: ${e}.\nFalling back to normal connection.`)
999
- cleanup(e, true)
1009
+ cleanup_multiplexer('retry', true)
1000
1010
  return false
1001
1011
  }
1002
1012
  }
@@ -1006,29 +1016,38 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
1006
1016
  parse_multiplex_stream(r.body.getReader(), async (request, bytes) => {
1007
1017
  if (requests.has(request)) requests.get(request)(bytes)
1008
1018
  else try_deleting_request(request)
1009
- }, e => cleanup(e))
1019
+ }, e => cleanup_multiplexer(e))
1010
1020
  })()
1011
1021
 
1012
1022
  // return a "fetch" for this multiplexer
1013
- return async (url, params) => {
1023
+ return async (url, params, mux_params, attempt) => {
1014
1024
 
1015
1025
  // if we already know the multiplexer is not working,
1016
1026
  // then fallback to normal fetch
1017
- // (unless the user is specifically asking for multiplexing)
1018
- if ((await promise_done(mux_promise))
1019
- && (await mux_promise) === false
1020
- && !params.headers.get('multiplex-through'))
1027
+ if ((await promise_done(mux_promise)) && (await mux_promise) === false) {
1028
+ // if the user is specifically asking for multiplexing,
1029
+ // throw an error instead
1030
+ if (params.headers.get('multiplex-through')) throw new Error('multiplexer failed')
1031
+
1021
1032
  return await normal_fetch(url, params)
1033
+ }
1022
1034
 
1023
1035
  // make up a new request id (unless it is being overriden)
1024
- var request = params.headers.get('multiplex-through')?.split('/')[4]
1025
- ?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
1036
+ var request = (attempt === 1
1037
+ && params.headers.get('multiplex-through')?.split('/')[4])
1038
+ || random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
1026
1039
 
1027
1040
  // add the Multiplex-Through header without affecting the underlying params
1028
1041
  var mux_headers = new Headers(params.headers)
1029
1042
  mux_headers.set('Multiplex-Through', `/.well-known/multiplexer/${multiplexer}/${request}`)
1030
1043
  mux_headers.set('Multiplex-Version', multiplex_version)
1031
- params = {...params, headers: mux_headers}
1044
+
1045
+ // also create our own aborter in case we need to abort ourselves
1046
+ var aborter = new AbortController()
1047
+ params.signal?.addEventListener('abort', () => aborter.abort())
1048
+
1049
+ // now create a new params with the new headers and abort signal
1050
+ params = {...params, headers: mux_headers, signal: aborter.signal}
1032
1051
 
1033
1052
  // setup a way to receive incoming data from the multiplexer
1034
1053
  var buffers = []
@@ -1066,11 +1085,16 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
1066
1085
  if (!requests.size) not_used_timeout = setTimeout(() => mux_aborter.abort(), mux_params?.not_used_timeout ?? 1000 * 20)
1067
1086
  request_error = e
1068
1087
  bytes_available()
1069
- await try_deleting_request(request)
1088
+ if (e !== 'retry') await try_deleting_request(request)
1070
1089
  }
1071
1090
 
1072
1091
  // do the underlying fetch
1073
1092
  try {
1093
+ var mux_was_done = await promise_done(mux_promise)
1094
+
1095
+ // callback for testing
1096
+ mux_params?.onFetch?.(url, params)
1097
+
1074
1098
  var res = await normal_fetch(url, params)
1075
1099
 
1076
1100
  if (res.status === 409) {
@@ -1078,7 +1102,7 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
1078
1102
  if (e.error === 'Request already multiplexed') {
1079
1103
  // the id is already in use,
1080
1104
  // so we want to retry right away with a different id
1081
- throw create_error(e.error, {dont_wait: true})
1105
+ throw "retry"
1082
1106
  }
1083
1107
  }
1084
1108
 
@@ -1087,7 +1111,18 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
1087
1111
  // could be we arrived before the multiplexer,
1088
1112
  // or after it was shutdown;
1089
1113
  // in either case we want to retry right away
1090
- throw create_error('multiplexer not connected', {dont_wait: true})
1114
+
1115
+ // but before we do,
1116
+ // if we know the multiplexer was created,
1117
+ // but it isn't there now,
1118
+ // and our client doesn't realize it,
1119
+ // then shut it down ourselves before retrying,
1120
+ // so when we retry,
1121
+ // a new multiplexer is created
1122
+ if (mux_was_done && !mux_error)
1123
+ cleanup_multiplexer(new Error('multiplexer detected to be closed'))
1124
+
1125
+ throw "retry"
1091
1126
  }
1092
1127
 
1093
1128
  // if the response says it's ok,
@@ -1172,14 +1207,14 @@ async function create_multiplexer(origin, mux_key, params, mux_params, aborter)
1172
1207
 
1173
1208
  // add a convenience property for the user to know if
1174
1209
  // this response is being multiplexed
1175
- res.is_multiplexed = true
1210
+ res.multiplexed_through = params.headers.get('multiplex-through')
1176
1211
 
1177
1212
  // return the fake response object
1178
1213
  return res
1179
1214
  } catch (e) {
1180
1215
  // if we had an error, be sure to unregister ourselves
1181
1216
  unset(e)
1182
- throw mux_error || e
1217
+ throw (e === 'retry' && e) || mux_error || e
1183
1218
  }
1184
1219
  }
1185
1220
  }
@@ -374,6 +374,7 @@ function braidify (req, res, next) {
374
374
  ':status': 293,
375
375
  'Multiplex-Through': req.headers['multiplex-through'],
376
376
  'Multiplex-Version': multiplex_version,
377
+ 'Cache-Control': 'no-store',
377
378
  ...Object.fromEntries(cors_headers)
378
379
  })
379
380
  og_stream.write('Ok.')
@@ -382,6 +383,7 @@ function braidify (req, res, next) {
382
383
  og_socket.write('HTTP/1.1 293 Responded via multiplexer\r\n')
383
384
  og_socket.write(`Multiplex-Through: ${req.headers['multiplex-through']}\r\n`)
384
385
  og_socket.write(`Multiplex-Version: ${multiplex_version}\r\n`)
386
+ og_socket.write(`Cache-Control: no-store\r\n`)
385
387
  cors_headers.forEach(([key, value]) =>
386
388
  og_socket.write(`${key}: ${value}\r\n`))
387
389
  og_socket.write('\r\n')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.3.53",
3
+ "version": "1.3.55",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"