braid-http 1.3.44 → 1.3.45
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 +233 -198
- package/braid-http-server.js +4 -5
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -163,7 +163,10 @@ async function braid_fetch (url, params = {}) {
|
|
|
163
163
|
params.headers.set('peer', params.peer)
|
|
164
164
|
|
|
165
165
|
if (params.heartbeats)
|
|
166
|
-
params.headers.set('heartbeats',
|
|
166
|
+
params.headers.set('heartbeats',
|
|
167
|
+
typeof params.heartbeats === 'number'
|
|
168
|
+
? `${params.heartbeats}s`
|
|
169
|
+
: params.heartbeats)
|
|
167
170
|
|
|
168
171
|
// Prevent browsers from going to disk cache
|
|
169
172
|
params.cache = 'no-cache'
|
|
@@ -262,7 +265,7 @@ async function braid_fetch (url, params = {}) {
|
|
|
262
265
|
underlying_aborter?.abort()
|
|
263
266
|
|
|
264
267
|
// see if we should retry..
|
|
265
|
-
var retry = params.retry &&
|
|
268
|
+
var retry = params.retry && // only try to reconnect if the user has chosen to
|
|
266
269
|
e.name !== "AbortError" && // don't retry if the user has chosen to abort
|
|
267
270
|
!e.startsWith?.('Parse error in headers') && // in this case, the server is spewing garbage, so reconnecting might be bad
|
|
268
271
|
!e.message?.startsWith?.('Could not establish multiplexed request') && // the server has told us no, or is using a different version of multiplexing
|
|
@@ -314,9 +317,8 @@ async function braid_fetch (url, params = {}) {
|
|
|
314
317
|
braid_fetch.subscription_counts?.[origin] >
|
|
315
318
|
(!mux_params ? 1 : (mux_params.after ?? 0))))) {
|
|
316
319
|
res = await multiplex_fetch(url, params, mux_params?.via === 'POST')
|
|
317
|
-
} else
|
|
320
|
+
} else
|
|
318
321
|
res = await normal_fetch(url, params)
|
|
319
|
-
}
|
|
320
322
|
|
|
321
323
|
// And customize the response with a couple methods for getting
|
|
322
324
|
// the braid subscription data:
|
|
@@ -338,7 +340,7 @@ async function braid_fetch (url, params = {}) {
|
|
|
338
340
|
clearTimeout(timeout)
|
|
339
341
|
let wait_seconds = 1.2 * heartbeats + 3
|
|
340
342
|
timeout = setTimeout(() => {
|
|
341
|
-
on_error(new Error(`heartbeat
|
|
343
|
+
on_error(new Error(`heartbeat seen in ${wait_seconds.toFixed(2)}s`))
|
|
342
344
|
}, wait_seconds * 1000)
|
|
343
345
|
}
|
|
344
346
|
on_heartbeat()
|
|
@@ -361,7 +363,8 @@ async function braid_fetch (url, params = {}) {
|
|
|
361
363
|
async (result, err) => {
|
|
362
364
|
if (!err) {
|
|
363
365
|
// check whether we aborted
|
|
364
|
-
if (original_signal?.aborted)
|
|
366
|
+
if (original_signal?.aborted)
|
|
367
|
+
throw create_abort_error('already aborted')
|
|
365
368
|
|
|
366
369
|
// Yay! We got a new version! Tell the callback!
|
|
367
370
|
cb_running = true
|
|
@@ -540,7 +543,8 @@ var subscription_parser = (cb) => ({
|
|
|
540
543
|
|
|
541
544
|
Object.defineProperty(update, 'body_text', {
|
|
542
545
|
get: function () {
|
|
543
|
-
if (this.body != null)
|
|
546
|
+
if (this.body != null)
|
|
547
|
+
return new TextDecoder('utf-8').decode(this.body.buffer)
|
|
544
548
|
}
|
|
545
549
|
})
|
|
546
550
|
|
|
@@ -634,7 +638,9 @@ function parse_headers (input) {
|
|
|
634
638
|
|
|
635
639
|
// Extract the header string
|
|
636
640
|
var headers_source = input.slice(start, end)
|
|
637
|
-
headers_source = Array.isArray(headers_source)
|
|
641
|
+
headers_source = Array.isArray(headers_source)
|
|
642
|
+
? headers_source.map(x => String.fromCharCode(x)).join('')
|
|
643
|
+
: new TextDecoder().decode(headers_source)
|
|
638
644
|
|
|
639
645
|
// Convert "HTTP 200 OK" to a :status: 200 header
|
|
640
646
|
headers_source = headers_source.replace(/^HTTP\/?\d*\.?\d* (\d\d\d).*\r?\n/,
|
|
@@ -837,215 +843,244 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
837
843
|
var mux_key = params.headers.get('multiplex-through')?.split('/')[3] ?? origin
|
|
838
844
|
|
|
839
845
|
// create a new multiplexer if it doesn't exist for this origin
|
|
840
|
-
if (!multiplex_fetch.multiplexers)
|
|
841
|
-
if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', headers: {'Multiplex-Version': multiplex_version}, retry: true})
|
|
853
|
-
if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version) throw 'bad'
|
|
854
|
-
} catch (e) {
|
|
855
|
-
// some servers don't like custom methods,
|
|
856
|
-
// so let's try with a custom header
|
|
846
|
+
if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
|
|
847
|
+
if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (
|
|
848
|
+
async () => {
|
|
849
|
+
// make up a new multiplexer id (unless it is being overriden)
|
|
850
|
+
var multiplexer = params.headers.get('multiplex-through')?.split('/')[3]
|
|
851
|
+
?? Math.random().toString(36).slice(2)
|
|
852
|
+
|
|
853
|
+
var requests = new Map()
|
|
854
|
+
var mux_error = null
|
|
855
|
+
|
|
856
|
+
var mux_promise = (async () => {
|
|
857
|
+
// attempt to establish a multiplexed connection
|
|
857
858
|
try {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
859
|
+
if (skip_multiplex_method) throw 'skip multiplex method'
|
|
860
|
+
var r = await braid_fetch(`${origin}/${multiplexer}`, {
|
|
861
|
+
method: 'MULTIPLEX',
|
|
862
|
+
headers: {'Multiplex-Version': multiplex_version},
|
|
863
|
+
retry: true
|
|
864
|
+
})
|
|
865
|
+
if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version)
|
|
866
|
+
throw 'bad'
|
|
862
867
|
} catch (e) {
|
|
863
|
-
//
|
|
864
|
-
|
|
865
|
-
|
|
868
|
+
// some servers don't like custom methods,
|
|
869
|
+
// so let's try with a custom header
|
|
870
|
+
try {
|
|
871
|
+
r = await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}`,
|
|
872
|
+
{method: 'POST',
|
|
873
|
+
headers: {'Multiplex-Version': multiplex_version},
|
|
874
|
+
retry: true})
|
|
875
|
+
|
|
876
|
+
if (!r.ok) throw new Error('status not ok: ' + r.status)
|
|
877
|
+
if (r.headers.get('Multiplex-Version') !== multiplex_version)
|
|
878
|
+
throw new Error('wrong multiplex version: '
|
|
879
|
+
+ r.headers.get('Multiplex-Version')
|
|
880
|
+
+ ', expected ' + multiplex_version)
|
|
881
|
+
} catch (e) {
|
|
882
|
+
// fallback to normal fetch if multiplexed connection fails
|
|
883
|
+
console.error(`Could not establish multiplexer.\n`
|
|
884
|
+
+ `Got error: ${e}.\nFalling back to normal connection.`)
|
|
885
|
+
return false
|
|
886
|
+
}
|
|
866
887
|
}
|
|
867
|
-
}
|
|
868
888
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
889
|
+
// parse the multiplexed stream,
|
|
890
|
+
// and send messages to the appropriate requests
|
|
891
|
+
var try_deleting = new Set()
|
|
892
|
+
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
|
+
})
|
|
911
|
+
})()
|
|
912
|
+
|
|
913
|
+
// return a "fetch" for this multiplexer
|
|
914
|
+
return async (url, params) => {
|
|
915
|
+
|
|
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
|
+
// make up a new request id (unless it is being overriden)
|
|
925
|
+
var request = params.headers.get('multiplex-through')?.split('/')[4]
|
|
926
|
+
?? Math.random().toString(36).slice(2)
|
|
927
|
+
|
|
928
|
+
// add the Multiplex-Through header without affecting the underlying params
|
|
929
|
+
var mux_headers = new Headers(params.headers)
|
|
930
|
+
mux_headers.set('Multiplex-Through', `/.well-known/multiplexer/${multiplexer}/${request}`)
|
|
931
|
+
mux_headers.set('Multiplex-Version', multiplex_version)
|
|
932
|
+
params = {...params, headers: mux_headers}
|
|
933
|
+
|
|
934
|
+
// setup a way to receive incoming data from the multiplexer
|
|
935
|
+
var buffers = []
|
|
936
|
+
var bytes_available = () => {}
|
|
937
|
+
var request_error = null
|
|
938
|
+
|
|
939
|
+
// this utility calls the callback whenever new data is available to process
|
|
940
|
+
async function process_buffers(cb) {
|
|
941
|
+
while (true) {
|
|
942
|
+
// wait for data if none is available
|
|
943
|
+
if (!mux_error && !request_error && !buffers.length)
|
|
944
|
+
await new Promise(done => bytes_available = done)
|
|
945
|
+
if (mux_error || request_error) throw (mux_error || request_error)
|
|
946
|
+
|
|
947
|
+
// process the data
|
|
948
|
+
let ret = cb()
|
|
949
|
+
if (ret) return ret
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// tell the multiplexer to send bytes for this request to us
|
|
954
|
+
requests.set(request, bytes => {
|
|
955
|
+
if (!bytes) buffers.push(bytes)
|
|
956
|
+
else if (!mux_error) buffers.push(bytes)
|
|
957
|
+
bytes_available()
|
|
958
|
+
})
|
|
959
|
+
|
|
960
|
+
// prepare a function that we'll call to cleanly tear things down
|
|
961
|
+
var unset = async e => {
|
|
962
|
+
unset = () => {}
|
|
963
|
+
requests.delete(request)
|
|
964
|
+
request_error = e
|
|
965
|
+
bytes_available()
|
|
877
966
|
try {
|
|
878
|
-
await braid_fetch(`${origin}
|
|
967
|
+
var r = await braid_fetch(`${origin}${params.headers.get('multiplex-through')}`, {
|
|
879
968
|
method: 'DELETE',
|
|
880
969
|
headers: { 'Multiplex-Version': multiplex_version }, retry: true
|
|
881
970
|
})
|
|
882
|
-
} finally { try_deleting.delete(request) }
|
|
883
|
-
}
|
|
884
|
-
}, e => {
|
|
885
|
-
// the multiplexer stream has died.. let everyone know..
|
|
886
|
-
mux_error = e
|
|
887
|
-
for (var f of requests.values()) f()
|
|
888
|
-
delete multiplex_fetch.multiplexers[mux_key]
|
|
889
|
-
})
|
|
890
|
-
})()
|
|
891
971
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
var request = params.headers.get('multiplex-through')?.split('/')[4] ?? Math.random().toString(36).slice(2)
|
|
903
|
-
|
|
904
|
-
// add the Multiplex-Through header without affecting the underlying params
|
|
905
|
-
var mux_headers = new Headers(params.headers)
|
|
906
|
-
mux_headers.set('Multiplex-Through', `/.well-known/multiplexer/${multiplexer}/${request}`)
|
|
907
|
-
mux_headers.set('Multiplex-Version', multiplex_version)
|
|
908
|
-
params = {...params, headers: mux_headers}
|
|
909
|
-
|
|
910
|
-
// setup a way to receive incoming data from the multiplexer
|
|
911
|
-
var buffers = []
|
|
912
|
-
var bytes_available = () => {}
|
|
913
|
-
var request_error = null
|
|
914
|
-
|
|
915
|
-
// this utility calls the callback whenever new data is available to process
|
|
916
|
-
async function process_buffers(cb) {
|
|
917
|
-
while (true) {
|
|
918
|
-
// wait for data if none is available
|
|
919
|
-
if (!mux_error && !request_error && !buffers.length)
|
|
920
|
-
await new Promise(done => bytes_available = done)
|
|
921
|
-
if (mux_error || request_error) throw (mux_error || request_error)
|
|
922
|
-
|
|
923
|
-
// process the data
|
|
924
|
-
let ret = cb()
|
|
925
|
-
if (ret) return ret
|
|
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
|
+
}
|
|
926
982
|
}
|
|
927
|
-
}
|
|
928
983
|
|
|
929
|
-
|
|
930
|
-
requests.set(request, bytes => {
|
|
931
|
-
if (!bytes) buffers.push(bytes)
|
|
932
|
-
else if (!mux_error) buffers.push(bytes)
|
|
933
|
-
bytes_available()
|
|
934
|
-
})
|
|
935
|
-
|
|
936
|
-
// prepare a function that we'll call to cleanly tear things down
|
|
937
|
-
var unset = async e => {
|
|
938
|
-
unset = () => {}
|
|
939
|
-
requests.delete(request)
|
|
940
|
-
request_error = e
|
|
941
|
-
bytes_available()
|
|
984
|
+
// do the underlying fetch
|
|
942
985
|
try {
|
|
943
|
-
var
|
|
944
|
-
method: 'DELETE',
|
|
945
|
-
headers: { 'Multiplex-Version': multiplex_version }, retry: true
|
|
946
|
-
})
|
|
986
|
+
var mux_was_done = await promise_done(mux_promise)
|
|
947
987
|
|
|
948
|
-
|
|
949
|
-
if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
|
|
950
|
-
} catch (e) {
|
|
951
|
-
e = new Error(`Could not cancel multiplexed request: ${e}`)
|
|
952
|
-
console.error('' + e)
|
|
953
|
-
throw e
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// do the underlying fetch
|
|
958
|
-
try {
|
|
959
|
-
var mux_was_done = await promise_done(mux_promise)
|
|
960
|
-
|
|
961
|
-
var res = await normal_fetch(url, params)
|
|
988
|
+
var res = await normal_fetch(url, params)
|
|
962
989
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
// if the response says it's ok,
|
|
969
|
-
// but it's is not a multiplexed response,
|
|
970
|
-
// fall back to as if it was a normal fetch
|
|
971
|
-
if (res.ok && res.status !== 293) return res
|
|
972
|
-
|
|
973
|
-
if (res.status !== 293) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-through') + ', got status: ' + res.status)
|
|
974
|
-
|
|
975
|
-
if (res.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-through') + ', got unknown version: ' + res.headers.get('Multiplex-Version'))
|
|
976
|
-
|
|
977
|
-
// we want to present the illusion that the connection is still open,
|
|
978
|
-
// and therefor closable with "abort",
|
|
979
|
-
// so we handle the abort ourselves to close the multiplexed request
|
|
980
|
-
params.signal?.addEventListener('abort', () =>
|
|
981
|
-
unset(create_abort_error('request aborted')))
|
|
982
|
-
|
|
983
|
-
// first, we need to listen for the headers..
|
|
984
|
-
var headers_buffer = new Uint8Array()
|
|
985
|
-
var parsed_headers = await process_buffers(() => {
|
|
986
|
-
// check if the request has been closed
|
|
987
|
-
var request_ended = !buffers[buffers.length - 1]
|
|
988
|
-
if (request_ended) buffers.pop()
|
|
989
|
-
|
|
990
|
-
// aggregate all the new buffers into our big headers_buffer
|
|
991
|
-
headers_buffer = concat_buffers([headers_buffer, ...buffers])
|
|
992
|
-
buffers = []
|
|
993
|
-
|
|
994
|
-
// and if the request had ended, put that information back
|
|
995
|
-
if (request_ended) buffers.push(null)
|
|
996
|
-
|
|
997
|
-
// try parsing what we got so far as headers..
|
|
998
|
-
var x = parse_headers(headers_buffer)
|
|
999
|
-
|
|
1000
|
-
// how did it go?
|
|
1001
|
-
if (x.result === 'error') {
|
|
1002
|
-
// if we got an error, give up
|
|
1003
|
-
console.log(`headers_buffer: ` + new TextDecoder().decode(headers_buffer))
|
|
1004
|
-
throw new Error('error parsing headers')
|
|
1005
|
-
} else if (x.result === 'waiting') {
|
|
1006
|
-
if (request_ended) throw new Error('Multiplexed request ended before headers received.')
|
|
1007
|
-
} else return x
|
|
1008
|
-
})
|
|
1009
|
-
|
|
1010
|
-
// put the bytes left over from the header back
|
|
1011
|
-
if (parsed_headers.input.length) buffers.unshift(parsed_headers.input)
|
|
990
|
+
if (res.status === 424 && !mux_was_done) {
|
|
991
|
+
// this error will trigger a retry if the user is using that option
|
|
992
|
+
throw new Error('multiplexer not yet connected')
|
|
993
|
+
}
|
|
1012
994
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
995
|
+
// if the response says it's ok,
|
|
996
|
+
// but it's is not a multiplexed response,
|
|
997
|
+
// fall back to as if it was a normal fetch
|
|
998
|
+
if (res.ok && res.status !== 293) return res
|
|
999
|
+
|
|
1000
|
+
if (res.status !== 293)
|
|
1001
|
+
throw new Error('Could not establish multiplexed request '
|
|
1002
|
+
+ params.headers.get('multiplex-through')
|
|
1003
|
+
+ ', got status: ' + res.status)
|
|
1004
|
+
|
|
1005
|
+
if (res.headers.get('Multiplex-Version') !== multiplex_version)
|
|
1006
|
+
throw new Error('Could not establish multiplexed request '
|
|
1007
|
+
+ params.headers.get('multiplex-through')
|
|
1008
|
+
+ ', got unknown version: '
|
|
1009
|
+
+ res.headers.get('Multiplex-Version'))
|
|
1010
|
+
|
|
1011
|
+
// we want to present the illusion that the connection is still open,
|
|
1012
|
+
// and therefor closable with "abort",
|
|
1013
|
+
// so we handle the abort ourselves to close the multiplexed request
|
|
1014
|
+
params.signal?.addEventListener('abort', () =>
|
|
1015
|
+
unset(create_abort_error('request aborted')))
|
|
1016
|
+
|
|
1017
|
+
// first, we need to listen for the headers..
|
|
1018
|
+
var headers_buffer = new Uint8Array()
|
|
1019
|
+
var parsed_headers = await process_buffers(() => {
|
|
1020
|
+
// check if the request has been closed
|
|
1021
|
+
var request_ended = !buffers[buffers.length - 1]
|
|
1022
|
+
if (request_ended) buffers.pop()
|
|
1023
|
+
|
|
1024
|
+
// aggregate all the new buffers into our big headers_buffer
|
|
1025
|
+
headers_buffer = concat_buffers([headers_buffer, ...buffers])
|
|
1026
|
+
buffers = []
|
|
1027
|
+
|
|
1028
|
+
// and if the request had ended, put that information back
|
|
1029
|
+
if (request_ended) buffers.push(null)
|
|
1030
|
+
|
|
1031
|
+
// try parsing what we got so far as headers..
|
|
1032
|
+
var x = parse_headers(headers_buffer)
|
|
1033
|
+
|
|
1034
|
+
// how did it go?
|
|
1035
|
+
if (x.result === 'error') {
|
|
1036
|
+
// if we got an error, give up
|
|
1037
|
+
console.log(`headers_buffer: ` + new TextDecoder().decode(headers_buffer))
|
|
1038
|
+
throw new Error('error parsing headers')
|
|
1039
|
+
} else if (x.result === 'waiting') {
|
|
1040
|
+
if (request_ended)
|
|
1041
|
+
throw new Error('Multiplexed request ended before headers received.')
|
|
1042
|
+
} else return x
|
|
1043
|
+
})
|
|
1017
1044
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1045
|
+
// put the bytes left over from the header back
|
|
1046
|
+
if (parsed_headers.input.length) buffers.unshift(parsed_headers.input)
|
|
1047
|
+
|
|
1048
|
+
// these headers will also have the status,
|
|
1049
|
+
// but we want to present the status in a more usual way below
|
|
1050
|
+
var status = parsed_headers.headers[':status']
|
|
1051
|
+
delete parsed_headers.headers[':status']
|
|
1052
|
+
|
|
1053
|
+
// create our own fake response object,
|
|
1054
|
+
// to mimik fetch's response object,
|
|
1055
|
+
// feeding the user our request data from the multiplexer
|
|
1056
|
+
var res = new Response(new ReadableStream({
|
|
1057
|
+
async start(controller) {
|
|
1058
|
+
try {
|
|
1059
|
+
await process_buffers(() => {
|
|
1060
|
+
var b = buffers.shift()
|
|
1061
|
+
if (!b) return true
|
|
1062
|
+
controller.enqueue(b)
|
|
1063
|
+
})
|
|
1064
|
+
} finally { controller.close() }
|
|
1065
|
+
}
|
|
1066
|
+
}), {
|
|
1067
|
+
status,
|
|
1068
|
+
headers: parsed_headers.headers
|
|
1069
|
+
})
|
|
1035
1070
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1071
|
+
// add a convenience property for the user to know if
|
|
1072
|
+
// this response is being multiplexed
|
|
1073
|
+
res.is_multiplexed = true
|
|
1039
1074
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1075
|
+
// return the fake response object
|
|
1076
|
+
return res
|
|
1077
|
+
} catch (e) {
|
|
1078
|
+
// if we had an error, be sure to unregister ourselves
|
|
1079
|
+
unset(e)
|
|
1080
|
+
throw e
|
|
1081
|
+
}
|
|
1046
1082
|
}
|
|
1047
|
-
}
|
|
1048
|
-
})()
|
|
1083
|
+
})()
|
|
1049
1084
|
|
|
1050
1085
|
// call the special fetch function for the multiplexer
|
|
1051
1086
|
return await (await multiplex_fetch.multiplexers[mux_key])(url, params)
|
package/braid-http-server.js
CHANGED
|
@@ -269,8 +269,7 @@ function braidify (req, res, next) {
|
|
|
269
269
|
res.writeHead(409, 'Conflict', {'Content-Type': 'application/json'})
|
|
270
270
|
return res.end(JSON.stringify({
|
|
271
271
|
error: 'Multiplexer already exists',
|
|
272
|
-
|
|
273
|
-
details: 'This multiplexer ID must be unique'
|
|
272
|
+
details: `Cannot create duplicate multiplexer with ID '${multiplexer}'`
|
|
274
273
|
}))
|
|
275
274
|
}
|
|
276
275
|
|
|
@@ -344,9 +343,9 @@ function braidify (req, res, next) {
|
|
|
344
343
|
if (m.requests.has(request)) {
|
|
345
344
|
res.writeHead(409, 'Conflict', {'Content-Type': 'application/json'})
|
|
346
345
|
return res.end(JSON.stringify({
|
|
347
|
-
error: 'Request already
|
|
348
|
-
|
|
349
|
-
|
|
346
|
+
error: 'Request already multiplexed',
|
|
347
|
+
details: `Cannot multiplex request with duplicate ID '`
|
|
348
|
+
+ request + `' for multiplexer '` + multiplexer + `'`
|
|
350
349
|
}))
|
|
351
350
|
}
|
|
352
351
|
|