braid-http 1.3.11 → 1.3.13
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/braid-http-client.js +9 -19
- package/braid-http-server.js +60 -37
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -116,22 +116,11 @@ function braidify_http (http) {
|
|
|
116
116
|
// ***************************
|
|
117
117
|
|
|
118
118
|
var normal_fetch,
|
|
119
|
-
AbortController,
|
|
120
|
-
Headers,
|
|
121
119
|
is_nodejs = typeof window === 'undefined'
|
|
122
120
|
|
|
123
121
|
if (is_nodejs) {
|
|
124
122
|
// Nodejs
|
|
125
|
-
|
|
126
|
-
// Note that reconnect logic doesn't work in node-fetch, because it
|
|
127
|
-
// doesn't call the .catch() handler when the stream fails.
|
|
128
|
-
//
|
|
129
|
-
// See https://github.com/node-fetch/node-fetch/issues/753
|
|
130
|
-
|
|
131
|
-
normal_fetch = require('node-fetch')
|
|
132
|
-
AbortController = require('abort-controller')
|
|
133
|
-
Headers = normal_fetch.Headers
|
|
134
|
-
var to_whatwg_stream = require('web-streams-node').toWebReadableStream
|
|
123
|
+
normal_fetch = fetch
|
|
135
124
|
} else {
|
|
136
125
|
// Web Browser
|
|
137
126
|
normal_fetch = window.fetch
|
|
@@ -418,9 +407,6 @@ async function braid_fetch (url, params = {}) {
|
|
|
418
407
|
|
|
419
408
|
// Parse a stream of versions from the incoming bytes
|
|
420
409
|
async function handle_fetch_stream (stream, cb, on_bytes) {
|
|
421
|
-
if (is_nodejs)
|
|
422
|
-
stream = to_whatwg_stream(stream)
|
|
423
|
-
|
|
424
410
|
// Set up a reader
|
|
425
411
|
var reader = stream.getReader(),
|
|
426
412
|
parser = subscription_parser(cb)
|
|
@@ -595,7 +581,8 @@ function parse_headers (input) {
|
|
|
595
581
|
var headers_source = input.slice(start, end).map(x => String.fromCharCode(x)).join('')
|
|
596
582
|
|
|
597
583
|
// Convert "HTTP 200 OK" to a :status: 200 header
|
|
598
|
-
headers_source = headers_source.replace(/^HTTP\/?\d*\.?\d* (\d\d\d).*\r?\n/,
|
|
584
|
+
headers_source = headers_source.replace(/^HTTP\/?\d*\.?\d* (\d\d\d).*\r?\n/,
|
|
585
|
+
':status: $1\r\n')
|
|
599
586
|
|
|
600
587
|
var headers_length = headers_source.length
|
|
601
588
|
|
|
@@ -728,18 +715,21 @@ function parse_body (state) {
|
|
|
728
715
|
|
|
729
716
|
// Parse Range Patch format
|
|
730
717
|
{
|
|
718
|
+
var to_text = (bytes) =>
|
|
719
|
+
new TextDecoder('utf-8').decode(new Uint8Array(bytes))
|
|
720
|
+
|
|
731
721
|
if (!('content-length' in last_patch.headers))
|
|
732
722
|
return {
|
|
733
723
|
result: 'error',
|
|
734
724
|
message: 'no content-length in patch',
|
|
735
|
-
patch: last_patch, input: (
|
|
725
|
+
patch: last_patch, input: to_text(state.input)
|
|
736
726
|
}
|
|
737
727
|
|
|
738
728
|
if (!('content-range' in last_patch.headers))
|
|
739
729
|
return {
|
|
740
730
|
result: 'error',
|
|
741
731
|
message: 'no content-range in patch',
|
|
742
|
-
patch: last_patch, input: (
|
|
732
|
+
patch: last_patch, input: to_text(state.input)
|
|
743
733
|
}
|
|
744
734
|
|
|
745
735
|
var content_length = parseInt(last_patch.headers['content-length'])
|
|
@@ -755,7 +745,7 @@ function parse_body (state) {
|
|
|
755
745
|
return {
|
|
756
746
|
result: 'error',
|
|
757
747
|
message: 'cannot parse content-range in patch',
|
|
758
|
-
patch: last_patch, input: (
|
|
748
|
+
patch: last_patch, input: to_text(state.input)
|
|
759
749
|
}
|
|
760
750
|
|
|
761
751
|
last_patch.unit = match.unit
|
package/braid-http-server.js
CHANGED
|
@@ -25,11 +25,15 @@ var assert = require('assert')
|
|
|
25
25
|
//
|
|
26
26
|
// {"some": "json object"}
|
|
27
27
|
//
|
|
28
|
-
function write_patches(res, patches) {
|
|
28
|
+
function write_patches (res, patches) {
|
|
29
29
|
// `patches` must be a patch object or an array of patch objects
|
|
30
30
|
// - Object: {unit, range, content}
|
|
31
31
|
// - Array: [{unit, range, content}, ...]
|
|
32
32
|
|
|
33
|
+
if (typeof patches !== 'object')
|
|
34
|
+
console.error('We got bad patches!', {patches})
|
|
35
|
+
|
|
36
|
+
assert(patches)
|
|
33
37
|
assert(typeof patches === 'object') // An array is also an object
|
|
34
38
|
|
|
35
39
|
// An array of one patch behaves like a single patch
|
|
@@ -46,19 +50,29 @@ function write_patches(res, patches) {
|
|
|
46
50
|
assert(typeof patch.unit === 'string')
|
|
47
51
|
assert(typeof patch.range === 'string')
|
|
48
52
|
|
|
49
|
-
if (typeof patch.content === 'string')
|
|
50
|
-
patch.content = new TextEncoder().encode(patch.content)
|
|
51
|
-
|
|
52
53
|
if (i > 0)
|
|
53
54
|
res.write('\r\n\r\n')
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
// Use a slick object_destructuring line to extract the extra_headers
|
|
57
|
+
var {unit, range, content, ...extra_headers} = patch
|
|
58
|
+
|
|
59
|
+
// Binarize the patch content
|
|
60
|
+
var binary_content = (typeof patch.content === 'string'
|
|
61
|
+
? new TextEncoder().encode(patch.content)
|
|
62
|
+
: patch.content)
|
|
63
|
+
|
|
64
|
+
// Write the basic headers
|
|
65
|
+
res.write('Content-Length: ' + get_binary_length(binary_content) + '\r\n'
|
|
66
|
+
+ 'Content-Range: ' + patch.unit + ' ' + patch.range + '\r\n')
|
|
67
|
+
|
|
68
|
+
// Write the extra headers:
|
|
69
|
+
for (var header in extra_headers)
|
|
70
|
+
res.write(`${header}: ${extra_headers[header]}\r\n`)
|
|
71
|
+
|
|
72
|
+
res.write('\r\n')
|
|
56
73
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
${Object.entries(extra_headers).map(([k, v]) => `${k}: ${v}\r\n`).join('')}\r
|
|
60
|
-
`)
|
|
61
|
-
write_binary(res, patch.content)
|
|
74
|
+
// Write the patch content
|
|
75
|
+
write_binary(res, binary_content)
|
|
62
76
|
})
|
|
63
77
|
}
|
|
64
78
|
|
|
@@ -345,29 +359,27 @@ async function send_update(res, data, url, peer) {
|
|
|
345
359
|
write_binary(res, body)
|
|
346
360
|
}
|
|
347
361
|
|
|
348
|
-
// console.log('
|
|
349
|
-
// subscription: res.isSubscription})
|
|
362
|
+
// console.log('Sending Update', {url, peer, data, subscription: res.isSubscription})
|
|
350
363
|
|
|
351
|
-
// Validate
|
|
352
|
-
|
|
364
|
+
// Validate the body and patches
|
|
365
|
+
assert(!(patch && patches),
|
|
366
|
+
'sendUpdate: cannot have both `update.patch` and `update.patches` set')
|
|
367
|
+
if (patch)
|
|
368
|
+
patches = [patch]
|
|
369
|
+
assert(!(body && patches),
|
|
370
|
+
'sendUpdate: cannot have both `update.body` and `update.patch(es)')
|
|
371
|
+
assert(!patches || Array.isArray(patches),
|
|
372
|
+
'sendUpdate: `patches` provided is not array')
|
|
373
|
+
|
|
374
|
+
// Validate body format
|
|
353
375
|
if (body !== undefined) {
|
|
354
376
|
assert(typeof body === 'string' || get_binary_length(body) != null)
|
|
355
377
|
if (body instanceof Blob) body = await body.arrayBuffer()
|
|
356
|
-
}
|
|
357
|
-
// Only one of patch or patches can be set
|
|
358
|
-
assert(!(patch && patches))
|
|
359
|
-
assert((patch || patches) !== undefined)
|
|
360
|
-
assert((patch || patches) !== null)
|
|
361
|
-
|
|
362
|
-
// Patches must be an array
|
|
363
|
-
if (patches)
|
|
364
|
-
assert(Array.isArray(patches))
|
|
365
|
-
|
|
366
|
-
// But if using `patch`, then we set `patches` to just that object
|
|
367
|
-
if (patch)
|
|
368
|
-
patches = patch
|
|
378
|
+
}
|
|
369
379
|
|
|
370
|
-
|
|
380
|
+
// Validate patches format
|
|
381
|
+
if (patches !== undefined) {
|
|
382
|
+
// Now `patches` will be an array of patches
|
|
371
383
|
//
|
|
372
384
|
// This distinction is used in write_patches() to determine whether
|
|
373
385
|
// to inline a single patch in the update body vs. writing out a
|
|
@@ -377,16 +389,21 @@ async function send_update(res, data, url, peer) {
|
|
|
377
389
|
assert('unit' in p)
|
|
378
390
|
assert('range' in p)
|
|
379
391
|
assert('content' in p)
|
|
380
|
-
assert(typeof p.content === 'string'
|
|
392
|
+
assert(typeof p.content === 'string'
|
|
393
|
+
|| get_binary_length(p.content) != null)
|
|
381
394
|
if (p.content instanceof Blob) p.content = await p.content.arrayBuffer()
|
|
382
395
|
}
|
|
383
396
|
}
|
|
384
397
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
398
|
+
// To send a response without a body, we just send an empty body
|
|
399
|
+
if (!patches && !body)
|
|
400
|
+
body = ''
|
|
388
401
|
|
|
389
|
-
|
|
402
|
+
var reason =
|
|
403
|
+
status === 200 ? 'OK'
|
|
404
|
+
: 404 ? 'Not Found'
|
|
405
|
+
: 'Unknown'
|
|
406
|
+
if (res.isSubscription) res.write(`HTTP ${status} ${reason}\r\n`)
|
|
390
407
|
|
|
391
408
|
// Write the headers or virtual headers
|
|
392
409
|
for (var [header, value] of Object.entries(data)) {
|
|
@@ -396,6 +413,10 @@ async function send_update(res, data, url, peer) {
|
|
|
396
413
|
if (value === undefined)
|
|
397
414
|
continue
|
|
398
415
|
|
|
416
|
+
// Status headers are set in the status line (above)
|
|
417
|
+
if (header === 'status')
|
|
418
|
+
continue
|
|
419
|
+
|
|
399
420
|
// Version and Parents get output in the Structured Headers format,
|
|
400
421
|
// so we convert `value` from array to comma-separated strings.
|
|
401
422
|
if (header === 'version') {
|
|
@@ -414,10 +435,12 @@ async function send_update(res, data, url, peer) {
|
|
|
414
435
|
}
|
|
415
436
|
|
|
416
437
|
// Write the patches or body
|
|
417
|
-
if (
|
|
418
|
-
let
|
|
419
|
-
|
|
420
|
-
|
|
438
|
+
if (body || body === '') {
|
|
439
|
+
let binary = typeof body === 'string' ? new TextEncoder().encode(body) : body,
|
|
440
|
+
length = get_binary_length(binary)
|
|
441
|
+
assert(length !== undefined && length !== 'undefined')
|
|
442
|
+
set_header('Content-Length', length)
|
|
443
|
+
write_body(binary)
|
|
421
444
|
} else
|
|
422
445
|
write_patches(res, patches)
|
|
423
446
|
|