Skip to content

Commit eeddfb8

Browse files
committed
fixup! tweaks + make tests pass
Also: introduce a new synthetic status code 904 for unsupported host types (e.g. `ipv4` instead of `ip4`). Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
1 parent 8d0fe85 commit eeddfb8

File tree

4 files changed

+39
-35
lines changed

4 files changed

+39
-35
lines changed

deps.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export { encodeHex } from 'https://deno.land/std@0.203.0/encoding/hex.ts'
88
export { decodeBase64 } from 'https://deno.land/std@0.203.0/encoding/base64.ts'
99
export { decode as decodeVarint } from 'https://deno.land/x/varint@v2.0.0/varint.ts'
1010

11-
// Deno Bundle does not support npm dependencies, we have to load the via CDN
11+
// Deno Bundle does not support npm dependencies, we have to load them via CDN
1212
export { CarBlockIterator } from 'https://cdn.skypack.dev/@ipld/car@5.3.2/?dts'
1313
export {
1414
UnsupportedHashError,

lib/multiaddr.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function multiaddrToHttpUri (addr) {
2626
)
2727
}
2828

29-
return `${scheme}://${getUriHost(hostType, hostValue)}${buildUriPort(scheme, port)}`
29+
return `${scheme}://${getUriHost(hostType, hostValue)}${getUriPort(scheme, port)}`
3030
}
3131

3232
function getUriHost (hostType, hostValue) {
@@ -37,11 +37,18 @@ function getUriHost (hostType, hostValue) {
3737
case 'dns6':
3838
return hostValue
3939
case 'ip6':
40+
// See https://superuser.com/a/367788/135774:
41+
// According to RFC2732, literal IPv6 addresses should be put inside square brackets in URLs
4042
return `[${hostValue}]`
4143
}
44+
45+
throw Object.assign(
46+
new Error(`Unsupported multiaddr host type "${hostType}"`),
47+
{ code: 'UNSUPPORTED_MULTIADDR_HOST_TYPE' }
48+
)
4249
}
4350

44-
function buildUriPort (scheme, port) {
51+
function getUriPort (scheme, port) {
4552
if (scheme === 'http' && port === '80') return ''
4653
if (scheme === 'https' && port === '443') return ''
4754
return `:${port}`

lib/spark.js

+15-13
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ export default class Spark {
8888
} catch (err) {
8989
console.error(`Failed to fetch ${retrieval.cid} from ${provider.address} using ${provider.protocol}`)
9090
console.error(err)
91+
if (!stats.statusCode) {
92+
stats.statusCode = mapErrorToStatusCode(err)
93+
}
9194
}
9295
}
9396

@@ -145,13 +148,7 @@ export default class Spark {
145148
}
146149

147150
if (!stats.carTooLarge) {
148-
try {
149-
await verifyContent(cid, carBytes)
150-
stats.contentVerification = 'OK'
151-
} catch (err) {
152-
console.error('Content verification failed.', err)
153-
stats.contentVerification = 'ERROR_' + (err.code ?? 'UNKNOWN')
154-
}
151+
await verifyContent(cid, carBytes)
155152

156153
const digest = await crypto.subtle.digest('sha-256', carBytes)
157154
// 12 is the code for sha2-256
@@ -162,11 +159,6 @@ export default class Spark {
162159
console.error('Retrieval failed with status code %s: %s',
163160
res.status, (await res.text()).trimEnd())
164161
}
165-
} catch (err) {
166-
if (!stats.statusCode) {
167-
stats.statusCode = mapErrorToStatusCode(err)
168-
}
169-
throw err
170162
} finally {
171163
clearTimeout(timeout)
172164
}
@@ -273,7 +265,13 @@ function getRetrievalUrl (protocol, address, cid) {
273265
* @param {Uint8Array} carBytes
274266
*/
275267
async function verifyContent (cid, carBytes) {
276-
const reader = await CarBlockIterator.fromBytes(carBytes)
268+
let reader
269+
try {
270+
reader = await CarBlockIterator.fromBytes(carBytes)
271+
} catch (err) {
272+
throw Object.assign(err, {code: 'CANNOT_PARSE_CAR_BYTES' })
273+
}
274+
277275
for await (const block of reader) {
278276
if (block.cid.toString() !== cid.toString()) {
279277
throw Object.assign(
@@ -295,6 +293,8 @@ function mapErrorToStatusCode (err) {
295293
return 902
296294
case 'MULTIADDR_HAS_TOO_MANY_PARTS':
297295
return 903
296+
case 'UNSUPPORTED_MULTIADDR_HOST_TYPE':
297+
return 904
298298
}
299299

300300
// 92x for content verification errors
@@ -304,6 +304,8 @@ function mapErrorToStatusCode (err) {
304304
return 922
305305
} else if (err.code === 'UNEXPECTED_CAR_BLOCK') {
306306
return 923
307+
} else if (err.code === 'CANNOT_PARSE_CAR_BYTES') {
308+
return 924
307309
}
308310

309311
// 91x errors for network connection errors

test/spark.js

+14-19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { test } from 'zinnia:test'
55
import { assertInstanceOf, assertEquals, assertArrayIncludes } from 'zinnia:assert'
66
import { SPARK_VERSION } from '../lib/constants.js'
77

8+
const KNOWN_CID = 'bafkreih25dih6ug3xtj73vswccw423b56ilrwmnos4cbwhrceudopdp5sq'
9+
810
test('getRetrieval', async () => {
911
const round = {
1012
roundId: '123',
@@ -47,19 +49,12 @@ test('getRetrieval', async () => {
4749

4850
// TODO: test more cases
4951
test('fetchCAR', async () => {
50-
const URL = 'url'
5152
const requests = []
52-
const fetch = async url => {
53-
requests.push({ url })
54-
return {
55-
status: 200,
56-
ok: true,
57-
body: (async function * () {
58-
yield new Uint8Array([1, 2, 3])
59-
})()
60-
}
53+
const mockedFetch = async url => {
54+
requests.push(url.toString())
55+
return fetch(`https://frisbii.fly.dev/ipfs/${KNOWN_CID}`)
6156
}
62-
const spark = new Spark({ fetch })
57+
const spark = new Spark({ fetch: mockedFetch })
6358
const stats = {
6459
timeout: false,
6560
startAt: new Date(),
@@ -70,16 +65,16 @@ test('fetchCAR', async () => {
7065
carChecksum: null,
7166
statusCode: null
7267
}
73-
await spark.fetchCAR('http', '127.0.0.1', 'bafy', stats)
74-
assertEquals(stats.timeout, false)
68+
await spark.fetchCAR('http', '/ip4/127.0.0.1/tcp/80/http', KNOWN_CID, stats)
69+
assertEquals(stats.timeout, false, 'stats.timeout')
7570
assertInstanceOf(stats.startAt, Date)
7671
assertInstanceOf(stats.firstByteAt, Date)
7772
assertInstanceOf(stats.endAt, Date)
78-
assertEquals(stats.carTooLarge, false)
79-
assertEquals(stats.byteLength, 3)
80-
assertEquals(stats.carChecksum, '1220039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81')
81-
assertEquals(stats.statusCode, 200)
82-
assertEquals(requests, [{ url: URL }])
73+
assertEquals(stats.carTooLarge, false, 'stats.carTooLarge')
74+
assertEquals(stats.byteLength, 200, 'stats.byteLength')
75+
assertEquals(stats.carChecksum, '122069f03061f7ad4c14a5691b7e96d3ddd109023a6539a0b4230ea3dc92050e7136', 'stats.carChecksum')
76+
assertEquals(stats.statusCode, 200, 'stats.statusCode')
77+
assertEquals(requests, [`http://127.0.0.1/ipfs/${KNOWN_CID}?dag-scope=block`])
8378
})
8479

8580
/* Disabled as long as we are fetching the top-level block only
@@ -104,7 +99,7 @@ test('fetchCAR exceeding MAX_CAR_SIZE', async () => {
10499
carChecksum: null,
105100
statusCode: null
106101
}
107-
await spark.fetchCAR('http', '127.0.0.1', 'bafy', stats)
102+
await spark.fetchCAR('http', '/ipv4/127.0.0.1/tcp/80/http', 'bafy', stats)
108103
assertEquals(stats.timeout, false)
109104
assertEquals(stats.carTooLarge, true)
110105
assertEquals(stats.byteLength, MAX_CAR_SIZE + 1)

0 commit comments

Comments
 (0)