mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-09-01 01:46:16 +00:00
Fix: preserve non-ASCII filenames in document downloads (#9702)
This commit is contained in:
31
src-ui/src/app/utils/http.spec.ts
Normal file
31
src-ui/src/app/utils/http.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { getFilenameFromContentDisposition } from './http'
|
||||
|
||||
describe('getFilenameFromContentDisposition', () => {
|
||||
it('should extract filename from Content-Disposition header with filename*', () => {
|
||||
const header = "attachment; filename*=UTF-8''example%20file.txt"
|
||||
expect(getFilenameFromContentDisposition(header)).toBe('example file.txt')
|
||||
})
|
||||
|
||||
it('should extract filename from Content-Disposition header with filename=', () => {
|
||||
const header = 'attachment; filename="example-file.txt"'
|
||||
expect(getFilenameFromContentDisposition(header)).toBe('example-file.txt')
|
||||
})
|
||||
|
||||
it('should prioritize filename* over filename if both are present', () => {
|
||||
const header =
|
||||
'attachment; filename="fallback.txt"; filename*=UTF-8\'\'preferred%20file.txt'
|
||||
const result = getFilenameFromContentDisposition(header)
|
||||
expect(result).toBe('preferred file.txt')
|
||||
})
|
||||
|
||||
it('should gracefully fall back to null', () => {
|
||||
// invalid UTF-8 sequence
|
||||
expect(
|
||||
getFilenameFromContentDisposition("attachment; filename*=UTF-8''%E0%A4%A")
|
||||
).toBeNull()
|
||||
// missing filename
|
||||
expect(getFilenameFromContentDisposition('attachment;')).toBeNull()
|
||||
// empty header
|
||||
expect(getFilenameFromContentDisposition(null)).toBeNull()
|
||||
})
|
||||
})
|
23
src-ui/src/app/utils/http.ts
Normal file
23
src-ui/src/app/utils/http.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export function getFilenameFromContentDisposition(header: string): string {
|
||||
if (!header) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Try filename* (RFC 5987)
|
||||
const filenameStar = header.match(/filename\*=(?:UTF-\d['']*)?([^;]+)/i)
|
||||
if (filenameStar?.[1]) {
|
||||
try {
|
||||
return decodeURIComponent(filenameStar[1])
|
||||
} catch (e) {
|
||||
// Ignore decoding errors and fall through
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to filename=
|
||||
const filenameMatch = header.match(/filename="?([^"]+)"?/)
|
||||
if (filenameMatch?.[1]) {
|
||||
return filenameMatch[1]
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
Reference in New Issue
Block a user