diff --git "a/e2e/cypress/fixtures/images/\331\241\331\240 \331\203\331\205 \320\274\320\265\321\201\321\202 \320\264\320\273\321\217 \320\235\321\214\321\216-\320\231\320\276\321\200\320\272\320\265.pdf" "b/e2e/cypress/fixtures/images/\331\241\331\240 \331\203\331\205 \320\274\320\265\321\201\321\202 \320\264\320\273\321\217 \320\235\321\214\321\216-\320\231\320\276\321\200\320\272\320\265.pdf" new file mode 100644 index 0000000000..9ec444cfa4 Binary files /dev/null and "b/e2e/cypress/fixtures/images/\331\241\331\240 \331\203\331\205 \320\274\320\265\321\201\321\202 \320\264\320\273\321\217 \320\235\321\214\321\216-\320\231\320\276\321\200\320\272\320\265.pdf" differ diff --git a/e2e/cypress/integration/dashboard-aws-multipart.spec.ts b/e2e/cypress/integration/dashboard-aws-multipart.spec.ts index 3c960f4774..ab155a2b30 100644 --- a/e2e/cypress/integration/dashboard-aws-multipart.spec.ts +++ b/e2e/cypress/integration/dashboard-aws-multipart.spec.ts @@ -14,6 +14,15 @@ describe('Dashboard with @uppy/aws-s3-multipart', () => { cy.wait(['@post', '@get', '@put']) cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') }) + it('should upload Russian poem image successfully', () => { + const fileName = '١٠ كم мест для Нью-Йорке.pdf' + cy.get('@file-input').selectFile(`cypress/fixtures/images/${fileName}`, { force:true }) + + cy.get('.uppy-StatusBar-actionBtn--upload').click() + cy.wait(['@post', '@get', '@put']) + cy.get('.uppy-Dashboard-Item-name').should('contain', fileName) + cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') + }) it('should handle retry request gracefully', () => { cy.get('@file-input').selectFile('cypress/fixtures/images/cat.jpg', { force:true }) diff --git a/packages/@uppy/companion/src/server/controllers/s3.js b/packages/@uppy/companion/src/server/controllers/s3.js index 794e58a467..1948146901 100644 --- a/packages/@uppy/companion/src/server/controllers/s3.js +++ b/packages/@uppy/companion/src/server/controllers/s3.js @@ -1,5 +1,13 @@ const express = require('express') +function rfc2047Encode (data) { + // eslint-disable-next-line no-param-reassign + data = `${data}` + // eslint-disable-next-line no-control-regex + if (/^[\x00-\x7F]*$/.test(data)) return data // we return ASCII as is + return `=?UTF-8?B?${Buffer.from(data).toString('base64')}?=` // We encode non-ASCII strings +} + module.exports = function s3 (config) { if (typeof config.acl !== 'string' && config.acl != null) { throw new TypeError('s3: The `acl` option must be a string or null') @@ -102,7 +110,7 @@ module.exports = function s3 (config) { Bucket: config.bucket, Key: key, ContentType: type, - Metadata: metadata, + Metadata: Object.fromEntries(Object.entries(metadata).map(entry => entry.map(rfc2047Encode))), } if (config.acl != null) params.ACL = config.acl