MCPcopy
hub / github.com/tldraw/tldraw / handleAssetDownload

Function handleAssetDownload

templates/sync-cloudflare/worker/assetUploads.ts:35–105  ·  view source on GitHub ↗
(request: IRequest, env: Env, ctx: ExecutionContext)

Source from the content-addressed store, hash-verified

33
34// when a user downloads an asset, we retrieve it from the bucket. we also cache the response for performance.
35export async function handleAssetDownload(request: IRequest, env: Env, ctx: ExecutionContext) {
36 const objectName = getAssetObjectName(request.params.uploadId)
37
38 // if we have a cached response for this request (automatically handling ranges etc.), return it
39 const cacheKey = new Request(request.url, { headers: request.headers })
40 const cachedResponse = await caches.default.match(cacheKey)
41 if (cachedResponse) {
42 return cachedResponse
43 }
44
45 // if not, we try to fetch the asset from the bucket
46 const object = await env.TLDRAW_BUCKET.get(objectName, {
47 range: request.headers,
48 onlyIf: request.headers,
49 })
50
51 if (!object) {
52 return error(404)
53 }
54
55 // write the relevant metadata to the response headers
56 const headers = new Headers()
57 object.writeHttpMetadata(headers)
58
59 // assets are immutable, so we can cache them basically forever:
60 headers.set('cache-control', 'public, max-age=31536000, immutable')
61 headers.set('etag', object.httpEtag)
62
63 // we set CORS headers so all clients can access assets. we do this here so our `cors` helper in
64 // worker.ts doesn't try to set extra cors headers on responses that have been read from the
65 // cache, which isn't allowed by cloudflare.
66 headers.set('access-control-allow-origin', '*')
67
68 // Prevent XSS from user-uploaded SVGs (or any file served with an executable content-type).
69 headers.set('content-security-policy', "default-src 'none'")
70 headers.set('x-content-type-options', 'nosniff')
71
72 // cloudflare doesn't set the content-range header automatically in writeHttpMetadata, so we
73 // need to do it ourselves.
74 let contentRange
75 if (object.range) {
76 if ('suffix' in object.range) {
77 const start = object.size - object.range.suffix
78 const end = object.size - 1
79 contentRange = `bytes ${start}-${end}/${object.size}`
80 } else {
81 const start = object.range.offset ?? 0
82 const end = object.range.length ? start + object.range.length - 1 : object.size - 1
83 if (start !== 0 || end !== object.size - 1) {
84 contentRange = `bytes ${start}-${end}/${object.size}`
85 }
86 }
87 }
88
89 if (contentRange) {
90 headers.set('content-range', contentRange)
91 }
92

Callers

nothing calls this directly

Calls 6

getAssetObjectNameFunction · 0.85
getMethod · 0.65
setMethod · 0.65
teeMethod · 0.65
waitUntilMethod · 0.65
putMethod · 0.65

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…