braid-http 1.3.39 → 1.3.41
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 +59 -57
- package/braid-http-server.js +48 -36
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -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
|
|
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) {
|
|
@@ -307,9 +307,9 @@ async function braid_fetch (url, params = {}) {
|
|
|
307
307
|
// Now we run the original fetch....
|
|
308
308
|
|
|
309
309
|
// try multiplexing if the multiplex flag is set, and conditions are met
|
|
310
|
-
var mux_params = params.multiplex ?? braid_fetch.
|
|
310
|
+
var mux_params = params.multiplex ?? braid_fetch.enable_multiplex
|
|
311
311
|
if (mux_params !== false &&
|
|
312
|
-
(params.headers.has('
|
|
312
|
+
(params.headers.has('multiplex-at') ||
|
|
313
313
|
(params.headers.has('subscribe') &&
|
|
314
314
|
braid_fetch.subscription_counts?.[origin] >
|
|
315
315
|
(!mux_params ? 1 : (mux_params.after ?? 0))))) {
|
|
@@ -828,50 +828,52 @@ function parse_body (state) {
|
|
|
828
828
|
// multiplex_fetch provides a fetch-like experience for HTTP requests
|
|
829
829
|
// where the result is actually being sent over a separate multiplexed connection.
|
|
830
830
|
async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
831
|
+
var multiplex_version = '1.0'
|
|
832
|
+
|
|
831
833
|
var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
|
|
832
834
|
|
|
833
835
|
// the mux_key is the same as the origin, unless it is being overriden
|
|
834
836
|
// (the overriding is done by the tests)
|
|
835
|
-
var mux_key = params.headers.get('
|
|
837
|
+
var mux_key = params.headers.get('multiplex-at')?.split('/')[3] ?? origin
|
|
836
838
|
|
|
837
839
|
// create a new multiplexer if it doesn't exist for this origin
|
|
838
840
|
if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
|
|
839
841
|
if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (async () => {
|
|
840
842
|
// make up a new multiplexer id (unless it is being overriden)
|
|
841
|
-
var multiplexer = params.headers.get('
|
|
843
|
+
var multiplexer = params.headers.get('multiplex-at')?.split('/')[3] ?? Math.random().toString(36).slice(2)
|
|
842
844
|
|
|
843
|
-
var
|
|
845
|
+
var requests = new Map()
|
|
844
846
|
var mux_error = null
|
|
845
847
|
|
|
846
848
|
var mux_promise = (async () => {
|
|
847
849
|
// attempt to establish a multiplexed connection
|
|
848
850
|
try {
|
|
849
851
|
if (skip_multiplex_method) throw 'skip multiplex method'
|
|
850
|
-
var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', headers: {'Multiplex-Version':
|
|
851
|
-
if (!r.ok || r.headers.get('Multiplex-Version') !==
|
|
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'
|
|
852
854
|
} catch (e) {
|
|
853
855
|
// some servers don't like custom methods,
|
|
854
856
|
// so let's try with a custom header
|
|
855
857
|
try {
|
|
856
|
-
r = await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}`, {method: 'POST', headers: {'Multiplex-Version':
|
|
858
|
+
r = await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}`, {method: 'POST', headers: {'Multiplex-Version': multiplex_version}, retry: true})
|
|
857
859
|
|
|
858
860
|
if (!r.ok) throw new Error('status not ok: ' + r.status)
|
|
859
|
-
if (r.headers.get('Multiplex-Version') !==
|
|
861
|
+
if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
|
|
860
862
|
} catch (e) {
|
|
861
863
|
// fallback to normal fetch if multiplexed connection fails
|
|
862
|
-
console.error(`Could not establish
|
|
864
|
+
console.error(`Could not establish multiplexer.\nGot error: ${e}.\nFalling back to normal connection.`)
|
|
863
865
|
return false
|
|
864
866
|
}
|
|
865
867
|
}
|
|
866
868
|
|
|
867
869
|
// parse the multiplexed stream,
|
|
868
|
-
// and send messages to the appropriate
|
|
869
|
-
parse_multiplex_stream(r.body.getReader(), (
|
|
870
|
-
|
|
870
|
+
// and send messages to the appropriate requests
|
|
871
|
+
parse_multiplex_stream(r.body.getReader(), (reqest, bytes) => {
|
|
872
|
+
requests.get(reqest)?.(bytes)
|
|
871
873
|
}, e => {
|
|
872
874
|
// the multiplexer stream has died.. let everyone know..
|
|
873
875
|
mux_error = e
|
|
874
|
-
for (var f of
|
|
876
|
+
for (var f of requests.values()) f()
|
|
875
877
|
delete multiplex_fetch.multiplexers[mux_key]
|
|
876
878
|
})
|
|
877
879
|
})()
|
|
@@ -882,30 +884,30 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
882
884
|
// if we already know the multiplexer is not working,
|
|
883
885
|
// then fallback to normal fetch
|
|
884
886
|
// (unless the user is specifically asking for multiplexing)
|
|
885
|
-
if ((await promise_done(mux_promise)) && (await mux_promise) === false && !params.headers.get('
|
|
887
|
+
if ((await promise_done(mux_promise)) && (await mux_promise) === false && !params.headers.get('multiplex-at'))
|
|
886
888
|
return await normal_fetch(url, params)
|
|
887
889
|
|
|
888
|
-
// make up a new
|
|
889
|
-
var
|
|
890
|
+
// make up a new request id (unless it is being overriden)
|
|
891
|
+
var request = params.headers.get('multiplex-at')?.split('/')[4] ?? Math.random().toString(36).slice(2)
|
|
890
892
|
|
|
891
|
-
// add the
|
|
893
|
+
// add the Multiplex-At header without affecting the underlying params
|
|
892
894
|
var mux_headers = new Headers(params.headers)
|
|
893
|
-
mux_headers.set('
|
|
894
|
-
mux_headers.set('Multiplex-Version',
|
|
895
|
+
mux_headers.set('Multiplex-At', `/.well-known/multiplex/${multiplexer}/${request}`)
|
|
896
|
+
mux_headers.set('Multiplex-Version', multiplex_version)
|
|
895
897
|
params = {...params, headers: mux_headers}
|
|
896
898
|
|
|
897
899
|
// setup a way to receive incoming data from the multiplexer
|
|
898
900
|
var buffers = []
|
|
899
901
|
var bytes_available = () => {}
|
|
900
|
-
var
|
|
902
|
+
var request_error = null
|
|
901
903
|
|
|
902
904
|
// this utility calls the callback whenever new data is available to process
|
|
903
905
|
async function process_buffers(cb) {
|
|
904
906
|
while (true) {
|
|
905
907
|
// wait for data if none is available
|
|
906
|
-
if (!mux_error && !
|
|
908
|
+
if (!mux_error && !request_error && !buffers.length)
|
|
907
909
|
await new Promise(done => bytes_available = done)
|
|
908
|
-
if (mux_error ||
|
|
910
|
+
if (mux_error || request_error) throw (mux_error || request_error)
|
|
909
911
|
|
|
910
912
|
// process the data
|
|
911
913
|
let ret = cb()
|
|
@@ -913,31 +915,29 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
913
915
|
}
|
|
914
916
|
}
|
|
915
917
|
|
|
916
|
-
// tell the multiplexer to send bytes for this
|
|
917
|
-
|
|
918
|
-
if (!bytes)
|
|
919
|
-
|
|
920
|
-
buffers.push(bytes)
|
|
921
|
-
} else if (!mux_error) buffers.push(bytes)
|
|
918
|
+
// tell the multiplexer to send bytes for this request to us
|
|
919
|
+
requests.set(request, bytes => {
|
|
920
|
+
if (!bytes) buffers.push(bytes)
|
|
921
|
+
else if (!mux_error) buffers.push(bytes)
|
|
922
922
|
bytes_available()
|
|
923
923
|
})
|
|
924
924
|
|
|
925
925
|
// prepare a function that we'll call to cleanly tear things down
|
|
926
926
|
var unset = async e => {
|
|
927
927
|
unset = () => {}
|
|
928
|
-
|
|
929
|
-
|
|
928
|
+
requests.delete(request)
|
|
929
|
+
request_error = e
|
|
930
930
|
bytes_available()
|
|
931
931
|
try {
|
|
932
|
-
var r = await braid_fetch(`${origin}${params.headers.get('
|
|
932
|
+
var r = await braid_fetch(`${origin}${params.headers.get('multiplex-at')}`, {
|
|
933
933
|
method: 'DELETE',
|
|
934
|
-
headers: { 'Multiplex-Version':
|
|
934
|
+
headers: { 'Multiplex-Version': multiplex_version }, retry: true
|
|
935
935
|
})
|
|
936
936
|
|
|
937
937
|
if (!r.ok) throw new Error('status not ok: ' + r.status)
|
|
938
|
-
if (r.headers.get('Multiplex-Version') !==
|
|
938
|
+
if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
|
|
939
939
|
} catch (e) {
|
|
940
|
-
e = new Error(`Could not cancel multiplexed
|
|
940
|
+
e = new Error(`Could not cancel multiplexed request: ${e}`)
|
|
941
941
|
console.error('' + e)
|
|
942
942
|
throw e
|
|
943
943
|
}
|
|
@@ -945,9 +945,11 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
945
945
|
|
|
946
946
|
// do the underlying fetch
|
|
947
947
|
try {
|
|
948
|
+
var mux_was_done = await promise_done(mux_promise)
|
|
949
|
+
|
|
948
950
|
var res = await normal_fetch(url, params)
|
|
949
951
|
|
|
950
|
-
if (res.status === 424 && !
|
|
952
|
+
if (res.status === 424 && !mux_was_done) {
|
|
951
953
|
// this error will trigger a retry if the user is using that option
|
|
952
954
|
throw new Error('multiplexer not yet connected')
|
|
953
955
|
}
|
|
@@ -957,29 +959,29 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
957
959
|
// fall back to as if it was a normal fetch
|
|
958
960
|
if (res.ok && res.status !== 293) return res
|
|
959
961
|
|
|
960
|
-
if (res.status !== 293) throw new Error('Could not establish multiplexed
|
|
962
|
+
if (res.status !== 293) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-at') + ', got status: ' + res.status)
|
|
961
963
|
|
|
962
|
-
if (res.headers.get('Multiplex-Version') !==
|
|
964
|
+
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'))
|
|
963
965
|
|
|
964
966
|
// we want to present the illusion that the connection is still open,
|
|
965
967
|
// and therefor closable with "abort",
|
|
966
|
-
// so we handle the abort ourselves to close the multiplexed
|
|
968
|
+
// so we handle the abort ourselves to close the multiplexed request
|
|
967
969
|
params.signal?.addEventListener('abort', () =>
|
|
968
|
-
unset(create_abort_error('
|
|
970
|
+
unset(create_abort_error('request aborted')))
|
|
969
971
|
|
|
970
972
|
// first, we need to listen for the headers..
|
|
971
973
|
var headers_buffer = new Uint8Array()
|
|
972
974
|
var parsed_headers = await process_buffers(() => {
|
|
973
|
-
// check if the
|
|
974
|
-
var
|
|
975
|
-
if (
|
|
975
|
+
// check if the request has been closed
|
|
976
|
+
var request_ended = !buffers[buffers.length - 1]
|
|
977
|
+
if (request_ended) buffers.pop()
|
|
976
978
|
|
|
977
979
|
// aggregate all the new buffers into our big headers_buffer
|
|
978
980
|
headers_buffer = concat_buffers([headers_buffer, ...buffers])
|
|
979
981
|
buffers = []
|
|
980
982
|
|
|
981
|
-
// and if the
|
|
982
|
-
if (
|
|
983
|
+
// and if the request had ended, put that information back
|
|
984
|
+
if (request_ended) buffers.push(null)
|
|
983
985
|
|
|
984
986
|
// try parsing what we got so far as headers..
|
|
985
987
|
var x = parse_headers(headers_buffer)
|
|
@@ -990,7 +992,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
990
992
|
console.log(`headers_buffer: ` + new TextDecoder().decode(headers_buffer))
|
|
991
993
|
throw new Error('error parsing headers')
|
|
992
994
|
} else if (x.result === 'waiting') {
|
|
993
|
-
if (
|
|
995
|
+
if (request_ended) throw new Error('Multiplexed request ended before headers received.')
|
|
994
996
|
} else return x
|
|
995
997
|
})
|
|
996
998
|
|
|
@@ -1004,7 +1006,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
1004
1006
|
|
|
1005
1007
|
// create our own fake response object,
|
|
1006
1008
|
// to mimik fetch's response object,
|
|
1007
|
-
// feeding the user our
|
|
1009
|
+
// feeding the user our request data from the multiplexer
|
|
1008
1010
|
var res = new Response(new ReadableStream({
|
|
1009
1011
|
async start(controller) {
|
|
1010
1012
|
try {
|
|
@@ -1022,7 +1024,7 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
1022
1024
|
|
|
1023
1025
|
// add a convenience property for the user to know if
|
|
1024
1026
|
// this response is being multiplexed
|
|
1025
|
-
res.
|
|
1027
|
+
res.is_multiplexed = true
|
|
1026
1028
|
|
|
1027
1029
|
// return the fake response object
|
|
1028
1030
|
return res
|
|
@@ -1038,14 +1040,14 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
|
|
|
1038
1040
|
return await (await multiplex_fetch.multiplexers[mux_key])(url, params)
|
|
1039
1041
|
}
|
|
1040
1042
|
|
|
1041
|
-
// waits on reader for chunks like: 123 bytes for
|
|
1043
|
+
// waits on reader for chunks like: 123 bytes for request ABC\r\n..123 bytes..
|
|
1042
1044
|
// which would trigger cb("ABC", bytes)
|
|
1043
1045
|
async function parse_multiplex_stream(reader, cb, on_error) {
|
|
1044
1046
|
try {
|
|
1045
1047
|
var buffers = [new Uint8Array(0)]
|
|
1046
1048
|
var buffers_size = 0
|
|
1047
1049
|
var chunk_size = null
|
|
1048
|
-
var
|
|
1050
|
+
var request_id = null
|
|
1049
1051
|
var header_length = 0
|
|
1050
1052
|
var header_started = false
|
|
1051
1053
|
|
|
@@ -1072,15 +1074,15 @@ async function parse_multiplex_stream(reader, cb, on_error) {
|
|
|
1072
1074
|
}
|
|
1073
1075
|
if (headerComplete) {
|
|
1074
1076
|
var headerStr = new TextDecoder().decode(buffers[0].slice(0, header_length))
|
|
1075
|
-
var m = headerStr.match(/^[\r\n]*((\d+) bytes for|close)
|
|
1077
|
+
var m = headerStr.match(/^[\r\n]*((\d+) bytes for|close) request ([A-Za-z0-9_-]+)\r\n$/)
|
|
1076
1078
|
if (!m) throw new Error('invalid multiplex header')
|
|
1077
|
-
|
|
1079
|
+
request_id = m[3]
|
|
1078
1080
|
|
|
1079
1081
|
buffers[0] = buffers[0].slice(header_length)
|
|
1080
1082
|
buffers_size -= header_length
|
|
1081
1083
|
|
|
1082
1084
|
if (m[1] === 'close') {
|
|
1083
|
-
cb(
|
|
1085
|
+
cb(request_id)
|
|
1084
1086
|
break
|
|
1085
1087
|
} else chunk_size = 1 * m[2]
|
|
1086
1088
|
} else break
|
|
@@ -1091,12 +1093,12 @@ async function parse_multiplex_stream(reader, cb, on_error) {
|
|
|
1091
1093
|
buffers[0] = buffers[0].slice(chunk_size)
|
|
1092
1094
|
buffers_size -= chunk_size
|
|
1093
1095
|
|
|
1094
|
-
// console.log(`
|
|
1096
|
+
// console.log(`request_id: ${request_id}, ${new TextDecoder().decode(chunk)}`)
|
|
1095
1097
|
|
|
1096
|
-
cb(
|
|
1098
|
+
cb(request_id, chunk)
|
|
1097
1099
|
|
|
1098
1100
|
chunk_size = null
|
|
1099
|
-
|
|
1101
|
+
request_id = null
|
|
1100
1102
|
header_length = 0
|
|
1101
1103
|
header_started = false
|
|
1102
1104
|
} else break
|
package/braid-http-server.js
CHANGED
|
@@ -243,9 +243,10 @@ function braidify (req, res, next) {
|
|
|
243
243
|
req.subscribe = subscribe
|
|
244
244
|
|
|
245
245
|
// Multiplexer stuff
|
|
246
|
-
|
|
246
|
+
var multiplex_version = '1.0'
|
|
247
|
+
if ((braidify.enable_multiplex ?? true) &&
|
|
247
248
|
(req.method === 'MULTIPLEX' || req.url.startsWith('/.well-known/multiplex/')) &&
|
|
248
|
-
req.headers['multiplex-version'] ===
|
|
249
|
+
req.headers['multiplex-version'] === multiplex_version) {
|
|
249
250
|
|
|
250
251
|
// let the caller know we're handling things
|
|
251
252
|
req.is_multiplexer = res.is_multiplexer = true
|
|
@@ -255,37 +256,48 @@ function braidify (req, res, next) {
|
|
|
255
256
|
res.setHeader("Access-Control-Allow-Methods", "*")
|
|
256
257
|
res.setHeader("Access-Control-Allow-Headers", "*")
|
|
257
258
|
|
|
258
|
-
// parse the multiplexer id and
|
|
259
|
-
var [multiplexer,
|
|
259
|
+
// parse the multiplexer id and request id from the url
|
|
260
|
+
var [multiplexer, request] = req.url.split('/').slice(req.method === 'MULTIPLEX' ? 1 : 3)
|
|
260
261
|
|
|
261
262
|
// if there's just a multiplexer, then we're creating a multiplexer..
|
|
262
|
-
if (!
|
|
263
|
+
if (!request) {
|
|
263
264
|
// maintain a Map of all the multiplexers
|
|
264
265
|
if (!braidify.multiplexers) braidify.multiplexers = new Map()
|
|
265
|
-
|
|
266
|
+
|
|
267
|
+
// if this multiplexer already exists, respond with an error
|
|
268
|
+
if (braidify.multiplexers.has(multiplexer)) {
|
|
269
|
+
res.writeHead(409, 'Conflict', {'Content-Type': 'application/json'})
|
|
270
|
+
return res.end(JSON.stringify({
|
|
271
|
+
error: 'Multiplexer already exists',
|
|
272
|
+
message: `Cannot create duplicate multiplexer with ID '${multiplexer}'`,
|
|
273
|
+
details: 'This multiplexer ID must be unique'
|
|
274
|
+
}))
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
braidify.multiplexers.set(multiplexer, {requests: new Map(), res})
|
|
266
278
|
|
|
267
279
|
// when the response closes,
|
|
268
280
|
// let everyone know the multiplexer has died
|
|
269
281
|
res.on('close', () => {
|
|
270
|
-
for (var f of braidify.multiplexers.get(multiplexer).
|
|
282
|
+
for (var f of braidify.multiplexers.get(multiplexer).requests.values()) f()
|
|
271
283
|
braidify.multiplexers.delete(multiplexer)
|
|
272
284
|
})
|
|
273
285
|
|
|
274
286
|
// keep the connection open,
|
|
275
287
|
// so people can send multiplexed data to it
|
|
276
288
|
res.writeHead(200, 'OK', {
|
|
277
|
-
'Multiplex-Version':
|
|
289
|
+
'Multiplex-Version': multiplex_version,
|
|
278
290
|
'Incremental': '?1',
|
|
279
291
|
'Cache-Control': 'no-cache',
|
|
280
292
|
'X-Accel-Buffering': 'no',
|
|
281
293
|
...req.httpVersion !== '2.0' && {'Connection': 'keep-alive'}
|
|
282
294
|
})
|
|
283
295
|
|
|
284
|
-
// but write something.. won't interfere with
|
|
296
|
+
// but write something.. won't interfere with multiplexer,
|
|
285
297
|
// and helps flush the headers
|
|
286
298
|
return res.write(`\r\n`)
|
|
287
299
|
} else {
|
|
288
|
-
// in this case, we're closing the given
|
|
300
|
+
// in this case, we're closing the given request
|
|
289
301
|
|
|
290
302
|
// if the multiplexer doesn't exist, send an error
|
|
291
303
|
var m = braidify.multiplexers?.get(multiplexer)
|
|
@@ -294,32 +306,32 @@ function braidify (req, res, next) {
|
|
|
294
306
|
return res.end(`multiplexer ${multiplexer} does not exist`)
|
|
295
307
|
}
|
|
296
308
|
|
|
297
|
-
// if the
|
|
298
|
-
let s = m.
|
|
309
|
+
// if the request doesn't exist, send an error
|
|
310
|
+
let s = m.requests.get(request)
|
|
299
311
|
if (!s) {
|
|
300
|
-
res.writeHead(404, '
|
|
301
|
-
return res.end(`
|
|
312
|
+
res.writeHead(404, 'Multiplexed request not found', {'Bad-Request': request})
|
|
313
|
+
return res.end(`request ${request} does not exist`)
|
|
302
314
|
}
|
|
303
315
|
|
|
304
|
-
// remove this
|
|
305
|
-
m.
|
|
316
|
+
// remove this request, and notify it
|
|
317
|
+
m.requests.delete(request)
|
|
306
318
|
s()
|
|
307
319
|
|
|
308
320
|
// let the requester know we succeeded
|
|
309
|
-
res.writeHead(200, 'OK', { 'Multiplex-Version':
|
|
321
|
+
res.writeHead(200, 'OK', { 'Multiplex-Version': multiplex_version })
|
|
310
322
|
return res.end(``)
|
|
311
323
|
}
|
|
312
324
|
}
|
|
313
325
|
|
|
314
|
-
// a
|
|
326
|
+
// a Multiplex-At header means the user wants to send the
|
|
315
327
|
// results of this request to the provided multiplexer,
|
|
316
|
-
// tagged with the given
|
|
317
|
-
if (braidify.
|
|
318
|
-
req.headers
|
|
319
|
-
req.headers['multiplex-version'] ===
|
|
328
|
+
// tagged with the given request id
|
|
329
|
+
if ((braidify.enable_multiplex ?? true) &&
|
|
330
|
+
req.headers['multiplex-at'] &&
|
|
331
|
+
req.headers['multiplex-version'] === multiplex_version) {
|
|
320
332
|
|
|
321
|
-
// parse the multiplexer id and
|
|
322
|
-
var [multiplexer,
|
|
333
|
+
// parse the multiplexer id and request id from the header
|
|
334
|
+
var [multiplexer, request] = req.headers['multiplex-at'].split('/').slice(3)
|
|
323
335
|
|
|
324
336
|
// find the multiplexer object (contains a response object)
|
|
325
337
|
var m = braidify.multiplexers?.get(multiplexer)
|
|
@@ -349,16 +361,16 @@ function braidify (req, res, next) {
|
|
|
349
361
|
if (og_stream) {
|
|
350
362
|
og_stream.respond({
|
|
351
363
|
':status': 293,
|
|
352
|
-
|
|
353
|
-
'Multiplex-Version':
|
|
364
|
+
'Multiplex-At': req.headers['multiplex-at'],
|
|
365
|
+
'Multiplex-Version': multiplex_version,
|
|
354
366
|
...Object.fromEntries(cors_headers)
|
|
355
367
|
})
|
|
356
368
|
og_stream.write('Ok.')
|
|
357
369
|
og_stream.end()
|
|
358
370
|
} else {
|
|
359
371
|
og_socket.write('HTTP/1.1 293 Responded via multiplexer\r\n')
|
|
360
|
-
og_socket.write(`
|
|
361
|
-
og_socket.write(`Multiplex-Version:
|
|
372
|
+
og_socket.write(`Multiplex-At: ${req.headers['multiplex-at']}\r\n`)
|
|
373
|
+
og_socket.write(`Multiplex-Version: ${multiplex_version}\r\n`)
|
|
362
374
|
cors_headers.forEach(([key, value]) =>
|
|
363
375
|
og_socket.write(`${key}: ${value}\r\n`))
|
|
364
376
|
og_socket.write('\r\n')
|
|
@@ -372,10 +384,10 @@ function braidify (req, res, next) {
|
|
|
372
384
|
|
|
373
385
|
// first we create a kind of fake socket
|
|
374
386
|
class MultiplexedWritable extends require('stream').Writable {
|
|
375
|
-
constructor(multiplexer,
|
|
387
|
+
constructor(multiplexer, request) {
|
|
376
388
|
super()
|
|
377
389
|
this.multiplexer = multiplexer
|
|
378
|
-
this.
|
|
390
|
+
this.request = request
|
|
379
391
|
}
|
|
380
392
|
|
|
381
393
|
_write(chunk, encoding, callback) {
|
|
@@ -383,11 +395,11 @@ function braidify (req, res, next) {
|
|
|
383
395
|
|
|
384
396
|
try {
|
|
385
397
|
var len = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding)
|
|
386
|
-
this.multiplexer.res.write(`${len} bytes for
|
|
398
|
+
this.multiplexer.res.write(`${len} bytes for request ${this.request}\r\n`)
|
|
387
399
|
this.multiplexer.res.write(chunk, encoding, callback)
|
|
388
400
|
|
|
389
401
|
// console.log(`wrote:`)
|
|
390
|
-
// console.log(`${len} bytes for
|
|
402
|
+
// console.log(`${len} bytes for request /${this.request}\r\n`)
|
|
391
403
|
// if (Buffer.isBuffer(chunk)) console.log(new TextDecoder().decode(chunk))
|
|
392
404
|
// else console.log('STRING?: ' + chunk)
|
|
393
405
|
|
|
@@ -396,7 +408,7 @@ function braidify (req, res, next) {
|
|
|
396
408
|
}
|
|
397
409
|
}
|
|
398
410
|
}
|
|
399
|
-
var mw = new MultiplexedWritable(m,
|
|
411
|
+
var mw = new MultiplexedWritable(m, request)
|
|
400
412
|
|
|
401
413
|
// then we create a fake server response,
|
|
402
414
|
// that pipes data to our fake socket
|
|
@@ -405,15 +417,15 @@ function braidify (req, res, next) {
|
|
|
405
417
|
res2.assignSocket(mw)
|
|
406
418
|
|
|
407
419
|
// register a handler for when the multiplexer closes,
|
|
408
|
-
// to close our fake response
|
|
409
|
-
m.
|
|
420
|
+
// to close our fake response
|
|
421
|
+
m.requests.set(request, () => {
|
|
410
422
|
og_res_end?.()
|
|
411
423
|
res2.destroy()
|
|
412
424
|
})
|
|
413
425
|
|
|
414
426
|
// when our fake response is done,
|
|
415
427
|
// we want to send a special message to the multiplexer saying so
|
|
416
|
-
res2.on('finish', () => m.res.write(`close
|
|
428
|
+
res2.on('finish', () => m.res.write(`close request ${request}\r\n`))
|
|
417
429
|
|
|
418
430
|
// we want access to "res" to be forwarded to our fake "res2",
|
|
419
431
|
// so that it goes into the multiplexer
|