From de31b4e73c680d393f85c748cb50c45853c792c1 Mon Sep 17 00:00:00 2001 From: Daneryl Date: Mon, 28 Sep 2020 16:16:58 +0200 Subject: [PATCH] support download files with utf8 names --- app/api/files/routes.ts | 5 +++- app/api/files/specs/downloadRoute.spec.ts | 36 +++++++++++++++++++++-- app/api/files/specs/routes.spec.ts | 12 +------- package.json | 2 +- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/app/api/files/routes.ts b/app/api/files/routes.ts index 88e0c889db..2d76262d27 100644 --- a/app/api/files/routes.ts +++ b/app/api/files/routes.ts @@ -79,7 +79,10 @@ export default (app: Application) => { } if (file.originalname) { - res.setHeader('Content-Disposition', `filename=${file.originalname}`); + res.setHeader( + 'Content-Disposition', + `filename*=UTF-8''${encodeURIComponent(file.originalname)}` + ); } res.sendFile(uploadsPath(filename)); diff --git a/app/api/files/specs/downloadRoute.spec.ts b/app/api/files/specs/downloadRoute.spec.ts index 30d5777143..d4518d82ae 100644 --- a/app/api/files/specs/downloadRoute.spec.ts +++ b/app/api/files/specs/downloadRoute.spec.ts @@ -4,9 +4,10 @@ import { Application, Request, Response, NextFunction } from 'express'; import { setUpApp } from 'api/utils/testingRoutes'; import db from 'api/utils/testing_db'; -import { fixtures, fileName1 } from './fixtures'; +import { fixtures, fileName1, uploadId } from './fixtures'; import uploadRoutes from '../routes'; +import { files } from '../files'; jest.mock( '../../auth/authMiddleware.ts', @@ -26,12 +27,41 @@ describe('files routes download', () => { describe('GET/', () => { it('should send the file', async () => { - const response: SuperTestResponse = await request(app).get(`/api/files/${fileName1}`); + const response: SuperTestResponse = await request(app) + .get(`/api/files/${fileName1}`) + .expect(200); - expect(response.header['content-disposition']).toBe('filename=upload1'); expect(response.body instanceof Buffer).toBe(true); }); + it('should set the original filename as content-disposition header', async () => { + const response: SuperTestResponse = await request(app) + .get(`/api/files/${fileName1}`) + .expect(200); + + expect(response.get('Content-Disposition')).toBe("filename*=UTF-8''upload1"); + }); + + it('should properly uri encode original names', async () => { + await files.save({ _id: uploadId, originalname: '테스트 한글chinese-file' }); + + const response: SuperTestResponse = await request(app) + .get(`/api/files/${fileName1}`) + .expect(200); + + expect(response.get('Content-Disposition')).toBe( + `filename*=UTF-8''${encodeURIComponent('테스트 한글chinese-file')}` + ); + }); + + it('should not set content-disposition header when the file does not have an original name', async () => { + const response: SuperTestResponse = await request(app) + .get('/api/files/fileNotInDisk') + .expect(404); + + expect(response.get('Content-Disposition')).toBeUndefined(); + }); + describe('when file entry does not exist', () => { it('should respond with 404', async () => { const response = await request(app) diff --git a/app/api/files/specs/routes.spec.ts b/app/api/files/specs/routes.spec.ts index a7b0aadd2b..88b63e1262 100644 --- a/app/api/files/specs/routes.spec.ts +++ b/app/api/files/specs/routes.spec.ts @@ -9,7 +9,7 @@ import { setUpApp } from 'api/utils/testingRoutes'; import connections from 'api/relationships'; import { FileType } from 'shared/types/fileType'; -import { fileName1, fixtures, uploadId, uploadId2 } from './fixtures'; +import { fixtures, uploadId, uploadId2 } from './fixtures'; import { files } from '../files'; import uploadRoutes from '../routes'; @@ -62,16 +62,6 @@ describe('files routes', () => { 'upload2', ]); }); - - it('should set the original filename as content-disposition header', async () => { - const response: SuperTestResponse = await request(app).get(`/api/files/${fileName1}`); - expect(response.get('Content-Disposition')).toBe('filename=upload1'); - }); - - it('should not set content-disposition header when the file does not have an original name', async () => { - const response: SuperTestResponse = await request(app).get('/api/files/fileNotInDisk'); - expect(response.get('Content-Disposition')).toBeUndefined(); - }); }); describe('DELETE/api/files', () => { diff --git a/package.json b/package.json index 5dee862cf9..0751303890 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uwazi", - "version": "1.10.0", + "version": "1.10.1", "description": "Uwazi is a free, open-source solution for organising, analysing and publishing your documents.", "keywords": [ "react"