braid-http 1.3.7 → 1.3.9
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/README.md +19 -7
- package/braid-http-client.js +18 -13
- package/braid-http-server.js +9 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Braid-HTTP
|
|
2
2
|
|
|
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)
|
|
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), modified slightly to follow the HTTP Multiresponse concept discussed at [braid.org/meeting-89](https://braid.org/meeting-89). It provides browsers with a `braid_fetch()` drop-in replacement for the `fetch()` API, and offers nodejs an `http` plugin, enabling simple Braid communication.
|
|
4
4
|
|
|
5
5
|
Developed in [braid.org](https://braid.org).
|
|
6
6
|
|
|
@@ -53,8 +53,14 @@ fetch('https://braid.org/chat', {subscribe: true}).then(
|
|
|
53
53
|
// {
|
|
54
54
|
// version: ["me"],
|
|
55
55
|
// parents: ["mom", "dad"],
|
|
56
|
-
// patches: [{
|
|
57
|
-
|
|
56
|
+
// patches: [{
|
|
57
|
+
//. unit: "json",
|
|
58
|
+
// range: ".foo",
|
|
59
|
+
// content: new Uint8Array([51]),
|
|
60
|
+
// content_text: "3" <-- getter
|
|
61
|
+
//. }],
|
|
62
|
+
// body: new Uint8Array([51]),
|
|
63
|
+
// body_text: "3" <-- getter
|
|
58
64
|
// }
|
|
59
65
|
//
|
|
60
66
|
// Note that `update` will contain either patches *or* body
|
|
@@ -113,7 +119,7 @@ for await (var update of subscription_iterator) {
|
|
|
113
119
|
// Or complete snapshots:
|
|
114
120
|
else
|
|
115
121
|
// Beware the server doesn't send these yet.
|
|
116
|
-
chat = JSON.parse(update.
|
|
122
|
+
chat = JSON.parse(update.body_text)
|
|
117
123
|
|
|
118
124
|
render_stuff()
|
|
119
125
|
}
|
|
@@ -233,10 +239,16 @@ function connect () {
|
|
|
233
239
|
// {
|
|
234
240
|
// version: ["me"],
|
|
235
241
|
// parents: ["mom", "dad"],
|
|
236
|
-
// patches: [{
|
|
237
|
-
|
|
242
|
+
// patches: [{
|
|
243
|
+
//. unit: "json",
|
|
244
|
+
// range: ".foo",
|
|
245
|
+
// content: new Uint8Array([51]),
|
|
246
|
+
// content_text: "3" <-- getter
|
|
247
|
+
//. }],
|
|
248
|
+
// body: new Uint8Array([51]),
|
|
249
|
+
// body_text: "3" <-- getter
|
|
238
250
|
// }
|
|
239
|
-
//
|
|
251
|
+
// Update will contain either patches *or* body, but not both
|
|
240
252
|
console.log('We got a new update!', update)
|
|
241
253
|
})
|
|
242
254
|
|
package/braid-http-client.js
CHANGED
|
@@ -489,6 +489,7 @@ var subscription_parser = (cb) => ({
|
|
|
489
489
|
parents: this.state.parents,
|
|
490
490
|
body: this.state.body,
|
|
491
491
|
patches: this.state.patches,
|
|
492
|
+
status: this.state.status,
|
|
492
493
|
|
|
493
494
|
// Output extra_headers if there are some
|
|
494
495
|
extra_headers: extra_headers(this.state.headers)
|
|
@@ -563,6 +564,7 @@ function parse_update (state) {
|
|
|
563
564
|
state.headers = parsed.headers
|
|
564
565
|
state.version = state.headers.version
|
|
565
566
|
state.parents = state.headers.parents
|
|
567
|
+
state.status = state.headers[':status']
|
|
566
568
|
|
|
567
569
|
// Take the parsed headers out of the buffer
|
|
568
570
|
state.input = parsed.input
|
|
@@ -576,22 +578,24 @@ function parse_update (state) {
|
|
|
576
578
|
function parse_headers (input) {
|
|
577
579
|
|
|
578
580
|
// Find the start of the headers
|
|
579
|
-
let
|
|
580
|
-
while (input[
|
|
581
|
-
if (
|
|
581
|
+
let start = 0;
|
|
582
|
+
while (input[start] === 13 || input[start] === 10) start++
|
|
583
|
+
if (start === input.length) return {result: 'waiting'}
|
|
582
584
|
|
|
583
585
|
// Look for the double-newline at the end of the headers.
|
|
584
|
-
let
|
|
585
|
-
while (++
|
|
586
|
-
if (
|
|
587
|
-
if (input[
|
|
586
|
+
let end = start;
|
|
587
|
+
while (++end) {
|
|
588
|
+
if (end > input.length) return {result: 'waiting'}
|
|
589
|
+
if ( input[end - 1] === 10
|
|
590
|
+
&& (input[end - 2] === 10 || (input[end - 2] === 13 && input[end - 3] === 10)))
|
|
591
|
+
break
|
|
588
592
|
}
|
|
589
593
|
|
|
590
594
|
// Extract the header string
|
|
591
|
-
var headers_source = new TextDecoder('utf-8').decode(new Uint8Array(input.slice(
|
|
595
|
+
var headers_source = new TextDecoder('utf-8').decode(new Uint8Array(input.slice(start, end)))
|
|
592
596
|
|
|
593
|
-
//
|
|
594
|
-
headers_source = headers_source.replace(/^HTTP
|
|
597
|
+
// Convert "HTTP 200 OK" to a :status: 200 header
|
|
598
|
+
headers_source = headers_source.replace(/^HTTP\/?\d*\.?\d* (\d\d\d).*\r?\n/, ':status: $1\r\n')
|
|
595
599
|
|
|
596
600
|
var headers_length = headers_source.length
|
|
597
601
|
|
|
@@ -630,7 +634,7 @@ function parse_headers (input) {
|
|
|
630
634
|
headers.patches = JSON.parse(headers.patches)
|
|
631
635
|
|
|
632
636
|
// Update the input
|
|
633
|
-
input = input.slice(
|
|
637
|
+
input = input.slice(end)
|
|
634
638
|
|
|
635
639
|
// And return the parsed result
|
|
636
640
|
return { result: 'success', headers, input }
|
|
@@ -787,7 +791,7 @@ function extra_headers (headers) {
|
|
|
787
791
|
|
|
788
792
|
// Remove the non-extra parts
|
|
789
793
|
var known_headers = ['version', 'parents', 'patches',
|
|
790
|
-
'content-length', 'content-range']
|
|
794
|
+
'content-length', 'content-range', ':status']
|
|
791
795
|
for (var i = 0; i < known_headers.length; i++)
|
|
792
796
|
delete result[known_headers[i]]
|
|
793
797
|
|
|
@@ -807,7 +811,8 @@ function get_binary_length(x) {
|
|
|
807
811
|
function deep_copy(x) {
|
|
808
812
|
if (x === null || typeof x !== 'object') return x
|
|
809
813
|
if (Array.isArray(x)) return x.map(x => deep_copy(x))
|
|
810
|
-
if (Object.prototype.toString.call(x) === '[object Object]')
|
|
814
|
+
if (Object.prototype.toString.call(x) === '[object Object]')
|
|
815
|
+
return Object.fromEntries(Object.entries(x).map(([k, x]) => [k, deep_copy(x)]))
|
|
811
816
|
return x
|
|
812
817
|
}
|
|
813
818
|
|
package/braid-http-server.js
CHANGED
|
@@ -325,7 +325,14 @@ function braidify (req, res, next) {
|
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
async function send_update(res, data, url, peer) {
|
|
328
|
-
var {version, parents, patches, patch, body} = data
|
|
328
|
+
var {version, parents, patches, patch, body, status} = data
|
|
329
|
+
|
|
330
|
+
if (status) {
|
|
331
|
+
assert(typeof status === 'number', 'sendUpdate: status must be a number')
|
|
332
|
+
assert(status > 100 && status < 600, 'sendUpdate: status must be a number between 100 and 600')
|
|
333
|
+
}
|
|
334
|
+
else
|
|
335
|
+
status = 200
|
|
329
336
|
|
|
330
337
|
function set_header (key, val) {
|
|
331
338
|
if (res.isSubscription)
|
|
@@ -379,7 +386,7 @@ async function send_update(res, data, url, peer) {
|
|
|
379
386
|
assert(body_exists || patches, 'Missing body or patches')
|
|
380
387
|
assert(!(body_exists && patches), 'Cannot send both body and patches')
|
|
381
388
|
|
|
382
|
-
if (res.isSubscription) res.write(`HTTP
|
|
389
|
+
if (res.isSubscription) res.write(`HTTP ${status} OK\r\n`)
|
|
383
390
|
|
|
384
391
|
// Write the headers or virtual headers
|
|
385
392
|
for (var [header, value] of Object.entries(data)) {
|