braid-http 1.3.45 → 1.3.47

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.
@@ -1,4 +1,3 @@
1
- // var peer = Math.random().toString(36).substr(2)
2
1
 
3
2
  // ***************************
4
3
  // http
@@ -316,7 +315,7 @@ async function braid_fetch (url, params = {}) {
316
315
  (params.headers.has('subscribe') &&
317
316
  braid_fetch.subscription_counts?.[origin] >
318
317
  (!mux_params ? 1 : (mux_params.after ?? 0))))) {
319
- res = await multiplex_fetch(url, params, mux_params?.via === 'POST')
318
+ res = await multiplex_fetch(url, params, mux_params)
320
319
  } else
321
320
  res = await normal_fetch(url, params)
322
321
 
@@ -833,7 +832,7 @@ function parse_body (state) {
833
832
 
834
833
  // multiplex_fetch provides a fetch-like experience for HTTP requests
835
834
  // where the result is actually being sent over a separate multiplexed connection.
836
- async function multiplex_fetch(url, params, skip_multiplex_method) {
835
+ async function multiplex_fetch(url, params, mux_params) {
837
836
  var multiplex_version = '1.0'
838
837
 
839
838
  var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
@@ -848,31 +847,69 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
848
847
  async () => {
849
848
  // make up a new multiplexer id (unless it is being overriden)
850
849
  var multiplexer = params.headers.get('multiplex-through')?.split('/')[3]
851
- ?? Math.random().toString(36).slice(2)
850
+ ?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
852
851
 
853
852
  var requests = new Map()
854
853
  var mux_error = null
854
+ var try_deleting = new Set()
855
+
856
+ function cleanup(e, stay_dead) {
857
+ // the multiplexer stream has died.. let everyone know..
858
+ mux_error = e
859
+ if (!stay_dead) delete multiplex_fetch.multiplexers[mux_key]
860
+ for (var f of requests.values()) f()
861
+ }
862
+
863
+ async function try_deleting_request(request) {
864
+ if (!try_deleting.has(request)) {
865
+ try_deleting.add(request)
866
+ try {
867
+ var r = await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}/${request}`, {
868
+ method: 'DELETE',
869
+ headers: { 'Multiplex-Version': multiplex_version },
870
+ retry: true
871
+ })
872
+
873
+ if (!r.ok) throw new Error('status not ok: ' + r.status)
874
+ if (r.headers.get('Multiplex-Version') !== multiplex_version)
875
+ throw new Error('wrong multiplex version: '
876
+ + r.headers.get('Multiplex-Version')
877
+ + ', expected ' + multiplex_version)
878
+ } catch (e) {
879
+ e = new Error(`Could not cancel multiplexed request: ${e}`)
880
+ console.error('' + e)
881
+ throw e
882
+ } finally { try_deleting.delete(request) }
883
+ }
884
+ }
855
885
 
856
886
  var mux_promise = (async () => {
857
887
  // attempt to establish a multiplexed connection
858
888
  try {
859
- if (skip_multiplex_method) throw 'skip multiplex method'
889
+ if (mux_params?.via === 'POST') throw 'skip multiplex method'
860
890
  var r = await braid_fetch(`${origin}/${multiplexer}`, {
861
891
  method: 'MULTIPLEX',
862
892
  headers: {'Multiplex-Version': multiplex_version},
863
893
  retry: true
864
894
  })
895
+ if (r.status === 409) {
896
+ var e = await r.json()
897
+ if (e.error === 'Multiplexer already exists') return cleanup(new Error(e.error))
898
+ }
865
899
  if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version)
866
900
  throw 'bad'
867
901
  } catch (e) {
868
902
  // some servers don't like custom methods,
869
- // so let's try with a custom header
903
+ // so let's try with a well-known url
870
904
  try {
871
905
  r = await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}`,
872
906
  {method: 'POST',
873
907
  headers: {'Multiplex-Version': multiplex_version},
874
908
  retry: true})
875
-
909
+ if (r.status === 409) {
910
+ var e = await r.json()
911
+ if (e.error === 'Multiplexer already exists') return cleanup(new Error(e.error))
912
+ }
876
913
  if (!r.ok) throw new Error('status not ok: ' + r.status)
877
914
  if (r.headers.get('Multiplex-Version') !== multiplex_version)
878
915
  throw new Error('wrong multiplex version: '
@@ -882,7 +919,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
882
919
  // fallback to normal fetch if multiplexed connection fails
883
920
  console.error(`Could not establish multiplexer.\n`
884
921
  + `Got error: ${e}.\nFalling back to normal connection.`)
885
- return false
922
+ return cleanup(e, true)
886
923
  }
887
924
  }
888
925
 
@@ -890,40 +927,17 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
890
927
  // and send messages to the appropriate requests
891
928
  var try_deleting = new Set()
892
929
  parse_multiplex_stream(r.body.getReader(), async (request, bytes) => {
893
- if (requests.has(request)) {
894
- requests.get(request)(bytes)
895
- } else if (!try_deleting.has(request)) {
896
- try_deleting.add(request)
897
- try {
898
- await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}/${request}`, {
899
- method: 'DELETE',
900
- headers: { 'Multiplex-Version': multiplex_version },
901
- retry: true
902
- })
903
- } finally { try_deleting.delete(request) }
904
- }
905
- }, e => {
906
- // the multiplexer stream has died.. let everyone know..
907
- mux_error = e
908
- for (var f of requests.values()) f()
909
- delete multiplex_fetch.multiplexers[mux_key]
910
- })
930
+ if (requests.has(request)) requests.get(request)(bytes)
931
+ else try_deleting_request(request)
932
+ }, e => cleanup(e))
911
933
  })()
912
934
 
913
935
  // return a "fetch" for this multiplexer
914
936
  return async (url, params) => {
915
937
 
916
- // if we already know the multiplexer is not working,
917
- // then fallback to normal fetch
918
- // (unless the user is specifically asking for multiplexing)
919
- if ((await promise_done(mux_promise))
920
- && (await mux_promise) === false
921
- && !params.headers.get('multiplex-through'))
922
- return await normal_fetch(url, params)
923
-
924
938
  // make up a new request id (unless it is being overriden)
925
939
  var request = params.headers.get('multiplex-through')?.split('/')[4]
926
- ?? Math.random().toString(36).slice(2)
940
+ ?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
927
941
 
928
942
  // add the Multiplex-Through header without affecting the underlying params
929
943
  var mux_headers = new Headers(params.headers)
@@ -963,22 +977,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
963
977
  requests.delete(request)
964
978
  request_error = e
965
979
  bytes_available()
966
- try {
967
- var r = await braid_fetch(`${origin}${params.headers.get('multiplex-through')}`, {
968
- method: 'DELETE',
969
- headers: { 'Multiplex-Version': multiplex_version }, retry: true
970
- })
971
-
972
- if (!r.ok) throw new Error('status not ok: ' + r.status)
973
- if (r.headers.get('Multiplex-Version') !== multiplex_version)
974
- throw new Error('wrong multiplex version: '
975
- + r.headers.get('Multiplex-Version')
976
- + ', expected ' + multiplex_version)
977
- } catch (e) {
978
- e = new Error(`Could not cancel multiplexed request: ${e}`)
979
- console.error('' + e)
980
- throw e
981
- }
980
+ await try_deleting_request(request)
982
981
  }
983
982
 
984
983
  // do the underlying fetch
@@ -1218,6 +1217,10 @@ async function promise_done(promise) {
1218
1217
  return ret !== pending
1219
1218
  }
1220
1219
 
1220
+ function random_base64url(n) {
1221
+ return [...crypto.getRandomValues(new Uint8Array(n))].map(x => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'[x % 64]).join('')
1222
+ }
1223
+
1221
1224
  // ****************************
1222
1225
  // Exports
1223
1226
  // ****************************
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.3.45",
3
+ "version": "1.3.47",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"