From 8f5eb28945a4bf921f0afb29e09056b77f44e576 Mon Sep 17 00:00:00 2001 From: zhangxianlei <863837949@qq.com> Date: Sun, 9 Sep 2018 11:10:19 +0800 Subject: [PATCH 1/4] response.attachment append a parameter: options from contentDisposition --- lib/response.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/response.js b/lib/response.js index 8092c7aad..371875fe1 100644 --- a/lib/response.js +++ b/lib/response.js @@ -285,9 +285,9 @@ module.exports = { * @api public */ - attachment(filename) { + attachment(filename, options) { if (filename) this.type = extname(filename); - this.set('Content-Disposition', contentDisposition(filename)); + this.set('Content-Disposition', contentDisposition(filename, options)); }, /** From c35703272860bd8872bccc6cdfec0a5912533de9 Mon Sep 17 00:00:00 2001 From: zhangxianlei Date: Fri, 21 Sep 2018 12:15:14 +0800 Subject: [PATCH 2/4] add test case --- test/response/attachment.js | 135 ++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/test/response/attachment.js b/test/response/attachment.js index 5e0f732a9..7c7bcb6e4 100644 --- a/test/response/attachment.js +++ b/test/response/attachment.js @@ -48,3 +48,138 @@ describe('ctx.attachment([filename])', () => { }); }); }); + +// reference [content-disposition test case](https://github.com/jshttp/content-disposition/blob/master/test/test.js) +describe('contentDisposition(filename, options)', function () { + describe('with "fallback" option', function () { + it('should require a string or Boolean', function () { + const ctx = context(); + assert.throws(() => { ctx.attachment('plans.pdf', { fallback: 42 }) }, + /fallback.*string/); + }); + + it('should default to true', function () { + const ctx = context(); + ctx.attachment('€ rates.pdf'); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="? rates.pdf"; filename*=UTF-8\'\'%E2%82%AC%20rates.pdf'); + }); + + describe('when "false"', function () { + it('should not generate ISO-8859-1 fallback', function () { + const ctx = context(); + ctx.attachment('£ and € rates.pdf', { fallback: false }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf'); + }); + + it('should keep ISO-8859-1 filename', function () { + const ctx = context(); + ctx.attachment('£ rates.pdf', { fallback: false }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="£ rates.pdf"'); + }); + }); + + describe('when "true"', function () { + it('should generate ISO-8859-1 fallback', function () { + const ctx = context(); + ctx.attachment('£ and € rates.pdf', { fallback: true }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="£ and ? rates.pdf"; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf'); + }); + + it('should pass through ISO-8859-1 filename', function () { + const ctx = context(); + ctx.attachment('£ rates.pdf', { fallback: true }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="£ rates.pdf"'); + }); + }) + + describe('when a string', function () { + it('should require an ISO-8859-1 string', function () { + const ctx = context(); + assert.throws(() => { ctx.attachment('€ rates.pdf', { fallback: '€ rates.pdf' }); }, + /fallback.*iso-8859-1/i); + }); + + it('should use as ISO-8859-1 fallback', function () { + const ctx = context(); + ctx.attachment('£ and € rates.pdf', { fallback: '£ and EURO rates.pdf' }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="£ and EURO rates.pdf"; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf'); + }); + + it('should use as fallback even when filename is ISO-8859-1', function () { + const ctx = context(); + ctx.attachment('"£ rates".pdf', { fallback: '£ rates.pdf' }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="£ rates.pdf"; filename*=UTF-8\'\'%22%C2%A3%20rates%22.pdf'); + }); + + it('should do nothing if equal to filename', function () { + const ctx = context(); + ctx.attachment('plans.pdf', { fallback: 'plans.pdf' }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="plans.pdf"'); + }); + + it('should use the basename of the string', function () { + const ctx = context(); + ctx.attachment('€ rates.pdf', { fallback: '/path/to/EURO rates.pdf' }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment; filename="EURO rates.pdf"; filename*=UTF-8\'\'%E2%82%AC%20rates.pdf'); + }); + + it('should do nothing without filename option', function () { + const ctx = context(); + ctx.attachment(undefined, { fallback: 'plans.pdf' }); + assert.equal(ctx.response.header['content-disposition'], + 'attachment'); + }); + }) + }) + + describe('with "type" option', function () { + it('should default to attachment', function () { + const ctx = context(); + ctx.attachment(); + assert.equal(ctx.response.header['content-disposition'], + 'attachment'); + }); + + it('should require a string', function () { + const ctx = context(); + assert.throws(() => { ctx.attachment(undefined, { type: 42 }); }, + /invalid type/); + }); + + it('should require a valid type', function () { + const ctx = context(); + assert.throws(() => { ctx.attachment(undefined, { type: 'invlaid;type' }); }, + /invalid type/); + }); + + it('should create a header with inline type', function () { + const ctx = context(); + ctx.attachment(undefined, { type: 'inline' }); + assert.equal(ctx.response.header['content-disposition'], + 'inline'); + }); + + it('should create a header with inline type & filename', function () { + const ctx = context(); + ctx.attachment('plans.pdf', { type: 'inline' }); + assert.equal(ctx.response.header['content-disposition'], + 'inline; filename="plans.pdf"'); + }); + + it('should normalize type', function () { + const ctx = context(); + ctx.attachment(undefined, { type: 'INLINE' }); + assert.equal(ctx.response.header['content-disposition'], + 'inline'); + }); + }); +}); From 3be7f61dec1bc0a786c8b6b4217f0b23d304ef1c Mon Sep 17 00:00:00 2001 From: zhangxianlei Date: Fri, 21 Sep 2018 12:29:05 +0800 Subject: [PATCH 3/4] resolve lint error --- test/response/attachment.js | 56 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/test/response/attachment.js b/test/response/attachment.js index 7c7bcb6e4..dbbc5d879 100644 --- a/test/response/attachment.js +++ b/test/response/attachment.js @@ -50,30 +50,30 @@ describe('ctx.attachment([filename])', () => { }); // reference [content-disposition test case](https://github.com/jshttp/content-disposition/blob/master/test/test.js) -describe('contentDisposition(filename, options)', function () { - describe('with "fallback" option', function () { - it('should require a string or Boolean', function () { +describe('contentDisposition(filename, options)', () => { + describe('with "fallback" option', () => { + it('should require a string or Boolean', () => { const ctx = context(); - assert.throws(() => { ctx.attachment('plans.pdf', { fallback: 42 }) }, + assert.throws(() => { ctx.attachment('plans.pdf', { fallback: 42 }); }, /fallback.*string/); }); - it('should default to true', function () { + it('should default to true', () => { const ctx = context(); ctx.attachment('€ rates.pdf'); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="? rates.pdf"; filename*=UTF-8\'\'%E2%82%AC%20rates.pdf'); }); - describe('when "false"', function () { - it('should not generate ISO-8859-1 fallback', function () { + describe('when "false"', () => { + it('should not generate ISO-8859-1 fallback', () => { const ctx = context(); ctx.attachment('£ and € rates.pdf', { fallback: false }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf'); }); - it('should keep ISO-8859-1 filename', function () { + it('should keep ISO-8859-1 filename', () => { const ctx = context(); ctx.attachment('£ rates.pdf', { fallback: false }); assert.equal(ctx.response.header['content-disposition'], @@ -81,101 +81,101 @@ describe('contentDisposition(filename, options)', function () { }); }); - describe('when "true"', function () { - it('should generate ISO-8859-1 fallback', function () { + describe('when "true"', () => { + it('should generate ISO-8859-1 fallback', () => { const ctx = context(); ctx.attachment('£ and € rates.pdf', { fallback: true }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="£ and ? rates.pdf"; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf'); }); - it('should pass through ISO-8859-1 filename', function () { + it('should pass through ISO-8859-1 filename', () => { const ctx = context(); ctx.attachment('£ rates.pdf', { fallback: true }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="£ rates.pdf"'); }); - }) + }); - describe('when a string', function () { - it('should require an ISO-8859-1 string', function () { + describe('when a string', () => { + it('should require an ISO-8859-1 string', () => { const ctx = context(); assert.throws(() => { ctx.attachment('€ rates.pdf', { fallback: '€ rates.pdf' }); }, /fallback.*iso-8859-1/i); }); - it('should use as ISO-8859-1 fallback', function () { + it('should use as ISO-8859-1 fallback', () => { const ctx = context(); ctx.attachment('£ and € rates.pdf', { fallback: '£ and EURO rates.pdf' }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="£ and EURO rates.pdf"; filename*=UTF-8\'\'%C2%A3%20and%20%E2%82%AC%20rates.pdf'); }); - it('should use as fallback even when filename is ISO-8859-1', function () { + it('should use as fallback even when filename is ISO-8859-1', () => { const ctx = context(); ctx.attachment('"£ rates".pdf', { fallback: '£ rates.pdf' }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="£ rates.pdf"; filename*=UTF-8\'\'%22%C2%A3%20rates%22.pdf'); }); - it('should do nothing if equal to filename', function () { + it('should do nothing if equal to filename', () => { const ctx = context(); ctx.attachment('plans.pdf', { fallback: 'plans.pdf' }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="plans.pdf"'); }); - it('should use the basename of the string', function () { + it('should use the basename of the string', () => { const ctx = context(); ctx.attachment('€ rates.pdf', { fallback: '/path/to/EURO rates.pdf' }); assert.equal(ctx.response.header['content-disposition'], 'attachment; filename="EURO rates.pdf"; filename*=UTF-8\'\'%E2%82%AC%20rates.pdf'); }); - it('should do nothing without filename option', function () { + it('should do nothing without filename option', () => { const ctx = context(); ctx.attachment(undefined, { fallback: 'plans.pdf' }); assert.equal(ctx.response.header['content-disposition'], 'attachment'); }); - }) - }) + }); + }); - describe('with "type" option', function () { - it('should default to attachment', function () { + describe('with "type" option', () => { + it('should default to attachment', () => { const ctx = context(); ctx.attachment(); assert.equal(ctx.response.header['content-disposition'], 'attachment'); }); - it('should require a string', function () { + it('should require a string', () => { const ctx = context(); assert.throws(() => { ctx.attachment(undefined, { type: 42 }); }, /invalid type/); }); - it('should require a valid type', function () { + it('should require a valid type', () => { const ctx = context(); assert.throws(() => { ctx.attachment(undefined, { type: 'invlaid;type' }); }, /invalid type/); }); - it('should create a header with inline type', function () { + it('should create a header with inline type', () => { const ctx = context(); ctx.attachment(undefined, { type: 'inline' }); assert.equal(ctx.response.header['content-disposition'], 'inline'); }); - it('should create a header with inline type & filename', function () { + it('should create a header with inline type & filename', () => { const ctx = context(); ctx.attachment('plans.pdf', { type: 'inline' }); assert.equal(ctx.response.header['content-disposition'], 'inline; filename="plans.pdf"'); }); - it('should normalize type', function () { + it('should normalize type', () => { const ctx = context(); ctx.attachment(undefined, { type: 'INLINE' }); assert.equal(ctx.response.header['content-disposition'], From c3eb7e49a7617fa939f43f35380e02dcc294a5d8 Mon Sep 17 00:00:00 2001 From: zhangxianlei <863837949@qq.com> Date: Mon, 24 Sep 2018 20:01:31 +0800 Subject: [PATCH 4/4] modify comment and docs. --- docs/api/response.md | 4 ++-- test/response/attachment.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/response.md b/docs/api/response.md index c535e3b49..602bc1487 100644 --- a/docs/api/response.md +++ b/docs/api/response.md @@ -271,11 +271,11 @@ ctx.redirect('/cart'); ctx.body = 'Redirecting to shopping cart'; ``` -### response.attachment([filename]) +### response.attachment([filename], [options]) Set `Content-Disposition` to "attachment" to signal the client to prompt for download. Optionally specify the `filename` of the - download. + download and some [options](https://github.com/jshttp/content-disposition#options). ### response.headerSent diff --git a/test/response/attachment.js b/test/response/attachment.js index dbbc5d879..7ee16bdd6 100644 --- a/test/response/attachment.js +++ b/test/response/attachment.js @@ -49,7 +49,7 @@ describe('ctx.attachment([filename])', () => { }); }); -// reference [content-disposition test case](https://github.com/jshttp/content-disposition/blob/master/test/test.js) +// reference test case of content-disposition module describe('contentDisposition(filename, options)', () => { describe('with "fallback" option', () => { it('should require a string or Boolean', () => {