feat(storage-*): include modified headers into the response headers of files when using adapters (#12096)
This PR makes it so that `modifyResponseHeaders` is supported in our
adapters when set on the collection config. Previously it would be
ignored.
This means that users can now modify or append new headers to what's
returned by each service.
```ts
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
upload: {
modifyResponseHeaders: ({ headers }) => {
const newHeaders = new Headers(headers) // Copy existing headers
newHeaders.set('X-Frame-Options', 'DENY') // Set new header
return newHeaders
},
},
}
```
Also adds support for `void` return on the `modifyResponseHeaders`
function in the case where the user just wants to use existing headers
and doesn't need more control.
eg:
```ts
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
upload: {
modifyResponseHeaders: ({ headers }) => {
headers.set('X-Frame-Options', 'DENY') // You can directly set headers without returning
},
},
}
```
Manual testing checklist (no CI e2es setup for these envs yet):
- [x] GCS
- [x] S3
- [x] Azure
- [x] UploadThing
- [x] Vercel Blob
---------
Co-authored-by: James <james@trbl.design>
This commit is contained in:
@@ -15,27 +15,36 @@ export const getStaticHandler = (
|
||||
{ baseUrl, cacheControlMaxAge = 0, token }: StaticHandlerArgs,
|
||||
collection: CollectionConfig,
|
||||
): StaticHandler => {
|
||||
return async (req, { params: { clientUploadContext, filename } }) => {
|
||||
return async (req, { headers: incomingHeaders, params: { clientUploadContext, filename } }) => {
|
||||
try {
|
||||
const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })
|
||||
const fileKey = path.posix.join(prefix, encodeURIComponent(filename))
|
||||
const fileUrl = `${baseUrl}/${fileKey}`
|
||||
const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match')
|
||||
const blobMetadata = await head(fileUrl, { token })
|
||||
const uploadedAtString = blobMetadata.uploadedAt.toISOString()
|
||||
const { contentDisposition, contentType, size, uploadedAt } = blobMetadata
|
||||
const uploadedAtString = uploadedAt.toISOString()
|
||||
const ETag = `"${fileKey}-${uploadedAtString}"`
|
||||
|
||||
const { contentDisposition, contentType, size } = blobMetadata
|
||||
let headers = new Headers(incomingHeaders)
|
||||
|
||||
headers.append('Cache-Control', `public, max-age=${cacheControlMaxAge}`)
|
||||
headers.append('Content-Disposition', contentDisposition)
|
||||
headers.append('Content-Length', String(size))
|
||||
headers.append('Content-Type', contentType)
|
||||
headers.append('ETag', ETag)
|
||||
|
||||
if (
|
||||
collection.upload &&
|
||||
typeof collection.upload === 'object' &&
|
||||
typeof collection.upload.modifyResponseHeaders === 'function'
|
||||
) {
|
||||
headers = collection.upload.modifyResponseHeaders({ headers }) || headers
|
||||
}
|
||||
|
||||
if (etagFromHeaders && etagFromHeaders === ETag) {
|
||||
return new Response(null, {
|
||||
headers: new Headers({
|
||||
'Cache-Control': `public, max-age=${cacheControlMaxAge}`,
|
||||
'Content-Disposition': contentDisposition,
|
||||
'Content-Length': String(size),
|
||||
'Content-Type': contentType,
|
||||
ETag,
|
||||
}),
|
||||
headers,
|
||||
status: 304,
|
||||
})
|
||||
}
|
||||
@@ -55,15 +64,10 @@ export const getStaticHandler = (
|
||||
|
||||
const bodyBuffer = await blob.arrayBuffer()
|
||||
|
||||
headers.append('Last-Modified', uploadedAtString)
|
||||
|
||||
return new Response(bodyBuffer, {
|
||||
headers: new Headers({
|
||||
'Cache-Control': `public, max-age=${cacheControlMaxAge}`,
|
||||
'Content-Disposition': contentDisposition,
|
||||
'Content-Length': String(size),
|
||||
'Content-Type': contentType,
|
||||
ETag,
|
||||
'Last-Modified': blobMetadata.uploadedAt.toUTCString(),
|
||||
}),
|
||||
headers,
|
||||
status: 200,
|
||||
})
|
||||
} catch (err: unknown) {
|
||||
|
||||
Reference in New Issue
Block a user