fix: image optimization content-type (#46219)

Upstream images can have any arbitrary `content-type` header so this PR
normalizes the value before checking it.
This commit is contained in:
Steven 2023-02-21 21:00:14 -05:00 committed by GitHub
parent b8837ad636
commit 0b563e86de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 11 deletions

View file

@ -573,17 +573,21 @@ export async function imageOptimizer(
}
}
if (upstreamType === SVG && !nextConfig.images.dangerouslyAllowSVG) {
console.error(
`The requested resource "${href}" has type "${upstreamType}" but dangerouslyAllowSVG is disabled`
)
throw new ImageError(
400,
'"url" parameter is valid but image type is not allowed'
)
}
if (upstreamType) {
upstreamType = upstreamType.toLowerCase().trim()
if (
upstreamType.startsWith('image/svg') &&
!nextConfig.images.dangerouslyAllowSVG
) {
console.error(
`The requested resource "${href}" has type "${upstreamType}" but dangerouslyAllowSVG is disabled`
)
throw new ImageError(
400,
'"url" parameter is valid but image type is not allowed'
)
}
const vector = VECTOR_TYPES.includes(upstreamType)
const animate =
ANIMATABLE_TYPES.includes(upstreamType) && isAnimated(upstreamBuffer)
@ -591,7 +595,7 @@ export async function imageOptimizer(
if (vector || animate) {
return { buffer: upstreamBuffer, contentType: upstreamType, maxAge }
}
if (!upstreamType.startsWith('image/')) {
if (!upstreamType.startsWith('image/') || upstreamType.includes(',')) {
console.error(
"The requested resource isn't a valid image for",
href,

View file

@ -0,0 +1,6 @@
export default function handler(_req, res) {
res.setHeader('Content-Type', 'application/svg+xml')
res.end(
`<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="60" height="60"><text x="20" y="30">hi</text></svg>`
)
}

View file

@ -0,0 +1,6 @@
export default function handler(_req, res) {
res.setHeader('Content-Type', 'image/foo, text/html')
res.end(
`<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="60" height="60"><text x="20" y="30">hi</text></svg>`
)
}

View file

@ -0,0 +1,6 @@
export default function handler(_req, res) {
res.setHeader('Content-Type', 'image/SVG+XML')
res.end(
`<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="60" height="60"><text x="20" y="30">hi</text></svg>`
)
}

View file

@ -264,6 +264,36 @@ export function runTests(ctx) {
expect(res.status).toBe(400)
expect(await res.text()).toContain('valid but image type is not allowed')
})
it('should not allow svg with application header', async () => {
const query = { w: ctx.w, q: 45, url: '/api/application.svg' }
const opts = { headers: { accept: 'image/webp' } }
const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts)
expect(res.status).toBe(400)
expect(await res.text()).toContain(
"The requested resource isn't a valid image"
)
})
it('should not allow svg with comma header', async () => {
const query = { w: ctx.w, q: 55, url: '/api/comma.svg' }
const opts = { headers: { accept: 'image/webp' } }
const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts)
expect(res.status).toBe(400)
expect(await res.text()).toContain(
"The requested resource isn't a valid image"
)
})
it('should not allow svg with uppercase header', async () => {
const query = { w: ctx.w, q: 65, url: '/api/uppercase.svg' }
const opts = { headers: { accept: 'image/webp' } }
const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts)
expect(res.status).toBe(400)
expect(await res.text()).toContain(
'"url" parameter is valid but image type is not allowed'
)
})
}
it('should maintain ico format', async () => {