braid-http 1.2.0 → 1.3.1

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,9 @@ function parse_headers (input) {
579
578
  var h = extractHeader(input)
580
579
  if (!h) return {result: 'waiting'}
581
580
 
581
+ // Skip "HTTP 200 OK"
582
+ h.header_string = h.header_string.replace(/^HTTP 200.*\r?\n/, '')
583
+
582
584
  var headers_source = h.header_string
583
585
  var headers_length = headers_source.length
584
586
 
@@ -839,6 +841,12 @@ function extractHeader(input) {
839
841
  };
840
842
  }
841
843
 
844
+ function get_binary_length(x) {
845
+ return x instanceof ArrayBuffer ? x.byteLength :
846
+ x instanceof Uint8Array ? x.length :
847
+ x instanceof Blob ? x.size : undefined
848
+ }
849
+
842
850
  // ****************************
843
851
  // Exports
844
852
  // ****************************
@@ -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,25 @@ 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
+ res.write(`HTTP 200 OK\r\n`)
371
+
374
372
  // Write the headers or virtual headers
375
373
  for (var [header, value] of Object.entries(data)) {
376
374
  header = header.toLowerCase()
@@ -399,14 +397,10 @@ function send_update(res, data, url, peer) {
399
397
  // Write the patches or body
400
398
  if (body_exists) {
401
399
  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)
400
+ set_header('Content-Length', get_binary_length(x))
407
401
  write_body(x)
408
402
  } else
409
- res.write(generate_patches(res, patches))
403
+ write_patches(res, patches)
410
404
 
411
405
  // Add a newline to prepare for the next version
412
406
  // See also https://github.com/braid-org/braid-spec/issues/73
@@ -476,4 +470,16 @@ function extractHeader(input) {
476
470
  };
477
471
  }
478
472
 
473
+ function get_binary_length(x) {
474
+ return x instanceof ArrayBuffer ? x.byteLength :
475
+ x instanceof Uint8Array ? x.length :
476
+ x instanceof Blob ? x.size :
477
+ x instanceof Buffer ? x.length : undefined
478
+ }
479
+
480
+ function write_binary(res, body) {
481
+ if (body instanceof ArrayBuffer) body = new Uint8Array(body)
482
+ res.write(body)
483
+ }
484
+
479
485
  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.1",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"