braid-http 0.1.11 → 0.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.
@@ -49,6 +49,7 @@ function braidify_http (http) {
49
49
  options.headers.peer = options.headers.peer || peer
50
50
 
51
51
  // Wrap the callback to provide our new .on('version', ...) feature
52
+ // on nodejs servers
52
53
  var on_version,
53
54
  on_error,
54
55
  orig_cb = cb
@@ -153,7 +154,7 @@ async function braid_fetch (url, params = {}) {
153
154
 
154
155
  // We provide some shortcuts for Braid params
155
156
  if (params.version)
156
- params.headers.set('version', JSON.stringify(params.version))
157
+ params.headers.set('version', params.version.map(JSON.stringify).join(', '))
157
158
  if (params.parents)
158
159
  params.headers.set('parents', params.parents.map(JSON.stringify).join(', '))
159
160
  if (params.subscribe)
@@ -362,12 +363,19 @@ var subscription_parser = (cb) => ({
362
363
 
363
364
  // Maybe we parsed a version! That's cool!
364
365
  if (this.state.result === 'success') {
366
+ let ignore_headers = {
367
+ version: true,
368
+ parents: true,
369
+ patches: true,
370
+ 'content-length': true,
371
+ 'content-range': true,
372
+ }
365
373
  this.cb({
366
374
  version: this.state.version,
367
375
  parents: this.state.parents,
368
376
  body: this.state.body,
369
377
  patches: this.state.patches,
370
- headers: this.state.headers
378
+ ...((x => Object.keys(x).length ? {extra_headers: x} : {})(Object.fromEntries(Object.entries(this.state.headers).filter(([k, v]) => !ignore_headers[k]))))
371
379
  })
372
380
 
373
381
  // Reset the parser for the next version!
@@ -479,7 +487,7 @@ function parse_headers (input) {
479
487
 
480
488
  // Success! Let's parse special headers
481
489
  if ('version' in headers)
482
- headers.version = JSON.parse(headers.version)
490
+ headers.version = JSON.parse('['+headers.version+']')
483
491
  if ('parents' in headers)
484
492
  headers.parents = JSON.parse('['+headers.parents+']')
485
493
  if ('patches' in headers)
@@ -626,6 +634,13 @@ function parse_body (state) {
626
634
  last_patch.range = match.range
627
635
  last_patch.content = state.input.substr(0, content_length)
628
636
 
637
+ // instead of headers, we'll create an "extra_headers" field that ignore the headers we've used
638
+ last_patch.extra_headers = last_patch.headers
639
+ delete last_patch.headers
640
+ delete last_patch.extra_headers['content-length']
641
+ delete last_patch.extra_headers['content-range']
642
+ if (!Object.keys(last_patch.extra_headers).length) delete last_patch.extra_headers
643
+
629
644
  // Consume the parsed input
630
645
  state.input = state.input.substring(content_length)
631
646
  }
@@ -26,34 +26,37 @@ var assert = require('assert')
26
26
  // {"some": "json object"}
27
27
  //
28
28
  function generate_patches(res, patches) {
29
+ var result = ''
30
+
31
+ // `patches` must be a patch object or an array of patch objects
32
+ // - Object: {unit, range, content}
33
+ // - Array: [{unit, range, content}, ...]
29
34
 
30
- // `patches` must be an object or an array
31
- assert(typeof patches === 'object')
35
+ assert(typeof patches === 'object') // An array is also an object
32
36
 
33
37
  // An array of one patch behaves like a single patch
34
- if (!Array.isArray(patches))
35
- var patches = [patches]
38
+ if (Array.isArray(patches)) {
39
+
40
+ // Add `Patches: N` header if array
41
+ result += `Patches: ${patches.length}\r\n\r\n`
42
+ } else
43
+ // Else, we'll out put a single patch
44
+ patches = [patches]
36
45
 
37
- for (let patch of patches) {
46
+ // Generate each patch
47
+ patches.forEach((patch, i) => {
38
48
  assert(typeof patch.unit === 'string')
39
49
  assert(typeof patch.range === 'string')
40
50
  assert(typeof patch.content === 'string')
41
- }
42
51
 
43
- // Build up the string as a result
44
- var result = ''
45
-
46
- // Add `Patches: N` header
47
- result += `Patches: ${patches.length}\r\n\r\n`
48
-
49
- // Generate each patch
50
- patches.forEach((patch, i) => {
51
52
  if (i > 0)
52
53
  result += '\r\n\r\n'
53
54
 
55
+ let extra_headers = Object.fromEntries(Object.entries(patch).filter(([k, v]) => k != 'unit' && k != 'range' && k != 'content'))
56
+
54
57
  result += `Content-Length: ${patch.content.length}\r
55
58
  Content-Range: ${patch.unit} ${patch.range}\r
56
- \r
59
+ ${Object.entries(extra_headers).map(([k, v]) => `${k}: ${v}\r\n`).join('')}\r
57
60
  ${patch.content}`
58
61
  })
59
62
  return result
@@ -237,7 +240,10 @@ function braidify (req, res, next) {
237
240
  res.statusCode = 209
238
241
  res.setHeader("subscribe", req.headers.subscribe)
239
242
  res.setHeader('cache-control', 'no-cache, no-transform')
240
- if (req.httpVersionMajor == 1) res.setHeader('transfer-encoding', '')
243
+ if (req.httpVersionMajor == 1) {
244
+ // Explicitly disable transfer-encoding chunked for http 1
245
+ res.setHeader('transfer-encoding', '')
246
+ }
241
247
 
242
248
  // Tell nginx not to buffer the subscription
243
249
  res.setHeader('X-Accel-Buffering', 'no')
@@ -268,7 +274,7 @@ function braidify (req, res, next) {
268
274
  }
269
275
 
270
276
  function send_version(res, data, url, peer) {
271
- var {version, parents, patches, body} = data
277
+ var {version, parents, patches, patch, body} = data
272
278
 
273
279
  function set_header (key, val) {
274
280
  if (res.isSubscription)
@@ -290,12 +296,34 @@ function send_version(res, data, url, peer) {
290
296
  if (body !== undefined)
291
297
  assert(typeof body === 'string')
292
298
  else {
293
- assert(patches !== undefined)
294
- assert(patches !== null)
299
+ // Only one of patch or patches can be set
300
+ assert(!(patch && patches))
301
+ assert((patch || patches) !== undefined)
302
+ assert((patch || patches) !== null)
303
+
304
+ // Patches must be an array
305
+ if (patches)
306
+ assert(Array.isArray(patches))
307
+
308
+ // But if using `patch`, then we set `patches` to just that object
309
+ if (patch)
310
+ patches = patch
311
+
312
+ // Now `patches` will be an array of patches or a single patch object.
313
+ //
314
+ // This distinction is used in generate_patches() to determine whether
315
+ // to inline a single patch in the update body vs. writing out a
316
+ // Patches: N block.
295
317
  assert(typeof patches === 'object')
296
318
  if (Array.isArray(patches))
297
- patches.forEach(p => assert(typeof p.content === 'string'))
319
+ patches.forEach(p => {
320
+ assert('unit' in p)
321
+ assert('range' in p)
322
+ assert('content' in p)
323
+ assert(typeof p.content === 'string')
324
+ })
298
325
  }
326
+
299
327
  var body_exists = body || body === ''
300
328
  assert(body_exists || patches, 'Missing body or patches')
301
329
  assert(!(body_exists && patches), 'Cannot send both body and patches')
@@ -307,14 +335,14 @@ function send_version(res, data, url, peer) {
307
335
  // Version and Parents get output in the Structured Headers format
308
336
  if (header === 'version') {
309
337
  header = 'Version' // Capitalize for prettiness
310
- value = JSON.stringify(value)
338
+ value = value.map(JSON.stringify).join(", ")
311
339
  } else if (header === 'parents') {
312
340
  header = 'Parents' // Capitalize for prettiness
313
- value = parents.map(JSON.stringify).join(", ")
341
+ value = value.map(JSON.stringify).join(", ")
314
342
  }
315
343
 
316
344
  // We don't output patches or body yet
317
- else if (header === 'patches' || header == 'body')
345
+ else if (header === 'patches' || header === 'body' || header === 'patch')
318
346
  continue
319
347
 
320
348
  set_header(header, value)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "0.1.11",
3
+ "version": "0.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"
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Braid-HTTP
2
2
 
3
- This polyfill library implements the [Braid-HTTP v03 protocol](https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-braid-http-03.txt) in Javascript. It gives browsers a `braid_fetch()` drop-in replacement for the `fetch()` API, and gives nodejs an `http` plugin, allowing them to speak Braid in a simple way.
3
+ This polyfill library implements the [Braid-HTTP v04 protocol](https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-braid-http-04.txt) in Javascript. It gives browsers a `braid_fetch()` drop-in replacement for the `fetch()` API, and gives nodejs an `http` plugin, allowing them to speak Braid in a simple way.
4
4
 
5
5
  Developed in [braid.org](https://braid.org).
6
6