MCPcopy
hub / github.com/tldraw/tldraw / handleUserAssetGet

Function handleUserAssetGet

packages/worker-shared/src/userAssetUploads.ts:119–197  ·  view source on GitHub ↗
({
	request,
	bucket,
	objectName,
	context,
}: {
	request: IRequest
	bucket: R2BucketLike
	objectName: string
	context: ExecutionContext
})

Source from the content-addressed store, hash-verified

117 * @public
118 */
119export async function handleUserAssetGet({
120 request,
121 bucket,
122 objectName,
123 context,
124}: {
125 request: IRequest
126 bucket: R2BucketLike
127 objectName: string
128 context: ExecutionContext
129}): Promise<Response> {
130 // this cache automatically handles range responses etc.
131 const cacheKey = new Request(request.url, { headers: request.headers })
132 const cachedResponse = await caches.default.match(cacheKey)
133 if (cachedResponse) {
134 return cachedResponse
135 }
136
137 const object = await retry(
138 () => bucket.get(objectName, { range: request.headers, onlyIf: request.headers }),
139 TRANSIENT_RETRY_OPTIONS
140 )
141
142 if (!object) {
143 return notFound()
144 }
145
146 const headers = new Headers()
147 object.writeHttpMetadata(headers)
148
149 // assets are immutable, so we can cache them basically forever:
150 headers.set('cache-control', 'public, max-age=31536000, immutable')
151 headers.set('etag', object.httpEtag)
152
153 // we set CORS headers so all clients can access assets. we do this here so our `cors` helper in
154 // worker.ts doesn't try to set extra cors headers on responses that have been read from the
155 // cache, which isn't allowed by cloudflare.
156 headers.set('access-control-allow-origin', '*')
157
158 // Prevent XSS from user-uploaded SVGs (or any file served with an executable content-type).
159 // This is critical when assets are served from the same origin as the app.
160 headers.set('content-security-policy', "default-src 'none'")
161 headers.set('x-content-type-options', 'nosniff')
162
163 // cloudflare doesn't set the content-range header automatically in writeHttpMetadata, so we
164 // need to do it ourselves.
165 let contentRange
166 if (object.range) {
167 if ('suffix' in object.range) {
168 const start = object.size - object.range.suffix
169 const end = object.size - 1
170 contentRange = `bytes ${start}-${end}/${object.size}`
171 } else {
172 const start = object.range.offset ?? 0
173 const end = object.range.length ? start + object.range.length - 1 : object.size - 1
174 if (start !== 0 || end !== object.size - 1) {
175 contentRange = `bytes ${start}-${end}/${object.size}`
176 }

Callers 4

worker.tsFile · 0.90
WorkerClass · 0.90
WorkerClass · 0.90
WorkerClass · 0.90

Calls 7

retryFunction · 0.90
notFoundFunction · 0.90
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…