Skip to content
Source
Sign inSign up

fetch.ts

42 lines1.8 KB

1import { decodeEnvelope } from './cbor.ts';
2import { selectEntry } from './database.ts';
3import { badRequest, HttpError, unavailable } from './errors.ts';
4import type { Limits } from './limits.ts';
5import { parameters } from './multipart.ts';
6import type { Observations } from './observations.ts';
7import { contentLength, Deadline, readBody } from './streams.ts';
8​
9type FetchResult =
10 | { kind: 'exact'; value: Uint8Array; blob_id: string | null }
11 | { kind: 'fallback'; key: Uint8Array };
12​
13export async function fetchMetadata(
14 request: Request,
15 env: Pick<Env, 'INDEX' | 'ARTIFACTS'>,
16 scope: string,
17 limits: Limits,
18 deadline: Deadline,
19 stats: Observations,
20): Promise<FetchResult> {
21 if (parameters(request.headers.get('Content-Type') ?? '').type !== 'application/cbor')
22 badRequest();
23 contentLength(request, limits.fetch);
24 const body = await readBody(request.body, limits.fetch, deadline);
25 stats.request_bytes = body.length;
26 const data = decodeEnvelope(body, false, limits);
27 const selected = await deadline.run(
28 selectEntry(env.INDEX, scope, data.key, data.secondary_key, stats),
29 );
30 if (!selected) throw new HttpError(404, 'miss');
31 // Fallbacks only identify the associated key. They must not depend on R2 availability.
32 if (selected.kind === 'fallback') return { kind: 'fallback', key: new Uint8Array(selected.key) };
33​
34 stats.r2_operations++;
35 const object = await deadline
36 .run(env.ARTIFACTS.get(selected.value_object))
37 .catch(() => unavailable());
38 if (!object || object.size !== selected.value_size || object.size > limits.value) unavailable();
39 const value = await readBody(object.body, limits.value, deadline).catch(() => unavailable());
40 if (value.length !== selected.value_size) unavailable();
41 return { kind: 'exact', value, blob_id: selected.blob_id };