braid-http 1.3.35 → 1.3.37

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.
@@ -306,14 +306,14 @@ async function braid_fetch (url, params = {}) {
306
306
 
307
307
  // Now we run the original fetch....
308
308
 
309
- // try multiplexing if either of these is true:
310
- // - they explicitly want multiplexing
311
- // - this is not the first subscription to the same origin
312
- if (braid_fetch.use_multiplexing &&
309
+ // try multiplexing if the multiplex flag is set, and conditions are met
310
+ var mux_params = params.multiplex ?? braid_fetch.multiplex
311
+ if (mux_params !== false &&
313
312
  (params.headers.has('multiplexer') ||
314
- (params.headers.has('subscribe') &&
315
- braid_fetch.subscription_counts?.[origin] > 1))) {
316
- res = await multiplex_fetch(url, params)
313
+ (params.headers.has('subscribe') &&
314
+ braid_fetch.subscription_counts?.[origin] >
315
+ (!mux_params ? 1 : (mux_params.after ?? 0))))) {
316
+ res = await multiplex_fetch(url, params, mux_params?.via === 'POST')
317
317
  } else {
318
318
  res = await normal_fetch(url, params)
319
319
  }
@@ -827,24 +827,18 @@ function parse_body (state) {
827
827
 
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
- //
831
- // This function assumes a header in params called 'multiplexer' with a value
832
- // that looks like /multiplexer_id/stream_id. It creates a multiplexer if it
833
- // doesn't exist already, then performs a fetch providing the multiplexer header.
834
- // This tells the server to send the results to the given multiplexer.
835
- //
836
- async function multiplex_fetch(url, params) {
830
+ async function multiplex_fetch(url, params, skip_multiplex_method) {
837
831
  var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
838
832
 
839
833
  // the mux_key is the same as the origin, unless it is being overriden
840
834
  // (the overriding is done by the tests)
841
- var mux_key = params.headers.get('multiplexer')?.split('/')[1] ?? origin
835
+ var mux_key = params.headers.get('multiplexer')?.split('/')[3] ?? origin
842
836
 
843
837
  // create a new multiplexer if it doesn't exist for this origin
844
838
  if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
845
839
  if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (async () => {
846
840
  // make up a new multiplexer id (unless it is being overriden)
847
- var multiplexer = params.headers.get('multiplexer')?.split('/')[1] ?? Math.random().toString(36).slice(2)
841
+ var multiplexer = params.headers.get('multiplexer')?.split('/')[3] ?? Math.random().toString(36).slice(2)
848
842
 
849
843
  var streams = new Map()
850
844
  var mux_error = null
@@ -852,14 +846,14 @@ async function multiplex_fetch(url, params) {
852
846
  var mux_promise = (async () => {
853
847
  // attempt to establish a multiplexed connection
854
848
  try {
855
- if (params.use_multiplex_well_known_url) throw 'skip to trying header'
849
+ if (skip_multiplex_method) throw 'skip multiplex method'
856
850
  var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', headers: {'Multiplex-Version': '0.0.1'}, retry: true})
857
851
  if (!r.ok || r.headers.get('Multiplex-Version') !== '0.0.1') throw 'bad'
858
852
  } catch (e) {
859
853
  // some servers don't like custom methods,
860
854
  // so let's try with a custom header
861
855
  try {
862
- r = await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}`, {headers: {'Multiplex-Version': '0.0.1'}, retry: true})
856
+ r = await braid_fetch(`${origin}/.well-known/multiplex/${multiplexer}`, {method: 'POST', headers: {'Multiplex-Version': '0.0.1'}, retry: true})
863
857
 
864
858
  if (!r.ok) throw new Error('status not ok: ' + r.status)
865
859
  if (r.headers.get('Multiplex-Version') !== '0.0.1') throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected 0.0.1')
@@ -892,11 +886,11 @@ async function multiplex_fetch(url, params) {
892
886
  return await normal_fetch(url, params)
893
887
 
894
888
  // make up a new stream id (unless it is being overriden)
895
- var stream = params.headers.get('multiplexer')?.split('/')[2] ?? Math.random().toString(36).slice(2)
889
+ var stream = params.headers.get('multiplexer')?.split('/')[4] ?? Math.random().toString(36).slice(2)
896
890
 
897
891
  // add the multiplexer header without affecting the underlying params
898
892
  var mux_headers = new Headers(params.headers)
899
- mux_headers.set('Multiplexer', `/${multiplexer}/${stream}`)
893
+ mux_headers.set('Multiplexer', `/.well-known/multiplex/${multiplexer}/${stream}`)
900
894
  mux_headers.set('Multiplex-Version', '0.0.1')
901
895
  params = {...params, headers: mux_headers}
902
896
 
@@ -935,7 +929,7 @@ async function multiplex_fetch(url, params) {
935
929
  stream_error = e
936
930
  bytes_available()
937
931
  try {
938
- var r = await braid_fetch(`${origin}/.well-known/multiplex${params.headers.get('multiplexer')}`, {
932
+ var r = await braid_fetch(`${origin}${params.headers.get('multiplexer')}`, {
939
933
  method: 'DELETE',
940
934
  headers: { 'Multiplex-Version': '0.0.1' }, retry: true
941
935
  })
@@ -247,6 +247,14 @@ function braidify (req, res, next) {
247
247
  (req.method === 'MULTIPLEX' || req.url.startsWith('/.well-known/multiplex/')) &&
248
248
  req.headers['multiplex-version'] === '0.0.1') {
249
249
 
250
+ // let the caller know we're handling things
251
+ req.is_multiplexer = res.is_multiplexer = true
252
+
253
+ // free the cors
254
+ res.setHeader("Access-Control-Allow-Origin", "*")
255
+ res.setHeader("Access-Control-Allow-Methods", "*")
256
+ res.setHeader("Access-Control-Allow-Headers", "*")
257
+
250
258
  // parse the multiplexer id and stream id from the url
251
259
  var [multiplexer, stream] = req.url.split('/').slice(req.method === 'MULTIPLEX' ? 1 : 3)
252
260
 
@@ -265,7 +273,7 @@ function braidify (req, res, next) {
265
273
 
266
274
  // keep the connection open,
267
275
  // so people can send multiplexed data to it
268
- res.writeHead(200, {
276
+ res.writeHead(200, 'OK', {
269
277
  'Multiplex-Version': '0.0.1',
270
278
  'Incremental': '?1',
271
279
  'Cache-Control': 'no-cache',
@@ -282,15 +290,15 @@ function braidify (req, res, next) {
282
290
  // if the multiplexer doesn't exist, send an error
283
291
  var m = braidify.multiplexers?.get(multiplexer)
284
292
  if (!m) {
285
- res.writeHead(400, {'Content-Type': 'text/plain'})
286
- return res.end(`multiplexer /${multiplexer} does not exist`)
293
+ res.writeHead(422, 'Multiplexer no exist', {'Bad-Multiplexer': multiplexer})
294
+ return res.end(`multiplexer ${multiplexer} does not exist`)
287
295
  }
288
296
 
289
297
  // if the stream doesn't exist, send an error
290
298
  let s = m.streams.get(stream)
291
299
  if (!s) {
292
- res.writeHead(400, {'Content-Type': 'text/plain'})
293
- return res.end(`stream /${multiplexer}/${stream} does not exist`)
300
+ res.writeHead(422, 'Stream no exist', {'Bad-Stream': stream})
301
+ return res.end(`stream ${stream} does not exist`)
294
302
  }
295
303
 
296
304
  // remove this stream, and notify it
@@ -298,7 +306,7 @@ function braidify (req, res, next) {
298
306
  s()
299
307
 
300
308
  // let the requester know we succeeded
301
- res.writeHead(200, { 'Multiplex-Version': '0.0.1' })
309
+ res.writeHead(200, 'OK', { 'Multiplex-Version': '0.0.1' })
302
310
  return res.end(``)
303
311
  }
304
312
  }
@@ -310,23 +318,54 @@ function braidify (req, res, next) {
310
318
  req.headers.multiplexer &&
311
319
  req.headers['multiplex-version'] === '0.0.1') {
312
320
 
313
- // parse the multiplexer id and stream id from the url
314
- var [multiplexer, stream] = req.headers.multiplexer.slice(1).split('/')
321
+ // parse the multiplexer id and stream id from the header
322
+ var [multiplexer, stream] = req.headers.multiplexer.split('/').slice(3)
315
323
 
316
324
  // find the multiplexer object (contains a response object)
317
325
  var m = braidify.multiplexers?.get(multiplexer)
318
326
  if (!m) {
319
- // 422 = Unprocessable Entity (but good syntax!)
320
- res.writeHead(422, {Multiplexer: `/${multiplexer}`})
321
- res.end(`multiplexer ${multiplexer} does not exist`)
327
+ res.writeHead(422, 'Multiplexer no exist', {'Bad-Multiplexer': multiplexer})
328
+ return res.end(`multiplexer ${multiplexer} does not exist`)
322
329
  }
323
330
 
324
331
  // let the requester know we've multiplexed their response
325
- res.writeHead(293, {
326
- multiplexer: req.headers.multiplexer,
327
- 'Multiplex-Version': '0.0.1'
328
- })
329
- res.end('Ok.')
332
+ var og_stream = res.stream
333
+ var og_socket = res.socket
334
+ var og_res_end = () => {
335
+ og_res_end = null
336
+ if (!braidify.cors_headers) braidify.cors_headers = new Set([
337
+ 'Access-Control-Allow-Origin',
338
+ 'Access-Control-Allow-Methods',
339
+ 'Access-Control-Allow-Headers',
340
+ 'Access-Control-Allow-Credentials',
341
+ 'Access-Control-Expose-Headers',
342
+ 'Access-Control-Max-Age'
343
+ ].map(x => x.toLowerCase()))
344
+
345
+ // copy any CORS headers from the user
346
+ var cors_headers = Object.entries(res.getHeaders()).
347
+ filter(x => braidify.cors_headers.has(x.key))
348
+
349
+ if (og_stream) {
350
+ og_stream.respond({
351
+ ':status': 293,
352
+ Multiplexer: req.headers.multiplexer,
353
+ 'Multiplex-Version': '0.0.1',
354
+ ...Object.fromEntries(cors_headers)
355
+ })
356
+ og_stream.write('Ok.')
357
+ og_stream.end()
358
+ } else {
359
+ og_socket.write('HTTP/1.1 293 Responded via multiplexer\r\n')
360
+ og_socket.write(`Multiplexer: ${req.headers.multiplexer}\r\n`)
361
+ og_socket.write(`Multiplex-Version: 0.0.1\r\n`)
362
+ cors_headers.forEach(([key, value]) =>
363
+ og_socket.write(`${key}: ${value}\r\n`))
364
+ og_socket.write('\r\n')
365
+ og_socket.write('Ok.')
366
+ og_socket.end()
367
+ }
368
+ }
330
369
 
331
370
  // and now set things up so that future use of the
332
371
  // response object forwards stuff into the multiplexer
@@ -340,6 +379,8 @@ function braidify (req, res, next) {
340
379
  }
341
380
 
342
381
  _write(chunk, encoding, callback) {
382
+ og_res_end?.()
383
+
343
384
  try {
344
385
  var len = Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding)
345
386
  this.multiplexer.res.write(`${len} bytes for stream ${this.stream}\r\n`)
@@ -365,7 +406,10 @@ function braidify (req, res, next) {
365
406
 
366
407
  // register a handler for when the multiplexer closes,
367
408
  // to close our fake response stream
368
- m.streams.set(stream, () => res2.destroy())
409
+ m.streams.set(stream, () => {
410
+ og_res_end?.()
411
+ res2.destroy()
412
+ })
369
413
 
370
414
  // when our fake response is done,
371
415
  // we want to send a special message to the multiplexer saying so
@@ -384,22 +428,6 @@ function braidify (req, res, next) {
384
428
  // just touching these seems to cause issues
385
429
  key === '_events' || key === 'emit'
386
430
 
387
- // because we called res.end above,
388
- // in http 1, node is going to wait
389
- // for the event loop to fire again,
390
- // and then call these keys:
391
- // "socket" to set it to null,
392
- // "detachSocket" to do that,
393
- // "_closed" to determine if the socket is closed;
394
- // we're going to override that to say true,
395
- // we do that below..
396
- // we do it so we don't need to add "destroyed" here,
397
- // because if _closed was false,
398
- // it would try to set destroyed to true
399
- || key === 'socket'
400
- || key === 'detachSocket'
401
- || key === '_closed'
402
-
403
431
  // adding these lines gets rid of some deprecation warnings.. keep?
404
432
  || key === '_headers'
405
433
  || key === '_headerNames') continue
@@ -418,21 +446,8 @@ function braidify (req, res, next) {
418
446
  }
419
447
  }
420
448
 
421
- // node http 1 has the issue that when we call res.end,
422
- // which we do above, not everything happens right away..
423
- // in the next js event loop tick, it is going to
424
- // try to tear down the stream,
425
- // but we have proxied all the properties,
426
- // so it would tear down our new res2 stream..
427
- // to prevent that, we sacrafice this property
428
- // (which the end-user hopefully won't be accessing anyway)
429
- // to make the http 1 tear down code think its job is complete already,
430
- // otherwise it would want to set "destroyed",
431
- // and we would need to not proxy that key as well
432
- res._closed = true
433
-
434
449
  // this is provided so code can know if the response has been multiplexed
435
- res.multiplexer = res2
450
+ res.multiplexer = m.res
436
451
  }
437
452
 
438
453
  // Add the braidly request/response helper methods
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.3.35",
3
+ "version": "1.3.37",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"