fix: serve svg+xml as svg (#13277)
Based from https://github.com/payloadcms/payload/pull/13276 Fixes https://github.com/payloadcms/payload/issues/7624 If an uploaded image has `.svg` ext, and the mimeType is read as `application/xml` adjust the mimeType to `image/svg+xml`. --------- Co-authored-by: Philipp Schneider <47689073+philipp-tailor@users.noreply.github.com>
This commit is contained in:
@@ -93,9 +93,14 @@ export const getFileHandler: PayloadHandler = async (req) => {
|
||||
|
||||
const data = streamFile(filePath)
|
||||
const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath)
|
||||
let mimeType = fileTypeResult.mime
|
||||
|
||||
if (filePath.endsWith('.svg') && fileTypeResult.mime === 'application/xml') {
|
||||
mimeType = 'image/svg+xml'
|
||||
}
|
||||
|
||||
let headers = new Headers()
|
||||
headers.set('Content-Type', fileTypeResult.mime)
|
||||
headers.set('Content-Type', mimeType)
|
||||
headers.set('Content-Length', stats.size + '')
|
||||
headers = collection.config.upload?.modifyResponseHeaders
|
||||
? collection.config.upload.modifyResponseHeaders({ headers }) || headers
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
mediaWithoutCacheTagsSlug,
|
||||
relationPreviewSlug,
|
||||
relationSlug,
|
||||
svgOnlySlug,
|
||||
threeDimensionalSlug,
|
||||
withMetadataSlug,
|
||||
withOnlyJPEGMetadataSlug,
|
||||
@@ -87,6 +88,7 @@ let collectErrorsFromPage: () => boolean
|
||||
let stopCollectingErrorsFromPage: () => boolean
|
||||
let bulkUploadsURL: AdminUrlUtil
|
||||
let fileMimeTypeURL: AdminUrlUtil
|
||||
let svgOnlyURL: AdminUrlUtil
|
||||
|
||||
describe('Uploads', () => {
|
||||
let page: Page
|
||||
@@ -126,6 +128,7 @@ describe('Uploads', () => {
|
||||
constructorOptionsURL = new AdminUrlUtil(serverURL, constructorOptionsSlug)
|
||||
bulkUploadsURL = new AdminUrlUtil(serverURL, bulkUploadsSlug)
|
||||
fileMimeTypeURL = new AdminUrlUtil(serverURL, fileMimeTypeSlug)
|
||||
svgOnlyURL = new AdminUrlUtil(serverURL, svgOnlySlug)
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
@@ -270,6 +273,23 @@ describe('Uploads', () => {
|
||||
await expect(fileMetaSizeType).toHaveText(/model\/gltf-binary/)
|
||||
})
|
||||
|
||||
test('should show proper mimetype for svg+xml file', async () => {
|
||||
await page.goto(svgOnlyURL.create)
|
||||
|
||||
await page.setInputFiles('input[type="file"]', path.resolve(dirname, './svgWithXml.svg'))
|
||||
const filename = page.locator('.file-field__filename')
|
||||
await expect(filename).toHaveValue('svgWithXml.svg')
|
||||
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
const fileMetaSizeType = page.locator('.file-meta__size-type')
|
||||
await expect(fileMetaSizeType).toHaveText(/image\/svg\+xml/)
|
||||
|
||||
// ensure the svg loads
|
||||
const svgImage = page.locator('img[src*="svgWithXml"]')
|
||||
await expect(svgImage).toBeVisible()
|
||||
})
|
||||
|
||||
test('should create animated file upload', async () => {
|
||||
await page.goto(animatedTypeMediaURL.create)
|
||||
|
||||
|
||||
@@ -84,6 +84,9 @@ export interface Config {
|
||||
'allow-list-media': AllowListMedia;
|
||||
'skip-safe-fetch-media': SkipSafeFetchMedia;
|
||||
'skip-allow-list-safe-fetch-media': SkipAllowListSafeFetchMedia;
|
||||
'restrict-file-types': RestrictFileType;
|
||||
'no-restrict-file-types': NoRestrictFileType;
|
||||
'no-restrict-file-mime-types': NoRestrictFileMimeType;
|
||||
'animated-type-media': AnimatedTypeMedia;
|
||||
enlarge: Enlarge;
|
||||
'without-enlarge': WithoutEnlarge;
|
||||
@@ -113,6 +116,8 @@ export interface Config {
|
||||
'constructor-options': ConstructorOption;
|
||||
'bulk-uploads': BulkUpload;
|
||||
'simple-relationship': SimpleRelationship;
|
||||
'file-mime-type': FileMimeType;
|
||||
'svg-only': SvgOnly;
|
||||
users: User;
|
||||
'payload-locked-documents': PayloadLockedDocument;
|
||||
'payload-preferences': PayloadPreference;
|
||||
@@ -137,6 +142,9 @@ export interface Config {
|
||||
'allow-list-media': AllowListMediaSelect<false> | AllowListMediaSelect<true>;
|
||||
'skip-safe-fetch-media': SkipSafeFetchMediaSelect<false> | SkipSafeFetchMediaSelect<true>;
|
||||
'skip-allow-list-safe-fetch-media': SkipAllowListSafeFetchMediaSelect<false> | SkipAllowListSafeFetchMediaSelect<true>;
|
||||
'restrict-file-types': RestrictFileTypesSelect<false> | RestrictFileTypesSelect<true>;
|
||||
'no-restrict-file-types': NoRestrictFileTypesSelect<false> | NoRestrictFileTypesSelect<true>;
|
||||
'no-restrict-file-mime-types': NoRestrictFileMimeTypesSelect<false> | NoRestrictFileMimeTypesSelect<true>;
|
||||
'animated-type-media': AnimatedTypeMediaSelect<false> | AnimatedTypeMediaSelect<true>;
|
||||
enlarge: EnlargeSelect<false> | EnlargeSelect<true>;
|
||||
'without-enlarge': WithoutEnlargeSelect<false> | WithoutEnlargeSelect<true>;
|
||||
@@ -166,6 +174,8 @@ export interface Config {
|
||||
'constructor-options': ConstructorOptionsSelect<false> | ConstructorOptionsSelect<true>;
|
||||
'bulk-uploads': BulkUploadsSelect<false> | BulkUploadsSelect<true>;
|
||||
'simple-relationship': SimpleRelationshipSelect<false> | SimpleRelationshipSelect<true>;
|
||||
'file-mime-type': FileMimeTypeSelect<false> | FileMimeTypeSelect<true>;
|
||||
'svg-only': SvgOnlySelect<false> | SvgOnlySelect<true>;
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||
@@ -838,6 +848,60 @@ export interface SkipAllowListSafeFetchMedia {
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "restrict-file-types".
|
||||
*/
|
||||
export interface RestrictFileType {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "no-restrict-file-types".
|
||||
*/
|
||||
export interface NoRestrictFileType {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "no-restrict-file-mime-types".
|
||||
*/
|
||||
export interface NoRestrictFileMimeType {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "animated-type-media".
|
||||
@@ -1502,6 +1566,43 @@ export interface SimpleRelationship {
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "file-mime-type".
|
||||
*/
|
||||
export interface FileMimeType {
|
||||
id: string;
|
||||
title?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "svg-only".
|
||||
*/
|
||||
export interface SvgOnly {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users".
|
||||
@@ -1601,6 +1702,18 @@ export interface PayloadLockedDocument {
|
||||
relationTo: 'skip-allow-list-safe-fetch-media';
|
||||
value: string | SkipAllowListSafeFetchMedia;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'restrict-file-types';
|
||||
value: string | RestrictFileType;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'no-restrict-file-types';
|
||||
value: string | NoRestrictFileType;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'no-restrict-file-mime-types';
|
||||
value: string | NoRestrictFileMimeType;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'animated-type-media';
|
||||
value: string | AnimatedTypeMedia;
|
||||
@@ -1717,6 +1830,14 @@ export interface PayloadLockedDocument {
|
||||
relationTo: 'simple-relationship';
|
||||
value: string | SimpleRelationship;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'file-mime-type';
|
||||
value: string | FileMimeType;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'svg-only';
|
||||
value: string | SvgOnly;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'users';
|
||||
value: string | User;
|
||||
@@ -2429,6 +2550,57 @@ export interface SkipAllowListSafeFetchMediaSelect<T extends boolean = true> {
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "restrict-file-types_select".
|
||||
*/
|
||||
export interface RestrictFileTypesSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "no-restrict-file-types_select".
|
||||
*/
|
||||
export interface NoRestrictFileTypesSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "no-restrict-file-mime-types_select".
|
||||
*/
|
||||
export interface NoRestrictFileMimeTypesSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "animated-type-media_select".
|
||||
@@ -3138,6 +3310,41 @@ export interface SimpleRelationshipSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "file-mime-type_select".
|
||||
*/
|
||||
export interface FileMimeTypeSelect<T extends boolean = true> {
|
||||
title?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "svg-only_select".
|
||||
*/
|
||||
export interface SvgOnlySelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users_select".
|
||||
|
||||
Reference in New Issue
Block a user