braid-http 1.2.0 → 1.3.0

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.
@@ -193,7 +193,6 @@ async function braid_fetch (url, params = {}) {
193
193
  if (typeof patch.content === 'string')
194
194
  patch.content = new TextEncoder().encode(patch.content)
195
195
 
196
- params.headers.set('Content-Length', `${patch.content.length}`)
197
196
  params.body = patch.content
198
197
  }
199
198
 
@@ -208,7 +207,7 @@ async function braid_fetch (url, params = {}) {
208
207
  if (typeof patch.content === 'string')
209
208
  patch.content = te.encode(patch.content)
210
209
 
211
- var length = `content-length: ${patch.content.length}`
210
+ var length = `content-length: ${get_binary_length(patch.content)}`
212
211
  var range = `content-range: ${patch.unit} ${patch.range}`
213
212
  bufs.push(te.encode(`${length}\r\n${range}\r\n\r\n`))
214
213
  bufs.push(patch.content)
@@ -579,6 +578,15 @@ function parse_headers (input) {
579
578
  var h = extractHeader(input)
580
579
  if (!h) return {result: 'waiting'}
581
580
 
581
+ // Skip "HTTP 104 Multiresponse"
582
+ if (h.header_string.startsWith('HTTP 104')) {
583
+ h = extractHeader(h.remaining_bytes)
584
+ if (!h) return {result: 'waiting'}
585
+ }
586
+
587
+ // Skip "HTTP 200 OK"
588
+ h.header_string = h.header_string.replace(/^HTTP 200.*\r?\n/, '')
589
+
582
590
  var headers_source = h.header_string
583
591
  var headers_length = headers_source.length
584
592
 
@@ -839,6 +847,12 @@ function extractHeader(input) {
839
847
  };
840
848
  }
841
849
 
850
+ function get_binary_length(x) {
851
+ return x instanceof ArrayBuffer ? x.byteLength :
852
+ x instanceof Uint8Array ? x.length :
853
+ x instanceof Blob ? x.size : undefined
854
+ }
855
+
842
856
  // ****************************
843
857
  // Exports
844
858
  // ****************************
@@ -1,6 +1,6 @@
1
1
  var assert = require('assert')
2
2
 
3
- // Return a string of patches in pseudoheader format.
3
+ // Writes patches in pseudoheader format.
4
4
  //
5
5
  // The `patches` argument can be:
6
6
  // - Array of patches
@@ -25,9 +25,7 @@ var assert = require('assert')
25
25
  //
26
26
  // {"some": "json object"}
27
27
  //
28
- function generate_patches(res, patches) {
29
- var result = ''
30
-
28
+ function write_patches(res, patches) {
31
29
  // `patches` must be a patch object or an array of patch objects
32
30
  // - Object: {unit, range, content}
33
31
  // - Array: [{unit, range, content}, ...]
@@ -38,7 +36,7 @@ function generate_patches(res, patches) {
38
36
  if (Array.isArray(patches)) {
39
37
 
40
38
  // Add `Patches: N` header if array
41
- result += `Patches: ${patches.length}\r\n\r\n`
39
+ res.write(`Patches: ${patches.length}\r\n\r\n`)
42
40
  } else
43
41
  // Else, we'll out put a single patch
44
42
  patches = [patches]
@@ -47,19 +45,21 @@ function generate_patches(res, patches) {
47
45
  patches.forEach((patch, i) => {
48
46
  assert(typeof patch.unit === 'string')
49
47
  assert(typeof patch.range === 'string')
50
- assert(typeof patch.content === 'string')
48
+
49
+ if (typeof patch.content === 'string')
50
+ patch.content = new TextEncoder().encode(patch.content)
51
51
 
52
52
  if (i > 0)
53
- result += '\r\n\r\n'
53
+ res.write('\r\n\r\n')
54
54
 
55
55
  let extra_headers = Object.fromEntries(Object.entries(patch).filter(([k, v]) => k != 'unit' && k != 'range' && k != 'content'))
56
56
 
57
- result += `Content-Length: ${(new TextEncoder().encode(patch.content)).length}\r
57
+ res.write(`Content-Length: ${get_binary_length(patch.content)}\r
58
58
  Content-Range: ${patch.unit} ${patch.range}\r
59
59
  ${Object.entries(extra_headers).map(([k, v]) => `${k}: ${v}\r\n`).join('')}\r
60
- ${patch.content}`
60
+ `)
61
+ write_binary(res, patch.content)
61
62
  })
62
- return result
63
63
  }
64
64
 
65
65
 
@@ -312,7 +312,7 @@ function braidify (req, res, next) {
312
312
  next && next()
313
313
  }
314
314
 
315
- function send_update(res, data, url, peer) {
315
+ async function send_update(res, data, url, peer) {
316
316
  var {version, parents, patches, patch, body} = data
317
317
 
318
318
  function set_header (key, val) {
@@ -323,7 +323,7 @@ function send_update(res, data, url, peer) {
323
323
  }
324
324
  function write_body (body) {
325
325
  if (res.isSubscription) res.write('\r\n')
326
- res.write(body)
326
+ write_binary(res, body)
327
327
  }
328
328
 
329
329
  // console.log('sending version', {url, peer, version, parents, patches, body,
@@ -331,14 +331,10 @@ function send_update(res, data, url, peer) {
331
331
 
332
332
  // Validate that the body and patches are strings,
333
333
  // or in the case of body, it could be binary
334
- if (body !== undefined)
335
- assert(typeof body === 'string' ||
336
- body instanceof ArrayBuffer ||
337
- body instanceof Uint8Array ||
338
- body instanceof Blob ||
339
- body instanceof Buffer
340
- )
341
- else {
334
+ if (body !== undefined) {
335
+ assert(typeof body === 'string' || get_binary_length(body) != null)
336
+ if (body instanceof Blob) body = await body.arrayBuffer()
337
+ } else {
342
338
  // Only one of patch or patches can be set
343
339
  assert(!(patch && patches))
344
340
  assert((patch || patches) !== undefined)
@@ -354,23 +350,31 @@ function send_update(res, data, url, peer) {
354
350
 
355
351
  // Now `patches` will be an array of patches or a single patch object.
356
352
  //
357
- // This distinction is used in generate_patches() to determine whether
353
+ // This distinction is used in write_patches() to determine whether
358
354
  // to inline a single patch in the update body vs. writing out a
359
355
  // Patches: N block.
360
356
  assert(typeof patches === 'object')
361
- if (Array.isArray(patches))
362
- patches.forEach(p => {
363
- assert('unit' in p)
364
- assert('range' in p)
365
- assert('content' in p)
366
- assert(typeof p.content === 'string')
367
- })
357
+ for (let p of Array.isArray(patches) ? patches : [patch]) {
358
+ assert('unit' in p)
359
+ assert('range' in p)
360
+ assert('content' in p)
361
+ assert(typeof p.content === 'string' || get_binary_length(p.content) != null)
362
+ if (p.content instanceof Blob) p.content = await p.content.arrayBuffer()
363
+ }
368
364
  }
369
365
 
370
366
  var body_exists = body || body === ''
371
367
  assert(body_exists || patches, 'Missing body or patches')
372
368
  assert(!(body_exists && patches), 'Cannot send both body and patches')
373
369
 
370
+ // Write the beginning of a new multiresponse response
371
+ if (!res.wrote_104_multiresponse) {
372
+ res.write(`HTTP 104 Multiresponse\r\n\r\n`)
373
+ res.wrote_104_multiresponse = true
374
+ }
375
+
376
+ res.write(`HTTP 200 OK\r\n`)
377
+
374
378
  // Write the headers or virtual headers
375
379
  for (var [header, value] of Object.entries(data)) {
376
380
  header = header.toLowerCase()
@@ -399,14 +403,10 @@ function send_update(res, data, url, peer) {
399
403
  // Write the patches or body
400
404
  if (body_exists) {
401
405
  let x = typeof body === 'string' ? new TextEncoder().encode(body) : body
402
- set_header('Content-Length',
403
- x instanceof ArrayBuffer ? x.byteLength :
404
- x instanceof Uint8Array ? x.length :
405
- x instanceof Blob ? x.size :
406
- x instanceof Buffer ? x.length : null)
406
+ set_header('Content-Length', get_binary_length(x))
407
407
  write_body(x)
408
408
  } else
409
- res.write(generate_patches(res, patches))
409
+ write_patches(res, patches)
410
410
 
411
411
  // Add a newline to prepare for the next version
412
412
  // See also https://github.com/braid-org/braid-spec/issues/73
@@ -476,4 +476,16 @@ function extractHeader(input) {
476
476
  };
477
477
  }
478
478
 
479
+ function get_binary_length(x) {
480
+ return x instanceof ArrayBuffer ? x.byteLength :
481
+ x instanceof Uint8Array ? x.length :
482
+ x instanceof Blob ? x.size :
483
+ x instanceof Buffer ? x.length : undefined
484
+ }
485
+
486
+ function write_binary(res, body) {
487
+ if (body instanceof ArrayBuffer) body = new Uint8Array(body)
488
+ res.write(body)
489
+ }
490
+
479
491
  module.exports = braidify
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"